CryptoJs - Crypter / Décrypter par PHP et Javascript - Chaîne cryptée de sortie simple

Sep 23 2020

Je veux crypter et décrypter une chaîne en Php et en Javascript et en regardant sur le Web, le moyen le meilleur et le plus sûr semble être CryptoJs.

Ce message n'est pas un doublon de Encrypt with PHP, Decrypt with Javascript (cryptojs) car la chaîne de sortie n'est pas simple.

Ceci est mon code mais le code de décryptage Js ne fonctionne pas. Qu'est-ce qui ne va pas?

<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
    </head>
    <body>
        <p>--- PHP ------------------</p>
    
        <?php
            function myCrypt($value, $passphrase, $iv){ $encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $passphrase, true, $iv); return base64_encode($encrypted_data);
            }
            
            function myDecrypt($value, $passphrase, $iv){ $value = base64_decode($value); $data = openssl_decrypt($value, 'aes-256-cbc', $passphrase, true, $iv); return $data;
            }
            

            $valTxt="MyText"; $pswd="MyPassword";
            $vector="1234567890123412"; $encrypted = myCrypt($valTxt, $pswd, $vector); $decrypted = myDecrypt($encrypted, $pswd, $vector); echo "<p>Text to crypt --------> ".$valTxt." </p>";
            echo "<p>Password: ".$pswd." </p>"; echo "<p>Vector: ".$vector." </p>";
            echo "<p>TextEncrypt: ".$encrypted." </p>"; echo "<p>TextDecrypt: ".$decrypted." </p>";
        ?>
        
        <br><br><br>
        <p>--- Javascript ------------------</p>
        <p>JS-DataEncrypt: --------- <span id="DataEncrypt"></span></p>
        <p>JS-DataPassword: -------- <span id="DataPassword"></span></p>
        <p>JS-DataVector: ---------- <span id="DataVector"></span></p>
        <p>JS-TextDecrypted: ------- <span id="result"></span></p>
        
        <script>
            var DataEncrypt='<?php echo $encrypted;?>'; var DataPassword='<?php echo $pswd;?>';
            var DataVector='<?php echo $vector;?>';
            
            //var key = CryptoJS.enc.Hex.parse(DataPassword);
            //var iv = CryptoJS.enc.Hex.parse(DataVector);
            //var decrypted = CryptoJS.AES.decrypt(DataEncrypt, key, { iv: iv });
            
            var decrypted = CryptoJS.AES.decrypt(DataEncrypt, DataPassword, { iv: DataVector });
            
            decrypted= CryptoJS.enc.Utf8.stringify(decrypted)
            
            
            
            document.getElementById("DataEncrypt").innerHTML = DataEncrypt;
            document.getElementById("DataPassword").innerHTML = DataPassword;
            document.getElementById("DataVector").innerHTML = DataVector;
            document.getElementById("result").innerHTML = decrypted;
        </script>
    
    
        
    </body>
</html>

PS. Mieux vaut si la chaîne de sortie ($ encrypted) sera de 16 chiffres A-Za-z0-9 ... est-il possible de changer 'aes-256-cbc'?

Réponses

3 Topaco Sep 23 2020 at 03:21

Dans le code PHP, les éléments suivants doivent être pris en compte:

  • $passphrasene désigne pas une phrase de passe, mais la clé. Cette clé doit avoir une taille de 32 octets pour le choix aes-256-cbc. S'il est trop court, il est rempli de valeurs 0, s'il est trop long, il est tronqué. Il s'agit d'une source d'erreur courante, donc une clé d'exactement 32 octets doit être utilisée. Si vous voulez travailler avec une phrase secrète, vous devez utiliser un KDF (comme PBKDF2).
  • Dans le quatrième paramètre, des indicateurs sont définis, et aucune expression booléenne (comme true). Si les données doivent être renvoyées sous forme binaire, l' OPENSSL_RAW_DATAindicateur doit être défini.
  • Les IV statiques ne sont pas sécurisés, généralement un nouveau IV est généré pour chaque cryptage, qui est envoyé au destinataire avec le texte chiffré. Puisque l'IV n'est pas secret, il est généralement placé devant le texte chiffré au niveau de l'octet sans cryptage.

L'exemple de code PHP suivant (basé sur le code publié):

function myCrypt($value, $key, $iv){
    $encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    return base64_encode($encrypted_data); } function myDecrypt($value, $key, $iv){
    $value = base64_decode($value);
    $data = openssl_decrypt($value, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    return $data; } $valTxt="MyText";
$key="01234567890123456789012345678901"; // 32 bytes $vector="1234567890123412"; // 16 bytes
$encrypted = myCrypt($valTxt, $key, $vector);
$decrypted = myDecrypt($encrypted, $key, $vector);
print($encrypted . "\n"); print($decrypted . "\n");

renvoie le résultat suivant:

1SF+kez1CE5Rci3H6ff8og==
MyText

Le code CryptoJS correspondant pour le décryptage est:

var DataEncrypt = "1SF+kez1CE5Rci3H6ff8og==";
var DataKey = CryptoJS.enc.Utf8.parse("01234567890123456789012345678901");
var DataVector = CryptoJS.enc.Utf8.parse("1234567890123412");
var decrypted = CryptoJS.AES.decrypt(DataEncrypt, DataKey, { iv: DataVector });        
var decrypted = CryptoJS.enc.Utf8.stringify(decrypted);
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

avec la sortie MyTextqui correspond au texte brut d'origine.

Il est important que la clé soit transmise en tant que WordArray, afin qu'elle soit interprétée comme une clé et non comme une phrase de passe. Pour la conversion, CryptoJS fournit des encodeurs (comme CryptoJS.enc.Utf8).


En ce qui concerne votre question à la fin: Les textes chiffrés sont des séquences arbitraires binaires qui peuvent être converties en une chaîne avec des codages binaire-texte spéciaux (par exemple Base64 comme dans ce cas, ou hexadécimal), qui est généralement plus longue que les données brutes (Base64: 75% d'efficacité, hexadécimal: 50% d'efficacité, voir ici ).
La représentation d'un bloc de texte chiffré avec un nombre de caractères alphanumériques (par exemple 16 caractères) égal à la taille du bloc (par exemple 16 octets pour AES) n'est donc généralement pas possible.
Notez que la conversion en une chaîne avec un encodage de jeu de caractères tel que UTF8 n'est pas non plus une solution, mais corromprait les données.