Update 2 - it works
Thanks to Tom Leek for his answer.
The CFB
mode of mycrypt
for Rijndael
uses a 8-bit feedback loop and not a feedback loop the length of the key/iv.
You have to force it to use the full length with the parameter ncfb
. Confusingly this is not a documented constant in the PHP Mcrypt library: http://www.php.net/manual/en/mcrypt.constants.php
The appropriate lines in the PHP now looks like this:
$Crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Text, 'ncfb', $IV);
$Decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $Crypt, 'ncfb', $IV);
Updated - see bottom
I am trying to get and Erlang site to exchange information via aes_cfb_128
encryption with a PHP site. I am writing a test implementation which will demonstrate that the PHP will decrypt what the Erlang encrypts and vice-versa - but I am having problems.
Here is the PHP source (apologies it is a bit shoddy - my PHP is no good - I am an Erlang programmer):
<?php
function dump($String, $Bin) {
echo $String . " is " . ord($Bin[0]) . " " . ord($Bin[1]) . " " . ord($Bin[2]) . " " . ord($Bin[3]) . " " . ord($Bin[4]) . " " . ord($Bin[5]) . " " . ord($Bin[6]) . " " . ord($Bin[7]) . " " . ord($Bin[8]) . " " . ord($Bin[9]) . " " . ord($Bin[10]) . " " . ord($Bin[11]) . " " . ord($Bin[12]) . " " . ord($Bin[13]) . " " . ord($Bin[14]) . " " . ord($Bin[15]) . " " . ord($Bin[16]) . " " . ord($Bin[17]) . " " . ord($Bin[18]) . " " . ord($Bin[19]) . " " . ord($Bin[20]) . " " . ord($Bin[21]) . " " . ord($Bin[22]) . " " . ord($Bin[23]) . " " . ord($Bin[24]) . " " . ord($Bin[25]) . " " . ord($Bin[26]) . " " . ord($Bin[27]) . " " . ord($Bin[28]) . " " . ord($Bin[29]) . " " . ord($Bin[30]) . " " . ord($Bin[31]) ."\n";
}
$Key = "abcdefghabcdefgh";
$IV = "12345678abcdefgh";
$Text = "12345678123456781234567812345678";
$KeySize = strlen($Key) * 8;
$IVSize = strlen($IV) * 8;
$TextSize = strlen($Text) * 8;
$IVSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_NOFB);
echo "IVSze is " . $IVSize . " bytes or " . $IVSize * 8 . " bits\n";
$BlockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_NOFB);
echo "BlockSize is " . $BlockSize . " bytes or " . $IVSize * 8 . " bits\n";
$Crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Text, MCRYPT_MODE_NOFB, $IV);
$Decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $Crypt, MCRYPT_MODE_NOFB, $IV);
echo "Key is " . $Key . " with size " . $KeySize . "\n";
echo "IV is " . $IV . " with size " . $IVSize . "\n";
echo "Text is " . $Text . " with size " . $TextSize . "\n";
echo "Crypt is " . $Crypt . "\n";
dump("Crypt", $Crypt);
echo "Decrypt is " . $Decrypt . "\n";
dump("Decrypt", $Decrypt);
?>
Here is the corresponding Erlang source:
-module(test_crypto).
-export([
test/0
]).
test() ->
Key = <<"abcdefghabcdefgh">>,
IV = <<"12345678abcdefgh">>,
Text = <<"12345678123456781234567812345678">> ,
KeySize = bit_size(Key),
IVSize = bit_size(IV),
TextSize = bit_size(Text),
io:format("Key is ~p with size ~p~n", [Key, KeySize]),
io:format("IV is ~p with size ~p~n", [IV, IVSize]),
io:format("Text is ~p with size ~p~n", [Text, TextSize]),
Crypt = crypto:aes_cfb_128_encrypt(Key, IV, Text),
io:format("Crypt is ~p~n", [Crypt]),
B64 = base64:encode(Crypt),
io:format("Crypt B64 is ~p~n", [B64]),
Decrypt = crypto:aes_cfb_128_decrypt(Key, IV, Crypt),
io:format("Decrypt is ~p~n", [Decrypt]),
ok.
Here is the PHP output:
gordon@hypernumbers:~/crypto$ php test_crypto.php
IVSze is 16 bytes or 128 bits
BlockSize is 16 bytes or 128 bits
Key is abcdefghabcdefgh with size 128
IV is 12345678abcdefgh with size 16
Text is 12345678123456781234567812345678 with size 256
Crypt is ��^DЭZ�!�)�y�9�������ht���'!
Crypt is 139 182 94 68 208 173 127 90 14 236 33 230 41 29 210 121 153 57 173 191 237 169 242 222 217 104 116 144 240 175 39 33
Decrypt is 12345678123456781234567812345678
Decrypt is 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56
Here is the Erlang output:
7> test_crypto:test().
Key is <<"abcdefghabcdefgh">> with size 128
IV is <<"12345678abcdefgh">> with size 128
Text is <<"12345678123456781234567812345678">> with size 256
Crypt is <<139,182,94,68,208,173,127,90,14,236,33,230,41,29,210,121,147,172,
114,74,61,11,162,5,112,104,102,63,24,78,34,179>>
Crypt B64 is <<"i7ZeRNCtf1oO7CHmKR3SeZOscko9C6IFcGhmPxhOIrM=">>
Decrypt is <<"12345678123456781234567812345678">>
ok
As you can see both Code Blocks cycle themselves correctly - but they will not work together because they do not create identical cyphertext.
The first 16 bytes of the cypertext are the same - but the second block of 16 bytes is different.
I know this algorithm uses the first output block in the encryption of the second one - so I suspect there is some jiggery-pokery going on between how the Erlang crypto
module is doing it and the PHP mcrypt
code.
UPDATE
I tried using CFB mode in mycrypt but I believe that there is a different feedback blocksize or something - and only the first character of the cypertext was the same. NOFB mode seems to be related somehow and is the best I have got so far...
If I run the PHP with CFB mode I get this output:
~/crypto$ php test_crypto.php
IVSze is 16 bytes or 128 bits
BlockSize is 16 bytes or 128 bits
Key is abcdefghabcdefgh with size 128
IV is 12345678abcdefgh with size 16
Text is 12345678123456781234567812345678 with size 256
Crypt is ��*�b�ls�M����
��ҮF��Y�=O
Crypt is 139 0 188 42 175 98 18 177 108 27 115 189 77 144 127 176 171 193 11 32 245 139 210 174 70 151 230 89 169 22 61 79
Decrypt is 12345678123456781234567812345678
Decrypt is 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56
I tried getting help on StackOverflow https://stackoverflow.com/questions/14550195/crypto-between-erlang-and-php but it was mostly me talking to myself :(