aboutsummaryrefslogtreecommitdiffstats
path: root/Source/charon/transforms
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2005-11-21 18:01:20 +0000
committerMartin Willi <martin@strongswan.org>2005-11-21 18:01:20 +0000
commit784e2368390baeb5aab88d6e59ad2e2071690fc4 (patch)
treef9ecb45b5559bfa666bd177c167f9b752fed2869 /Source/charon/transforms
parent0666a152c28cd1ddf09a9c3d53fba345039c31bb (diff)
downloadstrongswan-784e2368390baeb5aab88d6e59ad2e2071690fc4.tar.bz2
strongswan-784e2368390baeb5aab88d6e59ad2e2071690fc4.tar.xz
- implementation of hasher_sha1
- tested
Diffstat (limited to 'Source/charon/transforms')
-rw-r--r--Source/charon/transforms/hashers/hasher.h24
-rw-r--r--Source/charon/transforms/hashers/hasher_sha1.c222
2 files changed, 237 insertions, 9 deletions
diff --git a/Source/charon/transforms/hashers/hasher.h b/Source/charon/transforms/hashers/hasher.h
index 24286782d..ff7fcc361 100644
--- a/Source/charon/transforms/hashers/hasher.h
+++ b/Source/charon/transforms/hashers/hasher.h
@@ -46,19 +46,30 @@ struct hasher_s {
/**
* @brief hash data and write it in the buffer
*
+ * If the parameter hash is NULL, no result is written back
+ * an more data can be appended to already hashed data.
+ * If not, the result is written back and the hasher is reset.
+ *
+ * @warning: the hash output parameter must hold at least
+ * #hash_t.get_block_size bytes.
+ *
* @param this calling hasher
* @param data data to hash
* @param [out]buffer pointer where the hash will be written
* @return
* - SUCCESS in any case
*/
- status_t (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *buffer);
+ status_t (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *hash);
/**
* @brief hash data and allocate space for the hash
*
+ * If the parameter hash is NULL, no result is written back
+ * an more data can be appended to already hashed data.
+ * If not, the result is written back and the hasher is reset.
+ *
* @param this calling hasher
- * @param seed a chunk containing the seed for the next bytes
+ * @param data chunk with data to hash
* @param [out]hash chunk which will hold allocated hash
* @return
* - SUCCESS in any case
@@ -75,6 +86,15 @@ struct hasher_s {
size_t (*get_block_size) (hasher_t *this);
/**
+ * @brief reset the hashers state, which allows
+ * computation of a completly new hash.
+ *
+ * @param this calling hasher
+ * @return - SUCCESS in any case
+ */
+ status_t (*reset) (hasher_t *this);
+
+ /**
* @brief Destroys a hasher object.
*
* @param this hasher_t object to destroy
diff --git a/Source/charon/transforms/hashers/hasher_sha1.c b/Source/charon/transforms/hashers/hasher_sha1.c
index 9a9df501f..1349a4135 100644
--- a/Source/charon/transforms/hashers/hasher_sha1.c
+++ b/Source/charon/transforms/hashers/hasher_sha1.c
@@ -9,6 +9,9 @@
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
+ *
+ * Ported from Steve Reid's <steve@edmweb.com> implementation
+ * "SHA1 in C" found in strongSwan.
*
* 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
@@ -23,19 +26,221 @@
#include "hasher_sha1.h"
+#include "../../definitions.h"
#include "../../utils/allocator.h"
+#define BLOCK_SIZE_SHA1 20
+
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+ #define blk0(i) block->l[i]
+#else
+ #error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
typedef struct private_hasher_sha1_s private_hasher_sha1_t;
struct private_hasher_sha1_s {
/**
* public interface for this hasher
*/
- hasher_sha1_t public;
+ hasher_sha1_t public;
+
+
+ u_int32_t state[5];
+ u_int32_t count[2];
+ u_int8_t buffer[64];
};
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64])
+{
+ u_int32_t a, b, c, d, e;
+ typedef union {
+ u_int8_t c[64];
+ u_int32_t l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+ memcpy(block, buffer, 64);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+ memset(block, '\0', sizeof(block));
+}
+
+/* Run your data through this. */
+void SHA1Update(private_hasher_sha1_t* this, u_int8_t *data, u_int32_t len)
+{
+ u_int32_t i;
+ u_int32_t j;
+
+ j = this->count[0];
+ if ((this->count[0] += len << 3) < j)
+ {
+ this->count[1]++;
+ }
+ this->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63)
+ {
+ memcpy(&this->buffer[j], data, (i = 64-j));
+ SHA1Transform(this->state, this->buffer);
+ for ( ; i + 63 < len; i += 64)
+ {
+ SHA1Transform(this->state, &data[i]);
+ }
+ j = 0;
+ }
+ else
+ {
+ i = 0;
+ }
+ memcpy(&this->buffer[j], &data[i], len - i);
+}
+/*
+ * Add padding and return the message digest.
+ */
+void SHA1Final(private_hasher_sha1_t *this, u_int8_t *digest)
+{
+ u_int32_t i;
+ u_int8_t finalcount[8];
+ u_int8_t c;
+
+ for (i = 0; i < 8; i++)
+ {
+ finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ c = 0200;
+ SHA1Update(this, &c, 1);
+ while ((this->count[0] & 504) != 448)
+ {
+ c = 0000;
+ SHA1Update(this, &c, 1);
+ }
+ SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++)
+ {
+ digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+}
+
+
+/**
+ * implementation of hasher_t.get_hash for sha1
+ */
+static status_t get_hash(private_hasher_sha1_t *this, chunk_t chunk, u_int8_t *buffer)
+{
+ SHA1Update(this, chunk.ptr, chunk.len);
+ if (buffer != NULL)
+ {
+ SHA1Final(this, buffer);
+ }
+ return SUCCESS;
+}
+
+
+/**
+ * implementation of hasher_t.allocate_hash for sha1
+ */
+static status_t allocate_hash(private_hasher_sha1_t *this, chunk_t chunk, chunk_t *hash)
+{
+ chunk_t allocated_hash;
+ allocated_hash.ptr = allocator_alloc(BLOCK_SIZE_SHA1);
+ allocated_hash.len = BLOCK_SIZE_SHA1;
+ if (allocated_hash.ptr == NULL)
+ {
+ return OUT_OF_RES;
+ }
+
+ SHA1Update(this, chunk.ptr, chunk.len);
+ if (hash != NULL)
+ {
+ SHA1Final(this, allocated_hash.ptr);
+ }
+
+ *hash = allocated_hash;
+
+ return SUCCESS;
+}
+
+/**
+ * implementation of hasher_t.get_block_size for sha1
+ */
+static size_t get_block_size(private_hasher_sha1_t *this)
+{
+ return BLOCK_SIZE_SHA1;
+}
+
+/**
+ * implementation of hasher_t.reset for sha1
+ */
+static status_t reset(private_hasher_sha1_t *this)
+{
+ this->state[0] = 0x67452301;
+ this->state[1] = 0xEFCDAB89;
+ this->state[2] = 0x98BADCFE;
+ this->state[3] = 0x10325476;
+ this->state[4] = 0xC3D2E1F0;
+ this->count[0] = 0;
+ this->count[1] = 0;
+ return SUCCESS;
+}
+/**
+ * implementation of hasher_t.destroy for sha1
+ */
+static status_t destroy(private_hasher_sha1_t *this)
+{
+ allocator_free(this);
+ return SUCCESS;
+}
/*
@@ -44,16 +249,19 @@ struct private_hasher_sha1_s {
hasher_sha1_t *hasher_sha1_create()
{
private_hasher_sha1_t *this = allocator_alloc_thing(private_hasher_sha1_t);
-
if (this == NULL)
{
return NULL;
}
+ this->public.hasher_interface.get_hash = (status_t (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
+ this->public.hasher_interface.allocate_hash = (status_t (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
+ this->public.hasher_interface.get_block_size = (size_t (*) (hasher_t*))get_block_size;
+ this->public.hasher_interface.reset = (size_t (*) (hasher_t*))reset;
+ this->public.hasher_interface.destroy = (size_t (*) (hasher_t*))destroy;
+
+ /* initialize */
+ this->public.hasher_interface.reset(&(this->public.hasher_interface));
+
return &(this->public);
}
-
-
-
-
-