AES is a block block : it is an algorithm (more precisely, a pair of algorithms) that takes a key and a message block and either encrypts or decrypts the block. The block size is always 16 bytes, regardless of the size of the key.
CTR is an operating mode . These are a couple of algorithms that are built on a block cipher to create stream encryption that can encrypt and decrypt messages of arbitrary length.
CTR works by combining consecutive message blocks with encryption of consecutive counter values. The counter size must be one block in order to be valid for block encryption.
- It does not functionally matter what the subsequent values ​​of the counter are if the same sequence is used on the encryption and decryption side. Typically, the counter is processed as a 256-bit number and incremented for each subsequent block, and the initial value is randomly selected. Thus, as a rule, the increment method is curved in the code, but the decryption side needs to know what the initial value is, so the encryption side sends or stores the initial counter value at the beginning of the encrypted message.
- To ensure security, it is important that you never repeat the same counter value with the given key . So, for a one-time key, start with
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' . But if the key is used several times, then the second message is not allowed to reuse any counter values ​​used by the first message, and the easiest way is to guarantee that it will generate the initial counter value in a random order (with 2 ^ 128 space, the probability of collision is acceptably negligible )
By letting the caller choose the counter function, PyCrypto library gives you a lot of rope to hang yourself. You should use Crypto.Util.Counter , not just “for better performance” as written in the documentation, but because it’s easier to create something safe than what you probably think of yourself. And even so, make sure to use a random initial value that is not the default value.
import binascii import os from Crypto.Cipher import AES from Crypto.Util import Counter def int_of_string(s): return int(binascii.hexlify(iv), 16) def encrypt_message(key, plaintext): iv = os.urandom(16) ctr = Counter.new(128, initial_value=int_of_string(iv)) aes = AES.new(key, AES.MODE_CTR, counter=ctr) return iv + aes.encrypt(plaintext) def decrypt_message(key, ciphertext): iv = ciphertext[:16] ctr = Counter.new(128, initial_value=int_of_string(iv)) aes = AES.new(key, AES.MODE_CTR, counter=ctr) return aes.decrypt(ciphertext[16:])
Gilles
source share