Michael S. Miller
Michael S. Miller

Reputation: 437

CryptoJS AES decrypt Hex String?

This is sort of a part two to the question Trying to print hex string with CryptoJS

Basically, I have a function that uses CryptoJS to encrypt a message and spit out the cypher text as a hex string.

function EncryptAES(text, key) {
  var encrypted = CryptoJS.AES.encrypt(text, key);
  return encrypted.ciphertext.toString()
}

I want to write a function DecryptAES that takes the hex string, key, and salt (which I apparently need) and returns the original plaintext. The problem is I can't figure out how to get the hex string back into a form that CryptoJS.AES.decrypt will accept, and I can't find anywhere in the documentation where it actually explains how to do it. Maybe I overlooked something. Please help.

Upvotes: 2

Views: 2600

Answers (2)

Yusuf Ganiyu
Yusuf Ganiyu

Reputation: 1095

CryptoJS expects a certain format for its encrypted data. If you're supplying only the hexadecimal string of the ciphertext, you'll need to reconstruct this formatted data when decrypting. Here's an example:

function EncryptAES(text, key) {
  var encrypted = CryptoJS.AES.encrypt(text, key);
  return encrypted.toString();  // this will be a string includes salt, iv and ciphertext
}

function DecryptAES(ciphertext, key) {
  var decrypted = CryptoJS.AES.decrypt(ciphertext, key);
  return decrypted.toString(CryptoJS.enc.Utf8); // decode to original text
}

In the EncryptAES function, by calling encrypted.toString(), it will generate a string which includes salt, iv, and ciphertext. When we decrypt it, we don't need to handle salt and iv separately.

However, if you are only dealing with the ciphertext (hexadecimal string), you can decrypt it using:

function DecryptFromHex(ciphertextHex, key, iv) {
  var cipherParams = CryptoJS.lib.CipherParams.create({
    ciphertext: CryptoJS.enc.Hex.parse(ciphertextHex)
  });
  var decrypted = CryptoJS.AES.decrypt(cipherParams, CryptoJS.enc.Utf8.parse(key), { iv: CryptoJS.enc.Utf8.parse(iv) });
  return decrypted.toString(CryptoJS.enc.Utf8);
}

DecryptFromHex takes the hexadecimal ciphertext string, parses it back into a format that CryptoJS can understand, and then decrypts it. Note that the key and the iv are also parsed from UTF8 to the WordArray format that CryptoJS uses.

Ensure the key and iv you use for the decryption match those used for encryption.

Upvotes: -1

Topaco
Topaco

Reputation: 49460

CryptoJS uses the WordArray data type internally and provides encoders for conversion. If you want to convert a hex encoded string into a WordArray, this is possible with the Hex encoder as follows:

CryptoJS.enc.Hex.parse(<your hex encoded string>)

or the other way around

<your WordArray>.toString(CryptoJS.enc.Hex)

or for short

<your WordArray>.toString()

Moreover, CryptoJS.AES.encrypt() returns a CipherParams object that encapsulates ciphertext and salt, among other things. This CipherParams object is to be passed to CryptoJS.AES.decrypt() for decryption.

With this, what you want can be implemented as follows:

function EncryptAES(text, key) {
    var encrypted = CryptoJS.AES.encrypt(text, key);
    return {ciphertext: encrypted.ciphertext.toString(), salt: encrypted.salt.toString()}
}

function DecryptAES(ciphertext, salt, key){
    var decrypted = CryptoJS.AES.decrypt({ciphertext:CryptoJS.enc.Hex.parse(ciphertext), salt:CryptoJS.enc.Hex.parse(salt)}, key); 
    return decrypted;
}

var {ciphertext, salt} = EncryptAES('The quick brown fox jumps over the lazy dog', 'my passphrase');
console.log('Ciphertext (hex): ', ciphertext);
console.log('Salt (hex): ', salt);

var decrypted = DecryptAES(ciphertext, salt, 'my passphrase');
console.log('Decrypted: ', decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>


However, there is an easier way to handle salt and ciphertext. For a CipherParams object, .toString() returns the data in the Base64 encoded OpenSSL format consisting of the hex encoding of Salted__ followed by the 8 bytes salt and the actual ciphertext. CryptoJS.AES.decrypt() implicitly converts such a Base64 string into a CipherParams object:

var encrypted = CryptoJS.AES.encrypt('The quick brown fox jumps over the lazy dog', 'my passphrase').toString();
console.log("Salt, ciphertext (OpenSSL format, Base64): ", encrypted);

var decrypted = CryptoJS.AES.decrypt(encrypted, 'my passphrase');
console.log("Decrypted: ", decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

Upvotes: 4

Related Questions