Eliminate MD5 as a loadable microcode module.
authorTaylor R Campbell <campbell@mumble.net>
Sat, 4 Nov 2017 02:56:22 +0000 (02:56 +0000)
committerTaylor R Campbell <campbell@mumble.net>
Sat, 4 Nov 2017 03:02:38 +0000 (03:02 +0000)
Unconditionally include a new portable C implementation.

src/microcode/configure.ac
src/microcode/makegen/Makefile.in.in
src/microcode/makegen/files-core.scm
src/microcode/makegen/files-optional.scm
src/microcode/md5.c [new file with mode: 0644]
src/microcode/md5.h [new file with mode: 0644]
src/microcode/prmd5.c
src/runtime/crypto.scm
tests/check.scm
tests/runtime/test-md5.scm [new file with mode: 0644]

index e30134b52b17645922703347063b7ce7c5bce996..4668474586cfe0ba061af8ddd8dc7ecfe71ce102 100644 (file)
@@ -182,7 +182,6 @@ OPTIONAL_BASES=
 OPTIONAL_SOURCES=
 OPTIONAL_OBJECTS=
 PRBFISH_LIBS=
-PRMD5_LIBS=
 SCHEME_DEFS=-DMIT_SCHEME
 SCHEME_LDFLAGS=
 MODULE_BASES=
@@ -844,9 +843,8 @@ if test "${with_openssl}" != no; then
        ])
     if test -n "${FOUND}"; then
        MODULE_LIBS="-lcrypto ${MODULE_LIBS}"
-       MODULE_BASES="${MODULE_BASES} prbfish prmd5"
+       MODULE_BASES="${MODULE_BASES} prbfish"
        PRBFISH_LIBS="-lcrypto"
-       PRMD5_LIBS="-lcrypto"
     fi
 fi
 
@@ -855,7 +853,6 @@ dnl file dependencies using "makegen/makegen.scm" when called on
 dnl "makegen/files-optional.scm".  To wit, "prmhash.c" & "prmcrypt.c"
 dnl must conditionalize their dependencies on <mhash.h> & <mcrypt.h>,
 dnl respectively, to avoid warnings in "Makefile.deps" and its embeds.
-dnl Finally, note that "prmd5.c" is similarly conditionalized as well.
 
 dnl The mhash library provides MD5 support.  It can be loaded in addition
 dnl to other MD5 libraries and provides a rich set of hashes.
@@ -877,9 +874,6 @@ if test "${with_mhash}" != no; then
            fi
            MODULE_LIBS="-lmhash ${MODULE_LIBS}"
            MODULE_BASES="${MODULE_BASES} prmhash"
-           if test "x${PRMD5_LIBS}" = x; then
-               PRMD5_LIBS="-lmhash"
-           fi
            ])
        ])
 fi
@@ -1108,7 +1102,6 @@ AC_SUBST([M4])
 AC_SUBST([OPTIONAL_SOURCES])
 AC_SUBST([OPTIONAL_OBJECTS])
 AC_SUBST([PRBFISH_LIBS])
-AC_SUBST([PRMD5_LIBS])
 AC_SUBST([SCHEME_DEFS])
 AC_SUBST([SCHEME_LDFLAGS])
 AC_SUBST([MODULE_TARGETS])
index 73709e2ed8112d72cf8d097e50e78465ab755ea1..c7847d20b882e72a1524835fa76a88f88e82ad2b 100644 (file)
@@ -102,7 +102,6 @@ GC_HEAD_FILES = @GC_HEAD_FILES@
 OPTIONAL_SOURCES = @OPTIONAL_SOURCES@
 OPTIONAL_OBJECTS = @OPTIONAL_OBJECTS@
 PRBFISH_LIBS = @PRBFISH_LIBS@
-PRMD5_LIBS = @PRMD5_LIBS@
 
 MODULE_TARGETS = @MODULE_TARGETS@
 MODULE_CFLAGS = @MODULE_CFLAGS@
