AES encryption without IV in PHP and JS gives different result - javascript

I have the next code in PHP:
$plain = 'some string to encode';
$key = '01234567891234567890123456789012';
$cipherSuite = 'aes-128-cbc';
$iv = null; // I have to use null, I know it's not safe
$result = #openssl_encrypt($plain, $cipherSuite, $key, null, $iv); // Suppress warning of an empty IV
dd($result); // result is 9VK02Mt8IaS+Bng8SbqhCVXUc5TteHKqt3y/EbaJZ1w=
I'm trying to encode the same in online tool - https://www.devglan.com/online-tools/aes-encryption-decryption. Tool says that key must be 16 byte, so I use just half of key - 0123456789123456
It returns exact same result as PHP. Please note that IV is empty.
I need to do the same encryption (and than decription) in JS using Crypto-js
const CryptoJS = require('crypto-js');
var key = CryptoJS.lib.WordArray.create('01234567891234567890123456789012');
var iv = CryptoJS.lib.WordArray.create('');
//var iv = null;
// var iv = CryptoJS.enc.Hex.parse("");
// var iv = CryptoJS.enc.Base64.parse('');
let cfg = {
mode: CryptoJS.mode.CBC,
keySize: 128,
iv: iv
};
const body = 'some string to encode';
const encryptedBody = CryptoJS.AES.encrypt(body, key, cfg).toString();
console.log( encryptedBody );
// result is VYCEPSx9nmb0FJGf1RiU/daL5nIk/qaJZU82jrlGQws=
Similar example at https://jsfiddle.net/pj76d5ov/
Result in JS is different with PHP. Is there a way to use CryptoJS without IV ?
If I use the key as a string, CryptoJS generates IV based on my key, so I have to use WordArray type.
Then I tried to change iv to some values, but it doesn't help. Setting iv to false or null, or not sending iv at all gives an error.

In the PHP code AES-128 is specified. Therefore PHP implicitly truncates the 32 bytes key to the first 16 bytes. In the CryptoJS code only this 16 bytes key may be used.
Furthermore, key and IV are converted most easily with the CryptoJS encoders into a WordArray.
A possible CryptoJS implementation is:
var key = CryptoJS.enc.Utf8.parse('0123456789123456');
var iv = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
let cfg = {
mode: CryptoJS.mode.CBC,
keySize: 128,
iv: iv
};
const body = 'some string to encode';
const encryptedBody = CryptoJS.AES.encrypt(body, key, cfg).toString();
console.log( encryptedBody ); // result is 9VK02Mt8IaS+Bng8SbqhCVXUc5TteHKqt3y/EbaJZ1w=
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
A static IV is insecure, but you already know that.

Related

How to decrypt AES256 data which was encrypted on PHP and get value in Javascript?

