X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=crypto%2Fcrypto.c;h=457dc9e37f242178a55b13acea3732199b7d8546;hb=5d466de467f28ae6f7125bef086d141a7734a4ce;hp=7cc2914c65908d6b681617d0989d36c2bc54ba82;hpb=b845521abfac164a92742f984eafb91d5d7c743d;p=chiark-tcl.git diff --git a/crypto/crypto.c b/crypto/crypto.c index 7cc2914..457dc9e 100644 --- a/crypto/crypto.c +++ b/crypto/crypto.c @@ -102,6 +102,7 @@ static void key_t_dup(Tcl_Obj *src_obj, Tcl_Obj *dup_obj) { memcpy(dup->value, src->value, src->valuelen); noalg(dup); dup_obj->internalRep.otherValuePtr= dup; + dup_obj->typePtr= &blockcipherkey_type; } static void key_t_ustr(Tcl_Obj *o) { @@ -133,8 +134,8 @@ Tcl_ObjType blockcipherkey_type = { key_t_free, key_t_dup, key_t_ustr, key_t_sfa }; -CiphKeyValue *get_key(Tcl_Interp *ip, Tcl_Obj *key_obj, - const void *alg, int want_bufferslen) { +static CiphKeyValue *get_key(Tcl_Interp *ip, Tcl_Obj *key_obj, + const void *alg, int want_bufferslen) { CiphKeyValue *key; int rc; @@ -155,59 +156,141 @@ CiphKeyValue *get_key(Tcl_Interp *ip, Tcl_Obj *key_obj, 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; +int do_hbytes_blockcipher(ClientData cd, Tcl_Interp *ip, + const BlockCipherOp *op, + int objc, Tcl_Obj *const *objv) { + return op->func((void*)op,ip,objc,objv); +} + +static int blockcipher_prep(Tcl_Interp *ip, Tcl_Obj *key_obj, + const HBytes_Value *iv, int decrypt, + const BlockCipherAlgInfo *alg, + const BlockCipherModeInfo *mode, int data_len, + const CiphKeyValue **key_r, const void **sched_r, + const Byte **iv_r, int *iv_lenbytes_r, + Byte **buffers_r, int *nblocks_r) { void *sched, **schedp; + int want_bufferslen, want_iv; + int rc; + CiphKeyValue *key; + + if (data_len % alg->blocksize) + return staticerr(ip, "block cipher input not whole number of blocks"); want_bufferslen= alg->blocksize * (mode->buf_blocks + mode->iv_blocks); - key= get_key(ip, key_obj, alg, want_bufferslen); + key= get_key(ip, key_obj, alg, want_bufferslen); if (!key) return TCL_ERROR; schedp= (alg->decrypt.make_schedule==alg->encrypt.make_schedule - || encrypt) ? &key->alpha : &key->beta; + || !decrypt) ? &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 + (decrypt ? &alg->decrypt : &alg->encrypt)->make_schedule (sched, key->value, key->valuelen); *schedp= sched; } - iv_want= alg->blocksize * mode->iv_blocks; - if (hbytes_issentinel(&iv)) { - if (!encrypt) return staticerr(ip,"must supply iv when decrypting"); - rc= get_urandom(ip, key->buffers, iv_want); + want_iv= alg->blocksize * mode->iv_blocks; + if (!want_iv) { + if (!hbytes_issentinel(iv)) + return staticerr(ip,"iv supplied but mode does not take one"); + } else if (hbytes_issentinel(iv)) { + if (decrypt) return staticerr(ip,"must supply iv when decrypting"); + rc= get_urandom(ip, key->buffers, want_iv); if (rc) return rc; } else { - int iv_supplied= hbytes_len(&iv); - if (iv_supplied > iv_want) + int iv_supplied= hbytes_len(iv); + if (iv_supplied > want_iv) return staticerr(ip, "iv too large for algorithm and mode"); - memcpy(key->buffers, hbytes_data(&iv), iv_supplied); - memset(key->buffers + iv_supplied, 0, iv_want - iv_supplied); + memcpy(key->buffers, hbytes_data(iv), iv_supplied); + memset(key->buffers + iv_supplied, 0, want_iv - iv_supplied); } - data_len= hbytes_len(v.hb); - if (data_len % alg->blocksize) - return staticerr(ip, "block cipher input not whole number of blocks"); + *key_r= key; + *sched_r= sched; + + *iv_r= key->buffers; + *iv_lenbytes_r= want_iv; + + *buffers_r= key->buffers + want_iv; + *nblocks_r= data_len / alg->blocksize; + + return TCL_OK; +} + +int do_blockcipherop_d(ClientData cd, Tcl_Interp *ip, + HBytes_Var v, const BlockCipherAlgInfo *alg, + Tcl_Obj *key_obj, const BlockCipherModeInfo *mode, + HBytes_Value iv, HBytes_Value *result) { + return do_blockcipherop_e(cd,ip,v,alg,key_obj,mode,iv,result); +} +int do_blockcipherop_e(ClientData cd, Tcl_Interp *ip, + HBytes_Var v, const BlockCipherAlgInfo *alg, + Tcl_Obj *key_obj, const BlockCipherModeInfo *mode, + HBytes_Value iv, HBytes_Value *result) { + const BlockCipherOp *op= (const void*)cd; + int encrypt= op->encrypt; + int rc, iv_lenbytes; + const CiphKeyValue *key; + const char *failure; + const Byte *ivbuf; + Byte *buffers; + const void *sched; + int nblocks; + + if (!mode->encrypt) + return staticerr(ip, "mode does not support encrypt/decrypt"); + + rc= blockcipher_prep(ip,key_obj,&iv,!encrypt, + alg,mode, hbytes_len(v.hb), + &key,&sched, + &ivbuf,&iv_lenbytes, + &buffers,&nblocks); + if (rc) return rc; + failure= (encrypt ? mode->encrypt : mode->decrypt) - (hbytes_data(v.hb), data_len / alg->blocksize, - key->buffers, key->buffers + iv_want, - alg, encrypt, - alg->blocksize, sched); + (hbytes_data(v.hb), nblocks, ivbuf, buffers, alg, encrypt, sched); if (failure) return staticerr(ip, failure); - hbytes_array(result, key->buffers, iv_want); + hbytes_array(result, ivbuf, iv_lenbytes); + + return TCL_OK; +} + +int do_blockcipherop_mac(ClientData cd, Tcl_Interp *ip, + HBytes_Value msg, const BlockCipherAlgInfo *alg, + Tcl_Obj *key_obj, const BlockCipherModeInfo *mode, + HBytes_Value iv, HBytes_Value *result) { + const CiphKeyValue *key; + const char *failure; + const Byte *ivbuf; + Byte *buffers; + const void *sched; + int nblocks, iv_lenbytes; + int rc; + + if (!mode->mac) + return staticerr(ip, "mode does not support mac generation"); + + rc= blockcipher_prep(ip,key_obj,&iv,0, + alg,mode, hbytes_len(&msg), + &key,&sched, + &ivbuf,&iv_lenbytes, + &buffers,&nblocks); + if (rc) return rc; + + failure= mode->mac(hbytes_data(&msg), nblocks, ivbuf, buffers, alg, sched); + if (failure) + return staticerr(ip,failure); + + hbytes_array(result, buffers, alg->blocksize * mode->mac_blocks); return TCL_OK; }