@@ -195,9 +194,6 @@ macosx-starter: macosx-starter.o
 prbfish.so: prbfish.o @MODULE_LOADER@
        $(LINK_MODULE) prbfish.o $(PRBFISH_LIBS) $(MODULE_LIBS)
 
-prmd5.so: prmd5.o @MODULE_LOADER@
-       $(LINK_MODULE) prmd5.o $(PRMD5_LIBS) $(MODULE_LIBS)
-
 prmhash.so: prmhash.o @MODULE_LOADER@
        $(LINK_MODULE) prmhash.o -lmhash $(MODULE_LIBS)
 
index a78032e7e7339c06a2d914308416ea7264fde6aa..fa356f795ad2070e8b149dfa2e6e1de8eaacab9d 100644 (file)
@@ -57,6 +57,7 @@ USA.
 "list"
 "lookprm"
 "lookup"
+"md5"
 "memmag"
 "missing"
 "obstack"
@@ -67,6 +68,7 @@ USA.
 "prim"
 "primutl"
 "prkeccak"
+"prmd5"
 "ptrvec"
 "purify"
 "purutl"
index f063d6d9fb4a1e0b880bb21f27cd390bc21d131e..6e9666c0f453ce3836e8ae0ff9b0283f936f124f 100644 (file)
@@ -31,7 +31,6 @@ USA.
 "prbfish"
 "prgdbm"
 "prmcrypt"
-"prmd5"
 "prmhash"
 "prpgsql"
 "pruxdld"
