Crypto between Erlang and PHP

Update 5

I switched the question to the Security StackExchange - got the answer. https://security.stackexchange.com/questions/30168/aes-cfb-128-decryption-encryption-problem-between-erlang-and-php

Update 4

Having a fixable problem or so I thought - I tried to continue with the implementation. It turned out that this is not enough.

As soon as we started inserting real data into it, everything went to hell. An example would be increasing plain text from 1234567812345678

to12345678123456781234567812345678

In this case, the first 128-bit cypertext block was the same, but the second was different:

PHP: 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

Erlang: <<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>>

Update 3 - (although it was) SOLVED (but I was wrong)

This answer gave the final key: Wrong key size while migrating Crypto ++ AES encryption to mcrypt PHP

The problem is that mode 'cfb'

in mycrypt

doesn't use proper feedback locking to emulate aes cfb

- you need to use mode nofb

.

Update 2

Trying to get AES-CFB-128 to work on both - so I determined that using mycrypt

with mode RINJDAEL_128

with block size 128 and type 'cfb'

is the PHP equivalent crypto:aes_cfb_128/3

in Erlang.

So, I start writing routines in both languages ​​to prove it.

PHP version:

<?php
// fugly because I don't know enough PHP to write it better
// big apologies to any PHP code poets out there, my bad :(
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]) . "\n";
}

$Key  = "abcdefghabcdefgh";
$IV   = "12345678abcdefgh";
$Text = "1234567812345678";

$KeySize  = strlen($Key) * 8;
$IVSize   = strlen($IV) * 8;
$TextSize = strlen($Text) * 8;

$Size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CFB);
echo "Block size is " . $Size . " bytes or " . $Size * 8 . " bits\n";

$Crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Text, MCRYPT_MODE_CFB, $IV);
$Decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $Crypt, MCRYPT_MODE_CFB, $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);
?>

      

When I run it, I get PHP output:

Block size is 16 bytes or 128 bits
Key   is   abcdefghabcdefgh with size 128
IV    is   12345678abcdefgh with size 128
Text  is   1234567812345678 with size 128
Crypt is   * b ls M  
Crypt is 139 0 188 42 175 98 18 177 108 27 115 189 77 144 127 176
Decrypt is 1234567812345678
Decrypt is 49 50 51 52 53 54 55 56 49 50 51 52 53 54 55 56

      

Erlang version:

-module(test_crypto).

-export([
         test/0
        ]).

test() ->

    Key  = <<"abcdefghabcdefgh">>,
    IV   = <<"12345678abcdefgh">>,
    Text = <<"1234567812345678">> ,

    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]),

    Decrypt = crypto:aes_cfb_128_decrypt(Key, IV, Crypt),
    io:format("Decrypt is ~p~n", [Decrypt]),
    ok.

      

And when I run it, I get Erlang output:

Key  is <<"abcdefghabcdefgh">> with size 128
IV   is <<"12345678abcdefgh">> with size 128
Text is <<"1234567812345678">> with size 128
Crypt is <<139,182,94,68,208,173,127,90,14,236,33,230,41,29,210,121>>
Decrypt is <<"1234567812345678">>

      

So they each do the encryption / decryption cycle correctly, but the crypto form is different - I can't use it between Erlang and PHP.

I'm sure there is a simple explanation, but I don't understand how to figure it out.

PHP accepts strings as input - Erlang accepts binaries, but it looks like PHP ascii strings are stored as binaries. Is this correct or am I missing something?

Update 1

I realized that the function crypto:md5_mac/2

can be replicated using a php function:

function encrypt_term_hex($Key, $Msg) {
    return hash_hmac("md5", $Msg, $Key);
}

      


Original question

I want to exchange information between two systems written in Erlang and one in PHP.

The plan is to use a system that already works between multiple Erlang systems, which involves signing an Erlang term with a private key that is shared between Erlang systems.

The Erlang side uses functions crypto:md5_mac/2

and crypto:aes_cfb_128_encrypt/3

, which in turn uses the underlying OpenSSL cryptographic libraries.

Encryption side (in Erlang):

encrypt_bin(Key0, PlainT0) ->
    PlainT = extend(PlainT0),
    Key = crypto:md5_mac(get_server_salt(), Key0),
    crypto:aes_cfb_128_encrypt(Key, get_salt(), PlainT).

      

What this function does is take a pair of key values. It then expands the term size to a fixed size, generates a key using md5_mac and a fixed (shared) salt, and finally encrypts - initializes it with a different salt vector.

So far so good. My task then is to replicate this fn in PHP (and of course to decrypt its double).

Erlang documentation is good:

http://erlang.org/doc/man/crypto.html

Trying to figure out exactly how Erlang calls the underlying Crypto libraries is a little trickier because the source code shows hidden NIF macros.

It looks like PHP is implementing a library wrapper around OpenSSL, so it should be straight forward. Unfortunately, I can neither head nor tail. For example, I am looking at openssl-encrypt and it states that it is not documented:

http://php.net/manual/en/function.openssl-encrypt.php

Is there somewhere I can get good examples / documentation on how OpenSSL is implemented in PHP? Or how does the Erlang NIF loader work? Or both?

+3


source to share


1 answer


I switched the question to the Security StackExchange - got the answer. https://security.stackexchange.com/questions/30168/aes-cfb-128-decryption-encryption-problem-between-erlang-and-php



0


source







All Articles