diff --git a/src/modules/_Crypto/crypto.c b/src/modules/_Crypto/crypto.c
index 726c19e37f14b4302d8a017e80f7af5ffa0ccd47..0d3efe96d48e1661c3bc7217736fd1bf57e35f00 100644
--- a/src/modules/_Crypto/crypto.c
+++ b/src/modules/_Crypto/crypto.c
@@ -1,5 +1,5 @@
 /*
- * $Id: crypto.c,v 1.6 1996/11/08 22:59:24 grubba Exp $
+ * $Id: crypto.c,v 1.7 1996/11/11 14:23:22 grubba Exp $
  *
  * A pike module for getting access to some common cryptos.
  *
@@ -42,9 +42,9 @@
 static const char *crypto_functions[] = {
   "query_block_size",
   "query_key_length",
-  "set_key",
-  "encrypt",
-  "decrypt",
+  "set_encrypt_key",
+  "set_decrypt_key",
+  "crypt_block",
   NULL
 };
 
@@ -64,13 +64,9 @@ static void exit_pike_crypto(struct object *o)
   if (PIKE_CRYPTO->object) {
     free_object(PIKE_CRYPTO->object);
   }
-  if (PIKE_CRYPTO->iv) {
-    MEMSET(PIKE_CRYPTO->iv, 0, PIKE_CRYPTO->block_size);
-    free(PIKE_CRYPTO->iv);
-  }
-  if (PIKE_CRYPTO->overflow) {
-    MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
-    free(PIKE_CRYPTO->overflow);
+  if (PIKE_CRYPTO->backlog) {
+    MEMSET(PIKE_CRYPTO->backlog, 0, PIKE_CRYPTO->block_size);
+    free(PIKE_CRYPTO->backlog);
   }
   memset(PIKE_CRYPTO, 0, sizeof(struct pike_crypto));
 }
@@ -97,50 +93,9 @@ static void check_functions(struct object *o, const char **requiered)
   }
 }
 
-INLINE static void cbc_encrypt_step(const unsigned char *source,
-				    unsigned char *dest)
+void assert_is_crypto_module(struct object *o)
 {
-  INT32 block_size = PIKE_CRYPTO->block_size;
-  INT32 i;
-  
-  for (i=0; i < block_size; i++) {
-    PIKE_CRYPTO->iv[i] ^= source[i];
-  }
-  push_string(make_shared_binary_string((char *)PIKE_CRYPTO->iv, block_size));
-  safe_apply(PIKE_CRYPTO->object, "encrypt", 1);
-  if (sp[-1].type != T_STRING) {
-    error("crypto->cbc_encrypt(): Expected string from encrypt()\n");
-  }
-  if (sp[-1].u.string->len != block_size) {
-    error("crypto->cbc_encrypt(): Bad string length %d returned from encrypt()\n",
-	  sp[-1].u.string->len);
-  }
-  MEMCPY(PIKE_CRYPTO->iv, sp[-1].u.string->str, block_size);
-  MEMCPY(dest, sp[-1].u.string->str, block_size);
-  pop_stack();
-}
-
-INLINE static void cbc_decrypt_step(const unsigned char *source,
-				    unsigned char *dest)
-{
-  INT32 block_size = PIKE_CRYPTO->block_size;
-  INT32 i;
-  
-  push_string(make_shared_binary_string((const char *)source, block_size));
-
-  safe_apply(PIKE_CRYPTO->object, "decrypt", 1);
-  if (sp[-1].type != T_STRING) {
-    error("crypto->cbc_decrypt(): Expected string from decrypt()\n");
-  }
-  if (sp[-1].u.string->len != block_size) {
-    error("crypto->cbc_decrypt(): Bad string length %d returned from decrypt()\n",
-	  sp[-1].u.string->len);
-  }
-  for (i=0; i < block_size; i++) {
-    dest[i] = PIKE_CRYPTO->iv[i] ^ sp[-1].u.string->str[i];
-  }
-  pop_stack();
-  MEMCPY(PIKE_CRYPTO->iv, source, block_size);
+  check_functions(o, crypto_functions);
 }
 
 /*
@@ -268,11 +223,9 @@ static void f_create(INT32 args)
     error("crypto->create(): Bad block size %d\n", PIKE_CRYPTO->block_size);
   }
 
-  PIKE_CRYPTO->iv = (unsigned char *)xalloc(PIKE_CRYPTO->block_size);
-  PIKE_CRYPTO->overflow = (unsigned char *)xalloc(PIKE_CRYPTO->block_size);
-  PIKE_CRYPTO->overflow_len = 0;
-  MEMSET(PIKE_CRYPTO->iv, 0, PIKE_CRYPTO->block_size);
-  MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
+  PIKE_CRYPTO->backlog = (unsigned char *)xalloc(PIKE_CRYPTO->block_size);
+  PIKE_CRYPTO->backlog_len = 0;
+  MEMSET(PIKE_CRYPTO->backlog, 0, PIKE_CRYPTO->block_size);
 }
 
 /* int query_block_size(void) */
