En el lado del cliente (dispositivo móvil) me cifrar la contraseña de un usuario con CryptoJS:

var lib_crypt = require('aes');

$.loginButton.addEventListener('click', function(e){

var key = lib_crypt.CryptoJS.enc.Hex.parse('bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3');
var iv  = lib_crypt.CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');

var encrypted = lib_crypt.CryptoJS.AES.encrypt($.passwordInput.value, key, { iv: iv });

var password_base64 = encrypted.ciphertext.toString(lib_crypt.CryptoJS.enc.Base64); 
return password_base64; 
});

En el lado del servidor quiero descifrarlo con mcrypt_decrypt:

function decryptPassword($password)
{
    $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
    $ciphertext_dec = base64_decode($password);
    $iv_dec = "101112131415161718191a1b1c1d1e1f";

    $ciphertext_dec = substr($ciphertext_dec, 16);
    $decryptedPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

    return trim($decryptedPassword);
}

Puedo usar la misma clave y IV, ¿qué hago mal?

Es posible que desee agregar ejemplos de lo que los problemas que experimentan. Yo actualmente acaba de asumir en mi respuesta a juzgar por el código.
Gracias por la rápida respuesta de Artjom, ¿qué es mejor utilizar para eliminar el relleno: la solución de Martín Bodewes o trim()? Gracias
trim() sólo funciona en una vez en dieciséis años. Uno nunca debe trim(), debido a que podría resultar en consecuencias imprevistas si el texto contiene cero bytes o espacios en blanco al principio o al final.

OriginalEl autor Papauha | 2015-04-08

3 Comentarios

  1. 0

    Usted no está haciendo lo mismo en ambos lados.

    IV

    Hizo analizar el IV en CryptoJS, pero se olvidó de hacerlo en PHP:

    $iv_dec = pack('H*', "101112131415161718191a1b1c1d1e1f");

    Arreglar su IV está mal, usted probablemente ha notado que los primeros 16 bytes son un galimatías. Que sucede cuando el IV está mal. Tenga en cuenta que CryptoJS utiliza el modo CBC por defecto, por lo que el IV sólo tiene influencia en el primer bloque durante el descifrado. Quitar este:

    $ciphertext_dec = substr($ciphertext_dec, 16);

    Relleno

    Usted probablemente ha notado que la mayoría de los plaintexts no salen a la derecha. Terminan con unos extraños caracteres repetidos al final. Este es el relleno PKCS#7 que se aplica por defecto en CryptoJS. Usted tiene que quitar el relleno de sí mismo en PHP. Lo bueno es que Martín Bodewes ha proporcionado una adecuada copiar y pegar solución para este aquí.

    trim() podría ser apropiado para ZeroPadding, pero no cuando un adecuado esquema de relleno como el definido en PKCS#7 se utiliza. Usted puede quitar la trim() llamar del todo, porque no es útil y puede resultar en un texto simple, porqués de cero bytes y el espacio en blanco recortado desde el principio y el final.

    OriginalEl autor Artjom B.

  2. 14

    Hola,

    para lograr esto se debe considerar para el uso de la tecla y iv con 32 dígitos hexadecimales cada uno, tenía que resolver exactamente esta haciendo mis cosas y aquí está la forma en que va a

    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">
    </script>
    <script type="text/javascript">
    //The key and iv should be 32 hex digits each, any hex digits you want, but it needs to be 32 on length each
    var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
    var iv =  CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
    /*
    if you wish to have a more friendly key, you can convert letters to Hex this way:
    var a = "D";
    var hex_D = a.charCodeAt(0).toString(16);
    just to mention,
    if it were to binary, it would be:
    var binary_D = a.charCodeAt(0).toString(2);
    */
    
    var secret = "Hi, this will be seen uncrypted later on";
    
    //crypted
    var encrypted = CryptoJS.AES.encrypt(secret, key, {iv:iv});
    //and the ciphertext put to base64
    encrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64);    
    //Assuming you have control on the server side, and know the key and iv hexes(we do),
    //the encrypted var is all you need to pass through ajax,
    //Let's follow with welcomed pure JS style, to reinforce one and other concept if needed
    var xh = new XMLHttpRequest();
    xh.open("POST", "decrypt_in_php.php", true);
    xh.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xh.send("encrypted="+encodeURIComponent(encrypted));
    </script>

    Y ahora la recepción y descodificación en PHP

    <?php
    //Here we have the key and iv which we know, because we have just chosen them on the JS,
    //the pack acts just like the parse Hex from JS
    
    $key = pack("H*", "0123456789abcdef0123456789abcdef");
    $iv =  pack("H*", "abcdef9876543210abcdef9876543210");
    
    //Now we receive the encrypted from the post, we should decode it from base64,
    $encrypted = base64_decode($_POST["encrypted"]);
    $shown = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
    
    echo $shown;
    //Although the decrypted is shown, there may be needed to trim and str_replace some \r \n \x06 \x05, if there is not a better "trim" way to do it though
    ?>

    Con esto vamos a tener de nuevo el «Hola, esto será visto uncrypted tarde»
    🙂

    funciona perfectamente, gracias…
    bonita respuesta! funciona a la perfección …
    Cómo cambiar esto en el uso de clave de la cadena en su lugar?
    mcrypt_decrypt función será eliminado en php v7.2. Cualquier alternativa? ¿cómo sería ?

    OriginalEl autor Danilo G. Veraszto

  3. 1

    Aquí es una solución basada en este comentario, utilizando openssl_decrypt de PHP.

    La JavaScript parte (desarrollo con NodeJS para los navegadores) — en primer lugar, instalar CryptoJS con npm install crypto-js, entonces su código JS:

    import aes from 'crypto-js/aes'
    import encHex from 'crypto-js/enc-hex'
    import padZeroPadding from 'crypto-js/pad-zeropadding'
    
    //message to encrypt
    let msg = "Hello world";
    
    //the key and iv should be 32 hex digits each, any hex digits you want, but it needs to be 32 on length each
    let key = encHex.parse("0123456789abcdef0123456789abcdef");
    let iv =  encHex.parse("abcdef9876543210abcdef9876543210");
    
    //encrypt the message
    let encrypted = aes.encrypt(msg, key, {iv:iv, padding:padZeroPadding}).toString();
    
    //and finally, send this "encrypted" string to your server

    Sobre la PHP lado, el código se verá así:

    //we use the same key and IV
    $key = hex2bin("0123456789abcdef0123456789abcdef");
    $iv =  hex2bin("abcdef9876543210abcdef9876543210");
    
    //we receive the encrypted string from the post
    $encrypted = $_POST['decrypt'];
    $decrypted = openssl_decrypt($encrypted, 'AES-128-CBC', $key, OPENSSL_ZERO_PADDING, $iv);
    //finally we trim to get our original string
    $decrypted = trim($decrypted);

    OriginalEl autor AymKdn

Dejar respuesta

Please enter your comment!
Please enter your name here