web-dev-qa-db-fra.com

Crypter avec PHP, décrypter avec Javascript (cryptojs)

J'ai des problèmes avec le cryptage/décryptage de base. J'ai cherché partout un exemple qui fonctionne, mais je n'ai pas encore trouvé un exemple qui fonctionne.

-Je vais chiffrer en php, déchiffrer avec cryptojs pour une petite couche de sécurité

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">
<?
$text = "this is the text here";
$key = "encryptionkey";

$msgEncrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_Rand));
$msgBase64 = trim(base64_encode($msgEncrypted));

echo "<h2>PHP</h2>";
echo "<p>Encrypted:</p>";
echo $msgEncrypted;
echo "<p>Base64:</p>";
echo $msgBase64;
 ?>

<p>AES Decrypt</p>
<script> 
    var key = 'encryptionkey';
    var encrypted = "<?php echo $msgBase64 ?>";
    //tried  var base64decode = CryptoJS.enc.Base64.parse(encrypted); 
    var decrypted = CryptoJS.AES.decrypt(encrypted, key);
    console.log( decrypted.toString(CryptoJS.enc.Utf8) );
</script>

Quel est le pas qui me manque?

28
user2769

J'ai demandé la même chose et j'ai écrit une courte bibliothèque qui fonctionne pour CryptoJS 3.x et PHP avec le support openssl. J'espère que cela vous aidera, la source et des exemples de fichiers ici https://github.com/brainfoolong/cryptojs-aes-php

PHP Lib

/**
* Decrypt data from a CryptoJS json encoding string
*
* @param mixed $passphrase
* @param mixed $jsonString
* @return mixed
*/
function cryptoJsAesDecrypt($passphrase, $jsonString){
    $jsondata = json_decode($jsonString, true);
    $salt = hex2bin($jsondata["s"]);
    $ct = base64_decode($jsondata["ct"]);
    $iv  = hex2bin($jsondata["iv"]);
    $concatedPassphrase = $passphrase.$salt;
    $md5 = array();
    $md5[0] = md5($concatedPassphrase, true);
    $result = $md5[0];
    for ($i = 1; $i < 3; $i++) {
        $md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
        $result .= $md5[$i];
    }
    $key = substr($result, 0, 32);
    $data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
    return json_decode($data, true);
}

/**
* Encrypt value to a cryptojs compatiable json encoding string
*
* @param mixed $passphrase
* @param mixed $value
* @return string
*/
function cryptoJsAesEncrypt($passphrase, $value){
    $salt = openssl_random_pseudo_bytes(8);
    $salted = '';
    $dx = '';
    while (strlen($salted) < 48) {
        $dx = md5($dx.$passphrase.$salt, true);
        $salted .= $dx;
    }
    $key = substr($salted, 0, 32);
    $iv  = substr($salted, 32,16);
    $encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true, $iv);
    $data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s" => bin2hex($salt));
    return json_encode($data);
}

Javascript Lib

var CryptoJSAesJson = {
    stringify: function (cipherParams) {
        var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)};
        if (cipherParams.iv) j.iv = cipherParams.iv.toString();
        if (cipherParams.salt) j.s = cipherParams.salt.toString();
        return JSON.stringify(j);
    },
    parse: function (jsonStr) {
        var j = JSON.parse(jsonStr);
        var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
        if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
        if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
        return cipherParams;
    }
}

Exemple Javascript

var encrypted = CryptoJS.AES.encrypt(JSON.stringify("value to encrypt"), "my passphrase", {format: CryptoJSAesJson}).toString();
var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, "my passphrase", {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));

Exemple PHP

$encrypted = cryptoJsAesEncrypt("my passphrase", "value to encrypt");
$decrypted = cryptoJsAesDecrypt("my passphrase", $encrypted);
50
Brain Foo Long

Vous utilisez deux bibliothèques qui tentent de prendre en charge des entrées qui, à proprement parler, ne sont pas valides. Rijndael nécessite des clés comportant de longues chaînes d'octets aléatoires de 16, 24 ou 32 octets. Vous fournissez une chaîne de 13 caractères. Mcrypt, la bibliothèque PHP, utilise la chaîne (probablement codée en utf8) directement en tant qu'entrée binaire et zéro la remplit aux 32 octets requis pour MCRYPT_RIJNDAEL_256. CryptoJS, d’autre part décide que vous avez entré quelque chose comme une phrase secrète et utilise plutôt une fonction de dérivation de clé pour générer une clé de 32 octets .

De plus, les algorithmes de chiffrement utilisés ne correspondent même pas. Mcrypt utilise une variante rarement implémentée de Rijndael d'origine pour la version 256 bits, tandis que CryptoJS implémente la variante bien connue AES256 de la proposition Rijndael. La version 128 bits des deux (MCRYPT_RIJNDAEL_128 et AES128) est identique.

Le troisième problème que vous allez rencontrer plus tard est que Mcrypt utilise également un schéma de remplissage insensé pour les données cryptées. Rijndael étant un chiffrement par bloc, il ne peut chiffrer que des blocs de 16, 24 ou 32 octets (selon la variante - AES utilise toujours des blocs de 16 octets). En tant que telles, les données doivent être complétées. Mcrypt le fait de manière non injective en ajoutant simplement des zéros. Si vous ne codifiez que des chaînes, cela ne vous posera pas un problème car les chaînes codées par utf8 ne contiennent jamais zéro octet. Vous pouvez donc les supprimer ( CryptoJS prend même en charge nativement ).

La solution la plus simple à tous ces problèmes est d’éviter de mettre en œuvre une cryptographie vous-même (elle est fortement déconseillée de toute façon sans une grande connaissance du sujet). Pouvez-vous plutôt transmettre vos informations sensibles via https, qui utilisera TLS (anciennement appelé SSL) pour chiffrer et authentifier le canal?

3
Perseids

N'allez pas trop loin avec le codage, utilisez simplement le décodeur Base64

sur le code php:

$encrypt_val=base64_encode("value");

et sur js juste:

var my_orignal_val = window.atob(passed_val);

Cela suffira à vos besoins.

0
Kashif Anwar