From c5d8261e0e5c4675b6238af2f25cad968b94d8c8 Mon Sep 17 00:00:00 2001 From: Simon Josefsson Date: Fri, 28 Oct 2005 12:09:31 +0000 Subject: [PATCH] Add MD2 and hash fixes. --- ChangeLog | 6 ++ lib/ChangeLog | 11 +++ lib/gc-gnulib.c | 234 +++++++++++++++++++++++++++++++++++++++++++ lib/gc-libgcrypt.c | 137 +++++++++++++++++++++---- lib/gc.h | 4 + lib/md2.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/md2.h | 82 +++++++++++++++ m4/ChangeLog | 4 + m4/gc-md2.m4 | 10 ++ m4/md2.m4 | 11 +++ modules/gc-md2 | 25 +++++ modules/gc-md2-tests | 11 +++ modules/md2 | 24 +++++ modules/md2-tests | 11 +++ tests/test-gc-md2.c | 130 ++++++++++++++++++++++++ tests/test-md2.c | 70 +++++++++++++ 16 files changed, 1024 insertions(+), 21 deletions(-) create mode 100644 lib/md2.c create mode 100644 lib/md2.h create mode 100644 m4/gc-md2.m4 create mode 100644 m4/md2.m4 create mode 100644 modules/gc-md2 create mode 100644 modules/gc-md2-tests create mode 100644 modules/md2 create mode 100644 modules/md2-tests create mode 100644 tests/test-gc-md2.c create mode 100644 tests/test-md2.c diff --git a/ChangeLog b/ChangeLog index 177859d36..1999e7695 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-10-28 Simon Josefsson + + * tests/test-gc-md2.c, tests/test-md2.c: New files. + + * modules/md2, modules/md2-tests: New files. + 2005-10-27 Paul Eggert * modules/verify (License): Change from GPL to LGPL. This is a diff --git a/lib/ChangeLog b/lib/ChangeLog index 7df414b2e..6a30f1e95 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,14 @@ +2005-10-28 Simon Josefsson + + * gc.h: Add MD2 and RMD160 length defines. Add prototypes. + + * gc-libgcrypt.c: Add MD2 (which is not available through + libgcrypt). + + * gc-gnulib.c: Add MD2. Implement gc_hash_* API. + + * md2.h, md2.c: New files. + 2005-10-24 Simon Josefsson * md4.h: Shrink buffer size, now that we changed the type. diff --git a/lib/gc-gnulib.c b/lib/gc-gnulib.c index 0b70ccebc..61143b0de 100644 --- a/lib/gc-gnulib.c +++ b/lib/gc-gnulib.c @@ -38,6 +38,9 @@ #include /* Hashes. */ +#ifdef GC_USE_MD2 +# include "md2.h" +#endif #ifdef GC_USE_MD4 # include "md4.h" #endif @@ -537,11 +540,233 @@ gc_cipher_close (gc_cipher_handle handle) /* Hashes. */ +#define MAX_DIGEST_SIZE 20 + +typedef struct _gc_hash_ctx { + Gc_hash alg; + Gc_hash_mode mode; + char hash[MAX_DIGEST_SIZE]; +#ifdef GC_USE_MD2 + struct md2_ctx md2Context; +#endif +#ifdef GC_USE_MD4 + struct md4_ctx md4Context; +#endif +#ifdef GC_USE_MD5 + struct md5_ctx md5Context; +#endif +#ifdef GC_USE_SHA1 + struct sha1_ctx sha1Context; +#endif +} _gc_hash_ctx; + +Gc_rc +gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle) +{ + _gc_hash_ctx *ctx; + Gc_rc rc = GC_OK; + + ctx = calloc (sizeof (*ctx), 1); + + ctx->alg = hash; + ctx->mode = mode; + + switch (hash) + { +#ifdef GC_USE_MD2 + case GC_MD2: + md2_init_ctx (&ctx->md2Context); + break; +#endif + +#ifdef GC_USE_MD4 + case GC_MD4: + md4_init_ctx (&ctx->md4Context); + break; +#endif + +#ifdef GC_USE_MD5 + case GC_MD5: + md5_init_ctx (&ctx->md5Context); + break; +#endif + +#ifdef GC_USE_SHA1 + case GC_SHA1: + sha1_init_ctx (&ctx->sha1Context); + break; +#endif + + default: + rc = GC_INVALID_HASH; + break; + } + + switch (mode) + { + case 0: + break; + + default: + rc = GC_INVALID_HASH; + break; + } + + if (rc == GC_OK) + *outhandle = ctx; + else + free (ctx); + + return rc; +} + +Gc_rc +gc_hash_clone (gc_hash_handle handle, gc_hash_handle * outhandle) +{ + _gc_hash_ctx *in = handle; + _gc_hash_ctx *out; + + *outhandle = out = calloc (sizeof (*out), 1); + if (!out) + return GC_MALLOC_ERROR; + + memcpy (out, in, sizeof (*out)); + + return GC_OK; +} + +size_t +gc_hash_digest_length (Gc_hash hash) +{ + size_t len; + + switch (hash) + { + case GC_MD2: + len = GC_MD2_DIGEST_SIZE; + break; + + case GC_MD4: + len = GC_MD4_DIGEST_SIZE; + break; + + case GC_MD5: + len = GC_MD5_DIGEST_SIZE; + break; + + case GC_RMD160: + len = GC_RMD160_DIGEST_SIZE; + break; + + case GC_SHA1: + len = GC_SHA1_DIGEST_SIZE; + break; + + default: + return 0; + } + + return len; +} + +void +gc_hash_write (gc_hash_handle handle, size_t len, const char *data) +{ + _gc_hash_ctx *ctx = handle; + + switch (ctx->alg) + { +#ifdef GC_USE_MD2 + case GC_MD2: + md2_process_bytes (data, len, &ctx->md2Context); + break; +#endif + +#ifdef GC_USE_MD4 + case GC_MD4: + md4_process_bytes (data, len, &ctx->md4Context); + break; +#endif + +#ifdef GC_USE_MD5 + case GC_MD5: + md5_process_bytes (data, len, &ctx->md5Context); + break; +#endif + +#ifdef GC_USE_SHA1 + case GC_SHA1: + sha1_process_bytes (data, len, &ctx->sha1Context); + break; +#endif + + default: + break; + } +} + +const char * +gc_hash_read (gc_hash_handle handle) +{ + _gc_hash_ctx *ctx = handle; + const char *ret = NULL; + + switch (ctx->alg) + { +#ifdef GC_USE_MD2 + case GC_MD2: + md2_finish_ctx (&ctx->md2Context, ctx->hash); + ret = ctx->hash; + break; +#endif + +#ifdef GC_USE_MD4 + case GC_MD4: + md4_finish_ctx (&ctx->md4Context, ctx->hash); + ret = ctx->hash; + break; +#endif + +#ifdef GC_USE_MD5 + case GC_MD5: + md5_finish_ctx (&ctx->md5Context, ctx->hash); + ret = ctx->hash; + break; +#endif + +#ifdef GC_USE_SHA1 + case GC_SHA1: + sha1_finish_ctx (&ctx->sha1Context, ctx->hash); + ret = ctx->hash; + break; +#endif + + default: + return NULL; + } + + return ret; +} + +void +gc_hash_close (gc_hash_handle handle) +{ + _gc_hash_ctx *ctx = handle; + + free (ctx); +} + Gc_rc gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf) { switch (hash) { +#ifdef GC_USE_MD2 + case GC_MD2: + md2_buffer (in, inlen, resbuf); + break; +#endif + #ifdef GC_USE_MD4 case GC_MD4: md4_buffer (in, inlen, resbuf); @@ -567,6 +792,15 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf) return GC_OK; } +#ifdef GC_USE_MD2 +Gc_rc +gc_md2 (const void *in, size_t inlen, void *resbuf) +{ + md2_buffer (in, inlen, resbuf); + return GC_OK; +} +#endif + #ifdef GC_USE_MD4 Gc_rc gc_md4 (const void *in, size_t inlen, void *resbuf) diff --git a/lib/gc-libgcrypt.c b/lib/gc-libgcrypt.c index 9272c19f4..bc0d12bba 100644 --- a/lib/gc-libgcrypt.c +++ b/lib/gc-libgcrypt.c @@ -27,8 +27,14 @@ /* Get prototype. */ #include "gc.h" +#include +#include + /* Get libgcrypt API. */ #include +#ifdef GC_USE_MD2 +# include "md2.h" +#endif #include @@ -218,14 +224,35 @@ gc_cipher_close (gc_cipher_handle handle) /* Hashes. */ +typedef struct _gc_hash_ctx { + Gc_hash alg; + Gc_hash_mode mode; + gcry_md_hd_t gch; +#ifdef GC_USE_MD2 + char hash[GC_MD2_DIGEST_SIZE]; + struct md2_ctx md2Context; +#endif +} _gc_hash_ctx; + Gc_rc gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle) { + _gc_hash_ctx *ctx; int gcryalg, gcrymode; gcry_error_t err; + Gc_rc rc = GC_OK; + + ctx = calloc (sizeof (*ctx), 1); + + ctx->alg = hash; + ctx->mode = mode; switch (hash) { + case GC_MD2: + gcryalg = GCRY_MD_NONE; + break; + case GC_MD4: gcryalg = GCRY_MD_MD4; break; @@ -243,7 +270,7 @@ gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle) break; default: - return GC_INVALID_HASH; + rc = GC_INVALID_HASH; } switch (mode) @@ -257,24 +284,43 @@ gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle) break; default: - return GC_INVALID_HASH; + rc = GC_INVALID_HASH; } - err = gcry_md_open ((gcry_md_hd_t *) outhandle, gcryalg, gcrymode); - if (gcry_err_code (err)) - return GC_INVALID_HASH; + if (rc == GC_OK && gcryalg != GCRY_MD_NONE) + { + err = gcry_md_open (&ctx->gch, gcryalg, gcrymode); + if (gcry_err_code (err)) + rc = GC_INVALID_HASH; + } - return GC_OK; + if (rc == GC_OK) + *outhandle = ctx; + else + free (ctx); + + return rc; } Gc_rc gc_hash_clone (gc_hash_handle handle, gc_hash_handle * outhandle) { + _gc_hash_ctx *in = handle; + _gc_hash_ctx *out; int err; - err = gcry_md_copy ((gcry_md_hd_t *) outhandle, (gcry_md_hd_t) handle); + *outhandle = out = calloc (sizeof (*out), 1); + if (!out) + return GC_MALLOC_ERROR; + + memcpy (out, in, sizeof (*out)); + + err = gcry_md_copy (&out->gch, in->gch); if (err) - return GC_INVALID_HASH; + { + free (out); + return GC_INVALID_HASH; + } return GC_OK; } @@ -282,52 +328,78 @@ gc_hash_clone (gc_hash_handle handle, gc_hash_handle * outhandle) size_t gc_hash_digest_length (Gc_hash hash) { - int gcryalg; + size_t len; switch (hash) { + case GC_MD2: + len = GC_MD2_DIGEST_SIZE; + break; + case GC_MD4: - gcryalg = GCRY_MD_MD4; + len = GC_MD4_DIGEST_SIZE; break; case GC_MD5: - gcryalg = GCRY_MD_MD5; + len = GC_MD5_DIGEST_SIZE; break; - case GC_SHA1: - gcryalg = GCRY_MD_SHA1; + case GC_RMD160: + len = GC_RMD160_DIGEST_SIZE; break; - case GC_RMD160: - gcryalg = GCRY_MD_RMD160; + case GC_SHA1: + len = GC_SHA1_DIGEST_SIZE; break; default: return 0; } - return gcry_md_get_algo_dlen (gcryalg); + return len; } void gc_hash_hmac_setkey (gc_hash_handle handle, size_t len, const char *key) { - gcry_md_setkey ((gcry_md_hd_t) handle, key, len); + _gc_hash_ctx *ctx = handle; +#ifdef GC_USE_MD2 + if (ctx->alg != GC_MD2) +#endif + gcry_md_setkey (ctx->gch, key, len); } void gc_hash_write (gc_hash_handle handle, size_t len, const char *data) { - gcry_md_write ((gcry_md_hd_t) handle, data, len); + _gc_hash_ctx *ctx = handle; + +#ifdef GC_USE_MD2 + if (ctx->alg == GC_MD2) + md2_process_bytes (data, len, &ctx->md2Context); + else +#endif + gcry_md_write (ctx->gch, data, len); } const char * gc_hash_read (gc_hash_handle handle) { + _gc_hash_ctx *ctx = handle; const char *digest; - gcry_md_final ((gcry_md_hd_t) handle); - digest = gcry_md_read ((gcry_md_hd_t) handle, 0); +#ifdef GC_USE_MD2 + if (ctx->alg == GC_MD2) + { + md2_finish_ctx (&ctx->md2Context, ctx->hash); + digest = ctx->hash; + } + else +#endif + { + gcry_md_final (ctx->gch); + digest = gcry_md_read (ctx->gch, 0); + } return digest; } @@ -335,7 +407,14 @@ gc_hash_read (gc_hash_handle handle) void gc_hash_close (gc_hash_handle handle) { - gcry_md_close ((gcry_md_hd_t) handle); + _gc_hash_ctx *ctx = handle; + +#ifdef GC_USE_MD2 + if (ctx->alg != GC_MD2) +#endif + gcry_md_close (ctx->gch); + + free (ctx); } Gc_rc @@ -345,6 +424,13 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf) switch (hash) { +#ifdef GC_USE_MD2 + case GC_MD2: + md2_buffer (in, inlen, resbuf); + return GC_OK; + break; +#endif + #ifdef GC_USE_MD4 case GC_MD4: gcryalg = GCRY_MD_MD4; @@ -380,6 +466,15 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf) /* One-call interface. */ +#ifdef GC_USE_MD2 +Gc_rc +gc_md2 (const void *in, size_t inlen, void *resbuf) +{ + md2_buffer (in, inlen, resbuf); + return GC_OK; +} +#endif + #ifdef GC_USE_MD4 Gc_rc gc_md4 (const void *in, size_t inlen, void *resbuf) diff --git a/lib/gc.h b/lib/gc.h index 7a385b1fc..84e4e635c 100644 --- a/lib/gc.h +++ b/lib/gc.h @@ -57,8 +57,10 @@ typedef enum Gc_hash_mode Gc_hash_mode; typedef void *gc_hash_handle; +#define GC_MD2_DIGEST_SIZE 16 #define GC_MD4_DIGEST_SIZE 16 #define GC_MD5_DIGEST_SIZE 16 +#define GC_RMD160_DIGEST_SIZE 20 #define GC_SHA1_DIGEST_SIZE 20 /* Cipher types. */ @@ -141,6 +143,8 @@ extern Gc_rc gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *out); /* One-call interface. */ +extern Gc_rc gc_md2 (const void *in, size_t inlen, void *resbuf); +extern Gc_rc gc_md4 (const void *in, size_t inlen, void *resbuf); extern Gc_rc gc_md5 (const void *in, size_t inlen, void *resbuf); extern Gc_rc gc_sha1 (const void *in, size_t inlen, void *resbuf); extern Gc_rc gc_hmac_md5 (const void *key, size_t keylen, diff --git a/lib/md2.c b/lib/md2.c new file mode 100644 index 000000000..787b76693 --- /dev/null +++ b/lib/md2.c @@ -0,0 +1,275 @@ +/* Functions to compute MD2 message digest of files or memory blocks. + according to the definition of MD2 in RFC 1319 from April 1992. + Copyright (C) 1995,1996,1997,1999,2000,2001,2002,2003,2005 + Free Software Foundation, Inc. + + 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Adapted by Simon Josefsson from public domain Libtomcrypt 1.06 by + Tom St Denis. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "md2.h" + +#include +#include + +#include + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +static void md2_update_chksum (struct md2_ctx *md); +static void md2_compress (struct md2_ctx *md); + +/* Initialize structure containing state of computation. + (RFC 1319, 3.3: Step 3) */ +void +md2_init_ctx (struct md2_ctx *ctx) +{ + memset (ctx->X, 0, sizeof (ctx->X)); + memset (ctx->chksum, 0, sizeof (ctx->chksum)); + memset (ctx->buf, 0, sizeof (ctx->buf)); + ctx->curlen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md2_read_ctx (const struct md2_ctx *ctx, void *resbuf) +{ + memcpy (resbuf, ctx->X, 16); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md2_finish_ctx (struct md2_ctx *ctx, void *resbuf) +{ + unsigned long i, k; + + /* pad the message */ + k = 16 - ctx->curlen; + for (i = ctx->curlen; i < 16; i++) + { + ctx->buf[i] = (unsigned char) k; + } + + /* hash and update */ + md2_compress (ctx); + md2_update_chksum (ctx); + + /* hash checksum */ + memcpy (ctx->buf, ctx->chksum, 16); + md2_compress (ctx); + + return md2_read_ctx (ctx, resbuf); +} + +/* Compute MD2 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md2_stream (FILE *stream, void *resblock) +{ + struct md2_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md2_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md2_process_block (buffer, BLOCKSIZE, &ctx); + } + +process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + md2_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md2_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md2_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md2_ctx ctx; + + /* Initialize the computation context. */ + md2_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md2_process_block (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md2_finish_ctx (&ctx, resblock); +} + +void +md2_process_bytes (const void *buffer, size_t len, struct md2_ctx *ctx) +{ + const char *in = buffer; + unsigned long n; + + while (len > 0) + { + n = MIN (len, (16 - ctx->curlen)); + memcpy (ctx->buf + ctx->curlen, in, (size_t) n); + ctx->curlen += n; + in += n; + len -= n; + + /* is 16 bytes full? */ + if (ctx->curlen == 16) + { + md2_compress (ctx); + md2_update_chksum (ctx); + ctx->curlen = 0; + } + } +} + +static const unsigned char PI_SUBST[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 +}; + +/* adds 16 bytes to the checksum */ +static void +md2_update_chksum (struct md2_ctx *ctx) +{ + int j; + unsigned char L; + + L = ctx->chksum[15]; + for (j = 0; j < 16; j++) + { + /* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the + reference source code [and test vectors] say otherwise. */ + L = (ctx->chksum[j] ^= PI_SUBST[(int) (ctx->buf[j] ^ L)] & 255); + } +} + +static void +md2_compress (struct md2_ctx *ctx) +{ + size_t j, k; + unsigned char t; + + /* copy block */ + for (j = 0; j < 16; j++) + { + ctx->X[16 + j] = ctx->buf[j]; + ctx->X[32 + j] = ctx->X[j] ^ ctx->X[16 + j]; + } + + t = (unsigned char) 0; + + /* do 18 rounds */ + for (j = 0; j < 18; j++) + { + for (k = 0; k < 48; k++) + { + t = (ctx->X[k] ^= PI_SUBST[(int) (t & 255)]); + } + t = (t + (unsigned char) j) & 255; + } +} + +/* Process LEN bytes of BUFFER, accumulating context into CTX. */ +void +md2_process_block (const void *buffer, size_t len, struct md2_ctx *ctx) +{ + md2_process_bytes (buffer, len, ctx); +} diff --git a/lib/md2.h b/lib/md2.h new file mode 100644 index 000000000..70d9e06ee --- /dev/null +++ b/lib/md2.h @@ -0,0 +1,82 @@ +/* Declarations of functions and data types used for MD2 sum + library functions. + Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + + 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef MD2_H +# define MD2_H 1 + +# include +# include + +# define MD2_DIGEST_SIZE 16 + +/* Structure to save state of computation between the single steps. */ +struct md2_ctx +{ + unsigned char chksum[16], X[48], buf[16]; + size_t curlen; +}; + + +/* Initialize structure containing state of computation. */ +extern void md2_init_ctx (struct md2_ctx *ctx); + +/* 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. + It is NOT required that LEN is a multiple of 64. */ +extern void md2_process_block (const void *buffer, size_t len, + struct md2_ctx *ctx); + +/* 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. + It is NOT required that LEN is a multiple of 64. */ +extern void md2_process_bytes (const void *buffer, size_t len, + struct md2_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF be correctly + aligned for a 32 bits value. */ +extern void *md2_finish_ctx (struct md2_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md2_read_ctx (const struct md2_ctx *ctx, void *resbuf); + + +/* Compute MD2 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int md2_stream (FILE *stream, void *resblock); + +/* Compute MD2 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *md2_buffer (const char *buffer, size_t len, void *resblock); + +#endif diff --git a/m4/ChangeLog b/m4/ChangeLog index b6e8f67b7..ddb6b18e6 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,7 @@ +2005-10-28 Simon Josefsson + + * gc-md2.m4, md2.m4: New file. + 2005-10-22 Simon Josefsson * gc.m4: Don't be fooled by --disable-*random-device parameters, diff --git a/m4/gc-md2.m4 b/m4/gc-md2.m4 new file mode 100644 index 000000000..5a5909d9f --- /dev/null +++ b/m4/gc-md2.m4 @@ -0,0 +1,10 @@ +# gc-md2.m4 serial 1 +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_GC_MD2], +[ + AC_DEFINE(GC_USE_MD2, 1, [Define if you want to support MD2 through GC.]) +]) diff --git a/m4/md2.m4 b/m4/md2.m4 new file mode 100644 index 000000000..81612c8f3 --- /dev/null +++ b/m4/md2.m4 @@ -0,0 +1,11 @@ +# md2.m4 serial 1 +dnl Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_MD2], +[ + AC_LIBSOURCES([md2.c, md2.h]) + AC_LIBOBJ([md2]) +]) diff --git a/modules/gc-md2 b/modules/gc-md2 new file mode 100644 index 000000000..18621a03a --- /dev/null +++ b/modules/gc-md2 @@ -0,0 +1,25 @@ +Description: +Generic crypto wrappers for MD2 functions. + +Files: +m4/gc-md2.m4 + +Depends-on: +stdint +gc +minmax +md2 + +configure.ac: +gl_GC_MD2 + +Makefile.am: + +Include: +"gc.h" + +License: +LGPL + +Maintainer: +Simon Josefsson diff --git a/modules/gc-md2-tests b/modules/gc-md2-tests new file mode 100644 index 000000000..e3b5c3e60 --- /dev/null +++ b/modules/gc-md2-tests @@ -0,0 +1,11 @@ +Files: +tests/test-gc-md2.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-gc-md2 +noinst_PROGRAMS += test-gc-md2 +test_gc_md2_SOURCES = test-gc-md2.c diff --git a/modules/md2 b/modules/md2 new file mode 100644 index 000000000..f3fa344e0 --- /dev/null +++ b/modules/md2 @@ -0,0 +1,24 @@ +Description: +Compute MD2 checksum. + +Files: +lib/md2.h +lib/md2.c +m4/md2.m4 + +Depends-on: +minmax + +configure.ac: +gl_MD2 + +Makefile.am: + +Include: +"md2.h" + +License: +LGPL + +Maintainer: +Simon Josefsson diff --git a/modules/md2-tests b/modules/md2-tests new file mode 100644 index 000000000..bcbac6072 --- /dev/null +++ b/modules/md2-tests @@ -0,0 +1,11 @@ +Files: +tests/test-md2.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-md2 +noinst_PROGRAMS += test-md2 +test_md2_SOURCES = test-md2.c diff --git a/tests/test-gc-md2.c b/tests/test-gc-md2.c new file mode 100644 index 000000000..d2e92d400 --- /dev/null +++ b/tests/test-gc-md2.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005 Free Software Foundation + * Written by Simon Josefsson + * + * 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "gc.h" + +int +main (int argc, char *argv[]) +{ + Gc_rc rc; + gc_hash_handle h; + + rc = gc_init (); + if (rc != GC_OK) + { + printf ("gc_init() failed\n"); + return 1; + } + + /* Test vectors from RFC 1319. */ + + { + char *in = "abcdefghijklmnopqrstuvwxyz"; + size_t inlen = strlen (in); + char *expect = + "\x4e\x8d\xdf\xf3\x65\x02\x92\xab\x5a\x41\x08\xc3\xaa\x47\x94\x0b"; + char out[16]; + const char *p; + + if (gc_md2 (in, inlen, out) != 0) + { + printf ("gc_md2 call failed\n"); + return 1; + } + + if (memcmp (out, expect, 16) != 0) + { + size_t i; + printf ("md2 1 missmatch. expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", expect[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", out[i] & 0xFF); + printf ("\n"); + return 1; + } + + if (gc_hash_buffer (GC_MD2, in, inlen, out) != 0) + { + printf ("gc_hash_buffer(MD2) call failed\n"); + return 1; + } + + if (memcmp (out, expect, 16) != 0) + { + size_t i; + printf ("md2 2 missmatch. expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", expect[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", out[i] & 0xFF); + printf ("\n"); + return 1; + } + + if (gc_hash_digest_length (GC_MD2) != 16) + { + printf ("gc_hash_digest_length (GC_MD2) failed\n"); + return 1; + } + + if ((rc = gc_hash_open (GC_MD2, 0, &h)) != GC_OK) + { + printf ("gc_hash_open(GC_MD2) failed (%d)\n", rc); + return 1; + } + + gc_hash_write (h, inlen, in); + + p = gc_hash_read (h); + + if (!p) + { + printf ("gc_hash_read failed\n"); + return 1; + } + + if (memcmp (p, expect, 16) != 0) + { + size_t i; + printf ("md2 3 missmatch. expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", expect[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", p[i] & 0xFF); + printf ("\n"); + return 1; + } + + gc_hash_close (h); + } + + gc_done (); + + return 0; +} diff --git a/tests/test-md2.c b/tests/test-md2.c new file mode 100644 index 000000000..0cfc529af --- /dev/null +++ b/tests/test-md2.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005 Free Software Foundation + * + * 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ + +/* Written by Simon Josefsson. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "md2.h" + +int +main (int argc, char *argv[]) +{ + const char *in1 = "abc"; + const char *out1 = + "\xda\x85\x3b\x0d\x3f\x88\xd9\x9b\x30\x28\x3a\x69\xe6\xde\xd6\xbb"; + const char *in2 = "abcdefghijklmnopqrstuvwxyz"; + const char *out2 = + "\x4e\x8d\xdf\xf3\x65\x02\x92\xab\x5a\x41\x08\xc3\xaa\x47\x94\x0b"; + char buf[MD2_DIGEST_SIZE]; + + if (memcmp (md2_buffer (in1, strlen (in1), buf), out1, MD2_DIGEST_SIZE) != + 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < MD2_DIGEST_SIZE; i++) + printf ("%02x ", out1[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < MD2_DIGEST_SIZE; i++) + printf ("%02x ", buf[i] & 0xFF); + printf ("\n"); + return 1; + } + + if (memcmp (md2_buffer (in2, strlen (in2), buf), out2, MD2_DIGEST_SIZE) != + 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < MD2_DIGEST_SIZE; i++) + printf ("%02x ", out2[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < MD2_DIGEST_SIZE; i++) + printf ("%02x ", buf[i] & 0xFF); + printf ("\n"); + return 1; + } + + return 0; +} -- 2.11.0