From 61078c44a19250ad7383e00e587eabe888c8f252 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Sat, 4 Nov 2017 02:56:22 +0000 Subject: [PATCH] Eliminate MD5 as a loadable microcode module. Unconditionally include a new portable C implementation. --- src/microcode/configure.ac | 9 +- src/microcode/makegen/Makefile.in.in | 4 - src/microcode/makegen/files-core.scm | 2 + src/microcode/makegen/files-optional.scm | 1 - src/microcode/md5.c | 320 +++++++++++++++++++++++ src/microcode/md5.h | 49 ++++ src/microcode/prmd5.c | 141 +++------- src/runtime/crypto.scm | 17 +- tests/check.scm | 1 + tests/runtime/test-md5.scm | 44 ++++ 10 files changed, 449 insertions(+), 139 deletions(-) create mode 100644 src/microcode/md5.c create mode 100644 src/microcode/md5.h create mode 100644 tests/runtime/test-md5.scm diff --git a/src/microcode/configure.ac b/src/microcode/configure.ac index e30134b52..466847458 100644 --- a/src/microcode/configure.ac +++ b/src/microcode/configure.ac @@ -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 & , 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]) diff --git a/src/microcode/makegen/Makefile.in.in b/src/microcode/makegen/Makefile.in.in index 73709e2ed..c7847d20b 100644 --- a/src/microcode/makegen/Makefile.in.in +++ b/src/microcode/makegen/Makefile.in.in @@ -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) diff --git a/src/microcode/makegen/files-core.scm b/src/microcode/makegen/files-core.scm index a78032e7e..fa356f795 100644 --- a/src/microcode/makegen/files-core.scm +++ b/src/microcode/makegen/files-core.scm @@ -57,6 +57,7 @@ USA. "list" "lookprm" "lookup" +"md5" "memmag" "missing" "obstack" @@ -67,6 +68,7 @@ USA. "prim" "primutl" "prkeccak" +"prmd5" "ptrvec" "purify" "purutl" diff --git a/src/microcode/makegen/files-optional.scm b/src/microcode/makegen/files-optional.scm index f063d6d9f..6e9666c0f 100644 --- a/src/microcode/makegen/files-optional.scm +++ b/src/microcode/makegen/files-optional.scm @@ -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 index 000000000..2f797b4db --- /dev/null +++ b/src/microcode/md5.c @@ -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 +#include +#include + +#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 index 000000000..a6a835ce9 --- /dev/null +++ b/src/microcode/md5.h @@ -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 + +#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 */ diff --git a/src/microcode/prmd5.c b/src/microcode/prmd5.c index 32200341f..cd7c3dd3a 100644 --- a/src/microcode/prmd5.c +++ b/src/microcode/prmd5.c @@ -29,57 +29,24 @@ USA. #include "scheme.h" #include "prims.h" -#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_MD5_H) -# include -#else -# ifdef HAVE_MD5_H -# include -# 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" 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 */ diff --git a/src/runtime/crypto.scm b/src/runtime/crypto.scm index 4bd204aba..14eaf2bd4 100644 --- a/src/runtime/crypto.scm +++ b/src/runtime/crypto.scm @@ -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)))) diff --git a/tests/check.scm b/tests/check.scm index 23976a39f..48ea077bc 100644 --- a/tests/check.scm +++ b/tests/check.scm @@ -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 index 000000000..8703967fe --- /dev/null +++ b/tests/runtime/test-md5.scm @@ -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 + )))))))) -- 2.25.1