diff --git a/.gitattributes b/.gitattributes
index 5b6c022c1e10ef81dc6980d36ff7f6630fa3c87a..8a79a980a31c44f3ae3168d81edc3a6f5f06d1bc 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -393,6 +393,7 @@ testfont binary
 /src/modules/_Crypto/include/crypto_types.h foreign_ident
 /src/modules/_Crypto/include/des.h foreign_ident
 /src/modules/_Crypto/include/idea.h foreign_ident
+/src/modules/_Crypto/include/md2.h foreign_ident
 /src/modules/_Crypto/include/md5.h foreign_ident
 /src/modules/_Crypto/include/rc4.h foreign_ident
 /src/modules/_Crypto/include/sha.h foreign_ident
@@ -413,9 +414,11 @@ testfont binary
 /src/modules/_Crypto/lib/desinfo.h foreign_ident
 /src/modules/_Crypto/lib/idea.c foreign_ident
 /src/modules/_Crypto/lib/install-sh foreign_ident
+/src/modules/_Crypto/lib/md2.c foreign_ident
 /src/modules/_Crypto/lib/md5.c foreign_ident
 /src/modules/_Crypto/lib/rc4.c foreign_ident
 /src/modules/_Crypto/lib/sha.c foreign_ident
+/src/modules/_Crypto/md2.c foreign_ident
 /src/modules/_Crypto/md5.c foreign_ident
 /src/modules/_Crypto/md5.pike foreign_ident
 /src/modules/_Crypto/nt.c foreign_ident
diff --git a/src/modules/_Crypto/Makefile.in b/src/modules/_Crypto/Makefile.in
index c544c855d4e06e88a7793090955e72d412fab9a4..c1d4c3581738876cb4f3c05d40cc2fa409b53514 100644
--- a/src/modules/_Crypto/Makefile.in
+++ b/src/modules/_Crypto/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.23 2000/03/28 12:13:12 grubba Exp $
+# $Id: Makefile.in,v 1.24 2000/08/01 19:48:34 sigge Exp $
 @make_variables@
 VPATH=@srcdir@:@srcdir@/../..:../..
 
@@ -6,7 +6,7 @@ VPATH=@srcdir@:@srcdir@/../..:../..
 MASS_DESTRUCTION_OBJS = idea.o des.o cast.o arcfour.o rsa.o
 # END NATIONAL SECURITY
 
-OBJS= $(MASS_DESTRUCTION_OBJS) crypto.o invert.o sha.o md5.o pipe.o cbc.o nt.o
+OBJS= $(MASS_DESTRUCTION_OBJS) crypto.o invert.o sha.o md2.o md5.o pipe.o cbc.o nt.o
 
 MODULE_ARCHIVES=lib/algorithms.a
 MODULE_SUBDIRS=lib
diff --git a/src/modules/_Crypto/crypto.c b/src/modules/_Crypto/crypto.c
index 6d435791fb244f2d2b64ca00bca7f3b478b7edb3..966fa37f0172957b2f664214fd23c3fe500834b1 100644
--- a/src/modules/_Crypto/crypto.c
+++ b/src/modules/_Crypto/crypto.c
@@ -1,5 +1,5 @@
 /*
- * $Id: crypto.c,v 1.33 2000/07/28 07:15:16 hubbe Exp $
+ * $Id: crypto.c,v 1.34 2000/08/01 19:48:34 sigge Exp $
  *
  * A pike module for getting access to some common cryptos.
  *
@@ -509,6 +509,7 @@ void pike_module_init(void)
   /* function(string:string) */
   ADD_FUNCTION("des_parity", f_des_parity,tFunc(tStr,tStr), 0);
 
+  pike_md2_init();
   pike_md5_init();
   pike_sha_init();
   pike_crypto_init();
