[PYTHON-CRYPTO] A pythonic way of calling crypto algorithms

Andrew Archibald aarchiba at YAHOO.COM
Thu Feb 22 18:13:54 CET 2001


On Thu, Feb 22, 2001 at 09:25:35AM +0100, Treutwein Guido wrote:
> Hi all,

Hi,

> I'm not sure how settled the design is in respect to calling the algorithm,
> once it is found via the mechanisms discussed here, but we found the
> following approach quite useful:
>         # alg() is assumed to be a cryptographic algorithm
>
>         cipher = alg(plain="something", key=aKey)
> #encrypt or signature generation or MAC computation
>         plain  = alg(cipher="$#qq!", key=aKey)
> #decrypt
>                 alg(plain="something", cipher="$#qq!", key=aKey)        #MAC
> or signature verification
> In the last case its a matter of taste, whether an exception results in the
> mismatch case, or something true is returned in the match case (e.g.
> timestamp) or both.

Hmm.  There seem to be some problems with this approach.  A very common
mode of usage of a block cipher, for example, is to set up a cipher in CBC
mode, hand it a packet, send off the ciphertext, hand it another packet,
send off the ciphertext, etc., with appropriate chaining between packets.
In this sort of application, it is important that the cipher be able to
save some state --- key setup for some ciphers (eg, Blowfish) is very
expensive.  So it is important that it be possible to save the machine with
keys all set up.

Similarly, a very common way to use a hash function is to set up a context
and shovel data into it as it becomes available.  This interface would
require all the data we will want to hash to be stored in one string.  This
is inappropriate, for example, for the Yarrow RNG, where what is being
hashed is an ever-growing stream of data.

So these design criteria suggest (to me) that the API should make available
"cipher machine" objects that encapsulate this sort of state.

> The advantages are
> - everything can be handled within the algorithm itself (so a hashing
> function would reject the decrpytion by raising an exception)
> - all types of algorithms can be called uniformly
> - no magic constants are needed for encryption/decryption

I don't think it's actually a good thing that all algorithms are treated
uniformly.  Cryptographic algorithms do very different things; why should
one treat them the same?

As I see it, the major categories of algorithm we have to support are
these:

Symmetric Algorithms
        Hashes
                Keyed hashes
                Unkeyed hashes
        Encryption
                Block ciphers
                Stream ciphers

Asymmetric Algorithms
        Signing/Verifying
        Encrypting/Decrypting

Protocols and Other
        Key agreement (Diffie-Hellman etc.)
        Package transforms
        Secret sharing

Interoperability
        Reading/Writing cryptographic data in various formats
        Key management
                Managing secrets --- burning passphrases when no longer
                needed, for example
                Keyring manipulation
        Implementations of various standards (SSL, S/MIME, OpenPGP, etc.)

I don't think it's even a good idea to try to make these look exactly the
same.  Of course, it would be easy to argue with my hierarchy; for example,
a MAC is essentially a hash function with a key, but it is also the
symmetric equivalent of a digital signature.  Asymmetric encryption should
perhaps be lumped in with symmetric encryption, but its behaviour is very
different (doesn't operate nicely on fixed-length bitstrings, for example).

So if anyone wants to start defining a class hierarchy for cryptographic
algorithms, I'll be very interested to see how they organize it.

Thanks,
Andrew





More information about the python-crypto mailing list