我正在尝试使用 Windows api cng 的 Bcrypt 库对缓冲区进行 RSA 加密。但是我第一次打电话给
BCryptDecrypt
失败了 STATUS_INVALID_PARAMETER
...
status = BCryptDecrypt(
hKey,
pbEncryptedBuffer,
cbEncryptedBuffer,
NULL,
NULL,
0,
NULL,
0,
pcbDecryptedBuffer,
BCRYPT_PAD_PKCS1);
我看了这些例子:
如何使用BCrypt进行RSA(非对称加密)
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/007a0e26-7fc0-4079-9b63-2ad23f866836/bug-in-rsa-encryptiondecryption-using-cng?forum=windowssdk
考虑到我需要填充。但是,如果我删除
BCRYPT_PAD_PKCS1
参数,那么第一次调用 BCryptDecrypt
就会成功。然后,无论 BCryptDecrypt
标志是否存在,第二次调用 STATUS_INVALID_PARAMETER
都会失败并显示 BCRYPT_PAD_PKCS1
。
下面是完整代码:
#include <windows.h>
#include <bcrypt.h>
#include <winternl.h>
#include <stdio.h>
#pragma comment(lib, "Bcrypt.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
BOOL Encrypt(PBYTE pbPrivKey, DWORD cbPrivKey, PBYTE pbInputData, DWORD cbInputData,
BYTE** ppbEncryptedBuffer, PDWORD pcbEncryptedBuffer)
{
BOOL bRet = TRUE;
NTSTATUS status = STATUS_UNSUCCESSFUL;
BCRYPT_ALG_HANDLE hAlgorithm = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
///
// Open provider.
///
status = BCryptOpenAlgorithmProvider(
&hAlgorithm,
BCRYPT_RSA_ALGORITHM,
NULL,
0);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
///
// Import private key.
///
status = BCryptImportKeyPair(hAlgorithm,
NULL,
BCRYPT_RSAPRIVATE_BLOB,
&hKey,
pbPrivKey,
cbPrivKey,
BCRYPT_NO_KEY_VALIDATION);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
///
// Get encrypted buffer size.
///
status = BCryptEncrypt(
hKey,
pbInputData,
cbInputData,
NULL,
NULL,
0,
NULL,
0,
pcbEncryptedBuffer,
BCRYPT_PAD_PKCS1);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
///
// Encrypt buffer.
///
*ppbEncryptedBuffer = HeapAlloc(GetProcessHeap(), 0, *pcbEncryptedBuffer);
if (*ppbEncryptedBuffer == NULL)
{
wprintf(L"**** Error 0x%x returned by HeapAlloc\n", GetLastError());
bRet = FALSE;
goto LBL_CLEANUP;
}
status = BCryptEncrypt(hKey,
pbInputData,
cbInputData,
NULL,
NULL,
0,
*ppbEncryptedBuffer,
*pcbEncryptedBuffer,
pcbEncryptedBuffer,
BCRYPT_PAD_PKCS1);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
LBL_CLEANUP:
if (hAlgorithm)
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
if (hKey)
BCryptDestroyKey(hKey);
return bRet;
}
BOOL Decrypt(PBYTE pbPubKey, DWORD cbPubKey, PBYTE pbEncryptedBuffer, DWORD cbEncryptedBuffer,
BYTE** ppbDecryptedBuffer, PDWORD pcbDecryptedBuffer)
{
BOOL bRet = TRUE;
NTSTATUS status = STATUS_UNSUCCESSFUL;
BCRYPT_ALG_HANDLE hAlgorithm = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
///
// Open provider.
///
status = BCryptOpenAlgorithmProvider(
&hAlgorithm,
BCRYPT_RSA_ALGORITHM,
NULL,
0);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
///
// Import public key.
///
status = BCryptImportKeyPair(hAlgorithm,
NULL,
BCRYPT_RSAPUBLIC_BLOB,
&hKey,
pbPubKey,
cbPubKey,
BCRYPT_NO_KEY_VALIDATION);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
///
// Get decrypted buffer size.
///
status = BCryptDecrypt(
hKey,
pbEncryptedBuffer,
cbEncryptedBuffer,
NULL,
NULL,
0,
NULL,
0,
pcbDecryptedBuffer,
BCRYPT_PAD_PKCS1);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptDecrypt\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
///
// Decrypt buffer.
///
*ppbDecryptedBuffer = HeapAlloc(GetProcessHeap(), 0, *pcbDecryptedBuffer);
if (*ppbDecryptedBuffer == NULL)
{
wprintf(L"**** Error 0x%x returned by HeapAlloc\n", GetLastError());
bRet = FALSE;
goto LBL_CLEANUP;
}
status = BCryptDecrypt(
hKey,
pbEncryptedBuffer,
cbEncryptedBuffer,
NULL,
NULL,
0,
*ppbDecryptedBuffer,
*pcbDecryptedBuffer,
pcbDecryptedBuffer,
BCRYPT_PAD_PKCS1);
if (!NT_SUCCESS(status))
{
wprintf(L"**** Error 0x%x returned by BCryptDecrypt\n", status);
bRet = FALSE;
goto LBL_CLEANUP;
}
LBL_CLEANUP:
if (hAlgorithm)
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
if (hKey)
BCryptDestroyKey(hKey);
return bRet;
}
BYTE PubKey[91] = {
0x52, 0x53, 0x41, 0x31, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0xD5, 0x0F, 0xFD, 0x75, 0xA3, 0xDC, 0xCD, 0xCA, 0xC1,
0x38, 0xBB, 0x3A, 0x8F, 0x6F, 0xC5, 0x53, 0xF7, 0xAC, 0x29, 0x5E, 0x14,
0xF5, 0x95, 0xA1, 0x76, 0xAA, 0xD0, 0xAB, 0xAA, 0x4E, 0x02, 0xFE, 0x28,
0xF5, 0xE0, 0xD7, 0xAC, 0x2E, 0x23, 0x5B, 0x20, 0x53, 0x22, 0x0D, 0x78,
0x33, 0x2B, 0x05, 0x93, 0xF7, 0xD2, 0x28, 0x24, 0xD4, 0x48, 0xC5, 0xEE,
0x1B, 0xE7, 0x41, 0x2E, 0x1A, 0x05, 0x7D
};
BYTE PrivKey[155] = {
0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0xD5, 0x0F, 0xFD, 0x75, 0xA3, 0xDC, 0xCD, 0xCA, 0xC1,
0x38, 0xBB, 0x3A, 0x8F, 0x6F, 0xC5, 0x53, 0xF7, 0xAC, 0x29, 0x5E, 0x14,
0xF5, 0x95, 0xA1, 0x76, 0xAA, 0xD0, 0xAB, 0xAA, 0x4E, 0x02, 0xFE, 0x28,
0xF5, 0xE0, 0xD7, 0xAC, 0x2E, 0x23, 0x5B, 0x20, 0x53, 0x22, 0x0D, 0x78,
0x33, 0x2B, 0x05, 0x93, 0xF7, 0xD2, 0x28, 0x24, 0xD4, 0x48, 0xC5, 0xEE,
0x1B, 0xE7, 0x41, 0x2E, 0x1A, 0x05, 0x7D, 0xF3, 0x4A, 0xE4, 0x0A, 0xF6,
0xCA, 0xBC, 0xB6, 0xE2, 0x10, 0xF3, 0x9F, 0x8D, 0x3B, 0x07, 0x7D, 0x83,
0x59, 0x51, 0xAA, 0x3C, 0xBA, 0x89, 0x2C, 0xCF, 0x69, 0x29, 0x8D, 0x96,
0x2C, 0x80, 0x67, 0xE0, 0x30, 0xE3, 0x27, 0xDC, 0x2C, 0x85, 0xF3, 0x8B,
0x47, 0xB0, 0x10, 0xC2, 0x49, 0x09, 0x14, 0x15, 0x47, 0x90, 0xAF, 0x5C,
0xF1, 0x3D, 0x4C, 0x6D, 0x88, 0xAB, 0x98, 0x7B, 0x80, 0x8C, 0x7B
};
BYTE Msg[10] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A };
int main()
{
BOOL bRet = TRUE;
PBYTE pbEncryptedMessage = NULL;
DWORD cbEncryptedMessage = 0;
PBYTE pbDecryptedMessage = NULL;
DWORD cbDecryptedMessage = 0;
bRet = Encrypt(
PrivKey,
sizeof(PrivKey),
Msg,
sizeof(Msg),
&pbEncryptedMessage,
&cbEncryptedMessage);
if (bRet == FALSE)
{
wprintf(L"**** Error FALSE returned by Encrypt\n");
goto LBL_CLEANUP;
}
wprintf(L"Encryption Success!\n");
bRet = Decrypt(
PubKey,
sizeof(PubKey),
pbEncryptedMessage,
cbEncryptedMessage,
&pbDecryptedMessage,
&cbDecryptedMessage);
if (bRet == FALSE)
{
wprintf(L"**** Error FALSE returned by Decrypt\n");
goto LBL_CLEANUP;
}
wprintf(L"Decryption Success!\n");
LBL_CLEANUP:
if (pbEncryptedMessage)
HeapFree(GetProcessHeap(), 0, pbEncryptedMessage);
if (pbDecryptedMessage)
HeapFree(GetProcessHeap(), 0, pbDecryptedMessage);
}```
我看不懂,我回答了两次这个问题,每次我的评论都被版主删除了。如果您是版主,请在删除之前添加评论说明您认为我的答案不正确的原因。 我再次复制答案,因为我确定它是正确的。
问候,
米歇尔·特里斯 当然你可以删除这个
NCryptDecrypt
无法解密缓冲区时返回STATUS_INVALID_PARAMETER
;这并不意味着您的参数无效。
在您的情况下,您使用私钥加密并使用公钥解密。尝试相反的方法,它会起作用。
这是发生了什么:私钥的句柄实际上知道私钥和公钥,如果您使用它来加密,则使用公钥而不是预期的私钥。只需测试一下:获取应该只是私钥的句柄,并使用相同的句柄解密,它可以工作。它已使用公钥加密并使用私钥解密。