diff --git a/src/microcode/md5.c b/src/microcode/md5.c
new file mode 100644 (file)
index 0000000..2f797b4
--- /dev/null
@@ -0,0 +1,320 @@
+/*-
+ * Copyright (c) 2017 Taylor R. Campbell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define        _POSIX_C_SOURCE 200809L
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "md5.h"
+
+#define        secret  /* can't use in variable-time operations, should zero */
+
+void *(*volatile md5_explicit_memset_impl)(void *, int, size_t) = &memset;
+
+static void *
+explicit_memset(void *p, int c, size_t n)
+{
+
+       return (*md5_explicit_memset_impl)(p, c, n);
+}
+
+static inline uint32_t
+le32dec(const void *buf)
+{
+       const uint8_t *p = buf;
+       uint32_t v = 0;
+
+       v |= (uint32_t)p[0];
+       v |= (uint32_t)p[1] << 8;
+       v |= (uint32_t)p[2] << 16;
+       v |= (uint32_t)p[3] << 24;
+
+       return v;
+}
+
+static inline void
+le64enc(void *buf, uint64_t v)
+{
+       uint8_t *p = buf;
+
+       p[0] = (v >>  0) & 0xff;
+       p[1] = (v >>  8) & 0xff;
+       p[2] = (v >> 16) & 0xff;
+       p[3] = (v >> 24) & 0xff;
+       p[4] = (v >> 32) & 0xff;
+       p[5] = (v >> 40) & 0xff;
+       p[6] = (v >> 48) & 0xff;
+       p[7] = (v >> 56) & 0xff;
+}
+
+static inline uint32_t
+rol32(secret uint32_t x, unsigned c)
+{
+
+       return ((x << c) | (x >> (32 - c)));
+}
+
+#define        F(X,Y,Z)        (((X) & (Y)) | (~(X) & (Z)))
+#define        G(X,Y,Z)        (((X) & (Z)) | ((Y) & ~(Z)))
+#define        H(X,Y,Z)        ((X) ^ (Y) ^ (Z))
+#define        I(X,Y,Z)        ((Y) ^ ((X) | ~(Z)))
+#define        OP(f, a,b,c,d, k,s,v) \
+  (a) = (b) + rol32((a) + f(b,c,d) + le32dec(&M[4*(k)]) + UINT32_C(v), (s))
+
+static void
+md5_compress(secret uint32_t S[4], const secret uint8_t M[16*4])
+{
+       uint32_t A = S[0];
+       uint32_t B = S[1];
+       uint32_t C = S[2];
+       uint32_t D = S[3];
+
+       /* Magic constant i is integer part of 2^32 abs(sin(i)).  */
+
+       /* Round 1 */
+       OP(F, A,B,C,D,  0,  7, 0xd76aa478); /* 1 */
+       OP(F, D,A,B,C,  1, 12, 0xe8c7b756); /* 2 */
+       OP(F, C,D,A,B,  2, 17, 0x242070db); /* 3 */
+       OP(F, B,C,D,A,  3, 22, 0xc1bdceee); /* 4 */
+
+       OP(F, A,B,C,D,  4,  7, 0xf57c0faf); /* 5 */
+       OP(F, D,A,B,C,  5, 12, 0x4787c62a); /* 6 */
+       OP(F, C,D,A,B,  6, 17, 0xa8304613); /* 7 */
+       OP(F, B,C,D,A,  7, 22, 0xfd469501); /* 8 */
+
+       OP(F, A,B,C,D,  8,  7, 0x698098d8); /* 9 */
+       OP(F, D,A,B,C,  9, 12, 0x8b44f7af); /* 10 */
+       OP(F, C,D,A,B, 10, 17, 0xffff5bb1); /* 11 */
+       OP(F, B,C,D,A, 11, 22, 0x895cd7be); /* 12 */
+
+       OP(F, A,B,C,D, 12,  7, 0x6b901122); /* 13 */
+       OP(F, D,A,B,C, 13, 12, 0xfd987193); /* 14 */
+       OP(F, C,D,A,B, 14, 17, 0xa679438e); /* 15 */
+       OP(F, B,C,D,A, 15, 22, 0x49b40821); /* 16 */
+
+       /* Round 2 */
+       OP(G, A,B,C,D,  1,  5, 0xf61e2562); /* 17 */
+       OP(G, D,A,B,C,  6,  9, 0xc040b340); /* 18 */
+       OP(G, C,D,A,B, 11, 14, 0x265e5a51); /* 19 */
+       OP(G, B,C,D,A,  0, 20, 0xe9b6c7aa); /* 20 */
+
+       OP(G, A,B,C,D,  5,  5, 0xd62f105d); /* 21 */
+       OP(G, D,A,B,C, 10,  9, 0x02441453); /* 22 */
+       OP(G, C,D,A,B, 15, 14, 0xd8a1e681); /* 23 */
+       OP(G, B,C,D,A,  4, 20, 0xe7d3fbc8); /* 24 */
+
+       OP(G, A,B,C,D,  9,  5, 0x21e1cde6); /* 25 */
+       OP(G, D,A,B,C, 14,  9, 0xc33707d6); /* 26 */
+       OP(G, C,D,A,B,  3, 14, 0xf4d50d87); /* 27 */
+       OP(G, B,C,D,A,  8, 20, 0x455a14ed); /* 28 */
+
+       OP(G, A,B,C,D, 13,  5, 0xa9e3e905); /* 29 */
+       OP(G, D,A,B,C,  2,  9, 0xfcefa3f8); /* 30 */
+       OP(G, C,D,A,B,  7, 14, 0x676f02d9); /* 31 */
+       OP(G, B,C,D,A, 12, 20, 0x8d2a4c8a); /* 32 */
+
+       /* Round 3 */
+       OP(H, A,B,C,D,  5,  4, 0xfffa3942); /* 33 */
+       OP(H, D,A,B,C,  8, 11, 0x8771f681); /* 34 */
+       OP(H, C,D,A,B, 11, 16, 0x6d9d6122); /* 35 */
+       OP(H, B,C,D,A, 14, 23, 0xfde5380c); /* 36 */
+
+       OP(H, A,B,C,D,  1,  4, 0xa4beea44); /* 37 */
+       OP(H, D,A,B,C,  4, 11, 0x4bdecfa9); /* 38 */
+       OP(H, C,D,A,B,  7, 16, 0xf6bb4b60); /* 39 */
+       OP(H, B,C,D,A, 10, 23, 0xbebfbc70); /* 40 */
+
+       OP(H, A,B,C,D, 13,  4, 0x289b7ec6); /* 41 */
+       OP(H, D,A,B,C,  0, 11, 0xeaa127fa); /* 42 */
+       OP(H, C,D,A,B,  3, 16, 0xd4ef3085); /* 43 */
+       OP(H, B,C,D,A,  6, 23, 0x04881d05); /* 44 */
+
+       OP(H, A,B,C,D,  9,  4, 0xd9d4d039); /* 45 */
+       OP(H, D,A,B,C, 12, 11, 0xe6db99e5); /* 46 */
+       OP(H, C,D,A,B, 15, 16, 0x1fa27cf8); /* 47 */
+       OP(H, B,C,D,A,  2, 23, 0xc4ac5665); /* 48 */
+
+       /* Round 4 */
+       OP(I, A,B,C,D,  0,  6, 0xf4292244); /* 49 */
+       OP(I, D,A,B,C,  7, 10, 0x432aff97); /* 50 */
+       OP(I, C,D,A,B, 14, 15, 0xab9423a7); /* 51 */
+       OP(I, B,C,D,A,  5, 21, 0xfc93a039); /* 52 */
+
+       OP(I, A,B,C,D, 12,  6, 0x655b59c3); /* 53 */
+       OP(I, D,A,B,C,  3, 10, 0x8f0ccc92); /* 54 */
+       OP(I, C,D,A,B, 10, 15, 0xffeff47d); /* 55 */
+       OP(I, B,C,D,A,  1, 21, 0x85845dd1); /* 56 */
+
+       OP(I, A,B,C,D,  8,  6, 0x6fa87e4f); /* 57 */
+       OP(I, D,A,B,C, 15, 10, 0xfe2ce6e0); /* 58 */
+       OP(I, C,D,A,B,  6, 15, 0xa3014314); /* 59 */
+       OP(I, B,C,D,A, 13, 21, 0x4e0811a1); /* 60 */
+
+       OP(I, A,B,C,D,  4,  6, 0xf7537e82); /* 61 */
+       OP(I, D,A,B,C, 11, 10, 0xbd3af235); /* 62 */
+       OP(I, C,D,A,B,  2, 15, 0x2ad7d2bb); /* 63 */
+       OP(I, B,C,D,A,  9, 21, 0xeb86d391); /* 64 */
+
+       S[0] += A;
+       S[1] += B;
+       S[2] += C;
+       S[3] += D;
+}
+
+static const uint32_t md5_iv[4] = {
+       UINT32_C(0x67452301),
+       UINT32_C(0xefcdab89),
+       UINT32_C(0x98badcfe),
+       UINT32_C(0x10325476),
+};
+
+void
+md5_init(struct md5 *M)
+{
+
+       M->state[0] = md5_iv[0];
+       M->state[1] = md5_iv[1];
+       M->state[2] = md5_iv[2];
+       M->state[3] = md5_iv[3];
+       M->b = 0;
+       M->i = 0;
+}
+
+void
+md5_update(struct md5 *M, const void *buf, size_t len)
+{
+       const uint8_t *p = buf;
+       size_t n = len;
+
+       assert(M->i < sizeof(M->block));
+       assert(M->i == M->b % 64);
+
+       if (n < sizeof(M->block) - M->i) {
+               /* Can only partially fill the buffer.  */
+               (void)memcpy(&M->block[M->i], p, n);
+               M->b += n;
+               M->i += n;
+               assert(M->i < sizeof(M->block));
+               assert(M->i == M->b % 64);
+               return;
+       } else if (0 < M->i) {
+               /* Can fill the partial buffer, compress, and go on.  */
+               (void)memcpy(&M->block[M->i], p, sizeof(M->block) - M->i);
+               M->b += sizeof(M->block) - M->i;
+               md5_compress(M->state, M->block);
+               p += sizeof(M->block) - M->i;
+               n -= sizeof(M->block) - M->i;
+       }
+
+       /* At a block boundary.  Compress straight from the input.  */
+       while (sizeof(M->block) <= n) {
+               M->b += sizeof(M->block);
+               md5_compress(M->state, p);
+               p += sizeof(M->block);
+               n -= sizeof(M->block);
+       }
+
+       /* Put whatever's left in the buffer.  */
+       (void)memcpy(M->block, p, n);
+       M->b += n;
+       M->i = n;
+       assert(M->i < sizeof(M->block));
+       assert(M->i == M->b % 64);
+}
+
+void
+md5_final(struct md5 *M, uint8_t h[16])
+{
+
+       assert(M->i < sizeof(M->block));
+       assert(M->i == M->b % 64);
+
+       /* Append 1 bit.  */
+       M->block[M->i++] = 0x80;
+
+       /* If there's less than 8 bytes left, zero and go to new block.  */
+       if (sizeof(M->block) - 8 < M->i) {
+               while (M->i < sizeof(M->block)) {
+                       M->block[M->i++] = 0;
+               }
+               md5_compress(M->state, M->block);
+               M->i = 0;
+       }
+
+       /* Zero up to the last 64 bits.  */
+       if (M->i < sizeof(M->block) - 8) {
+               do {
+                       M->block[M->i++] = 0;
+               } while (M->i < sizeof(M->block) - 8);
+       }
+
+       /* Append length in bits.  */
+       assert(M->i == sizeof(M->block) - 8);
+       le64enc(&M->block[sizeof(M->block) - 8], 8*M->b);
+
+       /* Compress one last time.  */
+       md5_compress(M->state, M->block);
+
+       /* Reveal the complete state.  (Sorry, length-extension!)  */
+       (void)memcpy(h, M->state, sizeof(M->state));
+
+       /* Zero it all.  */
+       (void)explicit_memset(M, 0, sizeof M);
+}
+
+int
+md5_selftest(void)
+{
+       static const uint8_t expected[16] = {
+               0xbf, 0xd5, 0x08, 0x30, 0xba, 0x3e, 0xbc, 0x1d,
+               0xf2, 0x78, 0xc0, 0x26, 0x97, 0x79, 0xa0, 0x3e,
+       };
+       struct md5 m;
+       uint8_t s[256], actual[16];
+       unsigned i;
+
+       for (i = 0; i < 256; i++)
+               s[i] = i;
+
+       md5_init(&m);
+       for (i = 0; i < 256; i++) {
+               struct md5 m0;
+               uint8_t h[16];
+
+               md5_init(&m0);
+               md5_update(&m0, s, i/2);
+               md5_update(&m0, s + i/2, i);
+               md5_final(&m0, h);
+               md5_update(&m, h, 16);
+       }
+       md5_final(&m, actual);
+       if (memcmp(expected, actual, 16) != 0)
+               return -1;
+
+       return 0;
+}
diff --git a/src/microcode/md5.h b/src/microcode/md5.h
new file mode 100644 (file)
index 0000000..a6a835c
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2017 Taylor R. Campbell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef        MD5_H
+#define        MD5_H
+
+#include <stdint.h>
+
+#define        MD5_HASHLEN     16
+#define        MD5_BLOCKLEN    64
+
+struct md5 {
+       uint32_t        state[4];       /* MD5 state, {A,B,C,D} */
+       uint8_t         block[16*4];    /* partial message block */
+       uint64_t        b;              /* number of bytes hashed */
+       uint_fast8_t    i;              /* index of next byte in block */
+};
+
+void   md5_init(struct md5 *);
+void   md5_update(struct md5 *, const void *, size_t);
+void   md5_final(struct md5 *, uint8_t[16]);
+int    md5_selftest(void);
+
+extern void *(*volatile md5_explicit_memset_impl)(void *, int, size_t);
+
+#endif /* MD5_H */
index 32200341f4afea1053138db6bed45a30ae983837..cd7c3dd3ac09a828b51d1318cf561084889ff7d9 100644 (file)
@@ -29,57 +29,24 @@ USA.
 #include "scheme.h"
 #include "prims.h"
 
