views:

282

answers:

1

I decrypt data using PHP with this code:

$content="1234";
$cp = mcrypt_module_open('rijndael-128', '', 'cbc', '');
$iv = mcrypt_create_iv(16, MCRYPT_RAND);
$key = pack("H*",md5('a'));
mcrypt_generic_init($cp, $key, $iv);
$encrypted = mcrypt_generic($cp, $content);
echo base64_encode($key)."\n";
echo base64_encode($iv)."\n";
echo base64_encode($encrypted)."\n";
mcrypt_generic_deinit($cp);
mcrypt_module_close($cp);

$iv and $encrypted is then saved to file and read in the C# sample app:

var iv=...;
var encrypted=...;
var md5 = new MD5CryptoServiceProvider();
var key = md5.ComputeHash(Encoding.Default.GetBytes("a"));
md5.Clear();

Console.WriteLine(Convert.ToBase64String(key));
Console.WriteLine(Convert.ToBase64String(iv));
Console.WriteLine(Convert.ToBase64String(encrypted));

The output here is exactly the same as the output from PHP, so I can assure there is no encoding error inbetween.

var rd = new RijndaelManaged {
  Key = key,
  IV = iv,
  Mode = CipherMode.CBC,
  KeySize = 128,
  Padding = PaddingMode.Zeros
};

var buffer = new byte[encrypted.Length];
using(var ms = new MemoryStream(buffer)) {
  using(var cs = new CryptoStream(ms, rd.CreateDecryptor(), CryptoStreamMode.Write)) {
    cs.Write(encrypted, 0, encrypted.Length);
    ms.Read(buffer, 0, buffer.Length);
    Console.WriteLine(Encoding.Default.GetString(buffer));
  } 
}
rd.Clear();

The result of the decryption varies on every program start, even with exactly the same input data:

First run:
DMF1ucDxtqgxw5niaXcmYQ== <-Key
GoCeRkrL/EMKNH/BYeLsqQ== <-IV
UBE3DkgbJgj1K/TISugLxA== <-Encrypted
OlOB99yiCYRDoLx+0xxZxQ== <-"Decrypted"

Second run:
DMF1ucDxtqgxw5niaXcmYQ== <-Key
GoCeRkrL/EMKNH/BYeLsqQ== <-IV
UBE3DkgbJgj1K/TISugLxA== <-Encrypted
w5fcY5Fbb9KRgoHfhqAztA== <-"Decrypted"

Key, IV, Encrypted data are identical, but still the decrypted date varies and is always wrong. buffer should contain "1234" or "1234" plus 12 trailing zeros.

I don't see why the results vary and what is not working, but I have been staring at this darn piece of code for several hours now, and probably miss the obvious error...

Reversing the CryptoStream like this creates identically wrong results:

using(var ms = new MemoryStream(encrypted)) {
  using(var cs = new CryptoStream(ms, rd.CreateDecryptor(), CryptoStreamMode.Read)) {
    cs.Read(buffer, 0, buffer.Length);
    Console.WriteLine(Convert.ToBase64String(buffer));
  }
}

Help? Thanks! Alexander

+1  A: 

Well, modifying an old sample of my sins of the past I ended up with this:

static string Decrypt() {            
  byte[] keyBytes = Convert.FromBase64String("DMF1ucDxtqgxw5niaXcmYQ==");
  byte[] iv = Convert.FromBase64String("GoCeRkrL/EMKNH/BYeLsqQ==");
  byte[] cipherTextBytes = Convert.FromBase64String("UBE3DkgbJgj1K/TISugLxA==");

  var symmetricKey = new RijndaelManaged { Mode = CipherMode.CBC, IV = iv, KeySize = 128, Key = keyBytes, Padding = PaddingMode.Zeros};

  using (var decryptor = symmetricKey.CreateDecryptor())
  using (var ms = new MemoryStream(cipherTextBytes))
  using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) {
    var plainTextBytes = new byte[cipherTextBytes.Length];
    int decryptedByteCount = cs.Read(plainTextBytes, 0, plainTextBytes.Length);
    return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
  }
}

which gave "1234" with trailing \0 characters.. Did you just forget to convert the byte[] to a string again? What other difference am I missing?

Benjamin Podszun
The solution is very simple, yet mostly annoying... You have to set the "KeySize" Property *before* setting the "Key" property. I converted my code step by step to match your code, and as soon as I switched the two setters, it worked.In case someone from Microsoft is listening, you might include that bit of information into MSDN. I know it is obvious once you know it, but... Benjamin, Danke!
Alexander Reifinger