@@ -288,304 +241,167 @@ static void f_query_key_length(INT32 args)
   safe_apply(PIKE_CRYPTO->object, "query_key_length", args);
 }
 
-/* void set_key(INT32 args) */
-static void f_set_key(INT32 args)
+/* void set_encrypt_key(INT32 args) */
+static void f_set_encrypt_key(INT32 args)
 {
   if (PIKE_CRYPTO->block_size) {
-    MEMSET(PIKE_CRYPTO->iv, 0, PIKE_CRYPTO->block_size);
-    MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
+    MEMSET(PIKE_CRYPTO->backlog, 0, PIKE_CRYPTO->block_size);
+    PIKE_CRYPTO->backlog_len = 0;
   } else {
-    error("crypto->set_key(): Object has not been created yet\n");
+    error("crypto->set_encrypt_key(): Object has not been created yet\n");
   }
-  safe_apply(PIKE_CRYPTO->object, "set_key", args);
-}
-
-/* string encrypt(string) */
-static void f_encrypt(INT32 args)
-{
-  safe_apply(PIKE_CRYPTO->object, "encrypt", args);
+  safe_apply(PIKE_CRYPTO->object, "set_encrypt_key", args);
 }
 
-/* string decrypt(string) */
-static void f_decrypt(INT32 args)
+/* void set_decrypt_key(INT32 args) */
+static void f_set_decrypt_key(INT32 args)
 {
-  safe_apply(PIKE_CRYPTO->object, "decrypt", args);
+  if (PIKE_CRYPTO->block_size) {
+    MEMSET(PIKE_CRYPTO->backlog, 0, PIKE_CRYPTO->block_size);
+    PIKE_CRYPTO->backlog_len = 0;
+  } else {
+    error("crypto->set_decrypt_key(): Object has not been created yet\n");
+  }
+  safe_apply(PIKE_CRYPTO->object, "set_decrypt_key", args);
 }
 
-/* string ecb_encrypt(string) */
-static void f_ecb_encrypt(INT32 args)
+/* string crypt(string) */
+static void f_crypt(INT32 args)
 {
   unsigned char *result;
   INT32 roffset = 0;
   INT32 soffset = 0;
+  INT32 len;
 
   if (args != 1) {
-    error("Wrong number of arguments to crypto->ecb_encrypt()\n");
+    error("Wrong number of arguments to crypto->crypt()\n");
   }
   if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to crypto->ecb_encrypt()\n");
+    error("Bad argument 1 to crypto->crypt()\n");
   }
   if (!(result = alloca(sp[-1].u.string->len + PIKE_CRYPTO->block_size))) {
-    error("crypto->ecb_encrypt(): Out of memory\n");
+    error("crypto->crypt(): Out of memory\n");
   }