-#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_MD5_H)
-#  include <openssl/md5.h>
-#else
-#  ifdef HAVE_MD5_H
-#    include <md5.h>
-#  endif
-#endif
-
-#ifdef HAVE_LIBCRYPTO
-#  define MD5_INIT MD5_Init
-#  define MD5_UPDATE MD5_Update
-#  define MD5_FINAL MD5_Final
-#else
-#  define MD5_INIT MD5Init
-#  define MD5_UPDATE MD5Update
-#  define MD5_FINAL MD5Final
-#  define MD5_DIGEST_LENGTH 16
-#endif
+#include "md5.h"
 \f
 DEFINE_PRIMITIVE ("MD5", Prim_md5, 1, 1,
-  "(STRING)\n\
-Generate an MD5 digest of string.\n\
-The digest is returned as a 16-byte string.")
+  "(BYTEVECTOR)\n\
+Generate an MD5 digest of bytevector.\n\
+The digest is returned as a 16-byte bytevector.")
 {
   PRIMITIVE_HEADER (1);
-  CHECK_ARG (1, STRING_P);
+  CHECK_ARG (1, BYTEVECTOR_P);
   {
-    SCHEME_OBJECT string = (ARG_REF (1));
-    SCHEME_OBJECT result = (allocate_string (16));
-    unsigned char * scan_result = (STRING_BYTE_PTR (result));
-    MD5_CTX context;
-#ifdef HAVE_LIBCRYPTO
-    unsigned char digest [MD5_DIGEST_LENGTH];
-#endif
-    unsigned char * scan_digest;
-    unsigned char * end_digest;
-
-    MD5_INIT (&context);
-    MD5_UPDATE ((&context),
-               (STRING_POINTER (string)),
-               (STRING_LENGTH (string)));
-#ifdef HAVE_LIBCRYPTO
-    MD5_FINAL (digest, (&context));
-    scan_digest = digest;
-#else
-    MD5_FINAL (&context);
-    scan_digest = (context . digest);
-#endif
-    end_digest = (scan_digest + MD5_DIGEST_LENGTH);
-    while (scan_digest < end_digest)
-      (*scan_result++) = (*scan_digest++);
+    SCHEME_OBJECT bytevector = (ARG_REF (1));
+    SCHEME_OBJECT result = (allocate_bytevector (16));
+    struct md5 context;
+    md5_init (&context);
+    md5_update ((&context),
+               (BYTEVECTOR_POINTER (bytevector)),
+               (BYTEVECTOR_LENGTH (bytevector)));
+    md5_final ((&context), (BYTEVECTOR_POINTER (result)));
     PRIMITIVE_RETURN (result);
   }
 }
