CryptoJs - Crittografa / decrittografa con PHP e Javascript - Stringa crittografata di output semplice
Voglio crittografare e decrittografare alcune stringhe in Php e in Javascript e cercando sul web, il modo migliore e più sicuro sembra essere CryptoJs.
Questo post non è un duplicato di Encrypt with PHP, Decrypt with Javascript (cryptojs) perché la stringa di output non è semplice.
Questo è il mio codice ma il codice di decrittografia di Js non funziona. Cosa c'è che non va?
<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. Meglio se la stringa di output ($ crittografata) fosse di 16 cifre A-Za-z0-9 ... è possibile cambiare 'aes-256-cbc'?
Risposte
Nel codice PHP dovrebbe essere considerato quanto segue:
$passphrasenon denota una passphrase, ma la chiave. Questa chiave deve avere una dimensione di 32 byte per la sceltaaes-256-cbc. Se è troppo corto, viene riempito con valori 0, se è troppo lungo, viene troncato. Questa è una comune fonte di errore, quindi dovrebbe essere utilizzata una chiave di esattamente 32 byte. Se vuoi lavorare con una passphrase, devi usare un KDF (come PBKDF2).- Nel quarto parametro vengono impostati i flag e nessuna espressione booleana (come
true). Se i dati devono essere restituiti in formato binario,OPENSSL_RAW_DATAè necessario impostare il flag. - Gli IV statici non sono sicuri, di solito viene generato un nuovo IV per ogni crittografia, che viene inviato al destinatario insieme al testo cifrato. Poiché l'IV non è segreto, di solito viene posizionato davanti al testo cifrato a livello di byte senza crittografia.
Il seguente codice PHP di esempio (basato sul codice pubblicato):
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");
restituisce il seguente risultato:
1SF+kez1CE5Rci3H6ff8og==
MyText
Il codice CryptoJS corrispondente per la decrittazione è:
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>
con l'output MyTextche corrisponde al testo in chiaro originale.
È importante che la chiave venga passata come WordArray, in modo che venga interpretata come una chiave e non come una passphrase. Per la conversione CryptoJS fornisce codificatori (simili CryptoJS.enc.Utf8).
Per quanto riguarda la tua domanda alla fine: i testi cifrati sono sequenze binarie arbitrarie che possono essere convertite in una stringa con speciali codifiche binarie in testo (ad esempio Base64 come in questo caso, o esadecimale), che è generalmente più lunga dei dati grezzi (Base64: 75% di efficienza, esadecimale: 50% di efficienza, vedi qui ).
La rappresentazione di un blocco di testo cifrato con un numero di caratteri alfanumerici (es. 16 caratteri) uguale alla dimensione del blocco (es. 16 byte per AES) non è generalmente possibile.
Si noti che la conversione in una stringa con una codifica del set di caratteri come UTF8 non è una soluzione, ma danneggerebbe i dati.