I have following AES encryption to perform in my Angular project where I am using CroyptoJS for this Example_aes
My code for above encryption is as follows -
let keyTool = {
"vector": "njdsslndlsnlkds",
"keySource": "abchjkolg@#!djfhrye"
}
let iv = keyTool.vector;
let key = CryptoJS.SHA256(keyTool.keySource).toString().substring(0, 31);
let newkey = CryptoJS.enc.Utf8.parse(key);
let value = CryptoJS.enc.Utf8.parse("abc@gmail.com");
let newIv = CryptoJS.enc.Utf8.parse(iv)
let newencrypted = CryptoJS.AES.encrypt(value, newkey,
{
iv: newIv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7 });
console.log(newencrypted)
console.log(newencrypted.toString())
The encrypted string of my code is - 51d3A1w5NWHy4uagWeRm+C9GYcesDVMSqcsEi9T2c1Y= Expected is - RBmAWXyJm8d9zV4XaR9BJcLQxTVTM3XEHSHFhGcV75E=
Updated:
textToEncrypt - "abc@gmail.com"
iv - "njdsslndlsnlkds"
key - "6779b2624c837845a4ec16e7cd1fa40"
other details - CBC, PKCS7, 256 bits (key-length)
cipherText - 51d3A1w5NWHy4uagWeRm+C9GYcesDVMSqcsEi9T2c1Y= (my o/p)
Yv9wOiDtSdBS+nWwSqsitg== (website o/p)
key
has UTF-8 encoded only a length of 31 bytes
e35417cb037f9911089ec4b94d2360b
The website implicitly pads to the 32 bytes length required for AES-256 by appending 0x00
to the end.
In the JavaScript code, the 0x00
value must be explicitly appended:
key = key + "\0";
Test:
let riskLogicKeyTool = {
"vector": "njdsslndlsnlkds",
"keySource": "abchjkolg@#!djfhrye"
}
let iv = riskLogicKeyTool.vector;
let key = CryptoJS.SHA256(riskLogicKeyTool.keySource).toString().substring(0, 31);
key = key + "\0"; // Fix!
let newkey = CryptoJS.enc.Utf8.parse(key);
let value = CryptoJS.enc.Utf8.parse("abc@gmail.com");
let newIv = CryptoJS.enc.Utf8.parse(iv)
let newencrypted = CryptoJS.AES.encrypt(value, newkey,
{
iv: newIv,
mode: CryptoJS.mode.CBC, // default
padding: CryptoJS.pad.Pkcs7 // default
});
//console.log(newencrypted);
console.log(newencrypted.toString()); // RBmAWXyJm8d9zV4XaR9BJcLQxTVTM3XEHSHFhGcV75E=
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
Both the website and CryptoJS make it harder to identify the problem because they both accept invalid keys. Valid key lengths for AES are 16, 24 and 32 bytes. For invalid key lengths, as here with 31 bytes, an appropriate error message/exception should be generated.
In the case of CryptoJS this is a (known) bug, see issue #293. Care should be taken with crypto websites in general, most are not reliable.
It is strange (but may of course meet your requirements) that from the hex encoded SHA-256 hash only 31 instead of 32 bytes are used. Therefore just for completeness: Considering 32 bytes key
has the value:
e35417cb037f9911089ec4b94d2360bf
and website and JavaScript code return as ciphertext:
YcJO+j3ID9eLbGkFR+TkVDsaO57y28IcHCLzuHOH4zA=
Security: It is a vulnerability if a fast hash like SHA256 is used as key derivation function. Instead, a reliable key derivation function like PBKDF2 or the more modern scrypt or Argon2 should be used (in combination with a random salt).
Similarly, the use of a static IV is a vulnerability.
In addition, deriving the key from a hex encoded string via UTF-8 encoding reduces security because the range of values per byte is reduced from 256 to 16 values. Also, there may be cross-platform compatibility issues (uppercase, lowercase hex digits).