diff options
-rw-r--r-- | LICENSING | 5 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | TODO.md | 2 | ||||
-rw-r--r-- | alg-md5.c | 539 | ||||
-rw-r--r-- | alg-md5.h | 79 | ||||
-rw-r--r-- | crypt-md5.c | 47 | ||||
-rw-r--r-- | crypt-port.h | 6 | ||||
-rw-r--r-- | crypt-sunmd5.c | 20 | ||||
-rw-r--r-- | test-alg-md5.c | 24 |
9 files changed, 349 insertions, 375 deletions
@@ -13,7 +13,7 @@ source tree. For specific licensing terms consult the files themselves. * Copyright Free Software Foundation, Inc.; LGPL (v2.1 or later): crypt.h, crypt-obsolete.h, crypt-private.h - alg-md5.h, alg-md5.c, crypt-md5.c, + crypt-md5.c, test-crypt-badsalt.c, test-crypt-nonnull.c * Copyright David Burren et al.; 3-clause BSD: @@ -24,7 +24,8 @@ source tree. For specific licensing terms consult the files themselves. crypt-sha256.c, crypt-sha512.c * Public domain, written by Solar Designer et al.: - alg-md4.h, alg-md4.c, crypt-bcrypt.c, crypt-gensalt.c, test-crypt-bcrypt.c + alg-md4.h, alg-md4.c, alg-md5.h, alg-md5.c, + crypt-bcrypt.c, crypt-gensalt.c, test-crypt-bcrypt.c * Copyright Solar Designer, Colin Percival; 0-clause BSD: alg-yescrypt-common.c, alg-yescrypt-platform.c @@ -8,6 +8,8 @@ Version 4.2.3 tarball release, use './bootstrap' to create the configure script. * Use sha512 implementation from Colin Percival. Thus we now have a sha512 implementation under the BSD license. +* Use md5 implementation from Alexander Peslyak. Thus we now have a + md5 implementation in the public domain. Version 4.2.2 * Convert existing manpages to BSD mdoc format. @@ -95,8 +95,6 @@ It was last updated 20 October 2018. at it, and no destructor function * Permissive relicensing, to encourage use beyond the GNU ecosystem? - * Replace remaining (L)GPLed crypto primitives (MD5) with - permissively licensed equivalents (e.g. from Openwall) * Replace crypt-md5.c with original md5crypt from FreeBSD? * Other files subject to the (L)GPL are crypt.c, crypt-static.c, crypt-gensalt-static.c, crypt-obsolete.h, crypt-port.h, @@ -1,308 +1,291 @@ -/* Functions to compute MD5 message digest of files or memory blocks. - according to the definition of MD5 in RFC 1321 from April 1992. - - Copyright (C) 1995-2017 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - This library 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see - <https://www.gnu.org/licenses/>. */ - -/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer <solar at openwall.com> + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ #include "crypt-port.h" -#include "alg-md5.h" -#include "byteorder.h" #if INCLUDE_md5 || INCLUDE_sunmd5 -static void md5_process_block (const void *buffer, size_t len, - struct md5_ctx *ctx); +#include "alg-md5.h" -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -void -md5_init_ctx (struct md5_ctx *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * MD5_u32plus. In practice, this problem may occur if these MD5 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD5 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(const MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif - ctx->total = 0; - ctx->buflen = 0; +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; } -/* Put result from CTX in first 16 bytes following RESBUF. The result - will be in little endian byte order. */ -static void * -md5_read_ctx (struct md5_ctx *ctx, void *resbuf) +void MD5_Init(MD5_CTX *ctx) { - unsigned char *buf = resbuf; - cpu_to_le32 (buf + 0, ctx->A); - cpu_to_le32 (buf + 4, ctx->B); - cpu_to_le32 (buf + 8, ctx->C); - cpu_to_le32 (buf + 12, ctx->D); - XCRYPT_SECURE_MEMSET (ctx, sizeof(*ctx)); - return resbuf; -} + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. */ + ctx->lo = 0; + ctx->hi = 0; +} -void * -md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +void MD5_Update(MD5_CTX *ctx, const void *data, size_t size) { - /* Take yet unprocessed bytes into account. */ - uint32_t bytes = ctx->buflen; - size_t pad; + MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += (MD5_u32plus) size >> 29; - /* Now count remaining bytes. */ - ctx->total += bytes; + used = saved_lo & 0x3f; - pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + if (used) { + available = 64 - used; - /* The first byte of padding should be 0x80 and the rest should be - zero. (RFC 1321, 3.1: Step 1) */ - ctx->buffer[bytes] = 0x80u; - XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1); + if (size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } - /* Put the 64-bit file length in little-endian *bits* at the end of - the buffer. */ - cpu_to_le64 (&ctx->buffer[bytes + pad], ctx->total << 3); + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } - /* Process last bytes. */ - md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + if (size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } - return md5_read_ctx (ctx, resbuf); + memcpy(ctx->buffer, data, size); } +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); -void -md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +void MD5_Final(uint8_t result[16], MD5_CTX *ctx) { - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - uint32_t left_over = ctx->buflen; - uint32_t add = 128 - left_over > len ? (uint32_t)len : 128 - left_over; - - memcpy (&ctx->buffer[left_over], buffer, add); - ctx->buflen += add; - - if (ctx->buflen > 64) - { - md5_process_block (ctx->buffer, ctx->buflen & ~63u, ctx); - - ctx->buflen &= 63; - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63u], - ctx->buflen); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len > 64) - { - md5_process_block (buffer, len & ~63u, ctx); - buffer = (const char *) buffer + (len & ~63u); - len &= 63; - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - uint32_t left_over = ctx->buflen; - - memcpy (&ctx->buffer[left_over], buffer, len); - left_over += (uint32_t)len; - if (left_over >= 64) - { - md5_process_block (ctx->buffer, 64, ctx); - left_over -= 64; - memcpy (ctx->buffer, &ctx->buffer[64], left_over); - } - ctx->buflen = left_over; - } -} + unsigned long used, available; + used = ctx->lo & 0x3f; -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) + ctx->buffer[used++] = 0x80; -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. */ + available = 64 - used; -static void -md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - const unsigned char *p = buffer; - const unsigned char *endp = p + len; - uint32_t A = ctx->A; - uint32_t B = ctx->B; - uint32_t C = ctx->C; - uint32_t D = ctx->D; - - /* First increment the byte count. RFC 1321 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. */ - ctx->total += len; - - /* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - while (p < endp) - { - uint32_t *cwp = ctx->correct_words; - uint32_t A_save = A; - uint32_t B_save = B; - uint32_t C_save = C; - uint32_t D_save = D; - - /* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - uint32_t word = le32_to_cpu (p); \ - p += 4; \ - *cwp++ = word; \ - a += FF (b, c, d) + word + T; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - - /* It is unfortunate that C does not provide an operator for - cyclic rotation. Hope the C compiler is smart enough. */ -#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - - /* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - - /* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + ctx->correct_words[k] + T; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - } - - /* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; + if (available < 8) { + XCRYPT_SECURE_MEMSET(&ctx->buffer[used], available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + XCRYPT_SECURE_MEMSET(&ctx->buffer[used], available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + XCRYPT_SECURE_MEMSET(ctx, sizeof(*ctx)); } #endif @@ -1,52 +1,43 @@ -/* Declaration of functions and data types used for MD5 sum computing - library functions. - - Copyright (C) 1995-2017 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - This library 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see - <https://www.gnu.org/licenses/>. */ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer <solar at openwall.com> + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ #ifndef _CRYPT_ALG_MD5_H #define _CRYPT_ALG_MD5_H 1 -/* Structure to save state of computation between the single steps. */ -struct md5_ctx -{ - uint32_t A; - uint32_t B; - uint32_t C; - uint32_t D; - - uint64_t total; - uint32_t buflen; - uint32_t correct_words[16]; - unsigned char buffer[128]; -}; - -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -extern void md5_init_ctx (struct md5_ctx *ctx); +/* Any 32-bit or wider unsigned integer data type will do */ +typedef uint32_t MD5_u32plus; -/* Starting with the result of former calls of this function (or the - initialization function) update the context for the next LEN bytes - starting at BUFFER. LEN does not need to be a multiple of 64. */ -extern void md5_process_bytes (const void *buffer, size_t len, - struct md5_ctx *ctx); +typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + uint8_t buffer[64]; + MD5_u32plus block[16]; +} MD5_CTX; -/* Process the remaining bytes in the buffer and write the finalized - hash to RESBUF, which should point to 16 bytes of storage. All - data written to CTX is erased before returning from the function. */ -extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf); +extern void MD5_Init(MD5_CTX *ctx); +extern void MD5_Update(MD5_CTX *ctx, const void *data, size_t size); +extern void MD5_Final(uint8_t result[16], MD5_CTX *ctx); #endif /* alg-md5.h */ diff --git a/crypt-md5.c b/crypt-md5.c index f64b6fc..108c31c 100644 --- a/crypt-md5.c +++ b/crypt-md5.c @@ -50,7 +50,7 @@ static_assert (MD5_HASH_LENGTH <= CRYPT_OUTPUT_SIZE, /* An md5_buffer holds all of the sensitive intermediate data. */ struct md5_buffer { - struct md5_ctx ctx; + MD5_CTX ctx; uint8_t result[16]; }; @@ -74,7 +74,7 @@ crypt_md5_rn (const char *phrase, size_t phr_size, } struct md5_buffer *buf = scratch; - struct md5_ctx *ctx = &buf->ctx; + MD5_CTX *ctx = &buf->ctx; uint8_t *result = buf->result; char *cp = (char *)output; const char *salt = setting; @@ -99,40 +99,40 @@ crypt_md5_rn (const char *phrase, size_t phr_size, /* Compute alternate MD5 sum with input PHRASE, SALT, and PHRASE. The final result will be added to the first context. */ - md5_init_ctx (ctx); + MD5_Init (ctx); /* Add phrase. */ - md5_process_bytes (phrase, phr_size, ctx); + MD5_Update (ctx, phrase, phr_size); /* Add salt. */ - md5_process_bytes (salt, salt_size, ctx); + MD5_Update (ctx, salt, salt_size); /* Add phrase again. */ - md5_process_bytes (phrase, phr_size, ctx); + MD5_Update (ctx, phrase, phr_size); /* Now get result of this (16 bytes). */ - md5_finish_ctx (ctx, result); + MD5_Final (result, ctx); /* Prepare for the real work. */ - md5_init_ctx (ctx); + MD5_Init (ctx); /* Add the phrase string. */ - md5_process_bytes (phrase, phr_size, ctx); + MD5_Update (ctx, phrase, phr_size); /* Because the SALT argument need not always have the salt prefix we add it separately. */ - md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1, ctx); + MD5_Update (ctx, md5_salt_prefix, sizeof (md5_salt_prefix) - 1); /* The last part is the salt string. This must be at most 8 characters and it ends at the first `$' character (for compatibility with existing implementations). */ - md5_process_bytes (salt, salt_size, ctx); + MD5_Update (ctx, salt, salt_size); /* Add for any character in the phrase one byte of the alternate sum. */ for (cnt = phr_size; cnt > 16; cnt -= 16) - md5_process_bytes (result, 16, ctx); - md5_process_bytes (result, cnt, ctx); + MD5_Update (ctx, result, 16); + MD5_Update (ctx, result, cnt); /* For the following code we need a NUL byte. */ *result = '\0'; @@ -142,11 +142,10 @@ crypt_md5_rn (const char *phrase, size_t phr_size, bit the first character of the phrase. This does not seem to be what was intended but we have to follow this to be compatible. */ for (cnt = phr_size; cnt > 0; cnt >>= 1) - md5_process_bytes ((cnt & 1) != 0 ? (const char *) result : phrase, 1, - ctx); + MD5_Update (ctx, (cnt & 1) != 0 ? (const char *) result : phrase, 1); /* Create intermediate result. */ - md5_finish_ctx (ctx, result); + MD5_Final (result, ctx); /* Now comes another weirdness. In fear of password crackers here comes a quite long loop which just processes the output of the @@ -154,30 +153,30 @@ crypt_md5_rn (const char *phrase, size_t phr_size, for (cnt = 0; cnt < 1000; ++cnt) { /* New context. */ - md5_init_ctx (ctx); + MD5_Init (ctx); /* Add phrase or last result. */ if ((cnt & 1) != 0) - md5_process_bytes (phrase, phr_size, ctx); + MD5_Update (ctx, phrase, phr_size); else - md5_process_bytes (result, 16, ctx); + MD5_Update (ctx, result, 16); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) - md5_process_bytes (salt, salt_size, ctx); + MD5_Update (ctx, salt, salt_size); /* Add phrase for numbers not divisible by 7. */ if (cnt % 7 != 0) - md5_process_bytes (phrase, phr_size, ctx); + MD5_Update (ctx, phrase, phr_size); /* Add phrase or last result. */ if ((cnt & 1) != 0) - md5_process_bytes (result, 16, ctx); + MD5_Update (ctx, result, 16); else - md5_process_bytes (phrase, phr_size, ctx); + MD5_Update (ctx, phrase, phr_size); /* Create intermediate result. */ - md5_finish_ctx (ctx, result); + MD5_Final (result, ctx); } /* Now we can construct the result string. It consists of three diff --git a/crypt-port.h b/crypt-port.h index a2c64b3..2571c94 100644 --- a/crypt-port.h +++ b/crypt-port.h @@ -247,9 +247,9 @@ _xcrypt_strcpy_or_abort (void *dst, const size_t d_size, #endif #if INCLUDE_md5 || INCLUDE_sunmd5 -#define md5_finish_ctx _crypt_md5_finish_ctx -#define md5_init_ctx _crypt_md5_init_ctx -#define md5_process_bytes _crypt_md5_process_bytes +#define MD5_Init _crypt_MD5_Init +#define MD5_Update _crypt_MD5_Update +#define MD5_Final _crypt_MD5_Final #endif #if INCLUDE_sha1 diff --git a/crypt-sunmd5.c b/crypt-sunmd5.c index 9f76ed1..7a30aae 100644 --- a/crypt-sunmd5.c +++ b/crypt-sunmd5.c @@ -165,7 +165,7 @@ crypt_sunmd5_rn (const char *phrase, size_t phr_size, { struct crypt_sunmd5_scratch { - struct md5_ctx ctx; + MD5_CTX ctx; uint8_t dg[16]; char rn[16]; }; @@ -238,27 +238,27 @@ crypt_sunmd5_rn (const char *phrase, size_t phr_size, struct crypt_sunmd5_scratch *s = scratch; /* Initial round. */ - md5_init_ctx (&s->ctx); - md5_process_bytes (phrase, phr_size, &s->ctx); - md5_process_bytes (setting, saltlen, &s->ctx); - md5_finish_ctx (&s->ctx, s->dg); + MD5_Init (&s->ctx); + MD5_Update (&s->ctx, phrase, phr_size); + MD5_Update (&s->ctx, setting, saltlen); + MD5_Final (s->dg, &s->ctx); /* Stretching rounds. */ for (unsigned int i = 0; i < nrounds; i++) { - md5_init_ctx (&s->ctx); + MD5_Init (&s->ctx); - md5_process_bytes (s->dg, sizeof s->dg, &s->ctx); + MD5_Update (&s->ctx, s->dg, sizeof s->dg); /* The trailing nul is intentionally included. */ if (muffet_coin_toss (s->dg, i)) - md5_process_bytes (hamlet_quotation, sizeof hamlet_quotation, &s->ctx); + MD5_Update (&s->ctx, hamlet_quotation, sizeof hamlet_quotation); int nwritten = snprintf (s->rn, sizeof s->rn, "%u", i); assert (nwritten >= 1 && (unsigned int)nwritten + 1 <= sizeof s->rn); - md5_process_bytes (s->rn, (unsigned int)nwritten, &s->ctx); + MD5_Update (&s->ctx, s->rn, (unsigned int)nwritten); - md5_finish_ctx (&s->ctx, s->dg); + MD5_Final (s->dg, &s->ctx); } memcpy (output, setting, saltlen); diff --git a/test-alg-md5.c b/test-alg-md5.c index dabc6ba..21c4309 100644 --- a/test-alg-md5.c +++ b/test-alg-md5.c @@ -52,7 +52,7 @@ static const struct static void report_failure(int n, const char *tag, - const char expected[16], const char actual[16]) + const char expected[16], uint8_t actual[16]) { int i; printf ("FAIL: test %d (%s):\n exp:", n, tag); @@ -76,27 +76,27 @@ report_failure(int n, const char *tag, int main (void) { - struct md5_ctx ctx; - char sum[16]; + MD5_CTX ctx; + uint8_t sum[16]; int result = 0; int cnt; int i; for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) { - md5_init_ctx (&ctx); - md5_process_bytes (tests[cnt].input, strlen (tests[cnt].input), &ctx); - md5_finish_ctx (&ctx, sum); + MD5_Init (&ctx); + MD5_Update (&ctx, tests[cnt].input, strlen (tests[cnt].input)); + MD5_Final (sum, &ctx); if (memcmp (tests[cnt].result, sum, 16)) { report_failure (cnt, "all at once", tests[cnt].result, sum); result = 1; } - md5_init_ctx (&ctx); + MD5_Init (&ctx); for (i = 0; tests[cnt].input[i] != '\0'; ++i) - md5_process_bytes (&tests[cnt].input[i], 1, &ctx); - md5_finish_ctx (&ctx, sum); + MD5_Update (&ctx, &tests[cnt].input[i], 1); + MD5_Final (sum, &ctx); if (memcmp (tests[cnt].result, sum, 16)) { report_failure (cnt, "byte by byte", tests[cnt].result, sum); @@ -108,10 +108,10 @@ main (void) <https://www.nist.gov/itl/ssd/software-quality-group/nsrl-test-data>. */ char buf[1000]; memset (buf, 'a', sizeof (buf)); - md5_init_ctx (&ctx); + MD5_Init (&ctx); for (i = 0; i < 1000; ++i) - md5_process_bytes (buf, sizeof (buf), &ctx); - md5_finish_ctx (&ctx, sum); + MD5_Update (&ctx, buf, sizeof (buf)); + MD5_Final (sum, &ctx); static const char expected[64] = "\x77\x07\xd6\xae\x4e\x02\x7c\x70\xee\xa2\xa9\x35\xc2\x29\x6f\x21"; if (memcmp (expected, sum, 16) != 0) |