diff --git a/src/modules/_Crypto/crypto.c b/src/modules/_Crypto/crypto.c
index 238998e552896eb1e73fdba3d982f67340b60ff8..415edc7cbb51bcf01a745e4e127d355f28f13df5 100644
--- a/src/modules/_Crypto/crypto.c
+++ b/src/modules/_Crypto/crypto.c
@@ -1,5 +1,5 @@
 /*
- * $Id: crypto.c,v 1.2 1996/11/07 19:29:02 grubba Exp $
+ * $Id: crypto.c,v 1.3 1996/11/07 20:15:39 grubba Exp $
  *
  * A pike module for getting access to some common cryptos.
  *
@@ -97,6 +97,52 @@ static void check_functions(struct object *o, const char **requiered)
   }
 }
 
+INLINE static void cbc_encrypt_step(const unsigned char *source,
+				    unsigned char *dest)
+{
+  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);
+}
+
 /*
  * efuns and the like
  */
@@ -301,8 +347,8 @@ static void f_ecb_encrypt(INT32 args)
 	      sp[-1].u.string->len);
       }
 	
-      MEMCPY(result + roffset, sp[-1].u.string->str, PIKE_CRYPTO->block_size);
-      roffset += PIKE_CRYPTO->block_size;
+      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 {
@@ -378,8 +424,8 @@ static void f_ecb_decrypt(INT32 args)
 	      sp[-1].u.string->len);
       }
 	
-      MEMCPY(result + roffset, sp[-1].u.string->str, PIKE_CRYPTO->block_size);
-      roffset += PIKE_CRYPTO->block_size;
+      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 {
@@ -420,6 +466,118 @@ static void f_ecb_decrypt(INT32 args)
   MEMSET(result, 0, roffset);
 }
 
+/* string cbc_encrypt(string) */
+static void f_cbc_encrypt(INT32 args)
+{
+  unsigned char *result;
+  INT32 roffset = 0;
+  INT32 soffset = 0;
+
+  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 (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;
+    }
+  }
+  
+  while (soffset + PIKE_CRYPTO->block_size <= sp[-1].u.string->len) {
+
+    cbc_encrypt_step(sp[-1].u.string->str + soffset, result + roffset);
+    soffset += PIKE_CRYPTO->block_size;
+    roffset += 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;
+  }
+
+  push_string(make_shared_binary_string((char *)result, roffset));
+  MEMSET(result, 0, roffset);
+}
+
+/* string cbc_decrypt(string) */
+static void f_cbc_decrypt(INT32 args)
+{
+  unsigned char *result;
+  INT32 roffset = 0;
+  INT32 soffset = 0;
+
+  if (args != 1) {
+    error("Wrong number of arguments to crypto->cbc_decrypt()\n");
+  }
+  if (sp[-1].type != T_STRING) {
+    error("Bad argument 1 to crypto->cbc_decrypt()\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);
+
+      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;
+    }
+  }
+  
+  while (soffset + PIKE_CRYPTO->block_size <= sp[-1].u.string->len) {
+
+    cbc_decrypt_step(sp[-1].u.string->str + soffset, result);
+    soffset += PIKE_CRYPTO->block_size;
+    roffset += 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;
+  }
+
+  push_string(make_shared_binary_string((char *)result, roffset));
+  MEMSET(result, 0, roffset);
+}
+
 /*
  * Module linkage
  */
@@ -471,6 +629,9 @@ void init_module_programs(void)
   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("cbc_encrypt", f_cbc_encrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
+  add_function("cbc_decrypt", f_cbc_decrypt, "function(string:string)", OPT_EXTERNAL_DEPEND);
+
   set_init_callback(init_pike_crypto);
   set_exit_callback(exit_pike_crypto);