-  if (PIKE_CRYPTO->overflow_len) {
+  if (PIKE_CRYPTO->backlog_len) {
     if (sp[-1].u.string->len >=
-	(PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len)) {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
+	(PIKE_CRYPTO->block_size - PIKE_CRYPTO->backlog_len)) {
+      MEMCPY(PIKE_CRYPTO->backlog + PIKE_CRYPTO->backlog_len,
 	     sp[-1].u.string->str,
-	     (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len));
-      soffset += (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len);
-      PIKE_CRYPTO->overflow_len = 0;
-      push_string(make_shared_binary_string((char *)PIKE_CRYPTO->overflow,
+	     (PIKE_CRYPTO->block_size - PIKE_CRYPTO->backlog_len));
+      soffset += (PIKE_CRYPTO->block_size - PIKE_CRYPTO->backlog_len);
+      PIKE_CRYPTO->backlog_len = 0;
+      push_string(make_shared_binary_string((char *)PIKE_CRYPTO->backlog,
 					    PIKE_CRYPTO->block_size));
-      safe_apply(PIKE_CRYPTO->object, "encrypt", 1);
+      safe_apply(PIKE_CRYPTO->object, "crypt_block", 1);
       if (sp[-1].type != T_STRING) {
-	error("crypto->ecb_encrypt(): encrypt() did not return string\n");
+	error("crypto->crypt(): crypt_block() did not return string\n");
       }
       if (sp[-1].u.string->len != PIKE_CRYPTO->block_size) {
-	error("crypto->ecb_encrypt(): Unexpected string length %d\n",
+	error("crypto->crypt(): Unexpected string length %d\n",
 	      sp[-1].u.string->len);
       }
 	
       MEMCPY(result, sp[-1].u.string->str, PIKE_CRYPTO->block_size);
       roffset = PIKE_CRYPTO->block_size;
       pop_stack();
-      MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
+      MEMSET(PIKE_CRYPTO->backlog, 0, PIKE_CRYPTO->block_size);
     } else {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
+      MEMCPY(PIKE_CRYPTO->backlog + PIKE_CRYPTO->backlog_len,
 	     sp[-1].u.string->str, sp[-1].u.string->len);
-      PIKE_CRYPTO->overflow_len += sp[-1].u.string->len;
+      PIKE_CRYPTO->backlog_len += sp[-1].u.string->len;
       pop_n_elems(args);
       push_string(make_shared_binary_string("", 0));
       return;
     }
   }
   
-  while (soffset + PIKE_CRYPTO->block_size <= sp[-1].u.string->len) {
-    push_string(make_shared_binary_string(sp[-1].u.string->str + soffset,
-					  PIKE_CRYPTO->block_size));
-    soffset += PIKE_CRYPTO->block_size;
-    safe_apply(PIKE_CRYPTO->object, "encrypt", 1);
-    if (sp[-1].type != T_STRING) {
-      error("crypto->ecb_encrypt(): encrypt() did not return string\n");
-    }
-    if (sp[-1].u.string->len != PIKE_CRYPTO->block_size) {
-      error("crypto->ecb_encrypt(): Unexpected string length %d\n",
-	    sp[-1].u.string->len);
-    }
-	
-    MEMCPY(result + roffset, sp[-1].u.string->str, PIKE_CRYPTO->block_size);
-    roffset += PIKE_CRYPTO->block_size;
-    pop_stack();
-  }
-
-  if (soffset < sp[-1].u.string->len) {
-    MEMCPY(PIKE_CRYPTO->overflow, sp[-1].u.string->str + soffset,
-	   sp[-1].u.string->len - soffset);
-    PIKE_CRYPTO->overflow_len = sp[-1].u.string->len - soffset;
-  }
-
-  pop_n_elems(args);
+  len = (sp[-1].u.string->len - soffset);
+  len -= len % PIKE_CRYPTO->block_size;
 
-  push_string(make_shared_binary_string((char *)result, roffset));
-  MEMSET(result, 0, roffset);
-}
+  if (len) {
+    push_string(make_shared_binary_string(sp[-1].u.string->str + soffset, len));
+    soffset += len;
 
-/* string ecb_decrypt(string) */
-static void f_ecb_decrypt(INT32 args)
-{
-  unsigned char *result;
-  INT32 roffset = 0;
-  INT32 soffset = 0;
+    safe_apply(PIKE_CRYPTO->object, "crypt_block", 1);
 
-  if (args != 1) {
-    error("Wrong number of arguments to crypto->ecb_decrypt()\n");
-  }
-  if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to crypto->ecb_decrypt()\n");
-  }
-  if (!(result = alloca(sp[-1].u.string->len + PIKE_CRYPTO->block_size))) {
-    error("crypto->ecb_decrypt(): Out of memory\n");
-  }
-  if (PIKE_CRYPTO->overflow_len) {
-    if (sp[-1].u.string->len >=
-	(PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len)) {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
-	     sp[-1].u.string->str,
-	     (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len));
-      soffset += (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len);
-      PIKE_CRYPTO->overflow_len = 0;
-      push_string(make_shared_binary_string((char *)PIKE_CRYPTO->overflow,
-					    PIKE_CRYPTO->block_size));
-      safe_apply(PIKE_CRYPTO->object, "decrypt", 1);
-      if (sp[-1].type != T_STRING) {
-	error("crypto->ecb_decrypt(): decrypt() did not return string\n");
-      }
-      if (sp[-1].u.string->len != PIKE_CRYPTO->block_size) {
-	error("crypto->ecb_decrypt(): Unexpected string length %d\n",
-	      sp[-1].u.string->len);
-      }
-	
-      MEMCPY(result, sp[-1].u.string->str, PIKE_CRYPTO->block_size);
-      roffset = PIKE_CRYPTO->block_size;
-      pop_stack();
-      MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
-    } else {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
-	     sp[-1].u.string->str, sp[-1].u.string->len);
-      PIKE_CRYPTO->overflow_len += sp[-1].u.string->len;
-      pop_n_elems(args);
-      push_string(make_shared_binary_string("", 0));
-      return;
-    }
-  }
-  
-  while (soffset + PIKE_CRYPTO->block_size <= sp[-1].u.string->len) {
-    push_string(make_shared_binary_string(sp[-1].u.string->str + soffset,
-					  PIKE_CRYPTO->block_size));
-    soffset += PIKE_CRYPTO->block_size;
-    safe_apply(PIKE_CRYPTO->object, "decrypt", 1);
     if (sp[-1].type != T_STRING) {
-      error("crypto->ecb_decrypt(): decrypt() did not return string\n");
+      error("crypto->crypt(): crypt_block() did not return string\n");
     }
-    if (sp[-1].u.string->len != PIKE_CRYPTO->block_size) {
-      error("crypto->ecb_decrypt(): Unexpected string length %d\n",
+    if (sp[-1].u.string->len != len) {
+      error("crypto->crypt(): Unexpected string length %d\n",
 	    sp[-1].u.string->len);
     }
 	
-    MEMCPY(result + roffset, sp[-1].u.string->str, PIKE_CRYPTO->block_size);
-    roffset += PIKE_CRYPTO->block_size;
+    MEMCPY(result + roffset, sp[-1].u.string->str, len);
+
     pop_stack();
   }
 
   if (soffset < sp[-1].u.string->len) {
-    MEMCPY(PIKE_CRYPTO->overflow, sp[-1].u.string->str + soffset,
+    MEMCPY(PIKE_CRYPTO->backlog, sp[-1].u.string->str + soffset,
 	   sp[-1].u.string->len - soffset);
-    PIKE_CRYPTO->overflow_len = sp[-1].u.string->len - soffset;
+    PIKE_CRYPTO->backlog_len = sp[-1].u.string->len - soffset;
   }
 
   pop_n_elems(args);
 
-  push_string(make_shared_binary_string((char *)result, roffset));
-  MEMSET(result, 0, roffset);
+  push_string(make_shared_binary_string((char *)result, roffset + len));
+  MEMSET(result, 0, roffset + len);
 }
 
-/* string cbc_encrypt(string) */
-static void f_cbc_encrypt(INT32 args)
+/* string pad(void) */
+static void f_pad(INT32 args)
 {
-  unsigned char *result;
-  INT32 roffset = 0;
-  INT32 soffset = 0;
+  int i;
 
-  if (args != 1) {
-    error("Wrong number of arguments to crypto->cbc_encrypt()\n");
-  }
-  if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to crypto->cbc_encrypt()\n");
-  }
-  if (!(result = alloca(sp[-1].u.string->len + PIKE_CRYPTO->block_size))) {
-    error("crypto->cbc_encrypt(): Out of memory\n");
+  if (args) {
+    error("Too many arguments to crypto->pad()\n");
   }
-  if (PIKE_CRYPTO->overflow_len) {
-    if (sp[-1].u.string->len >=
-	(PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len)) {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
-	     sp[-1].u.string->str,
-	     (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len));
-      soffset += (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len);
-      PIKE_CRYPTO->overflow_len = 0;
-
-      cbc_encrypt_step(PIKE_CRYPTO->overflow, result);
 
-      roffset = PIKE_CRYPTO->block_size;
-      MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
-    } else {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
-	     sp[-1].u.string->str, sp[-1].u.string->len);
-      PIKE_CRYPTO->overflow_len += sp[-1].u.string->len;
-      pop_n_elems(args);
-      push_string(make_shared_binary_string("", 0));
-      return;
-    }
+  for (i=PIKE_CRYPTO->backlog_len; i < (PIKE_CRYPTO->block_size - 1); i++) {
+    PIKE_CRYPTO->backlog[i] = my_rand() & 0xff;
   }
-  
-  while (soffset + PIKE_CRYPTO->block_size <= sp[-1].u.string->len) {
+  PIKE_CRYPTO->backlog[i] = PIKE_CRYPTO->backlog_len;
 
-    cbc_encrypt_step((const unsigned char *)sp[-1].u.string->str + soffset,
-		     result + roffset);
-    soffset += PIKE_CRYPTO->block_size;
-    roffset += PIKE_CRYPTO->block_size;
-  }
+  push_string(make_shared_binary_string((const char *)PIKE_CRYPTO->backlog,
+					PIKE_CRYPTO->block_size));
 
-  if (soffset < sp[-1].u.string->len) {
-    MEMCPY(PIKE_CRYPTO->overflow, sp[-1].u.string->str + soffset,
-	   sp[-1].u.string->len - soffset);
-    PIKE_CRYPTO->overflow_len = sp[-1].u.string->len - soffset;
-  }
+  MEMSET(PIKE_CRYPTO->backlog, 0, PIKE_CRYPTO->block_size);
+  PIKE_CRYPTO->backlog_len = 0;
 
-  pop_n_elems(args);
-
-  push_string(make_shared_binary_string((char *)result, roffset));
-  MEMSET(result, 0, roffset);
+  safe_apply(PIKE_CRYPTO->object, "crypt_block", 1);
 }
 
-/* string cbc_decrypt(string) */
-static void f_cbc_decrypt(INT32 args)
+/* string unpad(string) */
+static void f_unpad(INT32 args)
 {
-  unsigned char *result;
-  INT32 roffset = 0;
-  INT32 soffset = 0;
+  int len;
+  struct pike_string *str;
 
   if (args != 1) {
-    error("Wrong number of arguments to crypto->cbc_decrypt()\n");
+    error("Wrong number of arguments to crypto->unpad()\n");
   }
   if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to crypto->cbc_decrypt()\n");
+    error("Bad argument 1 to crypto->unpad()\n");
   }
-  if (!(result = alloca(sp[-1].u.string->len + PIKE_CRYPTO->block_size))) {
-    error("crypto->cbc_decrypt(): Out of memory\n");
-  }
-  if (PIKE_CRYPTO->overflow_len) {
-    if (sp[-1].u.string->len >=
-	(PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len)) {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
-	     sp[-1].u.string->str,
-	     (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len));
-      soffset += (PIKE_CRYPTO->block_size - PIKE_CRYPTO->overflow_len);
-      PIKE_CRYPTO->overflow_len = 0;
 
-      cbc_decrypt_step(PIKE_CRYPTO->overflow, result);
+  str = sp[-1].u.string;
 
-      roffset = PIKE_CRYPTO->block_size;
-      MEMSET(PIKE_CRYPTO->overflow, 0, PIKE_CRYPTO->block_size);
-    } else {
-      MEMCPY(PIKE_CRYPTO->overflow + PIKE_CRYPTO->overflow_len,
-	     sp[-1].u.string->str, sp[-1].u.string->len);
-      PIKE_CRYPTO->overflow_len += sp[-1].u.string->len;
-      pop_n_elems(args);
-      push_string(make_shared_binary_string("", 0));
-      return;
-    }
-  }
+  len = str->len;
   
-  while (soffset + PIKE_CRYPTO->block_size <= sp[-1].u.string->len) {
+  len += str->str[len - 1] - PIKE_CRYPTO->block_size;
 
-    cbc_decrypt_step((const unsigned char *)sp[-1].u.string->str + soffset,
-		     result + roffset);
-    soffset += PIKE_CRYPTO->block_size;
-    roffset += PIKE_CRYPTO->block_size;
+  if (len < 0) {
+    error("crypto->unpad(): String to short to unpad\n");
   }
+  
+  str->refs++;
 
-  if (soffset < sp[-1].u.string->len) {
-    MEMCPY(PIKE_CRYPTO->overflow, sp[-1].u.string->str + soffset,
-	   sp[-1].u.string->len - soffset);
-    PIKE_CRYPTO->overflow_len = sp[-1].u.string->len - soffset;
-  }
+  pop_stack();
 
-  pop_n_elems(args);
+  push_string(make_shared_binary_string(str->str, len));
 
-  push_string(make_shared_binary_string((char *)result, roffset));
-  MEMSET(result, 0, roffset);
+  free_string(str);
 }
 
 /*
@@ -601,9 +417,12 @@ void init_module_efuns(void)
 
   init_md2_efuns();
   init_md5_efuns();
+
   init_idea_efuns();
   init_des_efuns();
   init_invert_efuns();
+
+  init_cbc_efuns();
 }
 
 void init_module_programs(void)
@@ -633,15 +452,12 @@ void init_module_programs(void)
   add_function("query_block_size", f_query_block_size, "function(void:int)", OPT_TRY_OPTIMIZE);
   add_function("query_key_length", f_query_key_length, "function(void:int)", OPT_TRY_OPTIMIZE);
 
-  add_function("set_key", f_set_key, "function(string:void)", OPT_SIDE_EFFECT);
-  add_function("encrypt", f_encrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
-  add_function("decrypt", f_decrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
-
-  add_function("ecb_encrypt", f_ecb_encrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
-  add_function("ecb_decrypt", f_ecb_decrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
+  add_function("set_encrypt_key", f_set_encrypt_key, "function(string:void)", OPT_SIDE_EFFECT);
+  add_function("set_decrypt_key", f_set_decrypt_key, "function(string:void)", OPT_SIDE_EFFECT);
+  add_function("crypt", f_crypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
 
-  add_function("cbc_encrypt", f_cbc_encrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
-  add_function("cbc_decrypt", f_cbc_decrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
+  add_function("pad", f_pad, "function(void:string)", OPT_EXTERNAL_DEPEND);
+  add_function("unpad", f_unpad, "function(string:string)", OPT_EXTERNAL_DEPEND);
 
   set_init_callback(init_pike_crypto);
   set_exit_callback(exit_pike_crypto);
@@ -651,9 +467,12 @@ void init_module_programs(void)
 
   init_md2_programs();
   init_md5_programs();
+
   init_idea_programs();
   init_des_programs();
   init_invert_programs();
+
+  init_cbc_programs();
 }
 
 void exit_module(void)
@@ -661,7 +480,11 @@ void exit_module(void)
   /* free_program()s */
   exit_md2();
   exit_md5();
+
   exit_idea();
   exit_des();
   exit_invert();
+
+  exit_cbc();
 }
