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:
