Commit c5d8261e authored by Simon Josefsson's avatar Simon Josefsson

Add MD2 and hash fixes.

parent 8df4dfe1
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.
......
......@@ -38,6 +38,9 @@
#include <errno.h>
/* 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)
......
......@@ -27,8 +27,14 @@
/* 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>
......@@ -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)
......
......@@ -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,
......
/* 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,