windows 中的 rsa 加密和 openssl 中的解密
rsa encryption in windows crypto and decryption in openssl
我在 "OpenSSL" 和 "Windows CryptoAPI" 之间交换 public 密钥时遇到问题。 public 密钥是从 pem 中的 OpenSSL 导出的 format.My 程序是用 C++ 编写的。我得到 public 密钥并通过 "CryptoAPI" 加载它。加载 public 密钥后,我加密了一些数据并将它们发送到其他应用程序。其他应用程序无法通过自己的私钥解密接收到的数据。请帮助我找到解决方案。
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcJXxao6OzesjaM5VnsYTnHWUN
z8dosWEETARH6NOqq+hAoMscsv+2MgT0oOYKLf/c8i37YFXnswEan78QnWYO3jtX
UHfJgXcLcMz7o3lX3OwNqRXgXW6Db95EjPEnLuPCJ2Pafu9E75ZMglkgw9MrIAik
XKL9u2dc9fkbc7FptQIDAQAB
-----END PUBLIC KEY-----
源代码:
_ServerContextHandle = NULL;
_EncryptionKeyHandle = NULL;
void Initialize(char* inPublicKeyByPemFormat)
{
HCRYPTPROV serverContextHandle;
bool result = CryptAcquireContextW(&serverContextHandle, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == TRUE;
if (result)
{
_ServerContextHandle = serverContextHandle;
byte derPublicKey[2048];
DWORD derPublicKeyLength = 2048;
result = CryptStringToBinaryA(inPublicKeyByPemFormat, 0, CRYPT_STRING_BASE64HEADER, derPublicKey, &derPublicKeyLength, nullptr, nullptr) == TRUE;
CERT_PUBLIC_KEY_INFO* publicKeyInfo = nullptr;
DWORD publicKeyInfoLength;
if(result)
{
result = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPublicKey, derPublicKeyLength, CRYPT_ENCODE_ALLOC_FLAG, nullptr, &publicKeyInfo, &publicKeyInfoLength) == TRUE;
}
HCRYPTKEY encryptionKeyHandle;
if(result)
{
result = CryptImportPublicKeyInfo(_ServerContextHandle, X509_ASN_ENCODING, publicKeyInfo, &encryptionKeyHandle) == TRUE;
}
LocalFree(publicKeyInfo);
if (result)
{
_EncryptionKeyHandle = encryptionKeyHandle;
}
}
}
byte* EncryptData(byte* inData, DWORD inDataLength, DWORD* outLength) const
{
byte* result = nullptr;
*outLength = 0;
DWORD length = inDataLength;
result = CloneByteArray(inData, inDataLength);
if (!CryptEncrypt(_EncryptionKeyHandle, NULL, TRUE, 0, result, &length, length))
{
delet result;
result = new byte[length];
CopyByteArray(inData, result, inDataLength);
*outLength = inDataLength;
if (!CryptEncrypt(_EncryptionKeyHandle, NULL, TRUE, 0, result, outLength, length))
{
delete result;
result = nullptr;
*outLength = 0;
}
}
else
{
*outLength = length;
}
return result;
}
CryptEncrypt
,出于当时可能对作者有意义的原因,将字节向后写。或者,更确切地说,它以字节 minor/little-endian 顺序写入它们,而几乎所有其他密码库(包括 Windows CNG BCryptEncrypt
和 NCryptEncrypt
例程)都以字节 [=29] 写入它们=]订单。
因此您需要反转来自 CryptEncrypt
的数据,并将其反转进入 CryptDecrypt
。
例如,在 .NET Core 的 RSACryptoServiceProvider.Encrypt it calls CapiHelper.EncryptKey 中调用 CryptEncrypt
然后 Array.Reverse
返回之前。
CryptEncrypt documentation已作为备注部分的最后一句
The ciphertext is returned in little-endian format.
我在 "OpenSSL" 和 "Windows CryptoAPI" 之间交换 public 密钥时遇到问题。 public 密钥是从 pem 中的 OpenSSL 导出的 format.My 程序是用 C++ 编写的。我得到 public 密钥并通过 "CryptoAPI" 加载它。加载 public 密钥后,我加密了一些数据并将它们发送到其他应用程序。其他应用程序无法通过自己的私钥解密接收到的数据。请帮助我找到解决方案。
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcJXxao6OzesjaM5VnsYTnHWUN
z8dosWEETARH6NOqq+hAoMscsv+2MgT0oOYKLf/c8i37YFXnswEan78QnWYO3jtX
UHfJgXcLcMz7o3lX3OwNqRXgXW6Db95EjPEnLuPCJ2Pafu9E75ZMglkgw9MrIAik
XKL9u2dc9fkbc7FptQIDAQAB
-----END PUBLIC KEY-----
源代码:
_ServerContextHandle = NULL;
_EncryptionKeyHandle = NULL;
void Initialize(char* inPublicKeyByPemFormat)
{
HCRYPTPROV serverContextHandle;
bool result = CryptAcquireContextW(&serverContextHandle, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == TRUE;
if (result)
{
_ServerContextHandle = serverContextHandle;
byte derPublicKey[2048];
DWORD derPublicKeyLength = 2048;
result = CryptStringToBinaryA(inPublicKeyByPemFormat, 0, CRYPT_STRING_BASE64HEADER, derPublicKey, &derPublicKeyLength, nullptr, nullptr) == TRUE;
CERT_PUBLIC_KEY_INFO* publicKeyInfo = nullptr;
DWORD publicKeyInfoLength;
if(result)
{
result = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPublicKey, derPublicKeyLength, CRYPT_ENCODE_ALLOC_FLAG, nullptr, &publicKeyInfo, &publicKeyInfoLength) == TRUE;
}
HCRYPTKEY encryptionKeyHandle;
if(result)
{
result = CryptImportPublicKeyInfo(_ServerContextHandle, X509_ASN_ENCODING, publicKeyInfo, &encryptionKeyHandle) == TRUE;
}
LocalFree(publicKeyInfo);
if (result)
{
_EncryptionKeyHandle = encryptionKeyHandle;
}
}
}
byte* EncryptData(byte* inData, DWORD inDataLength, DWORD* outLength) const
{
byte* result = nullptr;
*outLength = 0;
DWORD length = inDataLength;
result = CloneByteArray(inData, inDataLength);
if (!CryptEncrypt(_EncryptionKeyHandle, NULL, TRUE, 0, result, &length, length))
{
delet result;
result = new byte[length];
CopyByteArray(inData, result, inDataLength);
*outLength = inDataLength;
if (!CryptEncrypt(_EncryptionKeyHandle, NULL, TRUE, 0, result, outLength, length))
{
delete result;
result = nullptr;
*outLength = 0;
}
}
else
{
*outLength = length;
}
return result;
}
CryptEncrypt
,出于当时可能对作者有意义的原因,将字节向后写。或者,更确切地说,它以字节 minor/little-endian 顺序写入它们,而几乎所有其他密码库(包括 Windows CNG BCryptEncrypt
和 NCryptEncrypt
例程)都以字节 [=29] 写入它们=]订单。
因此您需要反转来自 CryptEncrypt
的数据,并将其反转进入 CryptDecrypt
。
例如,在 .NET Core 的 RSACryptoServiceProvider.Encrypt it calls CapiHelper.EncryptKey 中调用 CryptEncrypt
然后 Array.Reverse
返回之前。
CryptEncrypt documentation已作为备注部分的最后一句
The ciphertext is returned in little-endian format.