From b85ccaadf2ddb41b29c1664c4be5e4b6aa31d212 Mon Sep 17 00:00:00 2001 From: Paul J Stevens <paul@nfg.nl> Date: Tue, 10 Nov 2009 12:10:36 +0000 Subject: change md5 implementation (bug #816) Use GLib's md5 implementation. This introduces a dependency on glib >= 2.16 which is enforced by configure. --- diff --git a/INSTALL b/INSTALL index ccd6137..07edd52 100644 --- a/INSTALL +++ b/INSTALL @@ -18,7 +18,7 @@ What do you need? systems, make sure you install and use 'gmake'. - Development files (libs, scripts and include files) for your database server. These will probably be provided by separate packages. -- Glib (>= 2.8) development headers and libraries. +- Glib (>= 2.16) development headers and libraries. - Gmime (>= 2.1.18) development headers and libraries. - libSieve for Sieve support (libsieve.sf.net). - Any standard libldap for LDAP support (only tested with OpenLDAP, however). diff --git a/Makefile.am b/Makefile.am index 2d931d4..0f90d09 100644 --- a/Makefile.am +++ b/Makefile.am @@ -128,6 +128,7 @@ TESTS=check_dbmail_common \ check_dbmail_mailbox \ check_dbmail_auth \ check_dbmail_misc \ + check_dbmail_md5 \ check_dbmail_list \ check_dbmail_user \ check_dbmail_util \ @@ -149,6 +150,10 @@ check_dbmail_misc_SOURCES=check_dbmail_misc.c check_dbmail_misc_LDADD=libdbmail.la @CHECK_LIBS@ check_dbmail_misc_INCLUDES=@CHECK_CFLAGS@ +check_dbmail_md5_SOURCES=check_dbmail_md5.c +check_dbmail_md5_LDADD=libdbmail.la @CHECK_LIBS@ +check_dbmail_md5_INCLUDES=@CHECK_CFLAGS@ + check_dbmail_list_SOURCES=check_dbmail_list.c check_dbmail_list_LDADD=libdbmail.la @CHECK_LIBS@ check_dbmail_list_INCLUDES=@CHECK_CFLAGS@ diff --git a/acinclude.m4 b/acinclude.m4 index 898938a..e366d9d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -501,6 +501,15 @@ dnl First we're looking for straight GLib AC_MSG_ERROR([Unable to locate glib libaries]) fi + ac_glib_minvers="2.16" + AC_MSG_CHECKING([GLib version >= $ac_glib_minvers]) + ac_glib_vers=`${glibconfig} --atleast-version=$ac_glib_minvers glib-2.0 && echo yes` + if test -z "$ac_glib_vers" + then + AC_MSG_ERROR([At least GLib version $ac_glib_minvers is required.]) + else + AC_MSG_RESULT([$ac_glib_vers]) + fi LDFLAGS="$LDFLAGS $ac_glib_libs" AC_MSG_RESULT([$ac_glib_libs]) diff --git a/check_dbmail_md5.c b/check_dbmail_md5.c new file mode 100644 index 0000000..4b4863a --- a/dev/null +++ b/check_dbmail_md5.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2005-2006 NFG Net Facilities Group BV support@nfg.nl + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * + * + * + * + * + * Basic unit-test framework for dbmail (www.dbmail.org) + * + * See http://check.sf.net for details and docs. + * + * + * Run 'make check' to see some action. + * + */ + +#include <check.h> +#include "check_dbmail.h" + +extern char *configFile; + +/* + * + * the test fixtures + * + */ +void setup(void) +{ + configure_debug(5,0); +} + +void teardown(void) +{ + ; +} + +#define M(a,b) fail_unless(MATCH(dm_md5((a)),(b)), "dm_md5 failed [%s] != [%s]", dm_md5(a), b) +START_TEST(test_md5) +{ + M("","d41d8cd98f00b204e9800998ecf8427e"); + M("a","0cc175b9c0f1b6a831c399e269772661"); + M("abc", "900150983cd24fb0d6963f7d28e17f72"); +} +END_TEST + +#define B(a,b) fail_unless(MATCH(dm_md5_base64((a)),(b)), "dm_md5_base64 failed [%s] != [%s]", dm_md5(a), b) +START_TEST(test_md5_base64) +{ + B("","1B2M2Y8AsgTpgAmY7PhCfg=="); + B("a","DMF1ucDxtqgxw5niaXcmYQ=="); + B("abc","kAFQmDzST7DWlj99KOF/cg=="); +} +END_TEST + +Suite *dbmail_common_suite(void) +{ + Suite *s = suite_create("Dbmail md5"); + TCase *tc_util = tcase_create("Md5"); + + suite_add_tcase(s, tc_util); + + tcase_add_checked_fixture(tc_util, setup, teardown); + tcase_add_test(tc_util, test_md5); + tcase_add_test(tc_util, test_md5_base64); + + return s; +} + +int main(void) +{ + int nf; + Suite *s = dbmail_common_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + nf = srunner_ntests_failed(sr); + srunner_free(sr); + return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + + diff --git a/dm_md5.c b/dm_md5.c index 3fdebcf..09a064f 100644 --- a/dm_md5.c +++ b/dm_md5.c @@ -43,280 +43,20 @@ #include "dbmail.h" #define THIS_MODULE "md5" -typedef unsigned int uint32; - -struct GdmMD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -static void gdm_md5_init(struct GdmMD5Context *context); -static void gdm_md5_update(struct GdmMD5Context *context, - unsigned char const *buf, unsigned len); -static void gdm_md5_final(unsigned char digest[16], - struct GdmMD5Context *context); -static void gdm_md5_transform(uint32 buf[4], uint32 const in[16]); - - -/* If endian.h is present, it will tell us, otherwise - * autoconf's AC_C_BIGENDIAN will have tested the host. */ -#if (BYTE_ORDER == LITTLE_ENDIAN) || !defined(WORDS_BIGENDIAN) -#define byteReverse(buf, len) /* Nothing */ -#else - -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - uint32 t; - do { - t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32 *) buf = t; - buf += 4; - } while (--longs); -} - -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -static void gdm_md5_init(struct GdmMD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static void gdm_md5_update(struct GdmMD5Context *ctx, - unsigned char const *buf, unsigned len) -{ - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -static void gdm_md5_final(unsigned char digest[16], - struct GdmMD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *) ctx->in)[14] = ctx->bits[0]; - ((uint32 *) ctx->in)[15] = ctx->bits[1]; - - gdm_md5_transform(ctx->buf, (uint32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - - -/* The four core functions - F1 is optimized somewhat */ - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1 (z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define gdm_md5_step(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. GdmMD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void gdm_md5_transform(uint32 buf[4], uint32 const in[16]) -{ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - gdm_md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - gdm_md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - gdm_md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17); - gdm_md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - gdm_md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - gdm_md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - gdm_md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17); - gdm_md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22); - gdm_md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7); - gdm_md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - gdm_md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - gdm_md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - gdm_md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7); - gdm_md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12); - gdm_md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17); - gdm_md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - gdm_md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - gdm_md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9); - gdm_md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - gdm_md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - gdm_md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - gdm_md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9); - gdm_md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - gdm_md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - gdm_md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - gdm_md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - gdm_md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - gdm_md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - gdm_md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - gdm_md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - gdm_md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - gdm_md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - gdm_md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - gdm_md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11); - gdm_md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - gdm_md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - gdm_md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - gdm_md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - gdm_md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - gdm_md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - gdm_md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - gdm_md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - gdm_md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - gdm_md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23); - gdm_md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - gdm_md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - gdm_md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - gdm_md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - gdm_md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6); - gdm_md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10); - gdm_md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - gdm_md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - gdm_md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - gdm_md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - gdm_md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - gdm_md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - gdm_md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - gdm_md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - gdm_md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15); - gdm_md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - gdm_md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - gdm_md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - gdm_md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - gdm_md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - char *dm_md5(const unsigned char * const buf) { - struct GdmMD5Context mycontext; - unsigned char result[16]; + GChecksum *checksum; char *md5hash; - int i; if (buf == NULL) { TRACE(TRACE_ERROR, "received NULL argument"); return NULL; } - md5hash = g_new0(char, 33); - if (md5hash == NULL) { - TRACE(TRACE_ERROR, "error allocating memory"); - return NULL; - } - - gdm_md5_init(&mycontext); - gdm_md5_update(&mycontext, buf, strlen((char *)buf)); - gdm_md5_final(result, &mycontext); - - for (i = 0; i < 16; i++) { - sprintf(&md5hash[i * 2], "%02x", result[i]); - } + checksum = g_checksum_new(G_CHECKSUM_MD5); + g_checksum_update(checksum, buf, strlen((char *)buf)); + md5hash = g_strdup(g_checksum_get_string(checksum)); + g_checksum_free(checksum); return md5hash; } @@ -324,21 +64,24 @@ char *dm_md5(const unsigned char * const buf) /* Always returns an allocation of 18 bytes. */ char *dm_md5_base64(const unsigned char * const buf) { - struct GdmMD5Context mycontext; - unsigned char result[16]; - unsigned char base64[24]; + GChecksum *checksum; + guint8 result[32]; + gsize digest_len = 32; + unsigned char base64[32]; if (buf == NULL) { TRACE(TRACE_ERROR, "received NULL argument"); return NULL; } - gdm_md5_init(&mycontext); - gdm_md5_update(&mycontext, buf, strlen((char *)buf)); - gdm_md5_final(result, &mycontext); - memset(base64, '\0', sizeof(base64)); - base64_encode(base64, result, sizeof(result)); + checksum = g_checksum_new(G_CHECKSUM_MD5); + g_checksum_update(checksum, buf, strlen((char *)buf)); + g_checksum_get_digest(checksum, result, &digest_len); + + base64_encode(base64, (const unsigned char *)result, (int)digest_len); + + g_checksum_free(checksum); return g_strdup((char *)base64); } -- cgit v0.8.3-6-g21f6