+
diff --git a/src/modules/_Crypto/idea.c b/src/modules/_Crypto/idea.c
index 02abbde4fda65051d6a8ed874304117946137a09..276cd1f84bf6185ac1e08ecb9164f96b250e957a 100644
--- a/src/modules/_Crypto/idea.c
+++ b/src/modules/_Crypto/idea.c
@@ -1,5 +1,5 @@
 /*
- * $Id: idea.c,v 1.3 1996/11/08 22:44:50 grubba Exp $
+ * $Id: idea.c,v 1.4 1996/11/11 14:23:25 grubba Exp $
  *
  * IDEA crypto module for Pike
  *
@@ -63,6 +63,15 @@ void exit_pike_idea(struct object *o)
  * efuns and the like
  */
 
+/* string name(void) */
+static void f_name(INT32 args)
+{
+  if (args) {
+    error("Too many arguments to idea->name()\n");
+  }
+  push_string(make_shared_string("IDEA"));
+}
+
 /* int query_block_size(void) */
 static void f_query_block_size(INT32 args)
 {
@@ -81,135 +90,68 @@ static void f_query_key_length(INT32 args)
   push_int(16);
 }
 
-/* void set_key(string) */
-static void f_set_key(INT32 args)
+/* void set_encrypt_key(string) */
+static void f_set_encrypt_key(INT32 args)
 {
   if (args != 1) {
-    error("Wrong number of args to idea->set_key()\n");
+    error("Wrong number of args to idea->set_encrypt_key()\n");
   }
   if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to idea->set_key()\n");
+    error("Bad argument 1 to idea->set_encrypt_key()\n");
   }
   if (sp[-1].u.string->len < 16) {
-    error("idea->set_key(): Too short key\n");
+    error("idea->set_encrypt_key(): Too short key\n");
   }
   idea_set_encrypt_key((unsigned char *)sp[-1].u.string->str,
-		       &PIKE_IDEA->e_key);
-  idea_set_decrypt_key(&PIKE_IDEA->e_key, &PIKE_IDEA->d_key);
-
-  MEMCPY(&(PIKE_IDEA->key), sp[-1].u.string->str, 8);
+		       &PIKE_IDEA->key);
 
   pop_n_elems(args);
 }
 
