简体   繁体   中英

AES decryption with PyCryptodome does not produce the expected result

I have some difficulties reproducing AES encryption and decryption in python.

Context : A year ago, I created a small django based application using this javascript library for client side encryption . Basically, some users' inputs are encrypted with a key and sent as hexadecimal strings to be stored.

For the illustration, I'll focus on bd45bcccd0 (aka ' Masha ' encrypted with john's key: 3ed8bd71327aafd855aac37921519767 )

Encryption and decryption with the current js library

  • encryption utf-8 -> bytes -> encrypted bytes -> hex
  • decryption hex -> encrypted bytes -> bytes -> utf-8

id_password is a MD5 hash of the user's password. It is stored in the session storage and is used as a key

  function encrypt(t){
    var key = aesjs.utils.hex.toBytes(sessionStorage.getItem("id_password"));
    var textBytes = aesjs.utils.utf8.toBytes(t);
    var aesCtr = new aesjs.ModeOfOperation.ctr(key);
    var encryptedBytes = aesCtr.encrypt(textBytes);
    var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
    return encryptedHex;
    }

  function decrypt(t){
    var key = aesjs.utils.hex.toBytes(sessionStorage.getItem("id_password"));
    var textBytes = aesjs.utils.hex.toBytes(t);
    var aesCtr = new aesjs.ModeOfOperation.ctr(key);
    var decriptedBytes = aesCtr.decrypt(textBytes);
    var decrypted_utf8 = aesjs.utils.utf8.fromBytes(decriptedBytes);
    return decrypted_utf8;
    }

Once loaded in key , I get a 16 items array (So I guess a AES 128bits CTR is performed):

var key = aesjs.utils.hex.toBytes(sessionStorage.getItem("id_password"));
console.log(key)
Array(16) [ 62, 216, 189, 113, 50, 122, 175, 216, 85, 170, … ]

With the current code, encryption and decryption work

Python implementation

For unit-testing purposes, I wanted to be able to decrypt. I am using this library . To mimic the client side as much as possible, I tried the following:

john_key = "3ed8bd71327aafd855aac37921519767"
cipher = AES.new(codecs.decode(john_key,'hex_codec'), AES.MODE_CTR)
d = cipher.decrypt(codecs.decode('bd45bcccd0', 'hex_codec'))
d.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xac in position 0: invalid start byte

Here is the problem but I am not sure at which stage it occurs. Here is what I checked:

# key's length is correct
k = codecs.decode(john_key,'hex_codec')
k
b'>\xd8\xbdq2z\xaf\xd8U\xaa\xc3y!Q\x97g'
len(k)
16
# decoded message's length is correct
d = cipher.decrypt(codecs.decode('bd45bcccd0', 'hex_codec'))
len(d)
5

Since I can't rely on a library I can't reproduce the results, I wonder whether I misused PyCryptodome or whether the way this javascript library implements AES CTR encryption is reliable. Any insights?

The CTR -mode requires an IV . Since you do not explicitly create the IV, an implicitly created IV is used. However, both codes generate different IVs, so that the decryption fails. In the Python-code, a random IV is generated, in the aes-js-code a fixed IV (1) is used.

So that the decryption is possible with the Python-code, the same IV must be used here as in the aes-js-code ( here and here ). For this purpose:

cipher = AES.new(codecs.decode(john_key,'hex_codec'), AES.MODE_CTR)

has to be replaced by

counter = Counter.new(128, initial_value = 1)
cipher = AES.new(codecs.decode(john_key,'hex_codec'), AES.MODE_CTR, counter = counter) 

which decrypts the ciphertext to Maria (however not Masha ).


For security reasons it is mandatory for CTR that key/IV pairs may only be used once, ie if the same key is applied, a new IV must be generated for each encryption. The current code has the weakness that key/IV pairs would be repeated when using the same key. A better way would be to generate a random IV for each encryption, send this IV together with the ciphertext to the recipient (the IV isn't secret, so it is usually prepended to the ciphertext), where it can be used for the decryption.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM