You would have to parse the UTF-8 key first:
const cryptkey = CryptoJS.enc.Utf8.parse('1234567890123456');
If you don't do that CryptoJS will assume it is a password and derive the actual key from that.
As Maarten also pointed out...
The ciphertext also must be decoded from Base64:
const crypted = CryptoJS.enc.Base64.parse("8Z3dZzqn05FmiuBLowExK0CAbs4TY2GorC2dDPVlsn/tP+VuJGePqIMv1uSaVErr");
Note that the decryptor expects a CipherParams
object, which you can simulate by passing {ciphertext: crypted}
to the decrypt
function. Alternatively, you can rely on CryptoJS to decode the ciphertext from Base64, you pass in that string as-is.
The IV must be 16 bytes long for AES-CBC which are 32 characters if encoded as Hex:
CryptoJS.enc.Hex.parse('00000000000000000000000000000000')
Examples
const cryptkey = CryptoJS.enc.Utf8.parse('1234567890123456');
const crypted = CryptoJS.enc.Base64.parse("8Z3dZzqn05FmiuBLowExK0CAbs4TY2GorC2dDPVlsn/tP+VuJGePqIMv1uSaVErr");
var decrypt = CryptoJS.AES.decrypt({ciphertext: crypted}, cryptkey, {
iv: CryptoJS.enc.Hex.parse('00000000000000000000000000000000'),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(decrypt.toString(CryptoJS.enc.Utf8));
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
As Matt correctly noted, CryptoJS can do the ciphertext decoding for you if the ciphertext is encoded as Base64:
const cryptkey = CryptoJS.enc.Utf8.parse('1234567890123456');
const crypted = "8Z3dZzqn05FmiuBLowExK0CAbs4TY2GorC2dDPVlsn/tP+VuJGePqIMv1uSaVErr";
var decrypt = CryptoJS.AES.decrypt(crypted, cryptkey, {
iv: CryptoJS.enc.Hex.parse('00000000000000000000000000000000'),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(decrypt.toString(CryptoJS.enc.Utf8));
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Security considerations:
The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.
A key should be randomly chosen from all possible bytes, because a key consisting of ASCII characters is much easier to brute-force than a key consisting of all available bytes.
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.
If you're using only symmetric encryption you need the exact same key at the server and the client. If you send the encryption key from the server to the client or the other way around you need to encrypt your symmetric encryption key. The easiest way to do this would be to use TLS. If you use TLS, then the data as well as key are encrypted, so you don't need to encrypt it yourself. This doesn't provide any security, just a little bit of obfuscation. You should read: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/