@@ -530,6 +531,7 @@ void pike_module_init(void)
 
 void pike_module_exit(void)
 {
+  pike_md2_exit();
   pike_md5_exit();
   pike_sha_exit();
   pike_crypto_exit();
diff --git a/src/modules/_Crypto/include/md2.h b/src/modules/_Crypto/include/md2.h
new file mode 100644
index 0000000000000000000000000000000000000000..356802ecad988026765aeabb6b9288803d16facd
--- /dev/null
+++ b/src/modules/_Crypto/include/md2.h
@@ -0,0 +1,17 @@
+/*
+ * $Id: md2.h,v 1.1 2000/08/01 19:48:35 sigge Exp $
+ */
+
+#include "crypto_types.h"
+
+struct md2_ctx {
+  unsigned INT8 C[16], X[48];
+  unsigned INT8 buf[16];
+  INT32 count;
+};
+
+void md2_init(struct md2_ctx *ctx);
+void md2_update(struct md2_ctx *ctx, unsigned INT8 *buffer, unsigned INT32 len);
+void md2_final(struct md2_ctx *ctx);
+void md2_digest(struct md2_ctx *ctx, INT8 *s);
+void md2_copy(struct md2_ctx *dest, struct md2_ctx *src);
diff --git a/src/modules/_Crypto/lib/Makefile.in b/src/modules/_Crypto/lib/Makefile.in
index 8d43ca3a807a63dd810dc37aa98de56d5e4f83ac..218fe5c2436fb9f256b600c5eb970ae6f122249c 100644
--- a/src/modules/_Crypto/lib/Makefile.in
+++ b/src/modules/_Crypto/lib/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.21 2000/03/28 12:22:01 grubba Exp $
+# $Id: Makefile.in,v 1.22 2000/08/01 19:48:36 sigge Exp $
 #
 # Makefile for low-level crypto library
 
@@ -149,7 +149,7 @@ desQuickCore.c:
 MASS_DESTRUCTION_OBJS = idea.o arcfour.o cast.o $(O)
 # END NATIONAL SECURITY
 
-OBJS = $(MASS_DESTRUCTION_OBJS) sha.o md5.o
+OBJS = $(MASS_DESTRUCTION_OBJS) sha.o md2.o md5.o
 
 algorithms.a: $(OBJS)
 	rm -f algorithms.a
diff --git a/src/modules/_Crypto/lib/md2.c b/src/modules/_Crypto/lib/md2.c
new file mode 100644
index 0000000000000000000000000000000000000000..870a8c9f89d7247cedacdf7a235090a244b1bc8d
--- /dev/null
+++ b/src/modules/_Crypto/lib/md2.c
@@ -0,0 +1,109 @@
+
+/*
+ * $Id: md2.c,v 1.1 2000/08/01 19:48:36 sigge Exp $
+ *
+ *  md2.c : MD2 hash algorithm.
+ *
+ * Part of the Python Cryptography Toolkit, version 1.0.1
+ *
+ * Further hacked and adapted to pike by Andreas Sigfridsson
+ */
+
+#include "md2.h"
+
+void md2_copy(struct md2_ctx *dest, struct md2_ctx *src)
+{
+  dest->count=src->count;  
+  memcpy(dest->buf, src->buf, src->count); /* dest->count ? */
+  memcpy(dest->X, src->X, 48);
+  memcpy(dest->C, src->C, 16);
+}
+
+void md2_init(struct md2_ctx *ctx)
+{
+  memset(ctx->X, 0, 48);
+  memset(ctx->C, 0, 16);
+  ctx->count=0;
+}
+
+static unsigned INT8 S[256] = {
+  41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+  19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+  76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+  138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+  245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+  148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+  39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+  181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+  150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+  112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+  96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+  85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+  234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+  129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+  8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+  203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+  166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+  31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+void md2_update(struct md2_ctx *ctx,
+		unsigned INT8 *buffer,
+		unsigned INT32 len)
+{
+  unsigned INT32 L;
+  while (len) 
+  {
+    L=(16-ctx->count) < len ? (16-ctx->count) : len;
+    memcpy(ctx->buf+ctx->count, buffer, L);
+    ctx->count+=L;
+    buffer+=L;
+    len-=L;
+    if (ctx->count==16) 
+    {
+      unsigned INT8 t;
+      int i,j;
+
+      ctx->count=0;
+      memcpy(ctx->X+16, ctx->buf, 16);
+      t=ctx->C[15];
+      for(i=0; i<16; i++)
+      {
+	ctx->X[32+i]=ctx->X[16+i]^ctx->X[i];
+	t=ctx->C[i]^=S[ctx->buf[i]^t];
+      }
+
+      t=0;
+      for(i=0; i<18; i++)
+      {
+	for(j=0; j<48; j++)
+	  t=ctx->X[j]^=S[t];
+	t=(t+i) & 0xFF;
+      }
+    }
+  }
+}
+
+void md2_final(struct md2_ctx *ctx)
+{
+  unsigned INT32 L;
+  unsigned INT8 buf[16];
+  L=16-ctx->count;
+  memset(buf, (unsigned INT8)L, L);
+  md2_update(ctx, buf, L);
+}
+
+void md2_digest(struct md2_ctx *ctx, INT8 *s)
+{
+  unsigned INT8 padding[16];
+  unsigned INT32 padlen;
+  struct md2_ctx temp;
+  int i;
+
+  md2_copy(&temp, ctx);
+  padlen= 16-ctx->count;
+  for(i=0; i<padlen; i++) padding[i]=padlen;
+  md2_update(&temp, padding, padlen);
+  md2_update(&temp, temp.C, 16);
+  memcpy(s, temp.X, 16);
+}
diff --git a/src/modules/_Crypto/md2.c b/src/modules/_Crypto/md2.c
new file mode 100644
index 0000000000000000000000000000000000000000..d1ebfc5a3b10c87e7c3cb99d3a9416f11729d310
--- /dev/null
+++ b/src/modules/_Crypto/md2.c
@@ -0,0 +1,115 @@
+/*
+ * $Id: md2.c,v 1.8 2000/08/01 19:48:35 sigge Exp $
+ *
+ * A pike module for MD2 hashing.
+ *
+ * Andreas Sigfridsson 2000-08-01
+ * Based on md5.c by Henrik Grubbström and Niels Möller
+ *
+ */
+
+
+#include "global.h"
+#include "svalue.h"
+#include "string.h"
+#include "pike_types.h"
+#include "stralloc.h"
+#include "object.h"
+#include "interpret.h"
+#include "program.h"
+#include "error.h"
+#include "module_support.h"
+
+#include <md2.h>
+
+/* THIS MUST BE INCLUDED LAST */
+#include "module_magic.h"
+
+#undef THIS
+#define THIS ((struct md2_ctx *)(fp->current_storage))
+#define OBTOCTX(o) ((struct md2_ctx *)(o->storage))
+
+static struct program *md2mod_program;
+
+/* string name(void) */
+static void f_name(INT32 args)
+{
+  if (args)
+    error("Too many arguments to md2->name()\n");
+
+  push_string(make_shared_string("MD2"));
+}
+
+static void f_create(INT32 args)
+{
+  if (args)
+    {
+      if ( ((sp-args)->type != T_OBJECT)
+	   || ((sp-args)->u.object->prog != md2mod_program) )
+	error("Object not of md2 type.\n");
+      md2_copy(THIS, OBTOCTX((sp-args)->u.object));
+    }
+  else
+    md2_init(THIS);
+  pop_n_elems(args);
+}
+
+static void f_update(INT32 args)
+{
+  struct pike_string *s;
+  get_all_args("_Crypto.md2->update", args, "%S", &s);
+
+  md2_update(THIS, (unsigned INT8 *) s->str, s->len);
+  pop_n_elems(args);
+  push_object(this_object());
+}
+
+/* From RFC 1319
+ *  md2 OBJECT IDENTIFIER ::=
+ *    iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
+ *
+ * 0x2a86 4886 f70d 0202
+ */
+static char md2_id[] = {
+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02,
+};
+
+static void f_identifier(INT32 args)
+{
+  pop_n_elems(args);
+  push_string(make_shared_binary_string(md2_id, 8));
+}
+
+static void f_digest(INT32 args)
+{
+  struct pike_string *s;
+
+  s = begin_shared_string(16);
+
+  md2_digest(THIS, s->str);
+  md2_init(THIS);
+
+  pop_n_elems(args);
+  push_string(end_shared_string(s));
+}
+
+void pike_md2_exit(void)
+{
+}
+
+void pike_md2_init(void)
+{
+  start_new_program();
+  ADD_STORAGE(struct md2_ctx);
+  /* function(void:string) */
+  ADD_FUNCTION("name", f_name,tFunc(tVoid,tStr), 0);
+  /* function(void|object:void) */
+  ADD_FUNCTION("create", f_create,tFunc(tOr(tVoid,tObj),tVoid), 0);
+  /* function(string:object) */
+  ADD_FUNCTION("update", f_update,tFunc(tStr,tObj), 0);
+  /* function(void:string) */
+  ADD_FUNCTION("digest", f_digest,tFunc(tVoid,tStr), 0);
+  /* function(void:string) */
+  ADD_FUNCTION("identifier", f_identifier,tFunc(tVoid,tStr), 0);
+  end_class("md2", 0);
+}
diff --git a/src/modules/_Crypto/testsuite.in b/src/modules/_Crypto/testsuite.in
index 7f86a59810bd62f68c3a66ccedbe80710a89f183..c384cda08b714cb18d7aacfbf24db558634811bd 100644
--- a/src/modules/_Crypto/testsuite.in
+++ b/src/modules/_Crypto/testsuite.in
@@ -15,6 +15,7 @@ test_do(add_constant("xCrypto",_Crypto))
 test_true([[programp(xCrypto.cbc)]])
 test_true([[programp(xCrypto.crypto)]])
 test_true([[programp(xCrypto.invert)]])
+test_true([[programp(xCrypto.md2)]])
 test_true([[programp(xCrypto.md5)]])
 test_true([[programp(xCrypto.pipe)]])
 test_true([[programp(xCrypto.sha)]])
@@ -196,6 +197,24 @@ test_eq([[xCrypto.md5()->update("1234567890123456789012345678901234567890"
 			       "1234567890123456789012345678901234567890")->digest()]],
 	[[xCrypto.hex_to_string("57edf4a22be3c955ac49da2e2107b67a")]])
   
+// MD2
+test_true([[objectp(xCrypto.md2())]])
+test_eq([[xCrypto.md2()->update("")->digest()]],
+	[[xCrypto.hex_to_string("8350e5a3e24c153df2275c9f80692773")]])
+test_eq([[xCrypto.md2()->update("a")->digest()]],
+	[[xCrypto.hex_to_string("32ec01ec4a6dac72c0ab96fb34c0b5d1")]])
+test_eq([[xCrypto.md2()->update("abc")->digest()]],
+	[[xCrypto.hex_to_string("da853b0d3f88d99b30283a69e6ded6bb")]])
+test_eq([[xCrypto.md2()->update("message digest")->digest()]],
+	[[xCrypto.hex_to_string("ab4f496bfb2a530b219ff33031fe06b0")]])
+test_eq([[xCrypto.md2()->update("abcdefghijklmnopqrstuvwxyz")->digest()]],
+	[[xCrypto.hex_to_string("4e8ddff3650292ab5a4108c3aa47940b")]])
+test_eq([[xCrypto.md2()->update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")->digest()]],
+	[[xCrypto.hex_to_string("da33def2a42df13975352846c30338cd")]])
+test_eq([[xCrypto.md2()->update("1234567890123456789012345678901234567890"
+				"1234567890123456789012345678901234567890")->digest()]],
+	[[xCrypto.hex_to_string("d5976f79d83d3a0dc9806c3c66f3efd8")]])
+
 // SHA
 test_true([[objectp(xCrypto.sha())]])
 test_eq([[xCrypto.sha()->update("abc")->digest()]],