From b845521abfac164a92742f984eafb91d5d7c743d Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 2 Sep 2002 02:22:29 +0000 Subject: [PATCH] hmac seems to work --- base/chiark-tcl.h | 11 ++- base/tables-examples.tct | 22 +++--- base/troglodyte-Makefile | 4 +- crypto/algtables.c | 75 +++++++++++++++++++++ crypto/crypto.c | 140 +++++++++++++++++++++++++++++++-------- hbytes/hbytes.h | 11 ++- 6 files changed, 219 insertions(+), 44 deletions(-) create mode 100644 crypto/algtables.c diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h index c5ffc06..15abca2 100644 --- a/base/chiark-tcl.h +++ b/base/chiark-tcl.h @@ -140,13 +140,18 @@ typedef struct { Tcl_ObjType blockcipherkey_type; -/* from hash.c */ +/* from algtables.c */ typedef struct { - int blocksize, hashsize; + const char *name; + int hashsize, blocksize, statesize; + void (*init)(void *state); + void (*update)(void *state, const Byte *data, int len); + void (*final)(void *state, Byte *digest); + void (*oneshot)(Byte *digest, const Byte *data, int len); } HashAlgInfo; -/* from blockciph.c */ +extern const HashAlgInfo hashalginfos[]; typedef struct { void (*make_schedule)(void *schedule, const Byte *key, int keylen); diff --git a/base/tables-examples.tct b/base/tables-examples.tct index 922f844..5115813 100644 --- a/base/tables-examples.tct +++ b/base/tables-examples.tct @@ -50,7 +50,7 @@ Table hbytes HBytes_SubCommand v hbv block obj => int - blockciph + blockcipher encrypt charfrom("de","encrypt/decrypt") v hbv alg enum(BlockCipherAlgInfo, "alg") @@ -58,13 +58,13 @@ Table hbytes HBytes_SubCommand mode enum(BlockCipherModeInfo, "mode") ?iv hb => hb -# hash -# alg enum(HashAlgInfo, "hash alg") -# message hb -# => hb -# hmac -# alg enum(HashAlgInfo, "hash alg for hmac") -# message hb -# key hb -# maclen int -# => hb + hash + alg enum(HashAlgInfo, "hash alg") + message hb + => hb + hmac + alg enum(HashAlgInfo, "hash alg for hmac") + message hb + key obj + ?maclen obj + => hb diff --git a/base/troglodyte-Makefile b/base/troglodyte-Makefile index ce81f6b..c557d80 100644 --- a/base/troglodyte-Makefile +++ b/base/troglodyte-Makefile @@ -4,8 +4,10 @@ OBJS= tables.o \ chop.o \ hook.o \ bcmode.o \ - blockciph.o \ + algtables.o \ serpent.o \ + sha1.o \ + md5.o \ crypto.o \ parse.o diff --git a/crypto/algtables.c b/crypto/algtables.c new file mode 100644 index 0000000..87b365b --- /dev/null +++ b/crypto/algtables.c @@ -0,0 +1,75 @@ +/* + */ + +#include +#include + +#include "hbytes.h" +#include "serpent.h" +#include "sha1.h" +#include "md5.h" + +static void alg_serpent_byteswap_block(Byte *b) { + uint32_t t, *a= (void*)b; + + t= htonl(a[0]); + a[0]= htonl(a[3]); + a[3]= t; + + t= htonl(a[1]); + a[1]= htonl(a[2]); + a[2]= t; +} + +static void alg_serpent_makekey(void *schedule, const Byte *key, int keylen) { + serpent_makekey(schedule, keylen*8, key); +} + +static void alg_serpent_encrypt(const void *sch, const void *in, void *out) { + serpent_encrypt(sch, in, out); +} + +static void alg_serpent_decrypt(const void *sch, const void *in, void *out) { + serpent_decrypt(sch, in, out); +} + +const BlockCipherAlgInfo blockcipheralginfos[]= { + { "serpent", 16, sizeof(struct SerpentKeyInstance), 16,32, + alg_serpent_byteswap_block, + { alg_serpent_makekey, alg_serpent_encrypt }, + { alg_serpent_makekey, alg_serpent_decrypt } }, + { 0 } +}; + +static void alg_sha1_init(void *state) { sha1_init(state); } +static void alg_sha1_update(void *state, const Byte *data, int len) { + sha1_update(state, data, len); +} +static void alg_sha1_final(void *state, Byte *digest) { + sha1_final(state, digest); +} +static void alg_sha1_oneshot(Byte *digest, const Byte *data, int len) { + sha1(data,len,digest); +} + +static void alg_md5_init(void *state) { MD5Init(state); } +static void alg_md5_update(void *state, const Byte *data, int len) { + MD5Update(state, data, len); +} +static void alg_md5_final(void *state, Byte *digest) { + MD5Final(digest, state); +} +static void alg_md5_oneshot(Byte *digest, const Byte *data, int len) { + struct MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx,data,len); + MD5Final(digest,&ctx); +} + +const HashAlgInfo hashalginfos[]= { + { "sha1", 20, 64, sizeof(struct sha1_state), + alg_sha1_init, alg_sha1_update, alg_sha1_final, alg_sha1_oneshot }, + { "md5", 16, 64, sizeof(struct MD5Context), + alg_md5_init, alg_md5_update, alg_md5_final, alg_md5_oneshot }, + { 0 } +}; diff --git a/crypto/crypto.c b/crypto/crypto.c index 214b7fb..7cc2914 100644 --- a/crypto/crypto.c +++ b/crypto/crypto.c @@ -58,18 +58,27 @@ int do_hbytes_pkcs5(ClientData cd, Tcl_Interp *ip, return TCL_OK; } +int do_hbytes_hash(ClientData cd, Tcl_Interp *ip, const HashAlgInfo *alg, + HBytes_Value message, HBytes_Value *result) { + Byte *dest; + + dest= hbytes_arrayspace(result,alg->hashsize); + alg->oneshot(dest, hbytes_data(&message), hbytes_len(&message)); + return TCL_OK; +} + #define OBJ_CIPHKEY(o) ((CiphKeyValue*)(o)->internalRep.otherValuePtr) typedef struct { int valuelen, bufferslen; Byte *value, *buffers; - const BlockCipherAlgInfo *alg; - void *encrypt, *decrypt; /* key schedules; each may be 0 */ + const void *alg; + void *alpha, *beta; /* key schedules etc.; each may be 0 */ } CiphKeyValue; static void freealg(CiphKeyValue *key) { - TFREE(key->encrypt); - TFREE(key->decrypt); + TFREE(key->alpha); + TFREE(key->beta); } static void key_t_free(Tcl_Obj *obj) { @@ -81,7 +90,7 @@ static void key_t_free(Tcl_Obj *obj) { static void noalg(CiphKeyValue *key) { key->alg= 0; - key->encrypt= key->decrypt= 0; + key->alpha= key->beta= 0; } static void key_t_dup(Tcl_Obj *src_obj, Tcl_Obj *dup_obj) { @@ -124,43 +133,52 @@ Tcl_ObjType blockcipherkey_type = { key_t_free, key_t_dup, key_t_ustr, key_t_sfa }; -int do_hbytes_blockciph(ClientData cd, Tcl_Interp *ip, int encrypt, - HBytes_Var v, const BlockCipherAlgInfo *alg, - Tcl_Obj *key_obj, const BlockCipherModeInfo *mode, - HBytes_Value iv, HBytes_Value *result) { - int rc, want_bufferslen, data_len, iv_want; +CiphKeyValue *get_key(Tcl_Interp *ip, Tcl_Obj *key_obj, + const void *alg, int want_bufferslen) { CiphKeyValue *key; - const char *failure; - void *sched, **schedp; - - rc= Tcl_ConvertToType(ip,key_obj,&blockcipherkey_type); if (rc) return rc; + int rc; + + rc= Tcl_ConvertToType(ip,key_obj,&blockcipherkey_type); if (rc) return 0; key= OBJ_CIPHKEY(key_obj); if (key->alg != alg) { freealg(key); noalg(key); - - if (key->valuelen < alg->key_min) return staticerr(ip, "key too short"); - if (key->valuelen > alg->key_max) return staticerr(ip, "key too long"); key->alg= alg; } + + if (key->bufferslen < want_bufferslen) { + TFREE(key->buffers); + key->buffers= TALLOC(want_bufferslen); + key->bufferslen= want_bufferslen; + } + return key; +} + +int do_hbytes_blockcipher(ClientData cd, Tcl_Interp *ip, int encrypt, + HBytes_Var v, const BlockCipherAlgInfo *alg, + Tcl_Obj *key_obj, const BlockCipherModeInfo *mode, + HBytes_Value iv, HBytes_Value *result) { + int rc, want_bufferslen, data_len, iv_want; + CiphKeyValue *key; + const char *failure; + void *sched, **schedp; - schedp= (alg->decrypt.make_schedule!=alg->encrypt.make_schedule - && !encrypt) ? &key->decrypt : &key->encrypt; + want_bufferslen= alg->blocksize * (mode->buf_blocks + mode->iv_blocks); + key= get_key(ip, key_obj, alg, want_bufferslen); + + schedp= (alg->decrypt.make_schedule==alg->encrypt.make_schedule + || encrypt) ? &key->alpha : &key->beta; sched= *schedp; if (!sched) { + if (key->valuelen < alg->key_min) return staticerr(ip, "key too short"); + if (key->valuelen > alg->key_max) return staticerr(ip, "key too long"); + sched= TALLOC(alg->schedule_size); (encrypt ? &alg->encrypt : &alg->decrypt)->make_schedule (sched, key->value, key->valuelen); *schedp= sched; } - - want_bufferslen= alg->blocksize * (mode->buf_blocks + mode->iv_blocks); - if (key->bufferslen < want_bufferslen) { - TFREE(key->buffers); - key->buffers= TALLOC(want_bufferslen); - key->bufferslen= want_bufferslen; - } iv_want= alg->blocksize * mode->iv_blocks; if (hbytes_issentinel(&iv)) { @@ -193,3 +211,73 @@ int do_hbytes_blockciph(ClientData cd, Tcl_Interp *ip, int encrypt, return TCL_OK; } + +static void dbuf(const char *m, const Byte *a, int l) { + fprintf(stderr,"dbuf %s l=%d ",m,l); + while (l-->0) fprintf(stderr,"%02x",*a++); + putc('\n',stderr); +} + +int do_hbytes_hmac(ClientData cd, Tcl_Interp *ip, const HashAlgInfo *alg, + HBytes_Value message, Tcl_Obj *key_obj, + Tcl_Obj *maclen_obj, HBytes_Value *result) { + /* key->alpha = state after H(K XOR ipad + * key->beta = state after H(K XOR opad + * key->buffers = room for one block, or one state + */ + CiphKeyValue *key; + Byte *dest; + int i, ml, rc; + + if (maclen_obj) { + rc= Tcl_GetIntFromObj(ip, maclen_obj, &ml); if (rc) return rc; + if (ml<0 || ml>alg->hashsize) + return staticerr(ip, "requested hmac output size out of range"); + } else { + ml= alg->hashsize; + } + + key= get_key(ip, key_obj, alg, + alg->blocksize > alg->statesize + ? alg->blocksize : alg->statesize); + + if (!key->alpha) { + assert(!key->beta); + + if (key->valuelen > alg->blocksize) + return staticerr(ip, "key to hmac longer than hash block size"); + +dbuf("start key",key->value,key->valuelen); + memcpy(key->buffers, key->value, key->valuelen); + memset(key->buffers + key->valuelen, 0, alg->blocksize - key->valuelen); + for (i=0; iblocksize; i++) key->buffers[i] ^= 0x36; + + key->alpha= TALLOC(alg->statesize); + alg->init(key->alpha); +dbuf("inner key",key->buffers,alg->blocksize); + alg->update(key->alpha, key->buffers, alg->blocksize); + + key->beta= TALLOC(alg->statesize); + alg->init(key->beta); + for (i=0; iblocksize; i++) key->buffers[i] ^= (0x5c ^ 0x36); + alg->update(key->beta, key->buffers, alg->blocksize); +dbuf("inner key",key->buffers,alg->blocksize); + } + assert(key->beta); + + dest= hbytes_arrayspace(result, alg->hashsize); + + memcpy(key->buffers, key->alpha, alg->statesize); + alg->update(key->buffers, hbytes_data(&message), hbytes_len(&message)); + alg->final(key->buffers, dest); +dbuf("inner hash",dest,alg->hashsize); + + memcpy(key->buffers, key->beta, alg->statesize); + alg->update(key->buffers, dest, alg->hashsize); + alg->final(key->buffers, dest); +dbuf("outer hash",dest,alg->hashsize); + + hbytes_unappend(result, alg->hashsize - ml); + + return TCL_OK; +} diff --git a/hbytes/hbytes.h b/hbytes/hbytes.h index c5ffc06..15abca2 100644 --- a/hbytes/hbytes.h +++ b/hbytes/hbytes.h @@ -140,13 +140,18 @@ typedef struct { Tcl_ObjType blockcipherkey_type; -/* from hash.c */ +/* from algtables.c */ typedef struct { - int blocksize, hashsize; + const char *name; + int hashsize, blocksize, statesize; + void (*init)(void *state); + void (*update)(void *state, const Byte *data, int len); + void (*final)(void *state, Byte *digest); + void (*oneshot)(Byte *digest, const Byte *data, int len); } HashAlgInfo; -/* from blockciph.c */ +extern const HashAlgInfo hashalginfos[]; typedef struct { void (*make_schedule)(void *schedule, const Byte *key, int keylen); -- 2.30.2