2012-04-03 34 views
14

Actualmente tenemos una implementación de mcrypt en nuestros sistemas para cifrar algunos datos sensibles en nuestra aplicación PHP. Ahora tenemos un nuevo requisito de que tenemos que cambiar el módulo cripta a openssl. Otra cosa que es importante saber es que estamos usando el cifrado blowfish y el modo ecb. Así que comencé a probar cuáles son las diferencias y cómo puedo descifrar las cadenas cifradas de mcrypt con openssl.Reemplace Mcrypt con OpenSSL

I utiliza la función de PHP estándar:

  • MCRYPT_ENCRYPT vs. openssl_encrypt
  • MCRYPT_DECRYPT vs. openssl_decrypt

Ambos métodos están entregando resultados diferentes. Lo segundo es que en el cifrado (pez globo) y modo (ecb) dado en ambos tipos se requieren diferentes longitudes IV (openssl = 0 y mcrypt = 56).

¿Alguien sabe cómo puedo cambiar fácilmente los módulos sin tener que realizar un gran esfuerzo de migración?

¡Gracias de antemano!

ACTUALIZACIÓN:

Aquí está el código, lo que he comprobado:

<?php 

function say($message){ 
    if(!is_string($message)){ 
     if(!isset($_SERVER["HTTP_USER_AGENT"])) echo "<pre>"; 
     echo var_export($message, true) . ((!isset($_SERVER["HTTP_USER_AGENT"]) ? "\n" : "<br />")); 
     if(!isset($_SERVER["HTTP_USER_AGENT"])) echo "</pre>"; 
    }else{ 
     echo $message . ((!isset($_SERVER["HTTP_USER_AGENT"]) ? "\n" : "<br />")); 
    } 
} 

say("= Begin raw encryption"); 
$key = "anotherpass"; 
$str = "does it work"; 

say(" Params:"); 
say(" - String to encrypt '".$str."'"); 
say(" - Key: ".$key); 
say(""); 


$params = array(
    "openssl" => array(
     "cipher" => "BF", 
     "mode"  => "ECB", 
    ), 
    "mcrypt" => array(
     "cipher" => "blowfish", 
     "mode"  => "ecb", 
    ), 
); 

say("= Mcrypt"); 
$handler = mcrypt_module_open($params['mcrypt']['cipher'], '', $params['mcrypt']['mode'], ''); 
$iv  = mcrypt_create_iv (mcrypt_enc_get_iv_size($handler), MCRYPT_RAND); 
$keysize = mcrypt_enc_get_key_size($handler); 
mcrypt_generic_init($handler,$key,"\0\0\0\0\0\0\0\0"); 
say(" Params:"); 
say(" - InitVector ".bin2hex($iv)." (bin2hex)"); 
say(" - Max keysize ".$keysize); 
say(" - Cipher  ".$params['mcrypt']['cipher']); 
say(" - Mode   ".$params['mcrypt']['mode']); 
say(""); 
say(" Encryption:"); 
$m_encrypted = mcrypt_generic($handler, $str); 
$m_decrypted = mdecrypt_generic($handler, $m_encrypted); 
say(" - Encrypted ".bin2hex($m_encrypted)." (bin2hex)"); 
say(" - Descrypted ".$m_decrypted); 
say(""); 


say("= Openssl"); 
say(" Params:"); 
say(" - InitVector not needed"); 
say(" - Max keysize ".openssl_cipher_iv_length($params['openssl']['cipher']."-".$params['openssl']['mode'])); 
say(" - Cipher  ".$params['openssl']['cipher']); 
say(" - Mode   ".$params['openssl']['mode']); 
say(""); 
say(" Encryption:"); 
$o_encrypted = openssl_encrypt($str,$params['openssl']['cipher']."-".$params['openssl']['mode'],$key,true); 
$o_decrypted = openssl_decrypt($o_encrypted,$params['openssl']['cipher']."-".$params['openssl']['mode'],$key,true); 
say(" - Encrypted ".bin2hex($o_encrypted)." (bin2hex)"); 
say(" - Descrypted ".$o_decrypted); 

y este es mi resultado:

= Begin raw encryption 
    Params: 
    - String to encrypt 'does it work' 
    - Key: anotherpass 

