[PYTHON-CRYPTO] aes module API

Bram Cohen bram at GAWTH.COM
Fri Mar 29 20:53:15 CET 2002


This is a proposal for the API for a module called 'aes', which implements
the standard modes of rijndael.

The purpose of this module is *not* to be a complete library for all the
standard things one might want to do with aes. Rather, it's a bare-bones
library which does just enough to make it possible to implement all the
standard aes stuff efficiently in 'pure' Python, with the only C calls
being to this library.

For example, ciphertext stealing in CBC mode is to be implemented using
aes.CBC with a few calls at the end to aes.ECB to do the stealing part.
This results in the performance benefits of using C without the API bloat
of doing *everything* in C.

The methods of AES are CTR, CLE, OFB, CBC, ECB, and CFB. Each of them
takes a 16, 24, or 32 byte key and returns an encryption object.

ECB encryption objects have two methods, encrypt and decrypt, both of
which take a string whose length is a multiple of 16 bytes and return an
encrypted or decrypted string of the same length. Strings of length 0 are
allowed.

CTR encryption objects have a method called process, which takes a counter
(an integer) and a string to be encrypted. CTR is the same step for
encryption and decryption, hence the single process function instead of
separate encrypt and decrypt functions.  process() returns a string of the
same length as the one it received.

The counter passed in to process() is modulo 2 ** 128, so numbers such as
-1 are allowed. When the counter gets passed 2 ** 128 it should roll back
to zero.

The other method of CTR objects is processor(), which takes a counter and
returns a function. The function takes strings and returns each of them
encrypted incrementally. This is the same as using the process() method
only it isn't necessary to have the entire string in memory at once. The
following test should always pass -

def test_concat(key, s):
    x = CTR(key)
    p1 = x.process(0, s)
    f = x.processor(0)
    assert x.process(0, s) == f(s[:3]) + f(s[3:])

CLE has the same API as CTR, only CTR is big endian and CLE is little
endian.

OFB has the same API as CTR except that instead of a counter it takes an
iv of length 16.

CBC and CFB have a similar API to OFB, except that instead of process and
processor functions, they have analogous encrypt and encrypter() and also
an analagous decrypt and decrypter(). In these modes incremental
processing sometimes has to buffer a bit before it knows how to encrypt
the next byte, so they return as long a string as they can from each call
to incremental processing functions, never trailing the amount of data
passed in by 16 bytes or more.

Here's a quick cheat sheet to the API. What does everybody think?

CTR(key)
    process(counter, str)
    processor(counter)
        __call__(str)

CLE(key)
    process(counter, str)
    processor(counter)
        __call__(str)

OFB(key)
    process(iv, str)
    processor(iv)
        __call__(str)

CBC(key)
    encrypt(iv, str)
    decrypt(iv, str)
    encrypter(iv)
        __call__(str)
    decrypter(iv)
        __call__(str)

ECB(key)
    encrypt(str)
    decrypt(str)

CFB(key)
    encrypt(iv, str)
    decrypt(iv, str)
    encrypter(iv)
        __call__(str)
    decrypter(iv)
        __call__(str)


-Bram Cohen

"Markets can remain irrational longer than you can remain solvent"
                                        -- John Maynard Keynes





More information about the python-crypto mailing list