CryptoJs - Criptografar / Descriptografar por PHP e Javascript - String criptografada de saída simples
Eu quero criptografar e descriptografar alguma string em Php e em Javascript e olhando na web, a maneira melhor e mais segura parece ser CryptoJs.
Este post não é uma duplicata de Encrypt with PHP, Decrypt with Javascript (cryptojs) porque a string de saída não é simples.
Este é o meu código, mas o código de descriptografia Js não funciona. O que há de errado?
<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. Melhor se a string de saída ($ criptografada) tiver 16 dígitos A-Za-z0-9 ... é possível alterar 'aes-256-cbc'?
Respostas
No código PHP, o seguinte deve ser considerado:
$passphrasenão denota uma frase secreta, mas a chave. Essa chave deve ter 32 bytes para a escolhaaes-256-cbc. Se for muito curto, será preenchido com 0 valores; se for muito longo, será truncado. Esta é uma fonte comum de erro, portanto, uma chave de exatamente 32 bytes deve ser usada. Se você quiser trabalhar com uma frase-senha, terá que usar um KDF (como PBKDF2).- No quarto parâmetro, os sinalizadores são definidos e nenhuma expressão booleana (como
true). Se os dados devem ser retornados em formato binário, oOPENSSL_RAW_DATAsinalizador deve ser definido. - IVs estáticos são inseguros, geralmente um novo IV é gerado para cada criptografia, que é enviado ao destinatário junto com o texto cifrado. Como o IV não é secreto, ele geralmente é colocado na frente do texto cifrado no nível de byte sem criptografia.
O exemplo de código PHP a seguir (com base no código postado):
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");
retorna o seguinte resultado:
1SF+kez1CE5Rci3H6ff8og==
MyText
O código CryptoJS correspondente para descriptografia é:
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>
com a saída MyTextque corresponde ao texto simples original.
É importante que a chave seja passada como WordArray, para que seja interpretada como uma chave e não como uma frase secreta. Para a conversão, o CryptoJS fornece codificadores (como CryptoJS.enc.Utf8).
Em relação à sua pergunta no final: os textos criptografados são sequências arbitrárias binárias que podem ser convertidas em uma string com codificações binário para texto especiais (por exemplo, Base64 como neste caso, ou hexadecimal), que geralmente é mais longo do que os dados brutos (Base64: 75% de eficiência, hexadecimal: 50% de eficiência, veja aqui ).
A representação de um bloco de texto cifrado com um número de caracteres alfanuméricos (por exemplo, 16 caracteres) igual ao tamanho do bloco (por exemplo, 16 bytes para AES), portanto, geralmente não é possível.
Observe que a conversão para uma string com uma codificação de conjunto de caracteres como UTF8 também não é uma solução, mas corromperia os dados.