summaryrefslogtreecommitdiff
path: root/cipher/whirlpool.c
diff options
context:
space:
mode:
Diffstat (limited to 'cipher/whirlpool.c')
-rw-r--r--cipher/whirlpool.c132
1 files changed, 128 insertions, 4 deletions
diff --git a/cipher/whirlpool.c b/cipher/whirlpool.c
index 57ca8826..ffc6662c 100644
--- a/cipher/whirlpool.c
+++ b/cipher/whirlpool.c
@@ -54,6 +54,11 @@ typedef u64 whirlpool_block_t[BLOCK_SIZE / 8];
typedef struct {
gcry_md_block_ctx_t bctx;
whirlpool_block_t hash_state;
+ int use_bugemu;
+ struct {
+ size_t count;
+ unsigned char length[32];
+ } bugemu;
} whirlpool_context_t;
@@ -1166,7 +1171,7 @@ whirlpool_transform (void *ctx, const unsigned char *data, size_t nblks);
static void
-whirlpool_init (void *ctx)
+whirlpool_init (void *ctx, unsigned int flags)
{
whirlpool_context_t *context = ctx;
@@ -1174,9 +1179,17 @@ whirlpool_init (void *ctx)
context->bctx.blocksize = BLOCK_SIZE;
context->bctx.bwrite = whirlpool_transform;
+ if ((flags & GCRY_MD_FLAG_BUGEMU1))
+ {
+ memset (&context->bugemu, 0, sizeof context->bugemu);
+ context->use_bugemu = 1;
+ }
+ else
+ context->use_bugemu = 0;
}
+
/*
* Transform block.
*/
@@ -1295,15 +1308,120 @@ whirlpool_transform ( void *c, const unsigned char *data, size_t nblks )
return burn;
}
+
+/* Bug compatibility Whirlpool version. */
+static void
+whirlpool_add_bugemu (whirlpool_context_t *context,
+ const void *buffer_arg, size_t buffer_n)
+{
+ const unsigned char *buffer = buffer_arg;
+ u64 buffer_size;
+ unsigned int carry;
+ unsigned int i;
+
+ buffer_size = buffer_n;
+
+ if (context->bugemu.count == BLOCK_SIZE)
+ {
+ /* Flush the buffer. */
+ whirlpool_transform (context, context->bctx.buf, 1);
+ context->bugemu.count = 0;
+ }
+ if (! buffer)
+ return; /* Nothing to add. */
+
+ if (context->bugemu.count)
+ {
+ while (buffer_n && (context->bugemu.count < BLOCK_SIZE))
+ {
+ context->bctx.buf[context->bugemu.count++] = *buffer++;
+ buffer_n--;
+ }
+ whirlpool_add_bugemu (context, NULL, 0);
+ if (!buffer_n)
+ return; /* Done. This is the bug we emulate. */
+ }
+
+ while (buffer_n >= BLOCK_SIZE)
+ {
+ whirlpool_transform (context, buffer, 1);
+ context->bugemu.count = 0;
+ buffer_n -= BLOCK_SIZE;
+ buffer += BLOCK_SIZE;
+ }
+ while (buffer_n && (context->bugemu.count < BLOCK_SIZE))
+ {
+ context->bctx.buf[context->bugemu.count++] = *buffer++;
+ buffer_n--;
+ }
+
+ /* Update bit counter. */
+ carry = 0;
+ buffer_size <<= 3;
+ for (i = 1; i <= 32; i++)
+ {
+ if (! (buffer_size || carry))
+ break;
+
+ carry += context->bugemu.length[32 - i] + (buffer_size & 0xFF);
+ context->bugemu.length[32 - i] = carry;
+ buffer_size >>= 8;
+ carry >>= 8;
+ }
+ gcry_assert (! (buffer_size || carry));
+}
+
+
+/* Bug compatibility Whirlpool version. */
+static void
+whirlpool_final_bugemu (void *ctx)
+{
+ whirlpool_context_t *context = ctx;
+ unsigned int i;
+
+ /* Flush. */
+ whirlpool_add_bugemu (context, NULL, 0);
+
+ /* Pad. */
+ context->bctx.buf[context->bugemu.count++] = 0x80;
+
+ if (context->bugemu.count > 32)
+ {
+ /* An extra block is necessary. */
+ while (context->bugemu.count < 64)
+ context->bctx.buf[context->bugemu.count++] = 0;
+ whirlpool_add_bugemu (context, NULL, 0);
+ }
+ while (context->bugemu.count < 32)
+ context->bctx.buf[context->bugemu.count++] = 0;
+
+ /* Add length of message. */
+ memcpy (context->bctx.buf + context->bugemu.count,
+ context->bugemu.length, 32);
+ context->bugemu.count += 32;
+ whirlpool_add_bugemu (context, NULL, 0);
+
+ block_to_buffer (context->bctx.buf, context->hash_state, i);
+}
+
+
static void
whirlpool_write (void *ctx, const void *buffer, size_t buffer_n)
{
whirlpool_context_t *context = ctx;
- u64 old_nblocks = context->bctx.nblocks;
- _gcry_md_block_write (context, buffer, buffer_n);
+ if (context->use_bugemu)
+ {
+ whirlpool_add_bugemu (context, buffer, buffer_n);
+ }
+ else
+ {
+ u64 old_nblocks = context->bctx.nblocks;
+
+ _gcry_md_block_write (context, buffer, buffer_n);
- gcry_assert (old_nblocks <= context->bctx.nblocks);
+ gcry_assert (old_nblocks <= context->bctx.nblocks);
+ }
}
static void
@@ -1314,6 +1432,12 @@ whirlpool_final (void *ctx)
u64 t, th, lsb, msb;
unsigned char *length;
+ if (context->use_bugemu)
+ {
+ whirlpool_final_bugemu (ctx);
+ return;
+ }
+
t = context->bctx.nblocks;
/* if (sizeof t == sizeof context->bctx.nblocks) */
th = context->bctx.nblocks_high;