Roby Firnando Yusuf
Roby Firnando Yusuf

Reputation: 449

OpenSSL Encrypt-Decrypt with CryptoJS

I have a problem to generate encryption in JS, I've the encryption generator in PHP like this :

$secret_key = 'thisIsK3y';
$secret_iv  = 'tHis1s1v';
    
$output         = false;
$encrypt_method = "AES-256-CBC";
$key            = hash( 'sha256', $secret_key );
$iv             = substr( hash( 'sha256', $secret_iv ), 0, 16 );
    
if( $action == 'e' ) 
{
   $output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
}
else if( $action == 'd')
{
    $output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
}
    
return $output;

then I tried to translanguage to JS on React using CryptoJS :

import sha256 from "crypto-js/sha256";
import Base64 from "crypto-js/enc-base64";
import AES from "crypto-js/aes";

let secret_key = "thisIsK3y";
let secret_iv = "tHis1s1v";
            
let output = false;
let encrypt_method = "AES-256-CBC";
let key = sha256(secret_key);
let iv = String(sha256(secret_iv)).substr(0, 16);
     
if (action == "e") { // encrypt action
   output = AES.encrypt("test", Utf8.parse(key), {
            iv: Utf8.parse(iv),
   }).toString();

   alert(Base64.parse(output));
}

then the alert show me this encryption : fd0337c029ad25c240316a1d61db9144, then I try to decrypt in my php.but it's show me plain text seems like non-printable ascii

b"}¦7▀À4█ÍØ█ù6ÒM§Ú¡]ÙW[¸^8"

and there is PHP notice :

PHP Notice: iconv(): Detected an illegal character in input string in /var/www/html/blabla/vendor/symfony/var-dumper/Dumper/AbstractDumper.php on line 203

Anyone can help me out ?

Upvotes: 4

Views: 6878

Answers (1)

Topaco
Topaco

Reputation: 49251

If the PHP code is executed with the plaintext $string = "test"; then the encryption part provides:

MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09

Regarding the PHP code the following should be noted:

  1. The encryption process Base64 encodes twice. Once explicitly with base64_encode, once implicitly by default (s. openssl_encrypt, 4th parameter). This redundancy is not necessary, i.e. one of the two Base64 encodings should be removed. Analogous for decryption.
  2. The hash function returns by default the data hex encoded in lower case. Thus $key is 64 bytes in size. For AES-256 OpenSSL implicitly uses only the first 32 bytes.

The CryptoJS code you posted could be modified as follows to implement this functionality (JavaScript):

var Sha256 = CryptoJS.SHA256;
var Hex = CryptoJS.enc.Hex;
var Utf8 = CryptoJS.enc.Utf8;
var Base64 = CryptoJS.enc.Base64;
var AES = CryptoJS.AES;

var secret_key = 'thisIsK3y';
var secret_iv  = 'tHis1s1v';

var key = Sha256(secret_key).toString(Hex).substr(0,32); // Use the first 32 bytes (see 2.)
var iv = Sha256(secret_iv).toString(Hex).substr(0,16);

// Encryption
var output = AES.encrypt("test", Utf8.parse(key), {
            iv: Utf8.parse(iv),
   }).toString(); // First Base64 encoding, by default (see 1.)

var output2ndB64 = Utf8.parse(output).toString(Base64); // Second Base64 encoding (see 1.)
console.log(output2ndB64); // MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09

// Decryption
var decrypted = AES.decrypt(output, Utf8.parse(key), {
            iv: Utf8.parse(iv),
   }).toString(Utf8); 
console.log(decrypted); // test
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

taking into account the two points mentioned above for the PHP code. Like the hash function in the PHP code, toString(Hex) also uses lower case letters (so no conversion is necessary in this respect).

Note that in practice a static IV must not be used for security reasons. Instead, the IV should be newly generated for each encryption and sent to the recipient along with the ciphertext (the IV isn't secret). Also, using SHA256 as a key derivation function is not very secure.

Upvotes: 5

Related Questions