chiark / gitweb /
Padding works.
[chiark-tcl.git] / crypto / crypto.c
index 1866a6578504be8232074ecdd19d6f47322b6953..f6f12e1e70c568adeec252ee9379964834f89679 100644 (file)
@@ -11,7 +11,49 @@ void memxor(Byte *dest, const Byte *src, int l) {
   while (l--) *dest++ ^= *src++;
 }
 
+const PadMethod padmethods[]= {
+  { "un", 0, 0 },
+  { "ua", 0, 1 },
+  { "pn", 1, 0 },
+  { "pa", 1, 1 },
+  { 0 }
+};
+
 int do_hbytes_pkcs5(ClientData cd, Tcl_Interp *ip,
-                   const PadMethod *meth, int objc, Tcl_Obj *const *objv) {
-  return meth->func((void*)meth, ip, objc, objv);
+                   const PadMethod *meth, HBytes_Var v, Tcl_Obj *block,
+                   int *ok) {
+  int rc, blocksize, padlen, old_len, i;
+  Byte *padding;
+  const Byte *unpad;
+  
+  if (meth->use_algname) {
+    const BlockCipherAlgInfo *alg;
+    alg= enum_lookup_cached(ip,block,blockcipheralginfos,"cipher alg for pad");
+    if (!alg) return TCL_ERROR;
+    blocksize= alg->blocksize;
+  } else {
+    rc= Tcl_GetIntFromObj(ip, block, &blocksize);  if (rc) return rc;
+    if (blocksize < 1 || blocksize > 255)
+      return staticerr(ip, "block size out of pkcs#5 range 1..255");
+  }
+
+  if (meth->pad) {
+    padlen= blocksize - (hbytes_len(v.hb) % blocksize);
+    padding= hbytes_append(v.hb, padlen);
+    memset(padding, padlen, padlen);
+  } else {
+    old_len= hbytes_len(v.hb);  if (old_len % blocksize) goto bad;
+    unpad= hbytes_unappend(v.hb, 1);  if (!unpad) goto bad;
+    padlen= *unpad;
+    if (padlen < 1 || padlen > blocksize) goto bad;
+    unpad= hbytes_unappend(v.hb, padlen-1);  if (!unpad) goto bad;
+    for (i=0; i<padlen-1; i++, unpad++) if (*unpad != padlen) goto bad;
+  }
+
+  *ok= 1;
+  return TCL_OK;
+
+ bad:
+  *ok= 0;
+  return TCL_OK;
 }