diff options
author | Martin Willi <martin@strongswan.org> | 2005-11-21 18:01:20 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2005-11-21 18:01:20 +0000 |
commit | 784e2368390baeb5aab88d6e59ad2e2071690fc4 (patch) | |
tree | f9ecb45b5559bfa666bd177c167f9b752fed2869 /Source/charon/transforms | |
parent | 0666a152c28cd1ddf09a9c3d53fba345039c31bb (diff) | |
download | strongswan-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.h | 24 | ||||
-rw-r--r-- | Source/charon/transforms/hashers/hasher_sha1.c | 222 |
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); } - - - - - |