Cryptographic hash functions Hash functions are very useful cryptographic primitives. Catacomb provides a few of the best-known cryptographic hashes. Hash function interface Hash functions share a regular interface. I'll take Ron Rivest's MD5 as an example. Using a hash function is a three-stage process. You initialize a context, you hash some data, and you get the result out of the end. The data to be hashed need not be contiguous, and you don't have to have it all before you start. Hash function contexts don't use up lots of memory. An MD5 context is called `md5_ctx'. You initialize it with `md5_init'. You hash a block of data using `md5_hash' giving it the context, the pointer to the data and its length. Finally, you extract the data using `md5_done', giving it the address of a buffer of MD5_HASHSZ bytes for it to write the result. There are some other standard operations as well, but they're not often used: see the header files for details. The hash functions supported are: MD4 By Ron Rivest -- returns a 128-bit hash. MD4 is not collision-resistant, and may not even be second-preimage-resistant. Don't depend on its security. On the other hand, MD4 is *very* fast. MD5 Also by Rivest, also returns a 128-bit hash. MD5 is slower than MD4, and more conservative, but there are still grave doubts about its security. SHA1 Designed by the US National Security Agency. Returns a 160-bit hash. Slower than MD5. Looks strong. Fixes a problem in the earlier SHA. RIPEMD-160 Designed by the people who broke MD4 and MD5. Returns a 160-bit hash. Slower than SHA1. My personal preference. HMAC interface It's possible to construct a `keyed hash' or `message authentication code' from a hash function. Most methods for doing this are insecure. HMAC is a good method, with rigorously proven security properties. Each hash function above has an HMAC mode defined for it. This works much the same way as block cipher modes. Using HMAC is a two-step process. First, you initialize a MAC key block `mackey' to contain the key you'll use, and then you initialize MAC contexts `macctx' which to actually hash the data. Hashing works just the same as the basic hash function, except that you use `macinit', `machash' and `macdone' functions rather than the plain `init', `hash' and `done'. Generic interfaces Generic interfaces to hash functions and MACs are provided. See README.cipher to get an idea for how a similar generic interface works -- I'll only explain the differences here. The generic hash object, `ghash' contains an `ops' member referring to: h->ops->b->name The name of the hash function. h->ops->b->hashsz The output size of the hash function. h->ops->hash(h, p, sz) Hash sz bytes of data starting at address p. h->ops->done(h, b) Stop hashing, write the result to buffer b with size `hashsz'. h->ops->destroy(h) Destroy the generic hash object. The generic hash class, `gchash', contains a base which has the same members as `ops->b' above, and an `init' function which takes no arguments and returns a pointer to a `ghash'. There's a generic MAC interface too. A MAC class, `gcmac' contains a hash base (exactly the same, but with a different name), and a function `key' which takes a pointer to some key data and the key size, and returns a pointer to a `generic mac' object, `gmac'. A `gmac' contains an `ops' member: m->ops->b->name, m->ops->b->hashsz As above. m->ops->init(m) Returns a generic *hash* object to actually compute a MAC over some data. m->ops->destroy(m) Destroys the generic MAC block. That was quite complex. Here's an example of using a generic MAC. void compute_mac(gcmac *gcm, const void *k, size_t ksz, const void *p, size_t sz, void *hash) { gmac *m = gcm->init(k, ksz); ghash *h = m->ops->init(m); m->ops->destroy(m); h->ops->hash(h, p, sz); h->ops->done(h, hash); h->ops->destroy(h); } Note that the hash doesn't depend on the MAC object continuing to exist. -- [mdw] Local variables: mode: text End: