Tengo un código php heredado que cifra con el método TripleDES como parte de un flujo bancario para cifrar las operaciones de compra. Este es el código:
/****** 3DES Function ******/ function encrypt_3DES($message, $key){ $l = ceil(strlen($message) / 8) * 8; return substr(openssl_encrypt($message . str_repeat("\0", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0"), 0, $l); } Quiero reproducir el mismo código en javascript usando TripleDES de CriptoJS. Esta es mi prueba hasta ahora:
<script src=https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/tripledes.js></script> <script> function encrypt_3DES(message, key) { // Parse input parameters message = CryptoJS.enc.Utf8.parse(message); key = CryptoJS.enc.Utf8.parse(key); // Build an iv with zero values let iv = CryptoJS.lib.WordArray.create(64/8); let encrypted = CryptoJS.TripleDES.encrypt(message, key, {iv: iv}); // Encrypt with TripleDES return encrypted.toString(); } let message = "testMessage"; let key = "testKey"; let encrypted = encrypt_3DES(message, key); // encrypted: "HLu4p18KtFfy5VjwjFkDHA==" </script> Tomando los valores de ejemplo, el resultado es la cadena "HLu4p18KtFfy5VjwjFkDHA==" .
El problema es que los resultados entre js y php son ligeramente diferentes, y mis sospechas apuntan a la operación substr realizada en el lado php, porque cuando estoy convirtiendo el resultado de la operación open_ssl (sin la subcadena), mi código javascript está devolviendo la misma cadena base64 :
<?php /****** 3DES Function ******/ function encrypt_3DES($message, $key) { $l = ceil(strlen($message) / 8) * 8; return substr(openssl_encrypt($message . str_repeat("\0", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0"), 0, $l); } $message = "testMessage"; $key = "testKey"; $res = base64_encode(encrypt_3DES($message, $key)); $res2 = base64_encode(openssl_encrypt($message, 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0")); /* $res: HLu4p18KtFfTr47KvI/WEw== (My goal is to get this in javascript) */ /* $res2: HLu4p18KtFfy5VjwjFkDHA== (without the substr operation, the results match) */ ?>Entonces, mi pregunta es: ¿hay alguna forma de aplicar la misma subcadena al resultado cifrado de la operación CryptoJS de javascript?
El código PHP implementa un relleno cero personalizado. Sin embargo, el relleno PKCS#7 predeterminado no está deshabilitado, por lo que, además del relleno cero explícito, el relleno PKCS#7 implícito agrega innecesariamente un bloque completo.
Este último bloque innecesario se elimina usando substr() . La conclusión es que simplemente se utiliza relleno cero.
Una implementación de PHP más eficiente sería simplemente deshabilitar el relleno predeterminado con OPENSSL_ZERO_PADDING en lugar de truncar el último bloque:
return openssl_encrypt($message . str_repeat("\0", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, "\0\0\0\0\0\0\0\0"). De todos modos, para que el código C# devuelva el mismo texto cifrado que el código PHP, el relleno en el código C# debe cambiarse a CryptoJS.pad.ZeroPadding .
Tenga en cuenta que un IV estático (como el IV cero que se usa aquí) es inseguro, TripleDES es lento (mejor: AES) y el relleno cero no es confiable (mejor: PKCS#7).
Además, los tamaños de clave válidos para TripleDES son 24 bytes y 16 bytes .
Prueba:
El código PHP a continuación:
$key = '012345678901234567890123'; $message = 'The quick brown fox jumps over the lazy dog'; print(base64_encode(encrypt_3DES($message, $key)) . PHP_EOL);produce el siguiente texto cifrado codificado en Base64:
HNQad59lGkM83byQY2pwhluVkB7YOyIx/kGh/ibcIXQdFoiODkD1kTIIEHhqcoFmEl código JavaScript fijo proporciona el mismo texto cifrado.
function encrypt_3DES(message, key) { // Parse input parameters message = CryptoJS.enc.Utf8.parse(message); key = CryptoJS.enc.Utf8.parse(key); // Build an iv with zero values let iv = CryptoJS.lib.WordArray.create(64/8); let encrypted = CryptoJS.TripleDES.encrypt(message, key, {iv: iv, padding: CryptoJS.pad.ZeroPadding}); // Encrypt with TripleDES return encrypted.toString(); } let message = "The quick brown fox jumps over the lazy dog"; let key = "012345678901234567890123"; let encrypted = encrypt_3DES(message, key); document.getElementById("ct").innerHTML = encrypted; <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script> <p style="font-family:'Courier New', monospace;" id="ct"></p>