RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged
- From: Clayton Williams <ClaytonWilliams@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Thu, 2 Jul 2009 10:32:12 -0700
Thanks for the feedback, it is was much appreciated and helped me look at
this differently.
I was able to finally resolve this with a little help from Rong-Chun Zhang
at:
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/6a7af045-e414-4570-9491-70e542751f19
What I discovered in our case was related to what I found in this blog
posting that he sent me a link to:
http://blogs.msdn..com/shawnfa/archive/2006/10/09/The-Differences-Between-Rijndael-and-AES.aspx
I figured out how to use RijndaelManaged with AES in the C++ app.
RijndaelManaged allows you to set your BlockSize to be as high as 256 bits.
You can do this on the C++ side as well, but it will never be able to decode
the .NET generated encryption. If we leave our key size as 256 (bits in
..NET) on both sides (using CALG_AES_256 for the C++ crypto algorithm,
specifying 32 bytes instead of 256 bits for the key size), and set the
BlockSize to 128, C++ crypto WILL successfully decrypt the .NET generated
output! The size of the IV needs to match the specified BlockSize in .NET.
We use a simple byte array for the key in .NET and the same the values in a
BYTE array in C++.
If you then convert the resultant byte array to something more readable,
then you have to reverse that on the C++ side of course. But that's a
different issue.
So the main issue was an incompatible block size (and I.V.) between the two.
"Dave Herrmann" wrote:
We have the same situation as you. A .NET app and a C++ app that both need to.
encrypt and decrypt the same data. One thing we found is that the encryption
seeds for the .NET app need to be 7-bit ASCII, whereas the seeds used by the
C++ app can be binary if you want. So, if you are using binary seed values
(8-bit bytes), then the .NET app may not be encrypting/decrypting the same
way. In our case, I don't remember if the .NET app would fail or just not
encrypt/decrypt to the same values.
-Dave
"Clayton Williams" wrote:
I have library that generates encrypted strings using 256-bit RijndaelManaged
in a .NET library.
I am trying to write a Win32 app that can decrypt that string using the
Crypto APIs.
I can get both to encrypt and decrypt successfully in their own projects,
but I have been unable to get the Win32 based CryptDecrypt algorithm to
successfully decrypt the RijndaelManaged encrypted string.
I am using the same Key and IV for each one, the same string, etc. As far
as I can tell, I am using the same Padding, bit size, algorithm.
This whole post boils down to 2 questions that someone may have already
resolved in a similar scenario:
1) Is it easier to write one unmanaged C++ library source that both
applications share, with a managed wrapper in the .NET assembly that all use
the Win32 Crypto library, or:
2) Is there some tweak that I am missing that will enable me to decrypt my
.NET encrypted strings in CryptDecrypt?
I have listed code from apps to illustrate where I am. The resultant byte
arrays from both encryptions are different, and plugging in the byte array
from one into the other will not decrypt - NTE_BAD_DATA
Here is my .NET code:
/////////////////////////////////////////////////
Byte[] key = { 0x74, 0x6c, 0x9b, 0xf2, 0x24, 0xce, 0xdd, 0x55, 0x23, 0xba,
0x64, 0xfb, 0xe9, 0xbe, 0x17, 0x32, 0xcf, 0xf5, 0xe3, 0xf6, 0x18, 0xc0, 0x1f,
0xd5, 0x64, 0x5d, 0x84, 0xc1, 0x1a, 0xc8, 0x71, 0x7c };
Byte[] IV = { 0x18, 0x13, 0xb1, 0xb3, 0x26, 0x2b, 0x80, 0xd1, 0xe, 0x80,
0x9f, 0x47, 0xa0, 0xd9, 0x6c, 0x1f, 0xcd, 0x42, 0x1f, 0x33, 0xa9, 0x8e, 0x2f,
0x66, 0x68, 0xcf, 0x7d, 0xd6, 0x58, 0x57, 0xf2, 0xaa };
System.Security.Cryptography.RijndaelManaged rm = new
System.Security.Cryptography.RijndaelManaged();
rm.KeySize = 256;
rm.BlockSize = 256;
rm.Padding = PaddingMode.PKCS7; // default
rm.Key = key;
rm.IV = IV;
string toEncrypt = "String To Encrypt";
byte []plainTextBytes = Encoding.UTF8.GetBytes(toEncrypt);
ICryptoTransform ict = rm.CreateEncryptor();
byte []encrBytes = ict.TransformFinalBlock(plainTextBytes, 0,
plainTextBytes.Length);
string result = Convert.ToBase64String(encrBytes);
byte []dBytes = Convert.FromBase64String(result);
ICryptoTransform ict2 = rm.CreateDecryptor();
byte[] decryptedBytes = ict2.TransformFinalBlock(encrBytes, 0,
encrBytes.Length);
string plainText = Encoding.UTF8.GetString(decryptedBytes);
///////////////////////////////////////////
Here is my C++ code:
struct CryptoBlob {
BLOBHEADER header;
DWORD cbKeySize;
BYTE rgbKeyData [32];
} keyBlob;
..... <skipping _tmain initialization>
keyBlob.header.bType = PLAINTEXTKEYBLOB;
keyBlob.header.bVersion = CUR_BLOB_VERSION;
keyBlob.header.reserved = 0;
keyBlob.header.aiKeyAlg = CALG_AES_256;
keyBlob.cbKeySize = 32; // has to be in bytes, not bits
BYTE keyData[32] = { 0x74, 0x6c, 0x9b, 0xf2, 0x24, 0xce, 0xdd, 0x55, 0x23,
0xba, 0x64, 0xfb, 0xe9, 0xbe, 0x17, 0x32, 0xcf, 0xf5, 0xe3, 0xf6, 0x18, 0xc0,
0x1f, 0xd5, 0x64, 0x5d, 0x84, 0xc1, 0x1a, 0xc8, 0x71, 0x7c };
BYTE ivData[32] = { 0x18, 0x13, 0xb1, 0xb3, 0x26, 0x2b, 0x80, 0xd1, 0xe,
0x80, 0x9f, 0x47, 0xa0, 0xd9, 0x6c, 0x1f, 0xcd, 0x42, 0x1f, 0x33, 0xa9, 0x8e,
0x2f, 0x66, 0x68, 0xcf, 0x7d, 0xd6, 0x58, 0x57, 0xf2, 0xaa };
for (int idx = 0; idx < 32; idx++)
{
keyBlob.rgbKeyData[idx] = keyData[idx];
}
HCRYPTKEY hPubKey;
HCRYPTPROV hProv;
DWORD dwBlobLen;
DWORD errVal;
if (!CryptAcquireContext(
&hProv,
NULL,
NULL,
PROV_RSA_AES,
CRYPT_VERIFYCONTEXT))
{
errVal = GetLastError();
ErrLookup(errVal);
if (NTE_BAD_KEYSET == errVal)
{
if (!CryptAcquireContext(
&hProv,
_T("NVCryptoTestContainer"),
MS_ENHANCED_PROV,
PROV_RSA_AES,
CRYPT_NEWKEYSET |
CRYPT_VERIFYCONTEXT))
{
errVal = GetLastError();
ErrLookup(errVal);
printf("Error in AcquireContext 0x%08x \n", errVal);
return 1;
}
}
}
else
{
if (CryptImportKey(hProv, (const LPBYTE)&keyBlob, sizeof(keyBlob), 0, 0,
&hPubKey))
{
if (!CryptSetKeyParam(hPubKey, KP_IV, ivData, 0))
{
ErrLookup(GetLastError());
}
else
{
char szClearText[32];
strcpy(szClearText, "String To Encrypt");
DWORD dwDataLen = (DWORD)strlen(szClearText);
DWORD dwBufferSize = sizeof(szClearText);
if(!CryptEncrypt(hPubKey, 0, TRUE, 0, (LPBYTE)szClearText,
&dwDataLen, dwBufferSize))
{
ErrLookup(GetLastError());
}
else
{
printf("encrypted looks like: %s", szClearText);
dwBufferSize = sizeof(szClearText);
if(!CryptDecrypt(hPubKey, 0, TRUE, 0, (LPBYTE)zClearText, &dwBufferSize))
{
ErrLookup(GetLastError());
}
else
{
printf("decrypted looks like: %s", szClearText);
}
}
}
if(!CryptDestroyKey(hPubKey))
{
ErrLookup(GetLastError());
}
}
else
{
ErrLookup(GetLastError());
}
}
Any help is GREATLY appreciated.
- References:
- RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged
- From: Dave Herrmann
- RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged
- Prev by Date: Re: Key lengths
- Next by Date: RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged
- Previous by thread: RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged
- Next by thread: RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged
- Index(es):
Relevant Pages
|