MicroPython utility library around ucryptolib.aes
The ucryptolib
MicroPython module provides an aes
class that is capable of doing AES encryption. mpyaes
provides an implementation of PKCS7 padding and other facilities around ucryptolib.aes
.
mpyaes.generate_key
(mpyaes.generate_IV
): generates a specified amount of pseudorandom bytes, making use ofurandom.getrandbits
. It's intended for (but not limited to) key (and IV) generation.mpyaes.PKCS7
: pads and verifies padding, raisesmpyaes.PaddingError
if the padding is incorrect.mpyaes.AES
: handles AES encryption and decryption.mpyaes.new
: returns an AES cipher object i.e. instantiates thempyaes.AES
class.
Keys and IVs are generated by mpyaes.generate_key(x[, seed])
and mpyaes.generate_IV(x[, seed])
. mpyaes.generate_IV
is an alias of mpyaes.generate_key
.
The only mandatory argument to mpyaes.generate_key
is either the size in bytes of the key to be generated, or a bytes
-like object which will be filled with the pseudorandom data.
seed
is optional, but if supplied will result in urandom.seed(seed)
being executed.
>>> import mpyaes
>>> key = mpyaes.generate_key(32)
>>> key
bytearray(b'\xe5\x82\xe7\xc1\xcfP9\xab\x9e4-(\\}\xab\xaa\xf3\xe2S\x054d\xdf"\x82\xd0\xd8\'\x9ee\xc6\x1b')
>>> IV = mpyaes.generate_IV(16)
>>> IV
bytearray(b"\xfeYD\x91\xf2\xcd\xf1\xc6\xc9\xd0\x9c#\xf1\xad'\x9a")
With a buffer and seed value:
>>> key2 = bytearray(32)
>>> seed = 110011
>>> mpyaes.generate_key(key2, seed)
>>> key2
bytearray(b"\x81IV_i\xcd\xc5\xad9>\xe8'\x00\xf9<\x85")
Cipher objects are created using mpyaes.new(key, mode[, IV])
. Note that keys and IVs are consumed once used to instantiate a cipher object, so save them to variables for sharing (as done in the previous section). Alternatively, if communicating with a device that implements the Yasmarang PRNG, you could use and save a seed.
>>> aes = mpyaes.new(key, mpyaes.MODE_CBC, IV)
>>> aes
<AES 256-bit CBC>
Padding of plaintexts is carried out by mpyaes.PKCS7.pad
and similarly verified by mpyaes.PKCS7.verify
with every call for encryption and decryption. Note that decrypted ciphertexts are stripped of their padding.
bytearray
>>> message = bytearray("https://www.youtube.com/watch?v=_HHlclssEP4")
>>> aes.encrypt(message) # in place
>>> message
bytearray(b'\xe4\xb3\x90\xc3\x0b\x80%\xb3\xc2\n\xc3nY\xdfv\xc9\xd3X8\x82Y\xd8\xd7\xbc\xd0\xafP\xbdJ~\xe5\xdf\x8a\xbc\x9cU\xfd\xa3\x9a\x8d\x1a\xed\xdd\x99\x9a\xa5Ll\xff\xaa\xef\xf0\xfbU)o\xb11\xacC\x981\x0b\xdf')
>>> message = aes.decrypt(message) # zero-copy
>>> message
bytearray(b'https://www.youtube.com/watch?v=_HHlclssEP4')
bytes
/str
>>> message = "This is an example string." # alternatively b'This is an example bytes.'
>>> message = aes.encrypt(message) # mpyaes.AES.encrypt([bytes, str]) returns a bytearray
>>> message
bytearray(b'^"\x06u\x95\xcb\xb4\xf6\xf0\x90\xd6\xc7T\xd0)\xe1\xf6GMh\xf9\x0b\xd5\xbf\xb3\x12n\x037\xa0K\xfb')
>>> message = aes.decrypt(message) # zero-copy
>>> message
bytearray(b'This is an example string.')
- Files
>>> aes.encrypt_file('to_encrypt.txt', 'out.enc') # mpyaes.AES.encrypt_file(input_file, output_file)
>>> aes.decrypt_file('out.enc', 'challenger.txt') # mpyaes.AES.decrypt_file(input_file, output_file)
>>> with open('to_encrypt.txt', 'rb') as f, open('challenger.txt', 'rb') as g:
... assert f.read() == g.read()
...
>>>
mpyaes
makes use of generic MicroPython libraries to increase portability.- AES 128-bit and 256-bit, ECB and CBC modes were tested on an ESP32 running MicroPython 1.13.
- CTR mode isn't supported on the ESP32, so I haven't tested it.