[PYTHON-CRYPTO] aes library

Bram Cohen bram at GAWTH.COM
Thu Apr 4 06:58:53 CEST 2002


Paul Rubin wrote:

> Traditionally for streams, you'd use CFB, which is self-resynchronizing
> and doesn't need to be re-keyed so much.

For net protocols self-resynching is irrelevant. I think the larger block
length is very helpful with AES, since it means you don't have to re-key
at all, although mostly there's more focus on counter now because it
allows random access, which OFB and CBC do not (CBC allows it for reading,
but not writing.)

> CTR wasn't used much with DES.

I'm not sure what 3DES modes we might want to support - is there even a
canonical variant of it with canonical key format? The only mode I know of
being used for it widely was CBC.

If there isn't a good, standard least common denominator feature set for
3des then I say we drop it - it's just there for backwards compatibility,
not something we want to encourage people to use.

> Anyway, it sounds like there's desire to keep CTR, so fine, let's keep it.

So we seem to have general agreement on CBC, ECB, and CTR modes, at least
for aes.

> This fancy OO interface doesn't seem like the right thing for a C
> extension module.  Something like the SHA module interface (as we
> discussed before) could be ok.  Each update operation would produce
> ciphertext output (possibly 0 bytes) and keep up to one partial
> plaintext block buffered, and the final() call would flush any
> buffered partial block.  That way there's no magic buffer in the
> crypto object getting dynamically resized on each operation.

The simplicity of that approach certainly does have much appeal,
especially after I've spent some time thinking about what is involved in
implementing the more sophisticated one. There should be a call to find
out how much it's got buffered but unreturned regardless though, since it
has to have that information anyway.

> I think the encryption and Python function calls will be much slower
> than any string copies.  We could support Python buffer objects, but
> we're probably better off keeping things simple.

Okay then, simple it is.

> The advantage of putting AES and DES in the same module is that the
> same code can implement the modes of operation without creating
> dependencies between modules.  The other possible organization is
> three modules, a modes-of-operation module callable from python, and
> AES and DES modules that implement the raw block ciphers that the
> modes-of-operation module can use.

That makes some sense. DES can be added later though.

> As for documentation, rather than try to turn the poor app developer
> into a cryptographer by explaining CBC mode and so forth, I think the
> most important thing is to have an extremely simple interface for the
> most obvious case, e.g.
>
>    ciphertext = aes.encrypt(plaintext, key)
>    plaintext = aes.decrypt(ciphertext, key)
>
> where key and plaintext are arbitrary strings.  This however means the
> "encrypt" function should take care of all padding and IV generation,
> which means it needs good random numbers, which makes the encryption
> module depend on a CPRNG whether the CPRNG is in the same module or a
> separate one.

That can be included as a simpleencrypt and simpledecryt functions written
in pure Pyhton. Note that simpledecrypt will have to raise ValueError
though.

> Anyway, I think we're somewhat going around in circles at this point
> and we should implement something and see how we like it.  Anyone want
> to meet up with me (San Francisco area) and start coding?

I'm up for that.

I think we actually are making some progress, albeit slowly.

It occurs to me that the counter mode API should really use position
rather than counter - counter of x is the same as position 16 * x. If the
API is based on counter you just wind up making something based on
position on top of it.

Also, since one might want to do a few different operations using the same
key, I think it makes sense to have an AES class with all the methods
hanging off of it, to avoid unnecessary re-keying (and duplicate code in
the implementation.)

Here's my latest stab at the API (hey, it can't hurt to have this as
worked out as possible before we sit down and hack) -

AES.__init__(key)

key can be of length 16, 24, or 32.

AES.ECB_encryt(str)
AES.ECB_decryt(str)

Those do what you'd expect.

AES.CTR_encrypt(str, pos = 0, bigendian = 1)
AES.CTR_decrypt(str, pos = 0, bigendian = 1)

These are the same function. pos is a counter of bytes, not the counter
tally. In all cases, CTR_encrypt(s1, a) + CTR_encrypt(s2, len(s1)+a) =
CTR_encrypt(s1 + s2, a)

AES.CBC_encrypt(str, iv, padding = 1)
AES.CBC_decrypt(str, iv, padding = 1)

CBC_encrypt gets pissy if you give it padding = 0 and a str whose length
isn't a multiple of 16. CBC_decrypt automatically strips padding. padding
= 1 refers to pkcs5. padding values other than 0 and 1 are reserved for
possible later use.

AES.CBC_encrypter(pos = 0, bigendian = 1)
AES.CBC_decrypter(pos = 0, bigendian = 1)

These are the same function. They return an object with the following
methods -

setpos(pos)
getpos()
encrypt(str)
decrypt(str)

encrypt and decrypt above are the same function.

AES.CBC_encrypter(iv)

this returns an object with the following methods -

encrypt(str)
finish(padding = 1)
amount_buffered()

Note that it's possible to implement finish using the other two.

AES.CBC_decrypter(iv)

this returns an object with the following methods -

decrypt(str)
finish(padding = 1)
amount_buffered()

Note that, again, finish can be implemented using the other two, and also
that finish might raise a ValueError.

-Bram Cohen

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





More information about the python-crypto mailing list