Cryptography Reference
In-Depth Information
After block #N has been hashed, subsequent operations won't change the hash of
block #N. They are just added to it, modulo 32. Therefore, you can save memory
and time by allowing the hash operation to save its state and pick back up where
it left off later — that is, feed it a block of data, let it update the hash code, and
then feed it another, and so on.
Of course, the padding requirements of MD5 and SHA make this a little
trickier than it sounds at fi rst. You need to keep track of the running bit-length
of the input so that it can be appended later on. This is, incidentally, how a
32-bit architecture can hash an input of more than 2 32 bits. Plus, for additional
fl exibility, you'd want to allow the caller to pass in less than a single block at a
time and accumulate the blocks yourself.
You could store this running state in a static global, but this would cause
thread-safety problems (if you ever wanted to use this routine in a threaded
context, anyway). Instead, you'd do better to pass a context object into the hash-
ing function, with a routine named something like hash _update that would
also take the data to be added to the running hash, and another routine named
hash _finalize that would add the fi nal padding blocks and return the result.
This is, in fact, the only non-superfi cial difference between the MD5 code included
in RFC 1321 and the MD5 implementation presented here. You need to be able
to compute running hashes for SSL, so implement this extension for MD5 and
SHA. Change your digest function to allow running updates and improve the
HMAC implementation a bit.
Defi ning a Digest Structure
Because you can no longer call digest in one shot, but must instead keep track
of a long-running operation, defi ne a context structure that stores the state of
an ongoing digest computation as shown in Listing 4-21.
Listing 4-21: “digest.h” digest context structure declaration
typedef struct
{
unsigned int *hash;
int hash_len;
unsigned int input_len;
void (*block_operate)(const unsigned char *input, unsigned int hash[] );
void (*block_finalize)(const unsigned char *block, int length );
// Temporary storage
unsigned char block[ DIGEST_BLOCK_SIZE ];
int block_len;
}
digest_ctx;
 
Search WWH ::




Custom Search