= Mcrypt 
    Params: 
    - InitVector 06a184909d7bf863 (bin2hex) 
    - Max keysize 56 
    - Cipher  blowfish 
    - Mode   ecb 

    Encryption: 
    - Encrypted 0e93dce9a6a88e343fe5f90d1307684c (bin2hex) 
    - Descrypted does it work 

= Openssl 
    Params: 
    - InitVector not needed 
    - Max keysize 0 
    - Cipher  BF 
    - Mode   ECB 

    Encryption: 
    - Encrypted 213460aade8f9c14d8d51947b8231439 (bin2hex) 
    - Descrypted does it work 

Tal vez alguna idea ahora?

Gracias!

+7

ya sea que usted tiene que ejecutar un script de migración que descifra los datos actuales utilizando mcrypt y lo vuelve a cifrar usando openssl, o de lo contrario' Necesitaré implementar un método mediante el cual sepas qué funciones de cifrado/descifrado usar para cada elemento de datos, y cambiarlas de mcrypt a openssl según sea necesario cuando sigas accediendo a algunos datos cifrados usando mcrypt. – Jon

+1

Según tengo entendido, mcrypt y open_ssl usan diferentes métodos de derivación de claves y, por lo tanto, Jon tiene razón, deberá migrar por descifrado y luego cifrar o marcar datos para que se migre a medida que se acceda a ellos. –

+0

Me pregunto por qué se requiere IB en modo ECB. Consulte la descripción del modo ECB en http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation. – doptimusprime

Respuesta

8

Blowfish es la cifra del bloque. Requiere que los datos sean rellenos antes del cifrado. OpenSSL usa PKCS # 7 y mcrypt usa PKCS # 5. Diferentes algoritmos de relleno para los datos. La longitud mínima de relleno de PKCS # 5 es 0, para PKCS # 7 es 1 (wikipedia). Echar un vistazo a este ejemplo (he datos de entrada acolchados manualmente para mcrypt_encrypt() en PKCS # 7 estilo):

<?php 

$key = "anotherpassword1"; 
$str = "does it work 12"; 

$enc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $str."\1", MCRYPT_MODE_ECB); 
$dec = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $enc, MCRYPT_MODE_ECB); 
echo(bin2hex($enc).PHP_EOL); 
var_dump($dec); 

$enc = openssl_encrypt($str, 'bf-ecb', $key, true); 
$dec = openssl_decrypt($enc, 'bf-ecb', $key, true); 
echo(bin2hex($enc).PHP_EOL); 
var_dump($dec); 

?> 

Es imposible openssl_decrypt() datos cifrados con MCRYPT_ENCRYPT(), a menos que el relleno manual de los datos se realizó con Se llamó PKCS # 7 antes de mcrypt_encrypt().

Solo hay una forma en su caso: volver a cifrar los datos.

PS: Hay un error en su código fuente - modo ECB no se utiliza en absoluto IV (wikipedia)

+1

Gracias, esta sugerencia me ayudó a hacer Rijndael-128/AES-128 compatible entre MCrypt y OpenSSL. Desafortunadamente, no funciona para Blowfish - – Narf

+0

Resulta que funciona para Blowfish, PERO el tamaño de la clave debe tener al menos 16 bytes (el artículo de Wikipedia para Blowfish dice que admite menos). – Narf

+0

Es debido al relleno en PKCS # 7 – clover

-1

@clover es correcto que el relleno por defecto para Blowfish es diferente entre mcrypt y Openssl, pero es un error que no se puede hacer.Si se utiliza la opción OPENSSL_ZERO_PADDING para el descifrado en realidad ambos son compatibles:

openssl_decrypt($data, 'bf-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); 
+0

'OPENSSL_ZERO_PADDING' no agrega relleno, cualquier relleno no estándar deberá agregarse manualmente antes de cifrado y eliminado en el descifrado. Desde los documentos [openssl_encrypt] (https://secure.php.net/manual/en/function.openssl-encrypt.php), quizás esté usando una versión diferente. De los comentarios del doc: Entonces, OPENSSL_ZERO_PADDING desactiva el relleno para el contexto, lo que significa que tendrá que aplicar manualmente su propio relleno al tamaño del bloque. Sin usar OPENSSL_ZERO_PADDING, obtendrá automáticamente el relleno PKCS # 7. – zaph