windows中的rsa加密和openssl中的解密

时间:2021-09-07 15:00:41

I have a problem in exchanging public key between "OpenSSL" and "Windows CryptoAPI". The public key is exported from OpenSSL in pem format.My program is written in c++. I get the public key and load it by "CryptoAPI". After loading the public key, I encrypt some data and send them to the other application. The other application can not decrypt the received data by own private key. please help me to find the solution.

我在“OpenSSL”和“Windows CryptoAPI”之间交换公钥时遇到问题。公钥是以pem格式从OpenSSL导出的。我的程序是用c ++编写的。我获取公钥并通过“CryptoAPI”加载它。加载公钥后,我加密了一些数据并将它们发送到另一个应用程序。另一个应用程序无法通过自己的私钥解密接收的数据。请帮我找到解决方案。

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcJXxao6OzesjaM5VnsYTnHWUN
z8dosWEETARH6NOqq+hAoMscsv+2MgT0oOYKLf/c8i37YFXnswEan78QnWYO3jtX
UHfJgXcLcMz7o3lX3OwNqRXgXW6Db95EjPEnLuPCJ2Pafu9E75ZMglkgw9MrIAik
XKL9u2dc9fkbc7FptQIDAQAB
-----END PUBLIC KEY-----

Source code:

_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;
}

1 个解决方案

#1


0  

CryptEncrypt, for reasons that probably made sense to the author at the time, writes the bytes down backwards. Or, rather, it writes them in byte minor/little-endian order whereas almost every other cryptography library (including the Windows CNG BCryptEncrypt and NCryptEncrypt routines) writes them in byte major/big-endian order.

CryptEncrypt,由于当时可能对作者有意义的原因,将字节向下写入。或者,它以字节小/小端顺序写入它们,而几乎所有其他加密库(包括Windows CNG BCryptEncrypt和NCryptEncrypt例程)以字节主/大端顺序写入它们。

So you need to reverse data coming out of CryptEncrypt, and reverse it going in to CryptDecrypt.

所以你需要反转来自CryptEncrypt的数据,并将其反转进入CryptDecrypt。

For example, in .NET Core's RSACryptoServiceProvider.Encrypt it calls CapiHelper.EncryptKey which calls CryptEncrypt then Array.Reverse before returning.

例如,在.NET Core的RSACryptoServiceProvider.Encrypt中,它调用CapiHelper.EncryptKey,在返回之前调用CryptEncrypt然后调用Array.Reverse。

The CryptEncrypt documentation has as the last sentence in the Remarks section

CryptEncrypt文档作为备注部分的最后一句

The ciphertext is returned in little-endian format.

密文以little-endian格式返回。

#1


0  

CryptEncrypt, for reasons that probably made sense to the author at the time, writes the bytes down backwards. Or, rather, it writes them in byte minor/little-endian order whereas almost every other cryptography library (including the Windows CNG BCryptEncrypt and NCryptEncrypt routines) writes them in byte major/big-endian order.

CryptEncrypt,由于当时可能对作者有意义的原因,将字节向下写入。或者,它以字节小/小端顺序写入它们,而几乎所有其他加密库(包括Windows CNG BCryptEncrypt和NCryptEncrypt例程)以字节主/大端顺序写入它们。

So you need to reverse data coming out of CryptEncrypt, and reverse it going in to CryptDecrypt.

所以你需要反转来自CryptEncrypt的数据,并将其反转进入CryptDecrypt。

For example, in .NET Core's RSACryptoServiceProvider.Encrypt it calls CapiHelper.EncryptKey which calls CryptEncrypt then Array.Reverse before returning.

例如,在.NET Core的RSACryptoServiceProvider.Encrypt中,它调用CapiHelper.EncryptKey,在返回之前调用CryptEncrypt然后调用Array.Reverse。

The CryptEncrypt documentation has as the last sentence in the Remarks section

CryptEncrypt文档作为备注部分的最后一句

The ciphertext is returned in little-endian format.

密文以little-endian格式返回。