From 69cf6a7ea00224eed555e3c88db5c8de17d01f3c Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Fri, 22 Aug 2008 17:50:37 +0000 Subject: [PATCH] compact md5 implementation --- include/md5.h | 107 ++++------ src/md5.c | 551 +++++++++++++++++--------------------------------- 2 files changed, 217 insertions(+), 441 deletions(-) diff --git a/include/md5.h b/include/md5.h index 089e171..28f7175 100644 --- a/include/md5.h +++ b/include/md5.h @@ -1,82 +1,43 @@ -/* $PostgreSQL: pgsql/contrib/pgcrypto/md5.h,v 1.9 2005/10/15 02:49:06 momjian Exp $ */ -/* $KAME: md5.h,v 1.3 2000/02/22 14:01:18 itojun Exp $ */ - /* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + * MD5 implementation based on RFC1321. + * + * Copyright (c) 2008 Marko Kreen, Skype Technologies OÜ + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _NETINET6_MD5_H_ -#define _NETINET6_MD5_H_ - -#define MD5_BUFLEN 64 -#define MD5_DIGEST_LENGTH 16 - -typedef struct -{ - union - { - uint32_t md5_state32[4]; - uint8_t md5_state8[16]; - } md5_st; - -#define md5_sta md5_st.md5_state32[0] -#define md5_stb md5_st.md5_state32[1] -#define md5_stc md5_st.md5_state32[2] -#define md5_std md5_st.md5_state32[3] -#define md5_st8 md5_st.md5_state8 +#ifndef __MD5_H__ +#define __MD5_H__ - union - { - uint64_t md5_count64; - uint8_t md5_count8[8]; - } md5_count; -#define md5_n md5_count.md5_count64 -#define md5_n8 md5_count.md5_count8 +#define MD5_BLOCK_LENGTH 64 +#define MD5_DIGEST_LENGTH 16 - unsigned md5_i; - uint8_t md5_buf[MD5_BUFLEN]; -} md5_ctxt; +struct md5_ctx { + uint64_t nbytes; + uint32_t a, b, c, d; + uint32_t buf[16]; +}; -extern void md5_init(md5_ctxt *); -extern void md5_loop(md5_ctxt *, const uint8_t *, unsigned int); -extern void md5_pad(md5_ctxt *); -extern void md5_result(uint8_t *, md5_ctxt *); +void md5_reset(struct md5_ctx *ctx); +void md5_update(struct md5_ctx *ctx, const void *data, unsigned int len); +void md5_final(uint8_t *dst, struct md5_ctx *ctx); -/* compatibility with OpenSSL */ -#define MD5_CTX md5_ctxt -#define MD5_Init(x) md5_init((x)) -#define MD5_Update(x, y, z) md5_loop((x), (void*)(y), (z)) -#define MD5_Final(x, y) \ -do { \ - md5_pad((y)); \ - md5_result((x), (y)); \ -} while (0) +#ifndef AVOID_MD5_COMPAT +typedef struct md5_ctx MD5_CTX; +#define MD5_Init(c) md5_reset(c) +#define MD5_Update(c, d, l) md5_update(c, d, l) +#define MD5_Final(d, c) md5_final(d, c) +#endif -#endif /* ! _NETINET6_MD5_H_ */ +#endif -/* vi: set ts=4: */ diff --git a/src/md5.c b/src/md5.c index e1beb31..f76dd9e 100644 --- a/src/md5.c +++ b/src/md5.c @@ -1,397 +1,212 @@ -/* $KAME: md5.c,v 1.3 2000/02/22 14:01:17 itojun Exp $ */ - /* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. - * - * $PostgreSQL: pgsql/contrib/pgcrypto/md5.c,v 1.14 2007/04/06 05:36:50 tgl Exp $ + * MD5 implementation based on RFC1321. + * + * Copyright (c) 2008 Marko Kreen, Skype Technologies OÜ + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "bouncer.h" - +#include "system.h" #include "md5.h" -#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) - -#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 ROUND1(a, b, c, d, k, s, i) \ -do { \ - (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ - (a) = SHIFT((a), (s)); \ - (a) = (b) + (a); \ -} while (0) - -#define ROUND2(a, b, c, d, k, s, i) \ -do { \ - (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ - (a) = SHIFT((a), (s)); \ - (a) = (b) + (a); \ -} while (0) - -#define ROUND3(a, b, c, d, k, s, i) \ -do { \ - (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ - (a) = SHIFT((a), (s)); \ - (a) = (b) + (a); \ -} while (0) - -#define ROUND4(a, b, c, d, k, s, i) \ -do { \ - (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ - (a) = SHIFT((a), (s)); \ - (a) = (b) + (a); \ -} while (0) - -#define Sa 7 -#define Sb 12 -#define Sc 17 -#define Sd 22 - -#define Se 5 -#define Sf 9 -#define Sg 14 -#define Sh 20 - -#define Si 4 -#define Sj 11 -#define Sk 16 -#define Sl 23 - -#define Sm 6 -#define Sn 10 -#define So 15 -#define Sp 21 - -#define MD5_A0 0x67452301 -#define MD5_B0 0xefcdab89 -#define MD5_C0 0x98badcfe -#define MD5_D0 0x10325476 - -/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ -static const uint32_t T[65] = { - 0, - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, -}; - -static const uint8_t md5_paddat[MD5_BUFLEN] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; +/* + * Support functions. + */ -static void md5_calc(uint8_t *, md5_ctxt *); +#define bufpos(ctx) ((ctx)->nbytes & (MD5_BLOCK_LENGTH - 1)) -void -md5_init(md5_ctxt * ctxt) +static inline uint32_t rol(uint32_t v, int s) { - ctxt->md5_n = 0; - ctxt->md5_i = 0; - ctxt->md5_sta = MD5_A0; - ctxt->md5_stb = MD5_B0; - ctxt->md5_stc = MD5_C0; - ctxt->md5_std = MD5_D0; - memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf)); + return (v << s) | (v >> (32 - s)); } -void -md5_loop(md5_ctxt * ctxt, const uint8_t *input, unsigned len) +static inline void swap_words(uint32_t *w, int n) { - unsigned int gap, - i; - - ctxt->md5_n += len * 8; /* byte to bit */ - gap = MD5_BUFLEN - ctxt->md5_i; - - if (len >= gap) - { - memmove(ctxt->md5_buf + ctxt->md5_i, input, gap); - md5_calc(ctxt->md5_buf, ctxt); - - for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) - md5_calc((uint8_t *) (input + i), ctxt); - - ctxt->md5_i = len - i; - memmove(ctxt->md5_buf, input + i, ctxt->md5_i); - } - else - { - memmove(ctxt->md5_buf + ctxt->md5_i, input, len); - ctxt->md5_i += len; - } -} - -void -md5_pad(md5_ctxt * ctxt) -{ - unsigned int gap; - - /* Don't count up padding. Keep md5_n. */ - gap = MD5_BUFLEN - ctxt->md5_i; - if (gap > 8) - { - memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat, - gap - sizeof(ctxt->md5_n)); - } - else - { - /* including gap == 8 */ - memmove(ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap); - md5_calc(ctxt->md5_buf, ctxt); - memmove(ctxt->md5_buf, md5_paddat + gap, - MD5_BUFLEN - sizeof(ctxt->md5_n)); +#ifdef WORDS_BIGENDIAN + for (; n > 0; w++, n--) { + uint32_t v = rol(*w, 16); + *w = ((v >> 8) & 0x00FF00FF) | ((v << 8) & 0xFF00FF00); } - - /* 8 byte word */ -#ifndef WORDS_BIGENDIAN - memmove(&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8); -#else - ctxt->md5_buf[56] = ctxt->md5_n8[7]; - ctxt->md5_buf[57] = ctxt->md5_n8[6]; - ctxt->md5_buf[58] = ctxt->md5_n8[5]; - ctxt->md5_buf[59] = ctxt->md5_n8[4]; - ctxt->md5_buf[60] = ctxt->md5_n8[3]; - ctxt->md5_buf[61] = ctxt->md5_n8[2]; - ctxt->md5_buf[62] = ctxt->md5_n8[1]; - ctxt->md5_buf[63] = ctxt->md5_n8[0]; #endif - - md5_calc(ctxt->md5_buf, ctxt); } -void -md5_result(uint8_t *digest, md5_ctxt * ctxt) +static inline void put_word(uint8_t *dst, uint32_t val) { - /* 4 byte words */ -#ifndef WORDS_BIGENDIAN - memmove(digest, &ctxt->md5_st8[0], 16); +#ifdef WORDS_BIGENDIAN + dst[0] = val; + dst[1] = val >> 8; + dst[2] = val >> 16; + dst[3] = val >> 24; #else - digest[0] = ctxt->md5_st8[3]; - digest[1] = ctxt->md5_st8[2]; - digest[2] = ctxt->md5_st8[1]; - digest[3] = ctxt->md5_st8[0]; - digest[4] = ctxt->md5_st8[7]; - digest[5] = ctxt->md5_st8[6]; - digest[6] = ctxt->md5_st8[5]; - digest[7] = ctxt->md5_st8[4]; - digest[8] = ctxt->md5_st8[11]; - digest[9] = ctxt->md5_st8[10]; - digest[10] = ctxt->md5_st8[9]; - digest[11] = ctxt->md5_st8[8]; - digest[12] = ctxt->md5_st8[15]; - digest[13] = ctxt->md5_st8[14]; - digest[14] = ctxt->md5_st8[13]; - digest[15] = ctxt->md5_st8[12]; + memcpy(dst, &val, 4); #endif } -#ifdef WORDS_BIGENDIAN -static uint32_t X[16]; -#endif - -static void -md5_calc(uint8_t *b64, md5_ctxt * ctxt) -{ - uint32_t A = ctxt->md5_sta; - uint32_t B = ctxt->md5_stb; - uint32_t C = ctxt->md5_stc; - uint32_t D = ctxt->md5_std; +/* + * MD5 core. + */ -#ifndef WORDS_BIGENDIAN - uint32_t *X = (uint32_t *) b64; -#else - /* 4 byte words */ - /* what a brute force but fast! */ - uint8_t *y = (uint8_t *) X; +#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))) - y[0] = b64[3]; - y[1] = b64[2]; - y[2] = b64[1]; - y[3] = b64[0]; - y[4] = b64[7]; - y[5] = b64[6]; - y[6] = b64[5]; - y[7] = b64[4]; - y[8] = b64[11]; - y[9] = b64[10]; - y[10] = b64[9]; - y[11] = b64[8]; - y[12] = b64[15]; - y[13] = b64[14]; - y[14] = b64[13]; - y[15] = b64[12]; - y[16] = b64[19]; - y[17] = b64[18]; - y[18] = b64[17]; - y[19] = b64[16]; - y[20] = b64[23]; - y[21] = b64[22]; - y[22] = b64[21]; - y[23] = b64[20]; - y[24] = b64[27]; - y[25] = b64[26]; - y[26] = b64[25]; - y[27] = b64[24]; - y[28] = b64[31]; - y[29] = b64[30]; - y[30] = b64[29]; - y[31] = b64[28]; - y[32] = b64[35]; - y[33] = b64[34]; - y[34] = b64[33]; - y[35] = b64[32]; - y[36] = b64[39]; - y[37] = b64[38]; - y[38] = b64[37]; - y[39] = b64[36]; - y[40] = b64[43]; - y[41] = b64[42]; - y[42] = b64[41]; - y[43] = b64[40]; - y[44] = b64[47]; - y[45] = b64[46]; - y[46] = b64[45]; - y[47] = b64[44]; - y[48] = b64[51]; - y[49] = b64[50]; - y[50] = b64[49]; - y[51] = b64[48]; - y[52] = b64[55]; - y[53] = b64[54]; - y[54] = b64[53]; - y[55] = b64[52]; - y[56] = b64[59]; - y[57] = b64[58]; - y[58] = b64[57]; - y[59] = b64[56]; - y[60] = b64[63]; - y[61] = b64[62]; - y[62] = b64[61]; - y[63] = b64[60]; -#endif +#define OP(fn, a, b, c, d, k, s, T_i) \ + a = b + rol(a + fn(b, c, d) + X[k] + T_i, s) - ROUND1(A, B, C, D, 0, Sa, 1); - ROUND1(D, A, B, C, 1, Sb, 2); - ROUND1(C, D, A, B, 2, Sc, 3); - ROUND1(B, C, D, A, 3, Sd, 4); - ROUND1(A, B, C, D, 4, Sa, 5); - ROUND1(D, A, B, C, 5, Sb, 6); - ROUND1(C, D, A, B, 6, Sc, 7); - ROUND1(B, C, D, A, 7, Sd, 8); - ROUND1(A, B, C, D, 8, Sa, 9); - ROUND1(D, A, B, C, 9, Sb, 10); - ROUND1(C, D, A, B, 10, Sc, 11); - ROUND1(B, C, D, A, 11, Sd, 12); - ROUND1(A, B, C, D, 12, Sa, 13); - ROUND1(D, A, B, C, 13, Sb, 14); - ROUND1(C, D, A, B, 14, Sc, 15); - ROUND1(B, C, D, A, 15, Sd, 16); +static void md5_mix(struct md5_ctx *ctx, const uint32_t *X) +{ + uint32_t a, b, c, d; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + /* Round 1. */ + OP(F, a, b, c, d, 0, 7, 0xd76aa478); + OP(F, d, a, b, c, 1, 12, 0xe8c7b756); + OP(F, c, d, a, b, 2, 17, 0x242070db); + OP(F, b, c, d, a, 3, 22, 0xc1bdceee); + OP(F, a, b, c, d, 4, 7, 0xf57c0faf); + OP(F, d, a, b, c, 5, 12, 0x4787c62a); + OP(F, c, d, a, b, 6, 17, 0xa8304613); + OP(F, b, c, d, a, 7, 22, 0xfd469501); + OP(F, a, b, c, d, 8, 7, 0x698098d8); + OP(F, d, a, b, c, 9, 12, 0x8b44f7af); + OP(F, c, d, a, b, 10, 17, 0xffff5bb1); + OP(F, b, c, d, a, 11, 22, 0x895cd7be); + OP(F, a, b, c, d, 12, 7, 0x6b901122); + OP(F, d, a, b, c, 13, 12, 0xfd987193); + OP(F, c, d, a, b, 14, 17, 0xa679438e); + OP(F, b, c, d, a, 15, 22, 0x49b40821); + + /* Round 2. */ + OP(G, a, b, c, d, 1, 5, 0xf61e2562); + OP(G, d, a, b, c, 6, 9, 0xc040b340); + OP(G, c, d, a, b, 11, 14, 0x265e5a51); + OP(G, b, c, d, a, 0, 20, 0xe9b6c7aa); + OP(G, a, b, c, d, 5, 5, 0xd62f105d); + OP(G, d, a, b, c, 10, 9, 0x02441453); + OP(G, c, d, a, b, 15, 14, 0xd8a1e681); + OP(G, b, c, d, a, 4, 20, 0xe7d3fbc8); + OP(G, a, b, c, d, 9, 5, 0x21e1cde6); + OP(G, d, a, b, c, 14, 9, 0xc33707d6); + OP(G, c, d, a, b, 3, 14, 0xf4d50d87); + OP(G, b, c, d, a, 8, 20, 0x455a14ed); + OP(G, a, b, c, d, 13, 5, 0xa9e3e905); + OP(G, d, a, b, c, 2, 9, 0xfcefa3f8); + OP(G, c, d, a, b, 7, 14, 0x676f02d9); + OP(G, b, c, d, a, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP(H, a, b, c, d, 5, 4, 0xfffa3942); + OP(H, d, a, b, c, 8, 11, 0x8771f681); + OP(H, c, d, a, b, 11, 16, 0x6d9d6122); + OP(H, b, c, d, a, 14, 23, 0xfde5380c); + OP(H, a, b, c, d, 1, 4, 0xa4beea44); + OP(H, d, a, b, c, 4, 11, 0x4bdecfa9); + OP(H, c, d, a, b, 7, 16, 0xf6bb4b60); + OP(H, b, c, d, a, 10, 23, 0xbebfbc70); + OP(H, a, b, c, d, 13, 4, 0x289b7ec6); + OP(H, d, a, b, c, 0, 11, 0xeaa127fa); + OP(H, c, d, a, b, 3, 16, 0xd4ef3085); + OP(H, b, c, d, a, 6, 23, 0x04881d05); + OP(H, a, b, c, d, 9, 4, 0xd9d4d039); + OP(H, d, a, b, c, 12, 11, 0xe6db99e5); + OP(H, c, d, a, b, 15, 16, 0x1fa27cf8); + OP(H, b, c, d, a, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP(I, a, b, c, d, 0, 6, 0xf4292244); + OP(I, d, a, b, c, 7, 10, 0x432aff97); + OP(I, c, d, a, b, 14, 15, 0xab9423a7); + OP(I, b, c, d, a, 5, 21, 0xfc93a039); + OP(I, a, b, c, d, 12, 6, 0x655b59c3); + OP(I, d, a, b, c, 3, 10, 0x8f0ccc92); + OP(I, c, d, a, b, 10, 15, 0xffeff47d); + OP(I, b, c, d, a, 1, 21, 0x85845dd1); + OP(I, a, b, c, d, 8, 6, 0x6fa87e4f); + OP(I, d, a, b, c, 15, 10, 0xfe2ce6e0); + OP(I, c, d, a, b, 6, 15, 0xa3014314); + OP(I, b, c, d, a, 13, 21, 0x4e0811a1); + OP(I, a, b, c, d, 4, 6, 0xf7537e82); + OP(I, d, a, b, c, 11, 10, 0xbd3af235); + OP(I, c, d, a, b, 2, 15, 0x2ad7d2bb); + OP(I, b, c, d, a, 9, 21, 0xeb86d391); + + ctx->a += a; + ctx->b += b; + ctx->c += c; + ctx->d += d; +} - ROUND2(A, B, C, D, 1, Se, 17); - ROUND2(D, A, B, C, 6, Sf, 18); - ROUND2(C, D, A, B, 11, Sg, 19); - ROUND2(B, C, D, A, 0, Sh, 20); - ROUND2(A, B, C, D, 5, Se, 21); - ROUND2(D, A, B, C, 10, Sf, 22); - ROUND2(C, D, A, B, 15, Sg, 23); - ROUND2(B, C, D, A, 4, Sh, 24); - ROUND2(A, B, C, D, 9, Se, 25); - ROUND2(D, A, B, C, 14, Sf, 26); - ROUND2(C, D, A, B, 3, Sg, 27); - ROUND2(B, C, D, A, 8, Sh, 28); - ROUND2(A, B, C, D, 13, Se, 29); - ROUND2(D, A, B, C, 2, Sf, 30); - ROUND2(C, D, A, B, 7, Sg, 31); - ROUND2(B, C, D, A, 12, Sh, 32); +/* + * Public API. + */ - ROUND3(A, B, C, D, 5, Si, 33); - ROUND3(D, A, B, C, 8, Sj, 34); - ROUND3(C, D, A, B, 11, Sk, 35); - ROUND3(B, C, D, A, 14, Sl, 36); - ROUND3(A, B, C, D, 1, Si, 37); - ROUND3(D, A, B, C, 4, Sj, 38); - ROUND3(C, D, A, B, 7, Sk, 39); - ROUND3(B, C, D, A, 10, Sl, 40); - ROUND3(A, B, C, D, 13, Si, 41); - ROUND3(D, A, B, C, 0, Sj, 42); - ROUND3(C, D, A, B, 3, Sk, 43); - ROUND3(B, C, D, A, 6, Sl, 44); - ROUND3(A, B, C, D, 9, Si, 45); - ROUND3(D, A, B, C, 12, Sj, 46); - ROUND3(C, D, A, B, 15, Sk, 47); - ROUND3(B, C, D, A, 2, Sl, 48); +void md5_reset(struct md5_ctx *ctx) +{ + ctx->nbytes = 0; + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; +} - ROUND4(A, B, C, D, 0, Sm, 49); - ROUND4(D, A, B, C, 7, Sn, 50); - ROUND4(C, D, A, B, 14, So, 51); - ROUND4(B, C, D, A, 5, Sp, 52); - ROUND4(A, B, C, D, 12, Sm, 53); - ROUND4(D, A, B, C, 3, Sn, 54); - ROUND4(C, D, A, B, 10, So, 55); - ROUND4(B, C, D, A, 1, Sp, 56); - ROUND4(A, B, C, D, 8, Sm, 57); - ROUND4(D, A, B, C, 15, Sn, 58); - ROUND4(C, D, A, B, 6, So, 59); - ROUND4(B, C, D, A, 13, Sp, 60); - ROUND4(A, B, C, D, 4, Sm, 61); - ROUND4(D, A, B, C, 11, Sn, 62); - ROUND4(C, D, A, B, 2, So, 63); - ROUND4(B, C, D, A, 9, Sp, 64); +void md5_update(struct md5_ctx *ctx, const void *data, unsigned int len) +{ + unsigned int n; + const uint8_t *ptr = data; + uint8_t *buf = (uint8_t *)ctx->buf; + + while (len > 0) { + n = MD5_BLOCK_LENGTH - bufpos(ctx); + if (n > len) + n = len; + memcpy(buf + bufpos(ctx), ptr, n); + ptr += n; + len -= n; + ctx->nbytes += n; + if (bufpos(ctx) == 0) { + swap_words(ctx->buf, 16); + md5_mix(ctx, ctx->buf); + } + } +} - ctxt->md5_sta += A; - ctxt->md5_stb += B; - ctxt->md5_stc += C; - ctxt->md5_std += D; +void md5_final(uint8_t *dst, struct md5_ctx *ctx) +{ + static const uint8_t padding[MD5_BLOCK_LENGTH] = { 0x80 }; + uint64_t final_len = ctx->nbytes * 8; + int pad_len, pos = bufpos(ctx); + + /* add padding */ + pad_len = MD5_BLOCK_LENGTH - 8 - pos; + if (pad_len <= 0) + pad_len += MD5_BLOCK_LENGTH; + md5_update(ctx, padding, pad_len); + + /* add length directly */ + swap_words(ctx->buf, 14); + ctx->buf[14] = final_len; + ctx->buf[15] = final_len >> 32; + + /* final result */ + md5_mix(ctx, ctx->buf); + put_word(dst, ctx->a); + put_word(dst + 4, ctx->b); + put_word(dst + 8, ctx->c); + put_word(dst + 12, ctx->d); } -/* vi: set ts=4: */ -- 2.39.5