Reputation: 1053
I have a nodejs service that uses AES encryption on some data that needs to be decrypted in Python. No matter what I do I cannot make this to work. NodeJS code:
const algorithm = 'aes-128-ctr';
function encryptScript(data, key) {
const cipher = crypto.createCipher(algorithm, key);
let crypted = cipher.update(data, 'utf8', 'hex');
crypted += cipher.final('hex');
return crypted;
}
I have tried in Python:
counter = Counter.new(128)
cipher = AES.new(key, AES.MODE_CTR, counter=counter)
print cipher.decrypt(enc.decode("hex"))
But it is not working.
My first issue is that the Python code is not accepting keys that are longer than 32 bytes (and the Nodejs code does).
If I use NodeJS crypto module the decryption is working:
function decryptScript(data, key) {
const decipher = crypto.createDecipher(algorithm, key);
let dec = decipher.update(data, 'hex', 'utf8');
dec += decipher.final('utf8');
return dec;
}
I don't know what node is doing but it is probably related to some padding of the data.
How can I make it work?
(I will prefer a solution that will not require changes in the NodeJS code but only in the Python script).
Upvotes: 1
Views: 1281
Reputation: 49251
CreateCipher
uses EVP_BytesToKey
to create a key and an IV from a password (what is called a key in the NodeJS-code is actually the password). Here is an implementation of EVP_BytesToKey
in Python. The parameters to use are described in the documentation of CreateCipher
: MD5, no salt, one iteration. In CTR-mode the IV is usually incremented with each block starting with a value to be defined. CreateCipher
uses as start value the IV determined with EVP_BytesToKey
. The functionality of CreateCipher
can therefore be implemented in Python as follows:
import hashlib
from Crypto.Cipher import AES
from Crypto.Util import Counter
...
encrypted = '5e99b5190f12143c057f6bdd8625f958682e737c11e138a2f571c050313dbe1008347604c7c7e8bf506a0a' # Example
# Generate key and iv
keySize = 16
ivSize = 16
digest = hashlib.md5
salt = b''
password = b'123456' # Example
iteration = 1
keyiv = EVP_BytesToKey(keySize, ivSize, digest, salt, password, iteration)
key = keyiv[0]
iv = keyiv[1]
# Define counter
nbits = 128
initial_value = int.from_bytes(iv, byteorder = 'big');
counter = Counter.new(nbits, initial_value = initial_value)
# Decrypt
cipher = AES.new(key, AES.MODE_CTR, counter = counter)
decrypted = cipher.decrypt(bytes.fromhex(encrypted))
print("Decrypted: " + decrypted.decode('utf8'))
The ciphertext was generated with the NodeJS-code using the following input:
key = '123456';
data = 'The quick brown fox jumps over the lazy dog';
Note that CreateCipher
is deprecated and should no longer be used, especially not in combination with the CTR-mode. Instead CreateCipheriv
can be used. In CTR-mode, it is important that a key/IV-pair is used only once. Otherwise the security will be lost, see here. CreateCipher
doesn't provide randomization, i.e. the same password always generates the same key and IV and thus always the same keystream. Therefore, security is lost if the same password is used several times. CreateCipheriv
, on the other hand, expects a key and a random IV. Here a key can be
used several times as long as the randomization of the IV ensures that key/value-pairs are not repeated, see here.
Upvotes: 1