Commit 5e2075be authored by Michael Jung's avatar Michael Jung Committed by Alexandre Julliard

Moved PKCS1 #2 un-/padding from Import-/ExportKey to helper

functions. Support RSA en-/decryption via CPEncrypt and CPDecrypt. Added test case for RSA en-/decryption.
parent d56ccaa7
...@@ -744,6 +744,8 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK ...@@ -744,6 +744,8 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK
DWORD dwKeyLen = HIWORD(dwFlags); DWORD dwKeyLen = HIWORD(dwFlags);
const PROV_ENUMALGS_EX *peaAlgidInfo; const PROV_ENUMALGS_EX *peaAlgidInfo;
*ppCryptKey = NULL;
/* /*
* Retrieve the CSP's capabilities for the given ALG_ID value * Retrieve the CSP's capabilities for the given ALG_ID value
*/ */
...@@ -1275,6 +1277,84 @@ exit: ...@@ -1275,6 +1277,84 @@ exit:
} }
/****************************************************************************** /******************************************************************************
* pad_data [Internal]
*
* Helper function for data padding according to PKCS1 #2
*
* PARAMS
* abData [I] The data to be padded
* dwDataLen [I] Length of the data
* abBuffer [O] Padded data will be stored here
* dwBufferLen [I] Length of the buffer (also length of padded data)
* dwFlags [I] Padding format (CRYPT_SSL2_FALLBACK)
*
* RETURN
* Success: TRUE
* Failure: FALSE (NTE_BAD_LEN, too much data to pad)
*/
static BOOL pad_data(CONST BYTE *abData, DWORD dwDataLen, BYTE *abBuffer, DWORD dwBufferLen,
DWORD dwFlags)
{
DWORD i;
/* Ensure there is enough space for PKCS1 #2 padding */
if (dwDataLen > dwBufferLen-11) {
SetLastError(NTE_BAD_LEN);
return FALSE;
}
memmove(abBuffer + dwBufferLen - dwDataLen, abData, dwDataLen);
abBuffer[0] = 0x00;
abBuffer[1] = RSAENH_PKC_BLOCKTYPE;
for (i=2; i < dwBufferLen - dwDataLen - 1; i++)
do gen_rand_impl(&abBuffer[i], 1); while (!abBuffer[i]);
if (dwFlags & CRYPT_SSL2_FALLBACK)
for (i-=8; i < dwBufferLen - dwDataLen - 1; i++)
abBuffer[i] = 0x03;
abBuffer[i] = 0x00;
return TRUE;
}
/******************************************************************************
* unpad_data [Internal]
*
* Remove the PKCS1 padding from RSA decrypted data
*
* PARAMS
* abData [I] The padded data
* dwDataLen [I] Length of the padded data
* abBuffer [O] Data without padding will be stored here
* dwBufferLen [I/O] I: Length of the buffer, O: Length of unpadded data
* dwFlags [I] Currently none defined
*
* RETURNS
* Success: TRUE
* Failure: FALSE, (NTE_BAD_DATA, no valid PKCS1 padding or buffer too small)
*/
static BOOL unpad_data(CONST BYTE *abData, DWORD dwDataLen, BYTE *abBuffer, DWORD *dwBufferLen,
DWORD dwFlags)
{
DWORD i;
for (i=2; i<dwDataLen; i++)
if (!abData[i])
break;
if ((i == dwDataLen) || (*dwBufferLen < dwDataLen - i - 1) ||
(abData[0] != 0x00) || (abData[1] != RSAENH_PKC_BLOCKTYPE))
{
SetLastError(NTE_BAD_DATA);
return FALSE;
}
*dwBufferLen = dwDataLen - i - 1;
memmove(abBuffer, abData + i + 1, *dwBufferLen);
return TRUE;
}
/******************************************************************************
* CPAcquireContext (RSAENH.@) * CPAcquireContext (RSAENH.@)
* *
* Acquire a handle to the key container specified by pszContainer * Acquire a handle to the key container specified by pszContainer
...@@ -1719,11 +1799,6 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, ...@@ -1719,11 +1799,6 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash,
return FALSE; return FALSE;
} }
if (GET_ALG_CLASS(pCryptKey->aiAlgid) != ALG_CLASS_DATA_ENCRYPT) {
SetLastError(NTE_BAD_TYPE);
return FALSE;
}
if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE)
pCryptKey->dwState = RSAENH_KEYSTATE_ENCRYPTING; pCryptKey->dwState = RSAENH_KEYSTATE_ENCRYPTING;
...@@ -1786,6 +1861,22 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, ...@@ -1786,6 +1861,22 @@ BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash,
} }
} else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) { } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) {
encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen); encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen);
} else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_RSA) {
if (pCryptKey->aiAlgid == CALG_RSA_SIGN) {
SetLastError(NTE_BAD_KEY);
return FALSE;
}
if (dwBufLen < pCryptKey->dwBlockLen) {
SetLastError(ERROR_MORE_DATA);
return FALSE;
}
if (!pad_data(pbData, *pdwDataLen, pbData, pCryptKey->dwBlockLen, dwFlags)) return FALSE;
encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, pbData, RSAENH_ENCRYPT);
*pdwDataLen = pCryptKey->dwBlockLen;
Final = TRUE;
} else {
SetLastError(NTE_BAD_TYPE);
return FALSE;
} }
if (Final) setup_key(pCryptKey); if (Final) setup_key(pCryptKey);
...@@ -1845,11 +1936,6 @@ BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, ...@@ -1845,11 +1936,6 @@ BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash,
return FALSE; return FALSE;
} }
if (GET_ALG_CLASS(pCryptKey->aiAlgid) != ALG_CLASS_DATA_ENCRYPT) {
SetLastError(NTE_BAD_TYPE);
return FALSE;
}
if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE)
pCryptKey->dwState = RSAENH_KEYSTATE_DECRYPTING; pCryptKey->dwState = RSAENH_KEYSTATE_DECRYPTING;
...@@ -1896,8 +1982,18 @@ BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, ...@@ -1896,8 +1982,18 @@ BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash,
} else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) { } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) {
encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen); encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen);
} else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_RSA) { } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_RSA) {
if (pCryptKey->aiAlgid == CALG_RSA_SIGN) {
SetLastError(NTE_BAD_KEY);
return FALSE;
}
encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, pbData, RSAENH_DECRYPT); encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, pbData, RSAENH_DECRYPT);
} if (!unpad_data(pbData, pCryptKey->dwBlockLen, pbData, pdwDataLen, dwFlags)) return FALSE;
Final = TRUE;
} else {
SetLastError(NTE_BAD_TYPE);
return FALSE;
}
if (Final) setup_key(pCryptKey); if (Final) setup_key(pCryptKey);
if (is_valid_handle(&handle_table, hHash, RSAENH_MAGIC_HASH)) { if (is_valid_handle(&handle_table, hHash, RSAENH_MAGIC_HASH)) {
...@@ -1932,8 +2028,7 @@ BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubK ...@@ -1932,8 +2028,7 @@ BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubK
BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData; BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1); RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1);
ALG_ID *pAlgid = (ALG_ID*)(pBlobHeader+1); ALG_ID *pAlgid = (ALG_ID*)(pBlobHeader+1);
DWORD dwDataLen, i; DWORD dwDataLen;
BYTE *pbRawData;
TRACE("(hProv=%08lx, hKey=%08lx, hPubKey=%08lx, dwBlobType=%08lx, dwFlags=%08lx, pbData=%p," TRACE("(hProv=%08lx, hKey=%08lx, hPubKey=%08lx, dwBlobType=%08lx, dwFlags=%08lx, pbData=%p,"
"pdwDataLen=%p)\n", hProv, hKey, hPubKey, dwBlobType, dwFlags, pbData, pdwDataLen); "pdwDataLen=%p)\n", hProv, hKey, hPubKey, dwBlobType, dwFlags, pbData, pdwDataLen);
...@@ -1984,22 +2079,15 @@ BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubK ...@@ -1984,22 +2079,15 @@ BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubK
pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid; pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
*pAlgid = pPubKey->aiAlgid; *pAlgid = pPubKey->aiAlgid;
pbRawData = (BYTE*)(pAlgid+1); if (!pad_data(pCryptKey->abKeyValue, pCryptKey->dwKeyLen, (BYTE*)(pAlgid+1),
pbRawData[0] = 0x00; pPubKey->dwBlockLen, dwFlags))
pbRawData[1] = RSAENH_PKC_BLOCKTYPE; {
for (i=2; i < pPubKey->dwBlockLen - pCryptKey->dwKeyLen - 1; i++) return FALSE;
do gen_rand_impl(&pbRawData[i], 1); while (!pbRawData[i]); }
if (dwFlags & CRYPT_SSL2_FALLBACK)
for (i-=8; i < pPubKey->dwBlockLen - pCryptKey->dwKeyLen - 1; i++) encrypt_block_impl(pPubKey->aiAlgid, &pPubKey->context, (BYTE*)(pAlgid+1),
pbRawData[i] = 0x03; (BYTE*)(pAlgid+1), RSAENH_ENCRYPT);
pbRawData[i] = 0x00;
for (i=0; i<pCryptKey->dwKeyLen; i++)
pbRawData[pPubKey->dwBlockLen - pCryptKey->dwKeyLen + i] =
pCryptKey->abKeyValue[i];
encrypt_block_impl(pPubKey->aiAlgid, &pPubKey->context, pbRawData, pbRawData,
RSAENH_ENCRYPT);
} }
*pdwDataLen = dwDataLen; *pdwDataLen = dwDataLen;
return TRUE; return TRUE;
...@@ -2098,7 +2186,7 @@ BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDat ...@@ -2098,7 +2186,7 @@ BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDat
CONST ALG_ID *pAlgid = (CONST ALG_ID*)(pBlobHeader+1); CONST ALG_ID *pAlgid = (CONST ALG_ID*)(pBlobHeader+1);
CONST BYTE *pbKeyStream = (CONST BYTE*)(pAlgid + 1); CONST BYTE *pbKeyStream = (CONST BYTE*)(pAlgid + 1);
BYTE *pbDecrypted; BYTE *pbDecrypted;
DWORD dwKeyLen, i; DWORD dwKeyLen;
TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%ld, hPubKey=%08lx, dwFlags=%08lx, phKey=%p)\n", TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%ld, hPubKey=%08lx, dwFlags=%08lx, phKey=%p)\n",
hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey); hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
...@@ -2169,24 +2257,19 @@ BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDat ...@@ -2169,24 +2257,19 @@ BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDat
encrypt_block_impl(pPubKey->aiAlgid, &pPubKey->context, pbKeyStream, pbDecrypted, encrypt_block_impl(pPubKey->aiAlgid, &pPubKey->context, pbKeyStream, pbDecrypted,
RSAENH_DECRYPT); RSAENH_DECRYPT);
for (i=2; i<pPubKey->dwBlockLen && pbDecrypted[i]; i++); dwKeyLen = RSAENH_MAX_KEY_SIZE;
if ((i==pPubKey->dwBlockLen) || if (!unpad_data(pbDecrypted, pPubKey->dwBlockLen, pbDecrypted, &dwKeyLen, dwFlags)) {
(pbDecrypted[0] != 0x00) ||
(pbDecrypted[1] != RSAENH_PKC_BLOCKTYPE))
{
HeapFree(GetProcessHeap(), 0, pbDecrypted); HeapFree(GetProcessHeap(), 0, pbDecrypted);
SetLastError(NTE_BAD_DATA); /* FIXME: error code */
return FALSE; return FALSE;
} }
dwKeyLen = pPubKey->dwBlockLen-i-1;
*phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey); *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey);
if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
{ {
HeapFree(GetProcessHeap(), 0, pbDecrypted); HeapFree(GetProcessHeap(), 0, pbDecrypted);
return FALSE; return FALSE;
} }
memcpy(pCryptKey->abKeyValue, pbDecrypted+i+1, dwKeyLen); memcpy(pCryptKey->abKeyValue, pbDecrypted, dwKeyLen);
HeapFree(GetProcessHeap(), 0, pbDecrypted); HeapFree(GetProcessHeap(), 0, pbDecrypted);
setup_key(pCryptKey); setup_key(pCryptKey);
return TRUE; return TRUE;
......
...@@ -83,7 +83,7 @@ static void clean_up_environment(void) ...@@ -83,7 +83,7 @@ static void clean_up_environment(void)
result = CryptReleaseContext(hProv, 1); result = CryptReleaseContext(hProv, 1);
ok(!result && GetLastError()==NTE_BAD_FLAGS, "%08lx\n", GetLastError()); ok(!result && GetLastError()==NTE_BAD_FLAGS, "%08lx\n", GetLastError());
CryptAcquireContext(&hProv, szContainer, szProvider, PROV_RSA_FULL, CRYPT_DELETEKEYSET); CryptAcquireContext(&hProv, szContainer, szProvider, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
} }
...@@ -1085,6 +1085,40 @@ static void test_verify_signature() { ...@@ -1085,6 +1085,40 @@ static void test_verify_signature() {
if (!result) return; if (!result) return;
} }
void test_rsa_encrypt()
{
HCRYPTKEY hRSAKey;
BYTE abData[2048] = "Wine rocks!";
BOOL result;
DWORD dwLen;
/* It is allowed to use the key exchange key for encryption/decryption */
result = CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hRSAKey);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
dwLen = 12;
result = CryptEncrypt(hRSAKey, 0, TRUE, 0, abData, &dwLen, (DWORD)sizeof(abData));
ok (result, "%08lx\n", GetLastError());
if (!result) return;
result = CryptDecrypt(hRSAKey, 0, TRUE, 0, abData, &dwLen);
ok (result && dwLen == 12 && !memcmp(abData, "Wine rocks!", 12), "%08lx\n", GetLastError());
CryptDestroyKey(hRSAKey);
/* It is not allowed to use the signature key for encryption/decryption */
result = CryptGetUserKey(hProv, AT_SIGNATURE, &hRSAKey);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
dwLen = 12;
result = CryptEncrypt(hRSAKey, 0, TRUE, 0, abData, &dwLen, (DWORD)sizeof(abData));
ok (!result && GetLastError() == NTE_BAD_KEY, "%08lx\n", GetLastError());
CryptDestroyKey(hRSAKey);
}
void test_schannel_provider() void test_schannel_provider()
{ {
HCRYPTPROV hProv; HCRYPTPROV hProv;
...@@ -1349,6 +1383,7 @@ START_TEST(rsaenh) ...@@ -1349,6 +1383,7 @@ START_TEST(rsaenh)
test_block_cipher_modes(); test_block_cipher_modes();
test_import_private(); test_import_private();
test_verify_signature(); test_verify_signature();
test_rsa_encrypt();
clean_up_environment(); clean_up_environment();
test_schannel_provider(); test_schannel_provider();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment