英文:
BCryptDecrypt failes with STATUS_INVALID_PARAMETER
问题
我尝试使用Windows API的CNG的Bcrypt库对缓冲区进行RSA加密,但我的第一次调用BCryptDecrypt
失败,返回STATUS_INVALID_PARAMETER
...
status = BCryptDecrypt(
hKey,
pbEncryptedBuffer,
cbEncryptedBuffer,
NULL,
NULL,
0,
NULL,
0,
pcbDecryptedBuffer,
BCRYPT_PAD_PKCS1);
我查看了以下示例:
https://stackoverflow.com/questions/58419870/how-to-use-bcrypt-for-rsa-asymmetric-encryption
考虑到我需要填充,但如果我删除BCRYPT_PAD_PKCS1
参数,第一次调用BCryptDecrypt
会成功。然后无论BCRYPT_PAD_PKCS1
标志是否存在,第二次调用BCryptDecrypt
都会失败。
以下是完整的代码:
#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 Decrypt(PBYTE pbPubKey, DWORD cbPubKey, PBYTE pbEncryptedBuffer, DWORD cbEncryptedBuffer,
BYTE** ppbDecryptedBuffer, PDWORD pcbDecryptedBuffer)
{
// ... (省略了函数内容以节省空间)
}
// PubKey 和 PrivKey 以及 Msg 的定义被省略
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);
}
希望这对你有所帮助。
英文:
I am trying to RSA encrypt an buffer using Windows api cng's Bcrypt library. But my first call to BCryptDecrypt
failes with STATUS_INVALID_PARAMETER
...
status = BCryptDecrypt(
hKey,
pbEncryptedBuffer,
cbEncryptedBuffer,
NULL,
NULL,
0,
NULL,
0,
pcbDecryptedBuffer,
BCRYPT_PAD_PKCS1);
I looked at these examples:
https://stackoverflow.com/questions/58419870/how-to-use-bcrypt-for-rsa-asymmetric-encryption
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/007a0e26-7fc0-4079-9b63-2ad23f866836/bug-in-rsa-encryptiondecryption-using-cng?forum=windowssdk
Taking in account that I would require padding. But if I remove the BCRYPT_PAD_PKCS1
parameter the first call to BCryptDecrypt
is successful. Then the second call to BCryptDecrypt
would fail with STATUS_INVALID_PARAMETER
regardless if the BCRYPT_PAD_PKCS1
flag is present or not.
Bellow is the full code:
#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);
}```
</details>
# 答案1
**得分**: 1
`NCryptDecrypt` 在无法解密缓冲区时返回 `STATUS_INVALID_PARAMETER`;这并不意味着您的参数无效。
在您的情况下,您使用私钥加密,然后使用公钥解密。尝试反过来操作,它会起作用。
发生了什么事情是这样的:对于私钥的句柄实际上知道私钥和公钥,如果您使用它进行加密,实际上使用的是公钥,而不是预期的私钥。只需测试一下:获取句柄以获取实际上应该是私钥的内容,然后使用相同的句柄进行解密,它会起作用。它已经使用公钥进行加密,并使用私钥进行解密。
<details>
<summary>英文:</summary>
`NCryptDecrypt` returns `STATUS_INVALID_PARAMETER` when it can't decrypt the buffer; this doesn't mean that your parameters are invalid.
In your case, you encrypt with the private key and decrypt with the public key. Try the opposite and it will work.
Here is what happens: a handle to a private key knows in fact both the private key and the public key and if you use it to encrypt, the public key is used and not the private key as expected. Just test it: get the handle to what is supposed to be just the private key, and decrypt using the same handle, it works. It has encrypted with the public key and decrypted with the private key.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论