pythonencryptionaespycryptoctr-mode

How to set block size in PyCrypto AES CTR Mode


I am trying to get AES encryption to work through the PyCrypto library in Python.

I read in the password from the user and salt from a file. I then call PBKDF2 to generate a key from the textual password

PBKDF2(self.master_password, salt, 32)

I then generate an IV using the Random.get_random_bytes

IV = Random.get_random_bytes(len(key))

I then create a Counter from the Crypto.Util package

ctr = Counter.new(32, IV)

Then I create an AES object

e = AES.new(key, AES.MODE_CTR, counter=ctr)

However when I call e to encrypt

e.encrypt(user_name)

I get the following error

CTR counter function returned string not of length 16

From the way I understand this error means that the block cipher is 16 bytes which matches with the documentation I found at

https://www.dlitz.net/software/pycrypto/api/current/Crypto.Cipher.AES-module.html

I tried changing it to a 32 byte block size by create the AES object like this

AES_Encryptor = AES.new(key, AES.MODE_CTR, counter=ctr, block_size=32)

but then I get the following error

'block_size' is an invalid keyword argument for this function

If someone could point me towards the right direction that'd be great.


Solution

  • AES is a block cipher with a fixed block size of 128 bit (16 byte). It has three valid key sizes of 128 bit, 192 bit and 256 bit. A nonce for CTR mode, also called IV sometimes, needs to be at most as long as the block size which is 16 bytes.

    If you want a 256 bit block size, you can't use AES. There are several other algorithms that permit a 256 bit block size such as Rijndael, but there is no implementation of that in pycrypto. AES is a subset of Rijndael.

    Usually, we generate a nonce of either 64 bit or 96 bit for CTR mode in order to have some control over how many blocks we can encryption without a counter collision.

    nonce = Random.get_random_bytes(8)  # 8 bytes
    ctr = Counter.new(64, nonce)        # 64 bits remaining
    

    or

    nonce = Random.get_random_bytes(12) # 12 bytes
    ctr = Counter.new(32, nonce)        # 32 bits remaining
    

    For a 64 bit nonce, you can encrypt at most 264 blocks before running into problems. That's more than any data in the world, but the issue is that by choosing the nonce at random, you have a probability of 1 to get a nonce collision after 232 encryptions with the same key due to the birthday paradox.
    For 96 bit nonces, you can encryption at most 232 blocks which is roughly 68 GB of data, but you have a much lower chance of getting a nonce collision.

    The nonce 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. Since you know how long it is supposed to be, you know how much you can slice off.