+2005-10-28 Simon Josefsson <jas@extundo.com>
+
+ * tests/test-gc-md2.c, tests/test-md2.c: New files.
+
+ * modules/md2, modules/md2-tests: New files.
+
2005-10-27 Paul Eggert <eggert@cs.ucla.edu>
* modules/verify (License): Change from GPL to LGPL. This is a
+2005-10-28 Simon Josefsson <jas@extundo.com>
+
+ * 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 <jas@extundo.com>
* md4.h: Shrink buffer size, now that we changed the type.
#include <errno.h>
/* Hashes. */
+#ifdef GC_USE_MD2
+# include "md2.h"
+#endif
#ifdef GC_USE_MD4
# include "md4.h"
#endif
/* 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);
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)
/* Get prototype. */
#include "gc.h"
+#include <stdlib.h>
+#include <string.h>
+
/* Get libgcrypt API. */
#include <gcrypt.h>
+#ifdef GC_USE_MD2
+# include "md2.h"
+#endif
#include <assert.h>
/* 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;
break;
default:
- return GC_INVALID_HASH;
+ rc = GC_INVALID_HASH;
}
switch (mode)
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;
}
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;
}
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
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;
/* 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)
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. */
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,
--- /dev/null
+/* 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 <config.h>
+#endif
+
+#include "md2.h"
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <minmax.h>
+
+#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);
+}
--- /dev/null
+/* 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 <stdio.h>
+# include <stddef.h>
+
+# 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
+2005-10-28 Simon Josefsson <jas@extundo.com>
+
+ * gc-md2.m4, md2.m4: New file.
+
2005-10-22 Simon Josefsson <jas@extundo.com>
* gc.m4: Don't be fooled by --disable-*random-device parameters,
--- /dev/null
+# 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.])
+])
--- /dev/null
+# 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])
+])
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+Files:
+tests/test-md2.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-md2
+noinst_PROGRAMS += test-md2
+test_md2_SOURCES = test-md2.c
--- /dev/null
+/*
+ * 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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#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;
+}
--- /dev/null
+/*
+ * 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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#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;
+}