-/* string encrypt(string) */
-static void f_encrypt(INT32 args)
+/* void set_decrypt_key(string) */
+static void f_set_decrypt_key(INT32 args)
 {
-  unsigned char buffer[8];
+  IDEA_KEY_SCHEDULE key_tmp;
 
   if (args != 1) {
-    error("Wrong number of arguemnts to idea->encrypt()\n");
+    error("Wrong number of args to idea->set_decrypt_key()\n");
   }
   if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to idea->encrypt()\n");
+    error("Bad argument 1 to idea->set_decrypt_key()\n");
   }
-  if (sp[-1].u.string->len != 8) {
-    error("Bad length of argument 1 to idea->encrypt()\n");
-  }
-
-  idea_ecb_encrypt((unsigned char *)sp[-1].u.string->str, buffer,
-		   &(PIKE_IDEA->e_key));
-
-  pop_n_elems(args);
-
-  push_string(make_shared_binary_string((const char *)buffer, 8));
-
-  MEMSET(buffer, 0, 8);
-}
-
-/* string decrypt(string) */
-static void f_decrypt(INT32 args)
-{
-  unsigned char buffer[8];
-
-  if (args != 1) {
-    error("Wrong number of arguemnts to idea->decrypt()\n");
-  }
-  if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to idea->decrypt()\n");
-  }
-  if (sp[-1].u.string->len != 8) {
-    error("Bad length of argument 1 to idea->decrypt()\n");
+  if (sp[-1].u.string->len < 16) {
+    error("idea->set_decrypt_key(): Too short key\n");
   }
-
-  idea_ecb_encrypt((unsigned char *)sp[-1].u.string->str, buffer,
-		   &(PIKE_IDEA->d_key));
+  idea_set_encrypt_key((unsigned char *)sp[-1].u.string->str, &key_tmp);
+  idea_set_decrypt_key(&key_tmp, &PIKE_IDEA->key);
 
   pop_n_elems(args);
 
-  push_string(make_shared_binary_string((const char *)buffer, 8));
-
-  MEMSET(buffer, 0, 8);
+  MEMSET(&key_tmp, 0, sizeof(key_tmp));
 }
 
