aes cfb 128 descifrado / problema de encriptación entre Erlang y PHP

3

Actualización 2: funciona

Gracias a Tom Leek por su respuesta.

El modo CFB de mycrypt para Rijndael usa un bucle de retroalimentación de 8 bits y no un bucle de retroalimentación de la longitud de la clave / iv.

Tienes que obligarlo a usar la longitud completa con el parámetro ncfb . Confusamente, esta no es una constante documentada en la biblioteca de PHP Mcrypt: enlace

Las líneas apropiadas en el PHP ahora se ven así:

$Crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $Key, $Text, 'ncfb', $IV);

$Decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $Key, $Crypt, 'ncfb', $IV);

Actualizado - ver abajo

Estoy tratando de obtener un sitio de Erlang para intercambiar información a través del cifrado aes_cfb_128 con un sitio PHP. Estoy escribiendo una implementación de prueba que demostrará que el PHP descifra lo que el Erlang encripta y viceversa, pero tengo problemas.

Aquí está la fuente de PHP (disculpas, es un poco de mala calidad, mi PHP no es bueno, soy un programador de Erlang):

<?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);
?>

Aquí está la fuente correspondiente de Erlang:

-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.

Aquí está la salida de PHP:

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

Aquí está la salida de Erlang:

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

Como puede ver, ambos bloques de código se completan correctamente, pero no funcionarán juntos porque no crean el texto cifrado idéntico.

Los primeros 16 bytes del cipertexto son iguales, pero el segundo bloque de 16 bytes es diferente.

Sé que este algoritmo usa el primer bloque de salida en el cifrado del segundo, por lo que sospecho que hay algunos problemas entre el modo en que el módulo Erlang crypto lo está haciendo y el código PHP mcrypt .

ACTUALIZAR

Intenté usar el modo CFB en mycrypt pero creo que hay un tamaño de bloque de comentarios diferente o algo así, y solo el primer carácter del cipertexto fue el mismo. El modo NOFB parece estar relacionado de alguna manera y es lo mejor que he conseguido hasta ahora ...

Si ejecuto el modo PHP con CFB obtengo esta salida:

~/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

Intenté obtener ayuda en StackOverflow enlace pero era sobre todo yo hablando conmigo mismo :(

    
pregunta Gordon Guthrie 02.02.2013 - 20:10
fuente

1 respuesta

3

Su código PHP utiliza MCRYPT_MODE_NOFB al cifrar y descifrar; utiliza la constante correcta MCRYPT_MODE_CFB cuando obtiene los tamaños de bloque y IV, pero después de cambiar a la otra constante. Como se explica en esta página , MCRYPT_MODE_NOFB no implementa CFB , pero otro modo llamado OFB . De ahí la discrepancia.

Actualización: los modos CFB y OFB tienen una "longitud de realimentación". Cuando utilizan una retroalimentación de n bits (de 1 al tamaño de bloque, es decir, 128 con AES), cifran n bits de datos por invocación del cifrado de bloque subyacente. El uso de una longitud de realimentación más pequeña que el tamaño del bloque hace que el cifrado sea más lento, por lo que nadie lo hace.

Históricamente, las pequeñas longitudes de retroalimentación estaban destinadas a ayudar con los medios de transporte que pueden perder tanto bits como sincronización, el tipo de descripción que se aplica a El telégrafo de Samuel Morse . Con retroalimentación de 1 bit, el descifrado puede "recuperarse" después de unos pocos bits, lo que limita el impacto del error de transmisión. Esta propiedad es bastante inútil en cualquier dispositivo electrónico que se haya inventado desde los días de Elvis Presley.

Inexplicablemente (pero típicamente), los diseñadores de PHP decidieron usar OFB con retroalimentación de 8 bits, reservando la constante alternativa ( NOFB ) para retroalimentación de bloque completo. Es posible que hayan hecho el mismo tipo de elección rara para CFB.

Resumen: tanto para CFB como para OFB (que son distintos entre sí y no se pueden usar indistintamente), debe preocuparse por la "longitud de realimentación" que no está necesariamente documentada con alta claridad en Diversas bibliotecas criptográficas. Tanto el cifrado como el descifrado deben utilizar la misma longitud de realimentación para interoperar.

    
respondido por el Tom Leek 02.02.2013 - 20:16
fuente

Lea otras preguntas en las etiquetas