[PYTHON-CRYPTO] things missing from PEP 272

Bram Cohen bram at GAWTH.COM
Mon Mar 18 09:15:15 CET 2002

Paul Rubin wrote:

> The IV for counter mode should be an int or long giving the counter
> value.  CTR/CLE for endianness is ok, or just choose one endianness
> and stick to it.  Are there any applications/standards with specific
> endianness requirements?

Yes. All of them. If one machine encryptes big-endian, and another
decrypts little-endian, you get two very confused machines :-). Seriously,
endainness is a major gotcha for implementation which is often forgotten
about in algorithm design. I go so far in BitTorrent as to start my
counter at 1 instead of 0 to make endianness problems visible immediately.

Unfortunately the NIST document on modes shrugs off the whole endianness
issue. I wish I'd submitted comments during the review period emphasizing
how important this issue is.

One *can* use an integer to represent the counter, but it makes the API
different from other modes. They both work, but I slightly prefer it as a

>   3. The specifications of block_size and key_size are vague: is
>   "size" measured in bits, or in bytes?

Every crypto library I've used has measured everything in bytes.

>   4. The key_size variable must be either an integer (a specific number
>   of bits), or None (meaning any length at all is valid).  This doesn't
>   handle AES very well--AES accepts 128, 192, or 256 bits, but not other
>   values.

AES also has defined variants for block sizes of 192 and 256 bits, but
those aren't NIST standards.

>   5. I think it should be ok to pass an initial IV of None or 0,
>   equivalent to "\0"*(module.block_size) where block_size is in bytes.
>   Usually you use IV=0 to compute a CBC MAC, for example.

Also, the IV should be passed as an argument to encrypt() and decrypt(),
not to new().

Additionally, there should be support for encrypting a stream
incrementally, possibly by having make_encrypter() and make_decrypter()
methods, which return functions which you pass pieces of the string to be
processed in order, and they return the processed string as it's possible
to compute it.

Here's some test code in my app which shows how incremental encryption
should work -

def checkpoints(s, l):
    cm = make_encrypter('abcd' * 4)
    buf = ''
    for i in xrange(len(l) - 1):
        buf += cm(s[l[i]:l[i+1]])
    return buf

def test():
    p = ''.join([chr((3 * i) % 256) for i in xrange(500)])
    a = checkpoints(p, [0, 3, 11, 200, 350, 400, 500])
    b = checkpoints(p, [0, 0, 21, 27, 28, 29, 301, 500])
    assert a == b

-Bram Cohen

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

More information about the python-crypto mailing list