A few clarifications and corrections to the accepted answer
Short answer:
- Use "crytographically random" keys produced by
GenerateSecretKey()
rather than creating one with Tobase64(secret)
.
- Although technically ECB mode works (see below), CBC mode is preferred as the more secure method. For CBC, see my full example: Encrypt in ColdFusion, Decrypt in Node.js
Longer Answer:
- Don't use GenerateSecretKey if you want to decrypt in other language
No, it is perfectly fine to use the generated value with the encryption functions in other languages - as long as they follow the specifications. That does not mean the values can be used in any language exactly "as is". It may need tweaking to conform with language X or Y's implementation. (For example, a function in language X may expect the key to be a hexadecimal string, instead of base64. So you may need to convert the key value first). That did not quite happen in the original code, which is why the decryption did not work.
GenerateSecretKey() produces a cryptographically random key for the specified algorithm. (While CF generates base64 encoded key strings, it could just as easily be hex encoded. The binary value of the key is what matters.) The generated key is suitable for use with any language that implements the same encryption algorithms and key sizes. However, as I mentioned in the earlier comments, symmetric encryption only works if everything matches. You must use the same key, same algorithm, same iv, etcetera for both encrypting AND decrypting. In the original code, both the "key" and "algorithm" values were different. That is why the decryption failed.
The original code used crypto.createCipher(algorithm, password)
. Per the API, "password" is used to derive the cipher key. In other words, the Node.js code was using a totally different key than in the CF code. Also, Node.js was configured to use a 192 bit key, whereas the CF code was using a 128 bit key.
To answer your original question, yes - you can use ECB mode (though it is strongly discouraged). However, it requires modifying the CF code to derive the same password Node.js will be using. (The other direction is not possible as it involves one-way hashing.)
To derive the "password" in CF, decode the secret key string into binary and generate an md5 hash. Then decode the hash into binary and re-encode it as base64 to make the encrypt() function happy.
CF:
plainText = "7001010000006aaaaaabbbbbb";
secretKey = "WTq8zYcZfaWVvMncigHqwQ==";
keyHash = hash(binaryDecode(secretKey, "base64"), "md5");
nodeJSPassword = binaryEncode(binaryDecode(keyHash, "hex"), "base64");
encryptedText = encrypt(plainText, nodeJSPassword, "AES/ECB/PKCS5Padding", "Hex");
writeOutput(encryptedText);
Result:
C43E1179C15CD962373A6E28486D6F4ADB12FBB6731EF99C9212474E18D51C70
On the Node.js side, modify the code to use a 128 bit key, not 192. Also, password strings are first decoded into binary. When creating the cipher object, you need to indicate the input string is base64 encoded, to ensure it is interpreted properly.
Node.js
var password = 'WTq8zYcZfaWVvMncigHqwQ==';
var passwordBinary = new Buffer(password, "base64");
var encrypted = 'C43E1179C15CD962373A6E28486D6F4ADB12FBB6731EF99C9212474E18D51C70'
var crypto = require('crypto');
var decipher = crypto.createDecipher('aes-128-ecb', passwordBinary );
var decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
Result:
7001010000006aaaaaabbbbbb
Having said that, Using ECB mode is NOT recommended. The preferred method is CBC mode (with a random iv
), which generates less predictable output and hence is more secure.
- than CF Use Tobase64(secret) to generate key
Along those same lines, while you can technically use arbitrary strings, ie "abcdefghijkl1234", to generate a key - DON'T. A very important part of strong encryption is using secret keys that are "truly random and contain sufficient entropy". So do not just do it yourself. Use a proven function or library, like GenerateSecretKey(), which was specifically designed for the task.