-/* string cbc_encrypt(string) */
-static void f_cbc_encrypt(INT32 args)
+/* string crypt_block(string) */
+static void f_crypt_block(INT32 args)
 {
   unsigned char *buffer;
-  unsigned char iv[8];
   int len;
 
   if (args != 1) {
-    error("Wrong number of arguments to idea->cbc_encrypt()\n");
+    error("Wrong number of arguemnts to idea->crypt()\n");
   }
   if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to idea->cbc_encrypt()\n");
+    error("Bad argument 1 to idea->crypt()\n");
   }
-  
-  len = (sp[-1].u.string->len + 7) & ~7;
-
-  if (!(buffer = alloca(len))) {
-    error("Out of memory\n");
+  if (sp[-1].u.string->len % 8) {
+    error("Bad length of argument 1 to idea->crypt()\n");
   }
 
-  MEMCPY(iv, &(PIKE_IDEA->key), 8);
-
-  idea_cbc_encrypt((unsigned char *)sp[-1].u.string->str, buffer,
-		   sp[-1].u.string->len,
-		   &(PIKE_IDEA->e_key), iv, IDEA_ENCRYPT);
-
-  pop_n_elems(args);
-
-  push_string(make_shared_binary_string((const char *)buffer, len));
-
-  MEMSET(buffer, 0, len);
-}
-
-/* string cbc_decrypt(string) */
-static void f_cbc_decrypt(INT32 args)
-{
-  unsigned char *buffer;
-  unsigned char iv[8];
-  int len;
-
-  if (args != 1) {
-    error("Wrong number of arguments to idea->cbc_decrypt()\n");
-  }
-  if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to idea->cbc_decrypt()\n");
-  }
-  
-  len = (sp[-1].u.string->len + 7) & ~7;
-
-  if (!(buffer = alloca(len))) {
-    error("Out of memory\n");
+  if (!(buffer = alloca(len = sp[-1].u.string->len))) {
+    error("idea->crypt(): Out of memory\n");
   }
 
-  MEMCPY(iv, &(PIKE_IDEA->key), 8);
-
-  idea_cbc_encrypt((unsigned char *)sp[-1].u.string->str, buffer,
-		   sp[-1].u.string->len,
-		   &(PIKE_IDEA->d_key), iv, IDEA_DECRYPT);
+  idea_ecb_encrypt((unsigned char *)sp[-1].u.string->str, buffer,
+		   &(PIKE_IDEA->key));
 
   pop_n_elems(args);
 
@@ -250,13 +192,12 @@ void init_idea_programs(void)
   start_new_program();
   add_storage(sizeof(struct pike_idea));
 
+  add_function("name", f_name, "function(void:string)", OPT_TRY_OPTIMIZE);
   add_function("query_block_size", f_query_block_size, "function(void:int)", OPT_TRY_OPTIMIZE);
   add_function("query_key_length", f_query_key_length, "function(void:int)", OPT_TRY_OPTIMIZE);
-  add_function("set_key", f_set_key, "function(string:void)", OPT_SIDE_EFFECT);
-  add_function("encrypt", f_encrypt, "function(string:string)", OPT_SIDE_EFFECT);
-  add_function("decrypt", f_decrypt, "function(string:string)", OPT_SIDE_EFFECT);
-  add_function("cbc_encrypt", f_cbc_encrypt, "function(string:string)", OPT_SIDE_EFFECT);
-  add_function("cbc_decrypt", f_cbc_decrypt, "function(string:string)", OPT_SIDE_EFFECT);
+  add_function("set_encrypt_key", f_set_encrypt_key, "function(string:void)", OPT_SIDE_EFFECT);
+  add_function("set_decrypt_key", f_set_decrypt_key, "function(string:void)", OPT_SIDE_EFFECT);
+  add_function("crypt_block", f_crypt_block, "function(string:string)", OPT_EXTERNAL_DEPEND);
 
   set_init_callback(init_pike_idea);
   set_exit_callback(exit_pike_idea);
diff --git a/src/modules/_Crypto/idea.pike b/src/modules/_Crypto/idea.pike
index 8d33089007220c5720c0c3d2bbab1770118b2bf9..94ca1b57aad32f519f9d146f96cd24c1d1fb8836 100755
--- a/src/modules/_Crypto/idea.pike
+++ b/src/modules/_Crypto/idea.pike
@@ -1,6 +1,6 @@
 #!/home/grubba/src/pike/build/sol2.5/pike
 /*
- * $Id: idea.pike,v 1.2 1996/11/09 14:42:21 grubba Exp $
+ * $Id: idea.pike,v 1.3 1996/11/11 14:23:29 grubba Exp $
  *
  * An crypto using IDEA written in Pike
  * rename it to get it to use another crypto.
@@ -27,12 +27,14 @@ int main(int argc, string *argv)
   int hexkey = 0;
   int i;
   object crypto_object = ((program)"/precompiled/crypto")
-                         ((program)("/precompiled/crypto/" +
+                         ((program)"/precompiled/crypto/cbc",
+			  (program)("/precompiled/crypto/" +
 				    ((argv[0]/"/")[-1] / ".")[0]));
   object input = ((program)"/precompiled/file")("stdin");
   object output = ((program)"/precompiled/file")("stdout");
   string data = "";
   string outstr = "";
+  string key = "";
 
   for (i=1; i < argc; i++) {
     switch(argv[i]) {
@@ -43,11 +45,7 @@ int main(int argc, string *argv)
       encrypt=0;
       break;
     case "-k":
-      if (hexkey) {
-	crypto_object->set_key(hex_to_string(argv[i+1]));
-      } else {
-	crypto_object->set_key(argv[i+1]);
-      }
+      key = argv[i+1];
       i++;
       break;
     case "-h":
@@ -62,56 +60,32 @@ int main(int argc, string *argv)
     }
   }
   
+  if (hexkey) {
+    key = hex_to_string(key);
+  }
+  if (encrypt) {
+    crypto_object->set_encrypt_key(key);
+  } else {
+    crypto_object->set_decrypt_key(key);
+  }
+  
+  key="";
+
   while (1) {
     string newdata = input->read(1000000);
 
     if (stringp(newdata) && sizeof(newdata)) {
-      int len;
-
-      data += newdata;
-
-      /* Make blocks */
-      len = sizeof(data) & ~0x0f;
-
-      if (len) {
-	if (encrypt) {
-
-	  output->write(crypto_object->cbc_encrypt(data[0..len-1]));
-
-	} else {
-	  output->write(outstr);
-	  outstr = crypto_object->cbc_decrypt(data[0..len-1]);
-	}
-	data = data[len..];
+      if (encrypt) {
+	output->write(crypto_object->crypt(newdata));
+      } else {
+	output->write(outstr);
+	outstr = crypto_object->crypt(newdata);
       }
     } else {
       if (encrypt) {
-	int len = sizeof(data) & 0x0f;
-	
-	data += sprintf("%@c",
-			({ random(256), random(256), random(256), random(256),
-			   random(256), random(256), random(256), random(256),
-			   random(256), random(256), random(256), random(256),
-			   random(256), random(256), random(256), len })[len..]);
-	output->write(crypto_object->cbc_encrypt(data));
+	output->write(crypto_object->pad());
       } else {
-	if ((sizeof(data))||(outstr[-1] & ~0x0f)||(sizeof(outstr) & 0x0f)) {
-	  werror("Data didn't decrypt correctly\n");
-	  output->write(outstr);
-	  destruct(crypto_object);
-	  exit(1);
-	} else {
-	  int len = ((sizeof(outstr) & ~0x0f) | outstr[-1]) - 16;
-
-	  if ((len > sizeof(outstr)) || (len < 1)) {
-	    werror("Data didn't decrypt correctly\n");
-	    werror(sprintf("len:%d, %d\n", sizeof(outstr), len));
-	    destruct(crypto_object);
-	    exit(1);
-	  } else {
-	    output->write(outstr[0..len-1]);
-	  }
-	}
+	output->write(crypto_object->unpad(outstr));
       }
       break;
     }
diff --git a/src/modules/_Crypto/invert.c b/src/modules/_Crypto/invert.c
index 78deb6de8c1a6c486f0c1ea1e799b61ee74709ad..2fb5a91f15cdaecf58980c1680bf439ef9adbfe0 100644
--- a/src/modules/_Crypto/invert.c
+++ b/src/modules/_Crypto/invert.c
@@ -1,5 +1,5 @@
 /*
- * $Id: invert.c,v 1.1 1996/11/08 22:28:42 grubba Exp $
+ * $Id: invert.c,v 1.2 1996/11/11 14:23:27 grubba Exp $
  *
  * INVERT crypto module for Pike
  *
@@ -49,6 +49,15 @@ void exit_pike_invert(struct object *o)
  * efuns and the like
  */
 
+/* string name(void) */
+static void f_name(INT32 args)
+{
+  if (args) {
+    error("Too many arguments to invert->name()\n");
+  }
+  push_string(make_shared_string("INVERT"));
+}
+
 /* int query_block_size(void) */
 static void f_query_block_size(INT32 args)
 {
@@ -64,7 +73,7 @@ static void f_query_key_length(INT32 args)
   if (args) {
     error("Too many arguments to invert->query_key_length()\n");
   }
-  push_int(8);
+  push_int(0);
 }
 
 /* void set_key(string) */
@@ -80,33 +89,36 @@ static void f_set_key(INT32 args)
   pop_n_elems(args);
 }
 
