10 void memxor(Byte *dest, const Byte *src, int l) {
11 while (l--) *dest++ ^= *src++;
14 const PadMethod padmethods[]= {
22 int do_hbytes_pkcs5(ClientData cd, Tcl_Interp *ip,
23 const PadMethod *meth, HBytes_Var v, Tcl_Obj *block,
25 int rc, blocksize, padlen, old_len, i;
29 if (meth->use_algname) {
30 const BlockCipherAlgInfo *alg;
31 alg= enum_lookup_cached(ip,block,blockcipheralginfos,"cipher alg for pad");
32 if (!alg) return TCL_ERROR;
33 blocksize= alg->blocksize;
35 rc= Tcl_GetIntFromObj(ip, block, &blocksize); if (rc) return rc;
36 if (blocksize < 1 || blocksize > 255)
37 return staticerr(ip, "block size out of pkcs#5 range 1..255");
41 padlen= blocksize - (hbytes_len(v.hb) % blocksize);
42 padding= hbytes_append(v.hb, padlen);
43 memset(padding, padlen, padlen);
45 old_len= hbytes_len(v.hb); if (old_len % blocksize) goto bad;
46 unpad= hbytes_unappend(v.hb, 1); if (!unpad) goto bad;
48 if (padlen < 1 || padlen > blocksize) goto bad;
49 unpad= hbytes_unappend(v.hb, padlen-1); if (!unpad) goto bad;
50 for (i=0; i<padlen-1; i++, unpad++) if (*unpad != padlen) goto bad;
61 #define OBJ_CIPHKEY(o) ((CiphKeyValue*)(o)->internalRep.otherValuePtr)
64 int valuelen, bufferslen;
65 Byte *value, *buffers;
66 const BlockCipherAlgInfo *alg;
67 void *encrypt, *decrypt; /* key schedules; each may be 0 */
70 static void freealg(CiphKeyValue *key) {
75 static void key_t_free(Tcl_Obj *obj) {
76 CiphKeyValue *key= OBJ_CIPHKEY(obj);
82 static void noalg(CiphKeyValue *key) {
84 key->encrypt= key->decrypt= 0;
87 static void key_t_dup(Tcl_Obj *src_obj, Tcl_Obj *dup_obj) {
88 CiphKeyValue *src= OBJ_CIPHKEY(src_obj);
89 CiphKeyValue *dup= TALLOC(sizeof(*dup));
90 dup->valuelen= src->valuelen;
91 dup->value= src->valuelen ? TALLOC(src->valuelen) : 0;
92 dup->buffers= 0; dup->bufferslen= 0;
93 memcpy(dup->value, src->value, src->valuelen);
95 dup_obj->internalRep.otherValuePtr= dup;
98 static void key_t_ustr(Tcl_Obj *o) {
99 obj_updatestr_array(o, OBJ_CIPHKEY(o)->value, OBJ_CIPHKEY(o)->valuelen);
102 static int key_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
106 rc= Tcl_ConvertToType(ip,o,&hbytes_type); if (rc) return rc;
107 val= TALLOC(sizeof(*val));
108 val->valuelen= l= hbytes_len(OBJ_HBYTES(o));
109 val->value= TALLOC(l);
112 memcpy(val->value, hbytes_data(OBJ_HBYTES(o)), l);
116 o->internalRep.otherValuePtr= val;
117 o->typePtr= &blockcipherkey_type;
122 Tcl_ObjType blockcipherkey_type = {
124 key_t_free, key_t_dup, key_t_ustr, key_t_sfa
127 int do_hbytes_blockciph(ClientData cd, Tcl_Interp *ip, int encrypt,
128 HBytes_Var v, const BlockCipherAlgInfo *alg,
129 Tcl_Obj *key_obj, const BlockCipherModeInfo *mode,
130 HBytes_Value iv, HBytes_Value *result) {
131 int rc, want_bufferslen, data_len, iv_want;
134 void *sched, **schedp;
136 rc= Tcl_ConvertToType(ip,key_obj,&blockcipherkey_type); if (rc) return rc;
137 key= OBJ_CIPHKEY(key_obj);
139 if (key->alg != alg) {
143 if (key->valuelen < alg->key_min) return staticerr(ip, "key too short");
144 if (key->valuelen > alg->key_max) return staticerr(ip, "key too long");
148 schedp= (alg->decrypt.make_schedule!=alg->encrypt.make_schedule
149 && !encrypt) ? &key->decrypt : &key->encrypt;
152 sched= TALLOC(alg->schedule_size);
153 (encrypt ? &alg->encrypt : &alg->decrypt)->make_schedule
154 (sched, key->value, key->valuelen);
158 want_bufferslen= alg->blocksize * (mode->buf_blocks + mode->iv_blocks);
159 if (key->bufferslen < want_bufferslen) {
161 key->buffers= TALLOC(want_bufferslen);
162 key->bufferslen= want_bufferslen;
165 iv_want= alg->blocksize * mode->iv_blocks;
166 if (hbytes_issentinel(&iv)) {
167 if (!encrypt) return staticerr(ip,"must supply iv when decrypting");
168 rc= get_urandom(ip, key->buffers, iv_want);
171 int iv_supplied= hbytes_len(&iv);
172 if (iv_supplied > iv_want)
173 return staticerr(ip, "iv too large for algorithm and mode");
174 memcpy(key->buffers, hbytes_data(&iv), iv_supplied);
175 memset(key->buffers + iv_supplied, 0, iv_want - iv_supplied);
178 data_len= hbytes_len(v.hb);
179 if (data_len % alg->blocksize)
180 return staticerr(ip, "block cipher input not whole number of blocks");
183 (encrypt ? mode->encrypt : mode->decrypt)
184 (hbytes_data(v.hb), data_len / alg->blocksize,
185 key->buffers, key->buffers + iv_want,
187 alg->blocksize, sched);
190 return staticerr(ip, failure);
192 hbytes_array(result, key->buffers, iv_want);