@@ -90,34 +57,34 @@ Create and return an MD5 digest context.")
 {
   PRIMITIVE_HEADER (0);
   {
-    SCHEME_OBJECT context = (allocate_string (sizeof (MD5_CTX)));
-    MD5_INIT ((MD5_CTX *) (STRING_POINTER (context)));
+    SCHEME_OBJECT context = (allocate_bytevector (sizeof (struct md5)));
+    md5_init ((struct md5 *) (BYTEVECTOR_POINTER (context)));
     PRIMITIVE_RETURN (context);
   }
 }
 
-static MD5_CTX *
+static struct md5 *
 md5_context_arg (int arg)
 {
-  CHECK_ARG (arg, STRING_P);
-  if ((STRING_LENGTH (ARG_REF (arg))) != (sizeof (MD5_CTX)))
+  CHECK_ARG (arg, BYTEVECTOR_P);
+  if ((BYTEVECTOR_LENGTH (ARG_REF (arg))) != (sizeof (struct md5)))
     error_bad_range_arg (arg);
-  return ((MD5_CTX *) (STRING_POINTER (ARG_REF (arg))));
+  return ((struct md5 *) (BYTEVECTOR_POINTER (ARG_REF (arg))));
 }
 
 DEFINE_PRIMITIVE ("MD5-UPDATE", Prim_md5_update, 4, 4,
-  "(CONTEXT STRING START END)\n\
-Update CONTEXT with the contents of the substring (STRING,START,END).")
+  "(CONTEXT BYTEVECTOR START END)\n\
+Update CONTEXT with the contents of the subbytevector (BYTEVECTOR,START,END).")
 {
   PRIMITIVE_HEADER (4);
-  CHECK_ARG (2, STRING_P);
+  CHECK_ARG (2, BYTEVECTOR_P);
   {
-    SCHEME_OBJECT string = (ARG_REF (2));
+    SCHEME_OBJECT bytevector = (ARG_REF (2));
     unsigned long end
-      = (arg_ulong_index_integer (4, ((STRING_LENGTH (string)) + 1)));
+      = (arg_ulong_index_integer (4, ((BYTEVECTOR_LENGTH (bytevector)) + 1)));
     unsigned long start = (arg_ulong_index_integer (3, (end + 1)));
-    MD5_UPDATE ((md5_context_arg (1)),
-               (STRING_LOC (string, start)),
+    md5_update ((md5_context_arg (1)),
+               (BYTEVECTOR_LOC (bytevector, start)),
                (end - start));
     PRIMITIVE_RETURN (UNSPECIFIC);
   }
@@ -125,59 +92,13 @@ Update CONTEXT with the contents of the substring (STRING,START,END).")
 
 DEFINE_PRIMITIVE ("MD5-FINAL", Prim_md5_final, 1, 1,
   "(CONTEXT)\n\
-Finalize CONTEXT and return the digest as a 16-byte string.")
+Finalize CONTEXT and return the digest as a 16-byte bytevector.")
 {
   PRIMITIVE_HEADER (1);
   {
-    MD5_CTX * context = (md5_context_arg (1));
-#ifdef HAVE_LIBCRYPTO
-    unsigned char digest [MD5_DIGEST_LENGTH];
-    MD5_FINAL (digest, context);
-#else
-    MD5_FINAL (context);
-#endif
-    {
-      SCHEME_OBJECT result = (allocate_string (MD5_DIGEST_LENGTH));
-      unsigned char * scan_result = (STRING_BYTE_PTR (result));
-#ifdef HAVE_LIBCRYPTO
-      unsigned char * scan_digest = digest;
-#else
-      unsigned char * scan_digest = (context -> digest);
-#endif
-      unsigned char * end_digest = (scan_digest + MD5_DIGEST_LENGTH);
-      while (scan_digest < end_digest)
-       (*scan_result++) = (*scan_digest++);
-      PRIMITIVE_RETURN (result);
-    }
+    struct md5 * context = (md5_context_arg (1));
+    SCHEME_OBJECT result = (allocate_bytevector (MD5_HASHLEN));
+    md5_final (context, (BYTEVECTOR_POINTER (result)));
+    PRIMITIVE_RETURN (result);
   }
 }
-
-#ifdef COMPILE_AS_MODULE
-
-const char *
-dload_initialize_file (void)
-{
-  declare_primitive
-    ("MD5", Prim_md5, 1, 1,
-     "(STRING)\n\
-Generate an MD5 digest of string.\n\
-The digest is returned as a 16-byte string.");
-
-  declare_primitive
-    ("MD5-INIT", Prim_md5_init, 0, 0,
-     "()\n\
-Create and return an MD5 digest context.");
-
-  declare_primitive
-    ("MD5-UPDATE", Prim_md5_update, 4, 4,
-     "(CONTEXT STRING START END)\n\
-Update CONTEXT with the contents of the substring (STRING,START,END).");
-
-  declare_primitive
-    ("MD5-FINAL", Prim_md5_final, 1, 1,
-     "(CONTEXT)\n\
-Finalize CONTEXT and return the digest as a 16-byte string.");
-  return "#prmd5";
-}
-
-#endif /* COMPILE_AS_MODULE */
index 4bd204aba9fcc2dafb9a785eb619c4b3980853a6..14eaf2bd4e73240f9c37ea3e5462e32360782b43 100644 (file)
@@ -256,19 +256,9 @@ USA.
 ;;;; MD5
 
 (define (md5-available?)
-  (or (mhash-available?)
-      (%md5-available?)))
-
-(define (%md5-available?)
-  (load-library-object-file "prmd5" #f)
-  (implemented-primitive-procedure? (ucode-primitive md5-init 0)))
+  #t)
 
 (define (md5-file filename)
-  (cond ((mhash-available?) (mhash-file 'md5 filename))
-       ((%md5-available?) (%md5-file filename))
-       (else (error "This Scheme system was built without MD5 support."))))
-
-(define (%md5-file filename)
   (call-with-binary-input-file filename
     (port-consumer (ucode-primitive md5-init 0)
                   (ucode-primitive md5-update 4)
@@ -278,11 +268,6 @@ USA.
   (md5-bytevector (string->utf8 string start end)))
 
 (define (md5-bytevector bytes #!optional start end)
-  (cond ((mhash-available?) (mhash-bytevector 'md5 bytes start end))
-       ((%md5-available?) (%md5-bytevector bytes start end))
-       (else (error "This Scheme system was built without MD5 support."))))
-
-(define (%md5-bytevector bytes #!optional start end)
   (let ((end (fix:end-index end (bytevector-length bytes) 'md5-bytevector))
        (start (fix:start-index start end 'md5-bytevector))
        (context ((ucode-primitive md5-init 0))))
index 23976a39f77e13f45590d341de8561624969e854..48ea077bc6bb5ac397809a966542c37d99882494 100644 (file)
@@ -62,6 +62,7 @@ USA.
     "runtime/test-genmult"
     "runtime/test-hash-table"
     "runtime/test-integer-bits"
+    "runtime/test-md5"
     "runtime/test-mime-codec"
     ("runtime/test-parametric-predicate" (runtime parametric-predicate))
     ("runtime/test-predicate-lattice" (runtime))
diff --git a/tests/runtime/test-md5.scm b/tests/runtime/test-md5.scm
new file mode 100644 (file)
index 0000000..8703967
--- /dev/null
@@ -0,0 +1,44 @@
+#| -*-Scheme-*-
+
+Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+    1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
+    2017 Massachusetts Institute of Technology
+
+This file is part of MIT/GNU Scheme.
+
+MIT/GNU Scheme is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+MIT/GNU Scheme is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with MIT/GNU Scheme; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+USA.
+
+|#
+
+;;;; Tests of MD5
+
+(define-test 'MD5
+  (lambda ()
+    (let ((bv (make-bytevector 256)))
+      (do ((i 0 (+ i 1))) ((>= i 256))
+        (bytevector-u8-set! bv i i))
+      (let ((h (make-bytevector (* 16 256))))
+        (let loop ((i 0))
+          (if (< i 256)
+              (let ((hi (md5-bytevector bv 0 i)))
+                (bytevector-copy! h (* 16 i) hi)
+                (loop (+ i 1)))
+              (assert-equal (md5-bytevector h)
+                            #u8(
+                                #xbf #xd5 #x08 #x30 #xba #x3e #xbc #x1d
+                                #xf2 #x78 #xc0 #x26 #x97 #x79 #xa0 #x3e
+                                ))))))))