I have encrypted some value using aes-256-cbc mode on PHP like this:
public function encrypt(string $data): string
{
$iv = $this->getIv();
$encryptedRaw = openssl_encrypt(
$data,
$this->cryptMethod, //aes-256-cbc
$this->key,
OPENSSL_RAW_DATA,
$iv
);
$hash = hash_hmac('sha256', $encryptedRaw, $this->key, true);
return base64_encode( $iv . $hash . $encryptedRaw );
}
Then I tried to decrypt it on PHP and it works fine:
public function decrypt(string $data): string
{
$decoded = base64_decode($data);
$ivLength = openssl_cipher_iv_length($this->cryptMethod);
$iv = substr($decoded, 0, $ivLength);
$hmac = substr($decoded, $ivLength, $shaLength = 32);
$decryptedRaw = substr($decoded, $ivLength + $shaLength);
$originalData = openssl_decrypt(
$decryptedRaw,
$this->cryptMethod,
$this->key,
OPENSSL_RAW_DATA,
$iv
);
So I'm new to JavaScript and I don't know how to realize the same decrypt method as on php.
Example of encrypted string and it's key:
encrypted string lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ== secret key - 9SJ6O6IwmItSRICbXgdJ
Example what I found returns empty string:
const decodedString = base64.decode(
`lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ==`
);
const CryptoJS = require("crypto-js");
var key = CryptoJS.enc.Latin1.parse("9SJ6O6IwmItSRICbXgdJ");
var iv = CryptoJS.enc.Latin1.parse(decodedString.slice(0, 16));
var ctx = CryptoJS.enc.Base64.parse(
"lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ=="
);
var enc = CryptoJS.lib.CipherParams.create({ ciphertext: ctx });
console.log(
CryptoJS.AES.decrypt(enc, key, { iv: iv }).toString(CryptoJS.enc.Utf8)
);
}
What I did wrong?
The key used in the PHP code is only 20 bytes in size and thus too small for AES-256 (AES-256 requires a 32 bytes key). PHP/OpenSSL implicitly pads the key with 0x00 values to the required key length. In the CryptoJS code, this must be done explicitly.
Furthermore, in the CryptoJS code, IV (the first 16 bytes), HMAC (the following 32 bytes) and ciphertext (the rest) are not separated correctly.
Also, the authentication is missing. To do this, the HMAC for the ciphertext must be determined using the key and compared with the HMAC sent. Decryption only takes place if authentication is successful.
If all of this is taken into account, the posted code can be fixed e.g. as follows:
var key = CryptoJS.enc.Utf8.parse("9SJ6O6IwmItSRICbXgdJ".padEnd(32, "\0")); // pad key
var ivMacCiphertext = CryptoJS.enc.Base64.parse("lUIMFpajICh/e44Mwkr0q9xdyJh5Q8zEJHi8etax5BRl78Vsyh+wDknmBga1L8p8SDZA6WKz1CvAAREFGreRAQ==")
var iv = CryptoJS.lib.WordArray.create(ivMacCiphertext.words.slice(0, 4)); // get IV
var hmac = CryptoJS.lib.WordArray.create(ivMacCiphertext.words.slice(4, 4 + 8)); // get HMAC
var ct = CryptoJS.lib.WordArray.create(ivMacCiphertext.words.slice(4 + 8)); // get Ciphertext
var hmacCalc = CryptoJS.HmacSHA256(ct, key);
if (hmac.toString() === hmacCalc.toString()) { // authenticate
var dt = CryptoJS.AES.decrypt({ciphertext: ct}, key, { iv: iv }).toString(CryptoJS.enc.Utf8); // decrypt
console.log(dt);
} else {
console.log("Decryption failed");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
A few thoughts for you:
Check that your encoding/decoding is working properly. For each stage
of the process, endode/decode, then console log the output and
compare input to output, and also between PHP and javascript.
CBC mode uses padding to fill out the blocks. Check that both stacks
are using the same padding type.
Rather than using CBC and a separate HMAC, how about jumping to AEAD (like AES
GCM) which avoids the padding issue, and also incorporates the MAC
into the encryption, so is a more simple interface?

I tried crypto-js but the output is not correct, please see my code and correct me where I am wrong

I have a simple_crypt function in my backend which is working properly, now what I want is to make a similar function for javascript which for exactly the same as the php one.
So I have researched and got the CryptoJS library, my 'Key' and 'iv' values are correct as compared to the PHP one but when I encrypt my string the output is totally different.
This is my working PHP code and I want to convert this into javascript.
<?php
function simple_crypt( $string ) {
$secret_key = '1234567890';
$secret_iv = '0987654321';
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hash( 'sha256', $secret_key );
$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
echo "Key : ".$key."<br>";
echo "iv : ".$iv."<br>";
$output = openssl_encrypt( $string, $encrypt_method, $key, 0, $iv );
return $output;
}
$e = simple_crypt("text");
echo $e;
echo "<br>";
?>
This is my JS code in which I am getting the issue, please have a look and tell me where I am wrong in this js code.
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js" integrity="sha512-nOQuvD9nKirvxDdvQ9OMqe2dgapbPB7vYAMrzJihw5m+aNcf0dX53m6YxM4LgA9u8e9eg9QX+/+mPu8kCNpV2A==" crossorigin="anonymous"></script>
<script type="text/javascript">
function simple_crypt(string) {
var secret_key, secret_iv, output, key, iv;
secret_key = '1234567890';
secret_iv = '0987654321';
output = false;
key = CryptoJS.SHA256(secret_key).toString();
iv = CryptoJS.SHA256(secret_iv).toString().substr(0, 16);
console.log("key",key);
console.log("iv",iv);
var encrypted = CryptoJS.AES.encrypt(string, key, {iv: iv});
return (encrypted.toString());
}
console.log(simple_crypt("text"));
</script>
Here is the output:
PHP: T4F65n4AVlmkkb5LLFhRIQ==
JS: U2FsdGVkX18HJGpPYZPm6crBcxA7TfbZZ9Sc/4qHGBk=
So that both codes produces the same result, the key and IV in the NodeJS Code must be the same as in the PHP code and passed as WordArrays. For this, the key and IV you have generated must be further processed as follows:
key = CryptoJS.enc.Utf8.parse(key.substr(0, 32));
iv = CryptoJS.enc.Utf8.parse(iv);
In the PHP code, the SHA256 hash is returned as hex string. With hex encoding the number of bytes doubles, i.e. a SHA256 hash is hex encoded 64 bytes. PHP implicitly considers only the first 32 bytes regarding the key for AES-256, i.e. ignores the last 32 bytes. In the CryptoJS code this must happen explicitly (for the IV this happens, but for the key this is missing).
By parsing with the UTF8 encoder, key and IV are converted into WordArrays. If the key is passed as a string (as in the code posted in the question), then CryptoJS interprets the value as a password and uses a key derivation function to derive key and IV (which is incompatible with the logic in the PHP code).
With the above changes, the CryptoJS code gives the same result as the PHP code:
function simple_crypt(string) {
var secret_key, secret_iv, output, key, iv;
secret_key = '1234567890';
secret_iv = '0987654321';
output = false;
key = CryptoJS.SHA256(secret_key).toString();
iv = CryptoJS.SHA256(secret_iv).toString().substr(0, 16);
key = CryptoJS.enc.Utf8.parse(key.substr(0, 32));
iv = CryptoJS.enc.Utf8.parse(iv);
console.log("key",key.toString());
console.log("iv",iv.toString());
var encrypted = CryptoJS.AES.encrypt(string, key, {iv: iv});
return (encrypted.toString());
}
console.log(simple_crypt("text")); // T4F65n4AVlmkkb5LLFhRIQ==
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
Please note the following:
Using SHA256 to derive the key from a password is insecure. For this purpose, a reliable key derivation function such as PBKDF2 should be used.
For security reasons, a key/IV pair may only be applied once. Therefore, the IV is usually randomly generated for each encryption. The IV is not a secret and is commonly sent to the recipient along with the ciphertext (usually prepended). Alternatively, the IV can be derived together with the key using a KDF (in combination with a randomly generated salt).

CryptoJS AES decrypting a message encrypted in PHP openssl_encrypt

I have the following PHP code that uses openssl_encrypt() function to encrypt a message. Here is the code:
$ciphering = "AES-128-CTR";
$options = 0;
$encryption_iv = '5192001995060634';
$encryption_key = "TasKagitMakas";
function encrypt ($string) {
global $ciphering, $options, $encryption_iv, $encryption_key;
$encryption = openssl_encrypt($string, $ciphering,
$encryption_key, $options, $encryption_iv);
$encryption = strtr(base64_encode($encryption), '+/=', '-_,');
return $encryption;
}
I was trying to reverse the process above and get the Javascript implementation using CryptoJS. Here's what I came up with:
var str = "bzB5UVNBclRHbWhlQUs4aHJoMHVxR1BJNEF1Sk9BRkpvbEpBRDFnVmg0MEx4RGtqWllvdUIrSW0vZGY3eG1KMVd2b2JxRFlOTnJ6N2FnPT0,";
str = str.split("-").join("+");
str = str.split("_").join("/");
str = str.split(",").join("=");
var encrypted = CryptoJS.enc.Base64.parse(str);
var encryptedStr = encrypted.toString(CryptoJS.enc.Utf8);
var key = "TasKagitMakas";
var iv = "5192001995060634";
var decrypted = CryptoJS.AES.decrypt(encryptedStr, key, {iv: iv, mode: CryptoJS.mode.CTR});
console.log(decrypted.toString(CryptoJS.enc.Utf8));
This code gives me a blank output, just nothing. What am I doing wrong here? How can I correct my implementation?
PHP code:
openssl_encrypt pads the key with zero values until the specified key length is reached, i.e. the key TasKagitMakas is expanded to TasKagitMakas\0\0\0.
$options = 0 means that the ciphertext is implicitly Base64 encoded. Since the ciphertext is explicitly Base64 encoded again afterwards, it is Base64 encoded twice in total. This is unnecessary and should be changed, for example, with $options = OPENSSL_RAW_DATA.
For a stream cipher mode like CTR openssl_encrypt automatically disables the default PKCS7 padding.
JavaScript code:
Since it was Base64 encoded twice in the PHP code, it is necessary to Base64 decode twice in the JavaScript code. This step is of course only necessary for the unchanged PHP code.
Key and IV must be parsed into a WordArray with the Utf8 Encoder. The extended key must be used.
CryptoJS.AES.decrypt expects the ciphertext as CipherParams object.
Unlike PHP, CryptoJS does not automatically disable the default PKCS7 padding for a stream cipher mode, i.e. it must be explicitly disabled.
The following JavaScript code decrypts the ciphertext:
var str = "bzB5UVNBclRHbWhlQUs4aHJoMHVxR1BJNEF1Sk9BRkpvbEpBRDFnVmg0MEx4RGtqWllvdUIrSW0vZGY3eG1KMVd2b2JxRFlOTnJ6N2FnPT0,";
str = str.split("-").join("+");
str = str.split("_").join("/");
str = str.split(",").join("=");
var encrypted = CryptoJS.enc.Base64.parse(str); // Base64 decode twice (as long as this happens in the PHP code)
var encrypted = encrypted.toString(CryptoJS.enc.Utf8);
var encrypted = CryptoJS.enc.Base64.parse(encrypted);
var key = CryptoJS.enc.Utf8.parse("TasKagitMakas\0\0\0"); // Expand the key and use the Utf8 encoder
var iv = CryptoJS.enc.Utf8.parse("5192001995060634"); // Use the Utf8 encoder
var decrypted = CryptoJS.AES.decrypt(
{
ciphertext: encrypted // Pass teh ciphertext as CipherParams object
},
key,
{
iv: iv,
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding // Disable the PKCS7 padding
});
console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
with the output:
399002 Örnek2 Öğrenci student#ug.bilkent.edu.tr Team1 6 

How to decrypt AES 256 CBC by javascrypt (Not Nodejs)?

How can I decrypt an encrypted string like dIwykUwOomuWcdw/QX/Aig== in AES 256 CBC mode with the key ds8am3wys3pd75nf0ggtvajw2k3uny92 and iv jm8lgqa3j1d0ajus as the picture below just with javascript (not Nodejs). I used to try with CryptoJs library but the result not like I expected.
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/pbkdf2.js"></script>
<script>
var str = 'dIwykUwOomuWcdw/QX/Aig==';
var key = 'ds8am3wys3pd75nf0ggtvajw2k3uny92';
var iv = 'jm8lgqa3j1d0ajus';
var encrypted = CryptoJS.AES.encrypt("2730007809303", key, { iv: iv });
var decrypted = CryptoJS.AES.decrypt(encrypted, key, { iv: iv});
var base64_str = decrypted.toString(CryptoJS.enc.Base64);
console.log(atob(base64_str))
</script>
By the way, how can I convert input string dIwykUwOomuWcdw/QX/Aig== as encrypted object above ?
Your code snippet is almost right. However, the key must not be passed as a string, otherwise CryptoJS will interpret it as a passphrase and generate the actual key and IV from it [1], with an insecure algorithm by the way. Instead, key and IV must be passed as WordArray, which is easily achieved using the encoders [2]. Since key and IV are Utf8-strings in this example, they must be parsed with the Utf8-encoder. Then you will get the desired ciphertext of the web page. Be aware that encrypt returns a CipherParams-object that encapsulates the ciphertext among other data [3]. Furthermore, you don't need the Base64-detour and should decode the decrypted data directly as UTF8-string:
var key = CryptoJS.enc.Utf8.parse('ds8am3wys3pd75nf0ggtvajw2k3uny92'); // Use Utf8-Encoder.
var iv = CryptoJS.enc.Utf8.parse('jm8lgqa3j1d0ajus'); // Use Utf8-Encoder
var encryptedCP = CryptoJS.AES.encrypt("2730007809303", key, { iv: iv });
var decryptedWA = CryptoJS.AES.decrypt(encryptedCP, key, { iv: iv});
var encryptedBase64 = encryptedCP.toString(); // Short for: encryptedCP.ciphertext.toString(CryptoJS.enc.Base64);
var decryptedUtf8 = decryptedWA.toString(CryptoJS.enc.Utf8); // Avoid the Base64 detour.
// Alternatively: CryptoJS.enc.Utf8.stringify(decryptedWA);
console.log("Ciphertext (Base64) : " + encryptedBase64)
console.log("Decrypted data (Utf8): " + decryptedUtf8);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
Note that the CBC-mode and PKCS7-padding are implicitly used, which are the default parameters of CryptoJS [4], so it is not necessary to specify them explicitly.
Update:
If the ciphertext is a string or a WordArray, a CipherParams-object must be created from it, because the decrypt-method expects an object of this type [5]. The entirety of all data encapsulated by the CipherParams-object can be most easily taken from its definition [6]. In the current case at least the ciphertext must be specified as WordArray. Optionally a formatter can be specified which determines the formatting strategy of toString() (if used):
var key = CryptoJS.enc.Utf8.parse('ds8am3wys3pd75nf0ggtvajw2k3uny92'); // Use Utf8-Encoder.
var iv = CryptoJS.enc.Utf8.parse('jm8lgqa3j1d0ajus'); // Use Utf8-Encoder
var ciphertext = CryptoJS.enc.Base64.parse('dIwykUwOomuWcdw/QX/Aig=='); // Use Base64-Encoder.
var encryptedCP = CryptoJS.lib.CipherParams.create({
ciphertext: ciphertext,
formatter: CryptoJS.format.OpenSSL // Optional, but required for encryptedCP.toString()
});
var decryptedWA = CryptoJS.AES.decrypt(encryptedCP, key, { iv: iv});
var encryptedBase64 = encryptedCP.toString(); // Short for: encryptedCP.ciphertext.toString(CryptoJS.enc.Base64);
var decryptedUtf8 = decryptedWA.toString(CryptoJS.enc.Utf8); // Avoid the Base64 detour.
// Alternatively: CryptoJS.enc.Utf8.stringify(decryptedWA);
console.log("Ciphertext (Base64) : " + encryptedBase64)
console.log("Decrypted data (Utf8): " + decryptedUtf8);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>

Encryption on crypto-js and decryption on node crypto using CTR mode issue

I am trying to encrypt data using crypto-js javascript library and trying to decrypt the same encrypted text on nodejs side using node crypto library. I am using AES 256 encryption algo with CTR mode with no padding. I am able to encrypt properly but the description on nodejs crypto module is not producing same plain text.
If I try to encrypt or decrypt using the same crypto-js and node crypto library, it works fine but encryption on crypto-js and description on crypto is not working as expected. I have tried to confirm if I encrypt and decrypt in the same library than it works or not and it works perfectly fine. Can someone please check what mistake I am making here?
Please find below code samples.
Encryption:
var key = CryptoJS.enc.Hex.parse('F29BA22B55F9B229CC9C250E11FD4384');
var iv = CryptoJS.enc.Hex.parse('C160C947CD9FC273');
function encrypt(plainText) {
return CryptoJS.AES.encrypt(
plainText,
key,
{
iv: iv,
padding: CryptoJS.pad.NoPadding,
mode: CryptoJS.mode.CTR
}
);
}
Descryption using NodeJS crypo module:
var algorithm = 'aes-256-ctr';
var key = 'F29BA22B55F9B229CC9C250E11FD4384';
var iv = 'C160C947CD9FC273';
var outputEncoding = 'hex';
var inputEncoding = 'hex';
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update('8df5e11f521cf492437a95', inputEncoding, 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
As I have mentioned above, I have JavaScript crypo-js and NodeJS crypo module sessions working fine if I encrypt and decrypt using the same lib but doesn't work otherwise. Please check the working code as below.
JavaScript: http://jsfiddle.net/usr_r/2qwt8jsh/2/
NodeJS: https://repl.it/repls/AchingRegalPhp
I think your CryptoJS code isn't using AES-256, as the key and IV are too short and hence it's implicitly using AES-128. if you get the blockSize from the CryptoJS.AES object it says 4 for me. that said I don't know CryptoJS very well and that might not mean "4 words".
To bypass this implementation uncertainty, it's good to have a "gold standard" to replicate. NIST provides lots of test vectors, some of which apply to your CTR mode AES-256. First I pull out a set of (hex encoded) test vectors from that document:
const key = (
'603deb1015ca71be2b73aef0857d7781' +
'1f352c073b6108d72d9810a30914dff4'
)
const ctr = 'f0f1f2f3f4f5f6f7f8f9fafbfcfdff00'
const output = '5a6e699d536119065433863c8f657b94'
const cipher = 'f443e3ca4d62b59aca84e990cacaf5c5'
const plain = 'ae2d8a571e03ac9c9eb76fac45af8e51'
next I try and recover these from Node's crypto module:
const crypto = require('crypto')
function node_crypto(text) {
const dec = crypto.createDecipheriv(
'aes-256-ctr',
Buffer.from(key, 'hex'),
Buffer.from(ctr, 'hex')
);
const out = dec.update(Buffer.from(text, 'hex'))
return out.toString('hex')
}
now I can write a simple test harness for testing the above and use it with that function:
const zero = '00'.repeat(16);
function test_crypto(fn) {
return {
'zero => output': fn(zero) == output,
'cipher => plain': fn(cipher) == plain,
'plain => cipher': fn(plain) == cipher,
}
}
console.log(test_crypto(node_crypto))
which gives me true for all tests.
finally, the equivalent code for CryptoJS is:
const CryptoJS = require("crypto-js");
function cryptojs(text) {
const out = CryptoJS.AES.encrypt(
CryptoJS.enc.Latin1.parse(Buffer.from(text, 'hex').toString('binary')),
CryptoJS.enc.Hex.parse(key),
{
iv: CryptoJS.enc.Hex.parse(ctr),
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding,
}
);
return out.ciphertext.toString();
}
console.log(test_crypto(cryptojs))
which also works for me.
It's important to note that CryptoJS just silently accepts arbitrarily sized keys, with the docs saying:
CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key.
In contrast to the NodeJS-code (Crypto), the JavaScript-code (CryptoJS) interprets keys and IV as hexadecimal strings. Therefore, in the JavaScript-Code AES-128 is used and in the NodeJS-Code AES-256. To solve the problem, both codes must use the same encryption.
Option 1: Change the JavaScript-code to AES-256: Replace in the JavaScript-code
var key = CryptoJS.enc.Hex.parse('F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Hex.parse('D959B836CD9FB162');
by
var key = CryptoJS.enc.Utf8.parse('F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Utf8.parse('D959B836CD9FB162');
Option 2: Change the NodeJS-code to AES-128: Replace in the NodeJS-code
var algorithm = 'aes-256-ctr';
var key = 'F18AB33A57F9B229CC9C250D00FC3273';
var iv = 'D959B836CD9FB162';
by
var algorithm = 'aes-128-ctr';
var key = Buffer.from('F18AB33A57F9B229CC9C250D00FC3273', 'hex');
var iv = Buffer.from('D959B836CD9FB1620000000000000000', 'hex');
With one of each of the two changes, the codes of both links produce the same result.
If AES-256 should be used and key and IV should be specified as hexadecimal strings, a correspondingly large key and IV must be used, e.g. on the JavaScript-side:
var key = CryptoJS.enc.Hex.parse('F18AB33A57F9B229CC9C250D00FC3273F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Hex.parse('D959B836CD9FB16200000000000000');
and on the NodeJS-side:
var algorithm = 'aes-256-ctr';
var key = Buffer.from('F18AB33A57F9B229CC9C250D00FC3273F18AB33A57F9B229CC9C250D00FC3273', 'hex');
var iv = Buffer.from('D959B836CD9FB1620000000000000000', 'hex');

Categories

Resources