Skip to content

Instantly share code, notes, and snippets.

@promolic1
Created November 23, 2016 21:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save promolic1/b3dd4fef36852844cbaed198d05b6be3 to your computer and use it in GitHub Desktop.
Save promolic1/b3dd4fef36852844cbaed198d05b6be3 to your computer and use it in GitHub Desktop.
Just to avoid confusion, I wanted to point out a few things here.
For reference, all of the info I've gathered below is directly from the documentation found by running the following two lines of code through your Python interpreter:
>>> from Crypto.Cipher import AES
>>> help(AES)
Block Size vs Key Size
AES has a fixed data block size of 16 bytes (128 bits)
AES can have a key size of 128, 192, or 256 bits (16, 24, or 32 bytes)
This is the difference between AES-128, AES-192, and AES-256
Lines 5 & 6 of your Gist are therefore understandably confusing/incorrect as you seem to be referring to key size, not block size.
Plaintext Length Requirements
In regards to the encrypt method, which you used on line 18, the following is true:
For MODE_ECB, MODE_CBC, and MODE_OFB, plaintext length (in bytes) must be a multiple of block_size.
For MODE_CFB, plaintext length (in bytes) must be a multiple of segment_size/8.
For MODE_CTR, plaintext can be of any length.
For MODE_OPENPGP, plaintext must be a multiple of block_size, unless it is the last chunk of the message.
In your comments on lines 8 - 10 you state that by virtue of using AES as a cipher, the plaintext must be a multiple of the block size, but this isn't entirely true. It depends on which chaining mode is being used.
The doc also states that for the new method, which you used on line 25, the only required parameter is the key (which you've stored in a variable called secret). You can optionally pass in mode, IV, counter, and/or segment_size. Since you only passed in the key, the cipher took on the default mode of MODE_ECB. In this case, the plaintext length (in bytes) does indeed need to be a multiple of the block size.
Randomness
To come up with a randomly generated key, as you did in line 22, another good alternative is to use the Crypto.Random package as such:
from Crypto import Random
key = Random.new().read(AES.block_size)
The above snippet of code will output 16 cryptographically random bytes and save them in the key variable, thereby effectively making the AES cipher instantiated with this key AES-128. You could do Random.new().read(32) for AES-256.
Final Thoughts
Per the info shown on the Block cipher mode of operation Wikipedia page's entry, use of ECB mode is highly discouraged. MODE_CBC and MODE_CFB tend to be the suggested modes but also require that you create an Initialization vector (IV).
from Crypto.Cipher import AES
import base64
import os
# the block size for the cipher object; must be 16, 24, or 32 for AES
BLOCK_SIZE = 32
# the character used for padding--with a block cipher such as AES, the value
# you encrypt must be a multiple of BLOCK_SIZE in length. This character is
# used to ensure that your value is always a multiple of BLOCK_SIZE
PADDING = '{'
# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
# one-liners to encrypt/encode and decrypt/decode a string
# encrypt with AES, encode with base64
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
# generate a random secret key
secret = os.urandom(BLOCK_SIZE)
# create a cipher object using the random secret
cipher = AES.new(secret)
# encode a string
encoded = EncodeAES(cipher, 'password')
print 'Encrypted string:', encoded
# decode the encoded string
decoded = DecodeAES(cipher, encoded)
print 'Decrypted string:', decoded
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment