0

I have an application in which I am encrypting a json encoded array using AES CBC 128 algorithm and then Decrypting it in javascript(React/Next Js Project). My Encryption in php is as shown in the below code

ENCRYPTION PHP


$plaintext = "message to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );

I am facing problems in decryption of this in Javascript

my code so far is as shown below

 const baseenc = CryptoJS.enc.Base64.parse(cipher).toString();
  var encrypted = CryptoJS.AES.decrypt(cipher, key, { iv: iv }).toString();
  var plaintext = CryptoJS.enc.Latin1.stringify(encrypted);

Can any body please show what is the error or help me in getting the correct output

3
  • 1
    Your CryptoJS code is missing the separation of IV, HMAC and actual ciphertext. In addition, the HMAC for the ciphertext must be calculated. The ciphertext is authentic if the calculated and received HMAC match. You need the IV together with the key to decrypt the actual ciphertext after successful authentication. See also here for using the same key for encryption and authentication. Commented Jan 7, 2021 at 14:16
  • @Topaco So can you help me how can i seperate the iv hmac and the ciphertext Commented Jan 7, 2021 at 15:58
  • Sure, please see my answer. Commented Jan 7, 2021 at 17:16

1 Answer 1

5

The following steps must be implemented in the CryptoJS code:

  • Separate IV, HMAC and ciphertext (after Base64 decoding)
  • Calculate the HMAC for the ciphertext
  • Check the authenticity of the ciphertext. The ciphertext is authentic if the received and calculated HMAC are identical.
  • Perform decryption, only if the ciphertext is authentic

The following code is a possible implementation. As key 0123456789012345 was applied and with the PHP code the used ciphertext was generated:

var ciphertext = 'WqfMfCxKg7U7h5S1mbx7mSHOkkkIrUUpg++mX4ZdWt0I26VfKn7bsi60Oo/SIsWQGyC4dF5z081NvjTXwZGjIpguA0k/QqIM/GDEpCojaro=';
var key = '0123456789012345';

// Convert key and ciphertext into WordArrays
var ciphertextWA = CryptoJS.enc.Base64.parse(ciphertext);
var keyWA = CryptoJS.enc.Utf8.parse(key);

// Separate IV, HMAC and ciphertext
var ivWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(0, 4)); 
var hmacWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(4, 4 + 8)); 
var actualCiphertextWA = CryptoJS.lib.WordArray.create(ciphertextWA.words.slice(4 + 8)); 

// Authenticate
var hmacCalculatedWA = CryptoJS.HmacSHA256(actualCiphertextWA, keyWA); 
if(CryptoJS.enc.Base64.stringify(hmacCalculatedWA) === CryptoJS.enc.Base64.stringify(hmacWA)) {
  
  // Decrypt if authentication is successfull
  var decryptedMessageWA = CryptoJS.AES.decrypt({ciphertext: actualCiphertextWA}, keyWA, {iv: ivWA});
  var decryptedMessage = CryptoJS.enc.Utf8.stringify(decryptedMessageWA);
  console.log(decryptedMessage);
} else {
  console.log('Authentication failed!');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

Please note that it is better to use different keys for encryption and authentication, see here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.