I'm trying to synchronize my encryption and decryption methods between C# and PHP but something seems to be going wrong.
In the Windows Phone 7 SDK you can use AESManaged to encrypt your data
I use the following method:
public static string EncryptA(string dataToEncrypt, string password, string salt)
{
AesManaged aes = null;
MemoryStream memoryStream = null;
CryptoStream cryptoStream = null;
try
{
//Generate a Key based on a Password, Salt and HMACSHA1 pseudo-random number generator
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
//Create AES algorithm with 256 bit key and 128-bit block size
aes = new AesManaged();
aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // rfc2898.GetBytes(aes.BlockSize / 8);
// to check my results against those of PHP
var blaat1 = Convert.ToBase64String(aes.Key);
var blaat2 = Convert.ToBase64String(aes.IV);
//Create Memory and Crypto Streams
memoryStream = new MemoryStream();
cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
//Encrypt Data
byte[] data = Encoding.Unicode.GetBytes(dataToEncrypt);
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
//Return Base 64 String
string result = Convert.ToBase64String(memoryStream.ToArray());
return result;
}
finally
{
if (cryptoStream != null)
cryptoStream.Close();
if (memoryStream != null)
memoryStream.Close();
if (aes != null)
aes.Clear();
}
}
I solved the problem of generating the Key. The Key and IV are similar as those on the PHP end. But then the final step in the encryption is going wrong.
here is my PHP code
<?php
function pbkdf2($p, $s, $c, $dk_len, $algo = 'sha1') {
// experimentally determine h_len for the algorithm in question
static $lengths;
if (!isset($lengths[$algo])) { $lengths[$algo] = strlen(hash($algo, null, true)); }
$h_len = $lengths[$algo];
if ($dk_len > (pow(2, 32) - 1) * $h_len) {
return false; // derived key is too long
} else {
$l = ceil($dk_len / $h_len); // number of derived key blocks to compute
$t = null;
for ($i = 1; $i <= $l; $i++) {
$f = $u = hash_hmac($algo, $s . pack('N', $i), $p, true); // first iterate
for ($j = 1; $j < $c; $j++) {
$f ^= ($u = hash_hmac($algo, $u, $p, true)); // xor each iterate
}
$t .= $f; // concatenate blocks of the derived key
}
return substr($t, 0, $dk_len); // return the derived key of correct length
}
}
$password = 'test';
$salt = 'saltsalt';
$text = "texttoencrypt";
#$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
#echo $iv_size . '<br/>';
#$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
#print_r (mcrypt_list_algorithms());
$iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$key = pbkdf2($password, $salt, 1000, 32);
echo 'key: ' . base64_encode($key) . '<br/>';
echo 'iv: ' . base64_encode($iv) . '<br/>';
echo '<br/><br/>';
function addpadding($string, $blocksize = 32){
$len = strlen($string);
$pad = $blocksize - ($len % $blocksize);
$string .= str_repeat(chr($pad), $pad);
return $string;
}
echo 'text: ' . $text . '<br/>';
echo 'text: ' . addpadding($text) . '<br/>';
// -- works till here
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
echo '1.' . $crypttext . '<br/>';
$crypttext = base64_encode($crypttext);
echo '2.' . $crypttext . '<br/>';
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, addpadding($text), MCRYPT_MODE_CBC, $iv);
echo '1.' . $crypttext . '<br/>';
$crypttext = base64_encode($crypttext);
echo '2.' . $crypttext . '<br/>';
?>
So to point out, the Key and IV look similar on both .NET and PHP, but something seems to be going wrong in the final call when executing mcrypt_encrypt(). The end result, the encrypted string, differs from .NET.
Can anybody tell me what i'm doing wrong. As far as i can see everything should be correct.
Thank you!
EDIT:
Additional information on the AESManaged object in .NET
Keysize = 256
Mode = CBC
Padding = PKCS7