Aquí están mis requisitos:¿Por qué algo cifrado en PHP no coincide con la misma cadena cifrada en Ruby?
Necesito encriptar una cadena en PHP usando encriptación AES (incluyendo un iv aleatorio), Base64 la codifica, luego la URL lo codifica para que pueda pasarse como un parámetro de URL.
Estoy tratando de obtener el mismo resultado tanto en PHP como en Ruby, pero no puedo hacerlo funcionar.
Aquí está mi código PHP:
function encryptData($data,$iv){
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$iv_size = mcrypt_enc_get_iv_size($cipher);
if (mcrypt_generic_init($cipher, 'g6zys8dlvvut6b1omxc5w15gnfad3jhb', $iv) != -1){
$cipherText = mcrypt_generic($cipher,$data);
mcrypt_generic_deinit($cipher);
return $cipherText;
}
else {
return false;
}
}
$data = 'Mary had a little lamb';
$iv = '96b88a5f0b9efb43';
$crypted_base64 = base64_encode(encryptData($data, $iv));
Aquí está mi código Ruby:
module AESCrypt
def AESCrypt.encrypt(data, key, iv)
aes = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
aes.encrypt
aes.key = key
aes.iv = iv
aes.update(data) + aes.final
end
end
plaintext = "Mary had a little lamb"
iv = "96b88a5f0b9efb43"
@crypted = AESCrypt::encrypt(plaintext, "g6zys8dlvvut6b1omxc5w15gnfad3jhb", iv)
@crypted_base64 = Base64.encode64(@crypted)
@crypted_base64_url = CGI.escape(@crypted_base64)
Lo irritante es que ambos ejemplos de código producen similares pero no idénticos valores hash. Por ejemplo, el código anterior genera (base64, no codificado en URL):
PHP: /aRCGgLBMOOAarjjtfTW2Qg2OtbPDLhx3KmgfgMzDJU=
Ruby: /aRCGgLBMOOAarjjtfTW2XIZhZ9VjBx8PdozxSL8IE0=
¿Puede alguien explicar lo que estoy haciendo mal aquí? Además, es más fácil para mí (ya que soy un tipo de Ruby, no PHP por lo general) para arreglar el código de Ruby en lugar del código de PHP. Entonces, si quisieras proporcionar una solución en Ruby que se emparejara bien con PHP, estaría muy agradecido.
Ah, y también, en producción, el iv realmente será aleatorio, pero para este ejemplo lo configuré para que sea permanentemente el mismo, de manera que se pueda comparar la salida.
EDIT:
Gracias a la respuesta de Eugen Rieck, llegué a una solución. Ruby rellena los bloques, pero PHP no, y tienes que hacerlo manualmente. Cambiar el código PHP a la siguiente, y se obtiene cuerdas cifrados que el código anterior Ruby puede descifrar fácilmente:
$iv = '96b88a5f0b9efb43';
$data = 'Mary had a little lamb';
function encryptData($data,$iv){
$key = 'g6zys8dlvvut6b1omxc5w15gnfad3jhb';
$padded_data = pkcs5_pad($data);
$cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $padded_data, MCRYPT_MODE_CBC, $iv);
return $cryptogram;
}
function pkcs5_pad ($text, $blocksize){
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
No puedo ayudar con la solución, pero creo que esto podría tener algo que ver con el relleno de bloques (ya que las cadenas de salida son las mismas para los primeros n caracteres). Es posible que desee probar agregar relleno a texto plano de forma manual en función del tamaño del bloque. – Mikk
Tu código de Ruby está invocando AES-256. Su código PHP está invocando AES-128. ¿Estas seguro que esto es correcto? Tu IV es claramente para 128 ... – Charles
@Charles Yo tampoco entiendo esto. Sin embargo, esta es la única forma en que funcionan las cosas.Cambiar PHP para invocar AES-256 hace que Ruby genere un error de "descifrado incorrecto" de OpenSSL. (Consulte el hilo listado en mi comentario a la respuesta a continuación, discute esto más adelante) También [este] (http://www.chilkatsoft.com/p/php_aes.asp) proporciona una explicación completa de las rarezas de encriptación de PHP. Creo que aclara tu pregunta. – John