-/* string encrypt(string) */
-/* string decrypt(string) */
-/* string dencrypt(string) */
-static void f_dencrypt(INT32 args)
+/* string crypt_block(string) */
+static void f_crypt_block(INT32 args)
 {
-  char buffer[8];
+  char *buffer;
   int i;
+  int len;
 
   if (args != 1) {
-    error("Wrong number of arguments to invert->dencrypt()\n");
+    error("Wrong number of arguments to invert->crypt_block()\n");
   }
   if (sp[-1].type != T_STRING) {
-    error("Bad argument 1 to invert->dencrypt()\n");
+    error("Bad argument 1 to invert->crypt_block()\n");
   }
-  if (sp[-1].u.string->len != 8) {
-    error("Bad length of argument 1 to invert->dencrypt()\n");
+  if (sp[-1].u.string->len % 8) {
+    error("Bad length of argument 1 to invert->crypt_block()\n");
+  }
+
+  if (!(buffer = alloca(len = sp[-1].u.string->len))) {
+    error("invert->crypt_block(): Out of memory\n");
   }
 
-  for (i=0; i<8; i++) {
+  for (i=0; i<len; i++) {
     buffer[i] = ~sp[-1].u.string->str[i];
   }
 
   pop_n_elems(args);
 
-  push_string(make_shared_binary_string(buffer, 8));
+  push_string(make_shared_binary_string(buffer, len));
 
-  MEMSET(buffer, 0, 8);
+  MEMSET(buffer, 0, len);
 }
 
 /*
@@ -140,12 +152,12 @@ void init_invert_programs(void)
   /* /precompiled/crypto/invert */
   start_new_program();
 
+  add_function("name", f_name, "function(void:string)", OPT_TRY_OPTIMIZE);
   add_function("query_block_size", f_query_block_size, "function(void:int)", OPT_TRY_OPTIMIZE);
   add_function("query_key_length", f_query_key_length, "function(void:int)", OPT_TRY_OPTIMIZE);
-  add_function("set_key", f_set_key, "function(string:void)", OPT_SIDE_EFFECT);
-  add_function("encrypt", f_dencrypt, "function(string:string)", OPT_SIDE_EFFECT);
-  add_function("decrypt", f_dencrypt, "function(string:string)", OPT_SIDE_EFFECT);
-  add_function("dencrypt", f_dencrypt, "function(string:string)", OPT_SIDE_EFFECT);
+  add_function("set_encrypt_key", f_set_key, "function(string:void)", OPT_SIDE_EFFECT);
+  add_function("set_decrypt_key", f_set_key, "function(string:void)", OPT_SIDE_EFFECT);
+  add_function("crypt_block", f_crypt_block, "function(string:string)", OPT_SIDE_EFFECT);
 
   set_init_callback(init_pike_invert);
   set_exit_callback(exit_pike_invert);