RE: Using Win32 CryptDecrypt to Decrypt RijndaelManaged




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.
.



Relevant Pages

  • Re: Encrypt and Decrypt a file using .NET 2.0?
    ... public static string GenerateKey() ... DES des = DES.Create; ... // Distribute this key to the user who will decrypt this file. ... // Get the Key for the file to Encrypt. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: .NET Crypto Classes Interoperability with Win32 Crypto APIs
    ... >the hash of the string you are feeding in. ... when i encrypt a string using .NET classes and try ... >> decrypt it using Win32 APIs, ...
    (microsoft.public.dotnet.security)
  • Re: Encrypt and Decrypt a file using .NET 2.0?
    ... public static string GenerateKey() ... using (CryptoStream cryptoStream = new CryptoStream(outFile, ... // Distribute this key to the user who will decrypt this file. ... // Get the Key for the file to Encrypt. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Decryptionfailed to bring original text back....
    ... cryptography, but now using them on web.config, any idea, I like to ... There isn't really much reason to encrypt a .NET string with ... what happen when you decrypt the encrypted ...
    (microsoft.public.dotnet.security)
  • Encrypt ConnectionString in a *WINFORMS* App
    ... OK, I know how to encrypt and decrypt data, but here's the deal: ... the connection string in the app.config file unencrypted (currently ... Server account and password that the app needs to be using. ...
    (microsoft.public.dotnet.general)