CSP Blobs between C# and C++ - Interoperation with the Microsoft Cryptographic API (CAPI)
If you have a requirement as follows:
- Interoperate between C# & C++ using cryptographic blobs.
- Generate the private and public keys in C#. See code below:
public void GenerateKeys(out byte[] privateKey, out byte[] publicKey)
{
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
privateKey = rsa.ExportCspBlob(true);
publicKey = rsa.ExportCspBlob(false);
}
}
- Encrypt a file in C#.
- Decrypt it in C++.
You might get a failure with error code of 0x57 (Error code: (Win32) 0x57 (87) - The parameter is incorrect). This failure happens when you decrypt using the CryptDecrypt() API as shown in the code below.
if (!CryptDecrypt(hKey, NULL, TRUE, 0, pbData, &dwDataLen))
{
// Error
_tprintf(_T("CryptDecrypt error 0x%x\n"), GetLastError());
return 1;
}
Changing dwFlags (the 4th parameter to CryptDecrypt) to CRYPT_DECRYPT_RSA_NO_PADDING_CHECK (see code below) will make the API succeed but the decryption result is undesirable.
if (!CryptDecrypt(hKey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, pbData, &dwDataLen))
{
// Error
_tprintf(_T("CryptDecrypt error 0x%x\n"), GetLastError());
return 1;
}
The entire code succeeds if at the 3rd step you encrypt the file in C++.
Please note: Unlike the RSA implementation in unmanaged CAPI, the RSACryptoServiceProvider class reverses the order of an encrypted array of bytes after encryption and before decryption. By default, data encrypted by the RSACryptoServiceProvider class cannot be decrypted by the CAPI CryptDecrypt function and data encrypted by the CAPI CryptEncrypt method cannot be decrypted by the RSACryptoServiceProvider class.
To interoperate with CAPI, you must manually reverse the order of the encrypted bytes before the encrypted data interoperates with another API.
Example:
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportCspBlob(blob);
// Input string.
const string input = "This is a test.";
byte[] array = Encoding.ASCII.GetBytes(input);
byte[] encryptedData = rsa.Encrypt(array, false);
Array.Reverse(encryptedData, 0, encryptedData.Length);
using (var fs = new FileStream(encryptedFileName, FileMode.Create))
fs.Write(encryptedData, 0, encryptedData.Length);
}
Now you can use CryptDecrypt function to decrypt the file using the private key.
For reference see: https://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider(v=vs.110).aspx