/* This file is in the public domain. */ #include #include #include #include #include #include "algs.h" #include "panic.h" #include "algs-list.h" typedef struct hmac_state HMAC_STATE; struct hmac_state { int len; HASHALG *alg; void *k_xor_opad; void *k_xor_ipad; } ; static void *init_xor_block(HASHALG *alg, const void *key, int keylen, unsigned char xorv) { unsigned char kblk[64]; int i; void *h; if (keylen > 64) panic("key too long"); bcopy(key,&kblk[0],keylen); if (keylen < 64) bzero(&kblk[keylen],64-keylen); for (i=0;i<64;i++) kblk[i] ^= xorv; h = (*alg->init)(); (*alg->process)(h,&kblk[0],64); return(h); } static void mac_va(HMAC_STATE *s, int nb, va_list ap, void *into) { void *h; const void *buf; int len; unsigned char first[s->alg->hashlen]; h = (*s->alg->clone)(s->k_xor_ipad); for (;nb>0;nb--) { buf = va_arg(ap,const void *); len = va_arg(ap,int); (*s->alg->process)(h,buf,len); } (*s->alg->done)(h,&first[0]); h = (*s->alg->clone)(s->k_xor_opad); (*s->alg->process)(h,&first[0],s->alg->hashlen); (*s->alg->done)(h,into); } static void *hmac_init(const void *key, HASHALG *alg, int len) { HMAC_STATE *s; s = malloc(sizeof(HMAC_STATE)); if (! s) return(0); s->len = len; s->alg = alg; s->k_xor_opad = init_xor_block(alg,key,alg->hashlen,0x5c); s->k_xor_ipad = init_xor_block(alg,key,alg->hashlen,0x36); return(s); } static void *mac_hmac_init_sha1_160(const void *key) { return(hmac_init(key,&hashalg_sha1,20)); } static void *mac_hmac_init_sha1_96(const void *key) { return(hmac_init(key,&hashalg_sha1,12)); } static void *mac_hmac_init_md5_128(const void *key) { return(hmac_init(key,&hashalg_md5,16)); } static void *mac_hmac_init_md5_96(const void *key) { return(hmac_init(key,&hashalg_md5,12)); } static int mac_hmac_check(void *state, const void *vs, int nblk, ...) #define s ((HMAC_STATE *)state) { va_list ap; char tmp[20]; va_start(ap,nblk); mac_va(state,nblk,ap,&tmp[0]); va_end(ap); return(!bcmp(&tmp[0],vs,s->len)); } #undef s static void mac_hmac_gen(void *state, void *into, int nblk, ...) #define s ((HMAC_STATE *)state) { va_list ap; va_start(ap,nblk); if (s->len == s->alg->hashlen) { mac_va(state,nblk,ap,into); } else { unsigned char res[s->alg->hashlen]; mac_va(state,nblk,ap,&res[0]); bcopy(&res[0],into,s->len); } va_end(ap); } #undef s static void mac_hmac_done(void *state) { HMAC_STATE *s; s = state; (*s->alg->drop)(s->k_xor_opad); (*s->alg->drop)(s->k_xor_ipad); free(s); } MACALG macalg_hmac_sha1_160 = { "hmac-sha1", 0, 20, 20, 0, &mac_hmac_init_sha1_160, &mac_hmac_check, &mac_hmac_gen, &mac_hmac_done }; MACALG macalg_hmac_sha1_96 = { "hmac-sha1-96", 0, 12, 20, 0, &mac_hmac_init_sha1_96, &mac_hmac_check, &mac_hmac_gen, &mac_hmac_done }; MACALG macalg_hmac_md5_128 = { "hmac-md5", 0, 16, 16, 0, &mac_hmac_init_md5_128, &mac_hmac_check, &mac_hmac_gen, &mac_hmac_done }; MACALG macalg_hmac_md5_96 = { "hmac-md5-96", 0, 12, 16, 0, &mac_hmac_init_md5_96, &mac_hmac_check, &mac_hmac_gen, &mac_hmac_done };