From: ian Date: Mon, 2 Sep 2002 01:10:01 +0000 (+0000) Subject: Serpent seems to work. Byte order is very strange. X-Git-Tag: debian/1.1.1~169 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=commitdiff_plain;h=aa983421528c717a29c402c0cb4c8438b96fd860 Serpent seems to work. Byte order is very strange. --- diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h index cfc96e9..c5ffc06 100644 --- a/base/chiark-tcl.h +++ b/base/chiark-tcl.h @@ -15,7 +15,7 @@ * * hbytes pkcs5 pa|ua VAR ALG => worked? (always 1 for p) * hbytes pkcs5 pn|un VAR BLOCKSIZE => worked? (always 1 for p) - * hbytes blockcipher d|e VAR ALG MODE [IV] => IV + * hbytes blockcipher d|e VAR ALG KEY MODE [IV] => IV * * hbytes hash ALG MESSAGE => hash * hbytes hmac ALG MESSAGE KEY [MACLENGTH] => mac @@ -92,6 +92,8 @@ void hbytes_free(HBytes_Value *frees); int staticerr(Tcl_Interp *ip, const char *m); void objfreeir(Tcl_Obj *o); +void obj_updatestr_array(Tcl_Obj *o, const Byte *array, int l); +int get_urandom(Tcl_Interp *ip, Byte *buffer, int l); /* from parse.c */ @@ -136,6 +138,8 @@ typedef struct { int pad, use_algname; } PadMethod; +Tcl_ObjType blockcipherkey_type; + /* from hash.c */ typedef struct { diff --git a/base/hook.c b/base/hook.c index d6d96d9..68df783 100644 --- a/base/hook.c +++ b/base/hook.c @@ -1,6 +1,8 @@ /* */ +#include + #include "hbytes.h" #include "tables.h" @@ -9,6 +11,16 @@ int staticerr(Tcl_Interp *ip, const char *m) { return TCL_ERROR; } +int posixerr(Tcl_Interp *ip, int errnoval, const char *m) { + const char *em; + + Tcl_ResetResult(ip); + errno= errnoval; + em= Tcl_PosixError(ip); + Tcl_AppendResult(ip, m, ": ", em, (char*)0); + return TCL_ERROR; +} + void objfreeir(Tcl_Obj *o) { if (o->typePtr && o->typePtr->freeIntRepProc) o->typePtr->freeIntRepProc(o); @@ -16,27 +28,35 @@ void objfreeir(Tcl_Obj *o) { } int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip, - HBytes_Value v, Tcl_Obj **result) { + Tcl_Obj *obj, Tcl_Obj **result) { const char *tn; - int nums[3], i; + int nums[3], i, lnl; Tcl_Obj *objl[4]; - memset(nums,0,sizeof(nums)); - nums[1]= hbytes_len(&v); + if (obj->typePtr == &hbytes_type) { + HBytes_Value *v= OBJ_HBYTES(obj); + memset(nums,0,sizeof(nums)); + nums[1]= hbytes_len(v); - if (HBYTES_ISEMPTY(&v)) tn= "empty"; - else if (HBYTES_ISSENTINEL(&v)) tn= "sentinel!"; - else if (HBYTES_ISSIMPLE(&v)) tn= "simple"; - else { - HBytes_ComplexValue *cx= v.begin_complex; - tn= "complex"; - nums[0]= cx->prespace; - nums[2]= cx->avail - cx->len; + if (HBYTES_ISEMPTY(v)) tn= "empty"; + else if (HBYTES_ISSENTINEL(v)) tn= "sentinel!"; + else if (HBYTES_ISSIMPLE(v)) tn= "simple"; + else { + HBytes_ComplexValue *cx= v->begin_complex; + tn= "complex"; + nums[0]= cx->prespace; + nums[2]= cx->avail - cx->len; + } + lnl= 3; + } else { + tn= "other"; + lnl= 0; } objl[0]= Tcl_NewStringObj((char*)tn,-1); - for (i=0; i<3; i++) objl[i+1]= Tcl_NewIntObj(nums[i]); - *result= Tcl_NewListObj(4,objl); + for (i=0; ibytes= TALLOC(l*2+1); o->length= l*2; while (l>0) { @@ -67,6 +83,12 @@ static void hbytes_t_ustr(Tcl_Obj *o) { *str= 0; } +static void hbytes_t_ustr(Tcl_Obj *o) { + obj_updatestr_array(o, + hbytes_data(OBJ_HBYTES(o)), + hbytes_len(OBJ_HBYTES(o))); +} + static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { char *str, *ep, *os; Byte *startbytes, *bytes; @@ -131,8 +153,34 @@ int do__hbytes(ClientData cd, Tcl_Interp *ip, return subcmd->func(0,ip,objc,objv); } +#define URANDOM "/dev/urandom" + +int get_urandom(Tcl_Interp *ip, Byte *buffer, int l) { + static FILE *urandom; + + int r, esave; + + if (!urandom) { + urandom= fopen(URANDOM,"rb"); + if (!urandom) return posixerr(ip,errno,"open " URANDOM); + } + r= fread(buffer,1,l,urandom); + if (r==l) return 0; + + esave= errno; + fclose(urandom); urandom=0; + + if (ferror(urandom)) { + return posixerr(ip,errno,"read " URANDOM); + } else { + assert(feof(urandom)); + return staticerr(ip, URANDOM " gave eof!"); + } +} + int Hbytes_Init(Tcl_Interp *ip) { Tcl_RegisterObjType(&hbytes_type); + Tcl_RegisterObjType(&blockcipherkey_type); Tcl_RegisterObjType(&enum_nearlytype); Tcl_RegisterObjType(&enum1_nearlytype); Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,0,0); diff --git a/base/tables-examples.tct b/base/tables-examples.tct index d743530..922f844 100644 --- a/base/tables-examples.tct +++ b/base/tables-examples.tct @@ -28,7 +28,7 @@ Table hbytes HBytes_SubCommand v hbv str ... rep-info - v hb + v obj => obj concat str ... @@ -50,13 +50,14 @@ Table hbytes HBytes_SubCommand v hbv block obj => int -# blockcipher -# encrypt charfrom("de","encrypt/decrypt") -# v hbv -# alg enum(BlockCipherAlgInfo, "alg") -# mode enum(BlockCipherModeInfo, "mode") -# ?iv hb -# => hb + blockciph + encrypt charfrom("de","encrypt/decrypt") + v hbv + alg enum(BlockCipherAlgInfo, "alg") + key obj + mode enum(BlockCipherModeInfo, "mode") + ?iv hb + => hb # hash # alg enum(HashAlgInfo, "hash alg") # message hb diff --git a/base/troglodyte-Makefile b/base/troglodyte-Makefile index 8e94090..ce81f6b 100644 --- a/base/troglodyte-Makefile +++ b/base/troglodyte-Makefile @@ -18,7 +18,8 @@ AUTOS= $(AUTO_HDRS) $(AUTO_SRCS) TARGETS= hbytes.so -CFLAGS= -g -Wall -O +CFLAGS= -g -Wall $(OPTIMISE) +OPTIMISE= -O2 all: $(TARGETS) $(AUTOS) diff --git a/crypto/bcmode.c b/crypto/bcmode.c index 7d5a5d4..a40aff0 100644 --- a/crypto/bcmode.c +++ b/crypto/bcmode.c @@ -46,7 +46,21 @@ const char *mode_cbc_decrypt(Byte *data, int blocks, return 0; } +const char *mode_ecb(Byte *data, int blocks, + const Byte *iv, Byte *chain, + const BlockCipherAlgInfo *alg, int encr, + int blocksize, const void *sch) { + while (blocks > 0) { + alg->byteswap(data); + (encr ? &alg->encrypt : &alg->decrypt)->crypt(sch, data, data); + alg->byteswap(data); + blocks--; data += blocksize; + } + return 0; +} + const BlockCipherModeInfo blockciphermodeinfos[]= { { "cbc", 1, 2, mode_cbc_encrypt, mode_cbc_decrypt }, + { "ecb", 0, 0, mode_ecb, mode_ecb }, { 0 } }; diff --git a/crypto/crypto.c b/crypto/crypto.c index f6f12e1..214b7fb 100644 --- a/crypto/crypto.c +++ b/crypto/crypto.c @@ -57,3 +57,139 @@ int do_hbytes_pkcs5(ClientData cd, Tcl_Interp *ip, *ok= 0; 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 */ +} CiphKeyValue; + +static void freealg(CiphKeyValue *key) { + TFREE(key->encrypt); + TFREE(key->decrypt); +} + +static void key_t_free(Tcl_Obj *obj) { + CiphKeyValue *key= OBJ_CIPHKEY(obj); + freealg(key); + TFREE(key->value); + TFREE(key->buffers); +} + +static void noalg(CiphKeyValue *key) { + key->alg= 0; + key->encrypt= key->decrypt= 0; +} + +static void key_t_dup(Tcl_Obj *src_obj, Tcl_Obj *dup_obj) { + CiphKeyValue *src= OBJ_CIPHKEY(src_obj); + CiphKeyValue *dup= TALLOC(sizeof(*dup)); + dup->valuelen= src->valuelen; + dup->value= src->valuelen ? TALLOC(src->valuelen) : 0; + dup->buffers= 0; dup->bufferslen= 0; + memcpy(dup->value, src->value, src->valuelen); + noalg(dup); + dup_obj->internalRep.otherValuePtr= dup; +} + +static void key_t_ustr(Tcl_Obj *o) { + obj_updatestr_array(o, OBJ_CIPHKEY(o)->value, OBJ_CIPHKEY(o)->valuelen); +} + +static int key_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { + int rc, l; + CiphKeyValue *val; + + rc= Tcl_ConvertToType(ip,o,&hbytes_type); if (rc) return rc; + val= TALLOC(sizeof(*val)); + val->valuelen= l= hbytes_len(OBJ_HBYTES(o)); + val->value= TALLOC(l); + val->buffers= 0; + val->bufferslen= 0; + memcpy(val->value, hbytes_data(OBJ_HBYTES(o)), l); + noalg(val); + + objfreeir(o); + o->internalRep.otherValuePtr= val; + o->typePtr= &blockcipherkey_type; + + return TCL_OK; +} + +Tcl_ObjType blockcipherkey_type = { + "blockcipher-key", + 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 *key; + const char *failure; + void *sched, **schedp; + + rc= Tcl_ConvertToType(ip,key_obj,&blockcipherkey_type); if (rc) return rc; + 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; + } + + schedp= (alg->decrypt.make_schedule!=alg->encrypt.make_schedule + && !encrypt) ? &key->decrypt : &key->encrypt; + sched= *schedp; + if (!sched) { + 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)) { + if (!encrypt) return staticerr(ip,"must supply iv when decrypting"); + rc= get_urandom(ip, key->buffers, iv_want); + if (rc) return rc; + } else { + int iv_supplied= hbytes_len(&iv); + if (iv_supplied > iv_want) + 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); + } + + data_len= hbytes_len(v.hb); + if (data_len % alg->blocksize) + return staticerr(ip, "block cipher input not whole number of blocks"); + + 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); + + if (failure) + return staticerr(ip, failure); + + hbytes_array(result, key->buffers, iv_want); + + return TCL_OK; +} diff --git a/hbytes/hbytes.c b/hbytes/hbytes.c index 5f06d71..41fc12a 100644 --- a/hbytes/hbytes.c +++ b/hbytes/hbytes.c @@ -25,7 +25,7 @@ Byte *hbytes_data(const HBytes_Value *hb) { } int hbytes_issentinel(const HBytes_Value *hb) { - return HBYTES_ISCOMPLEX(hb); + return HBYTES_ISSENTINEL(hb); } /* constructors */ diff --git a/hbytes/hbytes.h b/hbytes/hbytes.h index cfc96e9..c5ffc06 100644 --- a/hbytes/hbytes.h +++ b/hbytes/hbytes.h @@ -15,7 +15,7 @@ * * hbytes pkcs5 pa|ua VAR ALG => worked? (always 1 for p) * hbytes pkcs5 pn|un VAR BLOCKSIZE => worked? (always 1 for p) - * hbytes blockcipher d|e VAR ALG MODE [IV] => IV + * hbytes blockcipher d|e VAR ALG KEY MODE [IV] => IV * * hbytes hash ALG MESSAGE => hash * hbytes hmac ALG MESSAGE KEY [MACLENGTH] => mac @@ -92,6 +92,8 @@ void hbytes_free(HBytes_Value *frees); int staticerr(Tcl_Interp *ip, const char *m); void objfreeir(Tcl_Obj *o); +void obj_updatestr_array(Tcl_Obj *o, const Byte *array, int l); +int get_urandom(Tcl_Interp *ip, Byte *buffer, int l); /* from parse.c */ @@ -136,6 +138,8 @@ typedef struct { int pad, use_algname; } PadMethod; +Tcl_ObjType blockcipherkey_type; + /* from hash.c */ typedef struct { diff --git a/hbytes/hook.c b/hbytes/hook.c index d6d96d9..68df783 100644 --- a/hbytes/hook.c +++ b/hbytes/hook.c @@ -1,6 +1,8 @@ /* */ +#include + #include "hbytes.h" #include "tables.h" @@ -9,6 +11,16 @@ int staticerr(Tcl_Interp *ip, const char *m) { return TCL_ERROR; } +int posixerr(Tcl_Interp *ip, int errnoval, const char *m) { + const char *em; + + Tcl_ResetResult(ip); + errno= errnoval; + em= Tcl_PosixError(ip); + Tcl_AppendResult(ip, m, ": ", em, (char*)0); + return TCL_ERROR; +} + void objfreeir(Tcl_Obj *o) { if (o->typePtr && o->typePtr->freeIntRepProc) o->typePtr->freeIntRepProc(o); @@ -16,27 +28,35 @@ void objfreeir(Tcl_Obj *o) { } int do_hbytes_rep_info(ClientData cd, Tcl_Interp *ip, - HBytes_Value v, Tcl_Obj **result) { + Tcl_Obj *obj, Tcl_Obj **result) { const char *tn; - int nums[3], i; + int nums[3], i, lnl; Tcl_Obj *objl[4]; - memset(nums,0,sizeof(nums)); - nums[1]= hbytes_len(&v); + if (obj->typePtr == &hbytes_type) { + HBytes_Value *v= OBJ_HBYTES(obj); + memset(nums,0,sizeof(nums)); + nums[1]= hbytes_len(v); - if (HBYTES_ISEMPTY(&v)) tn= "empty"; - else if (HBYTES_ISSENTINEL(&v)) tn= "sentinel!"; - else if (HBYTES_ISSIMPLE(&v)) tn= "simple"; - else { - HBytes_ComplexValue *cx= v.begin_complex; - tn= "complex"; - nums[0]= cx->prespace; - nums[2]= cx->avail - cx->len; + if (HBYTES_ISEMPTY(v)) tn= "empty"; + else if (HBYTES_ISSENTINEL(v)) tn= "sentinel!"; + else if (HBYTES_ISSIMPLE(v)) tn= "simple"; + else { + HBytes_ComplexValue *cx= v->begin_complex; + tn= "complex"; + nums[0]= cx->prespace; + nums[2]= cx->avail - cx->len; + } + lnl= 3; + } else { + tn= "other"; + lnl= 0; } objl[0]= Tcl_NewStringObj((char*)tn,-1); - for (i=0; i<3; i++) objl[i+1]= Tcl_NewIntObj(nums[i]); - *result= Tcl_NewListObj(4,objl); + for (i=0; ibytes= TALLOC(l*2+1); o->length= l*2; while (l>0) { @@ -67,6 +83,12 @@ static void hbytes_t_ustr(Tcl_Obj *o) { *str= 0; } +static void hbytes_t_ustr(Tcl_Obj *o) { + obj_updatestr_array(o, + hbytes_data(OBJ_HBYTES(o)), + hbytes_len(OBJ_HBYTES(o))); +} + static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { char *str, *ep, *os; Byte *startbytes, *bytes; @@ -131,8 +153,34 @@ int do__hbytes(ClientData cd, Tcl_Interp *ip, return subcmd->func(0,ip,objc,objv); } +#define URANDOM "/dev/urandom" + +int get_urandom(Tcl_Interp *ip, Byte *buffer, int l) { + static FILE *urandom; + + int r, esave; + + if (!urandom) { + urandom= fopen(URANDOM,"rb"); + if (!urandom) return posixerr(ip,errno,"open " URANDOM); + } + r= fread(buffer,1,l,urandom); + if (r==l) return 0; + + esave= errno; + fclose(urandom); urandom=0; + + if (ferror(urandom)) { + return posixerr(ip,errno,"read " URANDOM); + } else { + assert(feof(urandom)); + return staticerr(ip, URANDOM " gave eof!"); + } +} + int Hbytes_Init(Tcl_Interp *ip) { Tcl_RegisterObjType(&hbytes_type); + Tcl_RegisterObjType(&blockcipherkey_type); Tcl_RegisterObjType(&enum_nearlytype); Tcl_RegisterObjType(&enum1_nearlytype); Tcl_CreateObjCommand(ip,"hbytes", pa__hbytes,0,0);