views:

2044

answers:

3

Ok I'm trying to use the Win32 Crypto API in C++ to decrypt a string encrypted in C# (.NET 2) with the RijndaelManaged Class. But I'm having no luck at all i get jibberish or a bad data Win32 error code. All my keys, IV and salt match, I've looked in the watch for both test apps. I've spent all say looking at it and I'm officialy stuck.

Anyway here is the C#

            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(GetPassPhrase(), salt, 1000);
        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.BlockSize = 128;
        rijndael.KeySize = 256;
        rijndael.Mode = CipherMode.CBC;

        rijndael.Key = pdb.GetBytes(m_KeySize);
        rijndael.IV = GetIV(iv);

        ICryptoTransform encryptor = rijndael.CreateEncryptor(); 
        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
        Byte[] encryptedBytes = null;
        Byte[] toBeEncrypted = UnicodeEncoding.Unicode.GetBytes(value);

        csEncrypt.Write(toBeEncrypted, 0, toBeEncrypted.Length);
        csEncrypt.FlushFinalBlock();
        encryptedBytes = msEncrypt.ToArray();

The C++ to decrypt it is:

                                    keyBlob.hdr.bType = PLAINTEXTKEYBLOB;
    keyBlob.hdr.bVersion = CUR_BLOB_VERSION;
    keyBlob.hdr.reserved = 0;
    keyBlob.hdr.aiKeyAlg = CALG_AES_256;
    keyBlob.cbKeySize = KEY_SIZE;
    keyBlob.rgbKeyData = &byKey[0];

    if ( CryptImportKey( hProv, (const LPBYTE) &keyBlob, sizeof(BLOBHEADER) + sizeof(DWORD) + KEY_SIZE, 0, CRYPT_EXPORTABLE, &hKey ) )
    {

     if ( CryptSetKeyParam( hKey, KP_IV, (const BYTE *) &byIV, 0))
     {
      DWORD dwLen = iDestLen;
      if ( CryptDecrypt( hKey, 0, TRUE, 0, pbyData, &dwLen))
      {

       if ( dwLen < (DWORD) *plOutSize)
       {
        memcpy_s(pbyOutput, *plOutSize, pbyData, dwLen);

        *plOutSize = dwLen;

        bRet = TRUE; 
       }
      }
      else
      {
       // Log
       DWORD dwErr = ::GetLastError();
       int y =0;
      }
     }
    }

I'm calling CryptAcquireContext successfully and my C++ is executing fine. Can anyone spot the error in my ways. It's starting to depress me know :(

A: 

I see that you are using CBC chaining mode to encrypt the plain text.

Are you sure you are using the same chaining mode to decrypt the cypher text?

(I am sorry. I am not able to understand that from the code)

Niyaz
According to MSDN the default for AES is to CBC. Although it could be wrong.
L2Type
A: 

There are a handful of things you should check, since some of the code (declarations etc) are missing:

  • Block size - this usually should be the same as key size, I think it might even be the default since you dont specify it on C++ side. Set it to 256 on C# side, I guess it best that you explicitly specify it in C++ too.
  • Padding - the managed classes have PKCS7 as their default padding, I think its the default for cryptoAPI functions too, but I'm not sure.
  • I assume that GetPassPhrase, GetIV etc give you he same keys you're using on the C++ side?
  • It's not clear how the encrypted data is passed between the programs, is it possible there is some kind of translation error? E.g. base64, URL encode, etc.
AviD
+1  A: 

Ok my fault, I didn't include the Struct def for the keyblob in the C++ and it turns out you need a contigous block of data for the key with the header but I was using the MSDN example that had a pointer to the key data. Which is wrong!

L2Type