IV
You're using the CBC mode of operation which requires an IV. If you use a static IV for all your ciphertexts then you miss out on an important property of encryption which is semantic security. If you use the same IV, attackers may observe your ciphertext and determine whether you sent the same plaintext with the same key, because the ciphertext will be the same.
To prevent that, you can generate a random IV for each encryption you do. The IV doesn't have to be secret, but it has to be unpredictable. Since it doesn't have to be secret, you can simply prepend it to the ciphertext and slice it off before decryption or send it otherwise in a structured fashion. You need to use IV during decryption. Otherwise, the first block will be different from the original plaintext.
Keep in mind that CryptoJS' WordArray.random()
uses Math.random()
internally which is not cryptographically secure. It would be better to use a better randomness source. You can use this drop in replacement from my project of that function for semi-modern browsers which uses the WebCrypto API:
(function(C){
var WordArray = C.lib.WordArray;
var crypto = window.crypto;
var TypedArray = Int32Array;
if (TypedArray && crypto && crypto.getRandomValues) {
WordArray.random = function(nBytes){
var array = new TypedArray(Math.ceil(nBytes / 4));
crypto.getRandomValues(array);
return new WordArray.init(
[].map.call(array, function(word){
return word
}),
nBytes
);
};
} else {
console.log("No cryptographically secure randomness source available");
}
})(CryptoJS);
and use it like this:
var iv = CryptoJS.lib.WordArray.random(128/8);
Key
The key is trickier, because it needs to be kept confidential. The basic way is:
Let the user type in the password that is also present on the server and derive the key from the password by for example using PBKDF2 which CryptoJS also provides. Perfectly secure as long as you use TLS and the developers don't change the code.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…