I have the following PHP sample that I'm trying to mimic in C#. It is using AES 128bit ECB encryption with PKCS7 padding:
$trust_jsonString="hello";
echo "input: '" . $trust_jsonString . "'
";
echo "input (dump): " . var_dump($trust_jsonString) . "
";
$trust_key = "9840822c-14fc-49ac-9d68-ac532f9f171e";
echo "key: '" . $trust_key . "'
";
$blockSize=mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_ECB);
echo "block size: '" . $blockSize . "'
";
$padding = $blockSize - (strlen($trust_jsonString) % $blockSize);
echo "padding: '" . $padding . "'
";
$trust_jsonString .= str_repeat(chr($padding), $padding);
$trust_jsonString = utf8_encode($trust_jsonString);
echo "utf8 json: '" . $trust_jsonString . "'
";
echo "utf8 json (dump): " . var_dump($trust_jsonString) . "
";
$trust_key=utf8_encode($trust_key);
echo "encoded key: " . $trust_key . "
";
$trust_key=(md5($trust_key));
echo "md5 hash of key (raw): " . $trust_key . "
";
$mcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $trust_key, $trust_jsonString, MCRYPT_MODE_ECB);
echo "mcrypt (raw): " . var_dump($mcrypt) . "
";
echo "mcrypt: " . $mcrypt . "
";
echo "mcrypt (raw): ";
$byte_array = byteStr2byteArray($mcrypt);
for($i=0;$i<count($byte_array);$i++)
{
printf("%02x", $byte_array[$i]);
}
echo "
";
$presid = base64_encode($mcrypt);
echo "presid: " . $presid . "
";
$sid=strtr($presid,'+/', '-_');
echo "sid: " . $sid . "
";
function byteStr2byteArray($s) {
return array_slice(unpack("C*", "\0".$s), 1);
}
I am currently running the following C# code to try to mimic results:
static void Main( string[] args )
{
string data = "hello";
Encrypt(data);
}
static void Encrypt( string data )
{
PaddingMode padding = PaddingMode.PKCS7;
CipherMode cipherMode = CipherMode.ECB;
int size = 128;
Console.WriteLine("input: '" + data + "'");
string officialKey = "9840822c-14fc-49ac-9d68-ac532f9f171e";
Console.WriteLine("key: '" + officialKey + "'");
Console.WriteLine("block size: '16'");
Console.WriteLine( "padding: '11'" );
var utf8dataBytes = Encoding.UTF8.GetBytes(data);
var utf8data = Encoding.UTF8.GetString(utf8dataBytes);
Console.WriteLine("utf8 json: '" + utf8data + "'");
Console.WriteLine("encoded key (utf8): " + officialKey);
var utf8KeyBytes = Encoding.UTF8.GetBytes(officialKey);
var myMD5 = MD5.Create();
var md5HashOfKey = myMD5.ComputeHash(utf8KeyBytes);
Console.WriteLine( "md5 hash of key (raw): " + DumpBinary(md5HashOfKey) );
byte[] encryptedBlob;
using ( var aes = new AesManaged() )
{
try
{
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.ECB;
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Key = md5HashOfKey;
//aes.IV = new byte[] { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
var bytes = utf8dataBytes;
//var bytes = ForcePaddingManually( utf8dataBytes );
var cxform = aes.CreateEncryptor();
encryptedBlob = cxform.TransformFinalBlock( bytes, 0, bytes.Length );
}
finally
{
aes.Clear();
}
}
//var encryptedBlob = AesAlgo.Encrypt( data, md5HashOfKey, padding, cipherMode, size );
Console.WriteLine("mcrypt (raw): " + DumpBinary(encryptedBlob));
Console.WriteLine("mcrypt: " + Encoding.UTF8.GetString(encryptedBlob));
var encryptedBase64 = Convert.ToBase64String(encryptedBlob);
Console.WriteLine( "presid: " + encryptedBase64 );
var encodedEncryptedBlob = encryptedBase64.Replace( "+", "-" ).Replace( "/", "_" );
Console.WriteLine( "sid: " + encodedEncryptedBlob );
Console.WriteLine("COMPLETE!");
}
static byte[] ForcePaddingManually( byte[] data )
{
// force padding manually to test that PKCS7 works like we are expecting
var pad = ( 16 - data.Length % 16 ) % 16;
var bytes = new byte[data.Length + pad];
for ( int i = 0; i < data.Length; ++i )
{
bytes[i] = data[i];
}
for ( int i = data.Length; i < data.Length + pad; ++i )
{
bytes[i] = (byte)pad;
}
return bytes;
}
static string DumpBinary( byte[] data )
{
var sb = new StringBuilder();
for ( int i = 0; i < data.Length; ++i )
{
sb.Append( data[i].ToString( "X2" ) );
}
return sb.ToString();
}
When I look at the results for these, this is what I get:
PHP:
input: 'hello'
string(5) "hello"
input (dump):
key: '9840822c-14fc-49ac-9d68-ac532f9f171e'
block size: '16'
padding: '11'
utf8 json: 'hello'
string(16) "hello"
utf8 json (dump):
encoded key: 9840822c-14fc-49ac-9d68-ac532f9f171e
md5 hash of key (raw): 6d334201cb7625323da32e0c31b2b138
string(16) "�Ҙ�= �˹��C���"
mcrypt (raw):
mcrypt: �Ҙ�= �˹��C���
mcrypt (raw): b0d298c83d20a0cbb9f0ea4305cef2ec
presid: sNKYyD0goMu58OpDBc7y7A==
sid: sNKYyD0goMu58OpDBc7y7A==
C#:
input: 'hello'
key: '9840822c-14fc-49ac-9d68-ac532f9f171e'
block size: '16'
padding: '11'
utf8 json: 'hello'
encoded key (utf8): 9840822c-14fc-49ac-9d68-ac532f9f171e
md5 hash of key (raw): 6D334201CB7625323DA32E0C31B2B138
mcrypt (raw): 4CBAD7678AAB2B054371A1B572161280
mcrypt: L??g??+♣Cq??r▬↕?
presid: TLrXZ4qrKwVDcaG1chYSgA==
sid: TLrXZ4qrKwVDcaG1chYSgA==
COMPLETE!
There is a lot of diagnostic and misc code in there, but the basic issue is that when the same MD5 hash of the key is passed in (binaries are the same) and the same input data is passed in (bytes are the same, or I can force the padding to be the same in the C# code on input) I get different output results. I'm sure that this is something simple, but it isn't popping out to me. Is there someone who can identify the problem here?
The basic issue is that the SID shown at the bottom (the AES encrypted result) is different - what is causing the difference?