/* * Copyright (C) 1998 Nikos Mavroyanopoulos * Copyright (C) 1999,2000 Sascha Schumman, Nikos Mavroyanopoulos * Copyright (C) 2001 Nikos Mavroyanopoulos * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* $Id: mhash.c,v 1.42 2006/01/10 04:40:48 imipak Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 19/03/2000 Changes for better thread handling --nikos * Actually it is thread safe. */ #define MAX_BLOCK_SIZE 128 #define MHASH_ENTRY(name, blksize, hash_pblock, state_size, \ init_func, hash_func, final_func, deinit_func) \ { (mutils_word8 *) #name, name, blksize, hash_pblock, state_size, \ (INIT_FUNC) init_func, (HASH_FUNC) hash_func, \ (FINAL_FUNC) final_func, (DEINIT_FUNC) deinit_func } struct mhash_hash_entry { mutils_word8 *name; hashid id; mutils_word32 blocksize; mutils_word32 hash_pblock; mutils_word32 state_size; INIT_FUNC init_func; HASH_FUNC hash_func; FINAL_FUNC final_func; DEINIT_FUNC deinit_func; }; static __const mhash_hash_entry algorithms[] = { #if defined(ENABLE_CRC32) MHASH_ENTRY(MHASH_CRC32, 4, 0, sizeof(mutils_word32), mhash_clear_crc32, mhash_crc32, NULL, mhash_get_crc32), MHASH_ENTRY(MHASH_CRC32B, 4, 0, sizeof(mutils_word32), mhash_clear_crc32, mhash_crc32b, NULL, mhash_get_crc32), #endif #if defined(ENABLE_ADLER32) MHASH_ENTRY(MHASH_ADLER32, 4, 0, sizeof(mutils_word32), mhash_clear_adler32, mhash_adler32, NULL, mhash_get_adler32), #endif #if defined(ENABLE_MD5) MHASH_ENTRY(MHASH_MD5, 16, 64, sizeof(MD5_CTX), MD5Init, MD5Update, NULL, MD5Final), #endif #if defined(ENABLE_MD4) MHASH_ENTRY(MHASH_MD4, 16, 64, sizeof(MD4_CTX), MD4Init, MD4Update, NULL, MD4Final), #endif #if defined(ENABLE_MD2) MHASH_ENTRY(MHASH_MD2, 16, 16, sizeof(MD2_CTX), md2_init, md2_update, NULL, md2_digest), #endif #if defined(ENABLE_SHA1) MHASH_ENTRY(MHASH_SHA1, 20, 64, sizeof(SHA_CTX), sha_init, sha_update, sha_final, sha_digest), #endif #if defined(ENABLE_SHA256_SHA224) MHASH_ENTRY(MHASH_SHA256, 32, 64, sizeof( SHA256_SHA224_CTX), sha256_init, sha256_sha224_update, sha256_sha224_final, sha256_digest), MHASH_ENTRY(MHASH_SHA224, 28, 64, sizeof( SHA256_SHA224_CTX), sha224_init, sha256_sha224_update, sha256_sha224_final, sha224_digest), #endif #if defined(ENABLE_SHA512_SHA384) MHASH_ENTRY(MHASH_SHA512, 64, 128, sizeof( SHA512_SHA384_CTX), sha512_init, sha512_sha384_update, sha512_sha384_final, sha512_digest), MHASH_ENTRY(MHASH_SHA384, 48, 128, sizeof( SHA512_SHA384_CTX), sha384_init, sha512_sha384_update, sha512_sha384_final, sha384_digest), #endif #if defined(ENABLE_HAVAL) MHASH_ENTRY(MHASH_HAVAL256, 32, 128, sizeof(havalContext), havalInit256, havalUpdate, NULL, havalFinal), MHASH_ENTRY(MHASH_HAVAL128, 16, 128, sizeof(havalContext), havalInit128, havalUpdate, NULL, havalFinal), MHASH_ENTRY(MHASH_HAVAL160, 20, 128, sizeof(havalContext), havalInit160, havalUpdate, NULL, havalFinal), MHASH_ENTRY(MHASH_HAVAL192, 24, 128, sizeof(havalContext), havalInit192, havalUpdate, NULL, havalFinal), MHASH_ENTRY(MHASH_HAVAL224, 28, 128, sizeof(havalContext), havalInit224, havalUpdate, NULL, havalFinal), #endif #if defined(ENABLE_RIPEMD) MHASH_ENTRY(MHASH_RIPEMD128, 16, 64, sizeof(RIPEMD_CTX), ripemd128_init, ripemd_update, ripemd_final, ripemd_digest), MHASH_ENTRY(MHASH_RIPEMD160, 20, 64, sizeof(RIPEMD_CTX), ripemd160_init, ripemd_update, ripemd_final, ripemd_digest), MHASH_ENTRY(MHASH_RIPEMD256, 32, 64, sizeof(RIPEMD_CTX), ripemd256_init, ripemd_update, ripemd_final, ripemd_digest), MHASH_ENTRY(MHASH_RIPEMD320, 40, 64, sizeof(RIPEMD_CTX), ripemd320_init, ripemd_update, ripemd_final, ripemd_digest), #endif #if defined(ENABLE_TIGER) MHASH_ENTRY(MHASH_TIGER, 24, 64, sizeof(TIGER_CTX), tiger_init, tiger_update, tiger_final, tiger_digest), MHASH_ENTRY(MHASH_TIGER128, 16, 64, sizeof(TIGER_CTX), tiger_init, tiger_update, tiger_final, tiger128_digest), MHASH_ENTRY(MHASH_TIGER160, 20, 64, sizeof(TIGER_CTX), tiger_init, tiger_update, tiger_final, tiger160_digest), #endif #if defined(ENABLE_GOST) MHASH_ENTRY(MHASH_GOST, 32, 0, sizeof(GostHashCtx), gosthash_reset, gosthash_update, NULL, gosthash_final), #endif #if defined(ENABLE_WHIRLPOOL) MHASH_ENTRY(MHASH_WHIRLPOOL, 64, 64, sizeof(WHIRLPOOL_CTX), whirlpool_init, whirlpool_update, whirlpool_final, whirlpool_digest), #endif #if defined(ENABLE_SNEFRU) MHASH_ENTRY(MHASH_SNEFRU128, 16, 64, sizeof(SNEFRU_CTX), snefru_init, snefru128_update, snefru128_final, snefru128_digest), MHASH_ENTRY(MHASH_SNEFRU256, 32, 64, sizeof(SNEFRU_CTX), snefru_init, snefru256_update, snefru256_final, snefru256_digest), #endif {0} }; #define MHASH_LOOP(b) \ __const mhash_hash_entry *p; \ for (p = algorithms; p->name != NULL; p++) { b ; } #define MHASH_ALG_LOOP(a) \ MHASH_LOOP( if (p->id == type) { a; break; } ) #ifndef MMAX # define MMAX(x,y) (x>y?x:y) #endif WIN32DLL_DEFINE mutils_word32 mhash_count(void) { hashid count = 0; MHASH_LOOP( count = MMAX( p->id, count) ); return count; } WIN32DLL_DEFINE mutils_word32 mhash_get_block_size(hashid type) { mutils_word32 ret = 0; MHASH_ALG_LOOP(ret = p->blocksize); return ret; } WIN32DLL_DEFINE mutils_word32 _mhash_get_state_size(hashid type) { /* Fixed: Valid state sizes that exceeded maximum positive value for integer would be returned as an error. */ mutils_word32 size = 0; MHASH_ALG_LOOP(size = p->state_size); return size; } WIN32DLL_DEFINE INIT_FUNC _mhash_get_init_func(hashid type) { INIT_FUNC func = NULL; MHASH_ALG_LOOP(func = p->init_func); return func; } WIN32DLL_DEFINE HASH_FUNC _mhash_get_hash_func(hashid type) { HASH_FUNC func = NULL; MHASH_ALG_LOOP(func = p->hash_func); return func; } WIN32DLL_DEFINE FINAL_FUNC _mhash_get_final_func(hashid type) { FINAL_FUNC func = NULL; MHASH_ALG_LOOP(func = p->final_func); return func; } WIN32DLL_DEFINE DEINIT_FUNC _mhash_get_deinit_func(hashid type) { DEINIT_FUNC func = NULL; MHASH_ALG_LOOP(func = p->deinit_func); return func; } WIN32DLL_DEFINE hashid mhash_get_mhash_algo( MHASH tmp) { return tmp->algorithm_given; } WIN32DLL_DEFINE mutils_word8 *mhash_get_hash_name(hashid type) { mutils_word8 *ret = NULL; /* avoid prefix */ MHASH_ALG_LOOP(ret = p->name); if (ret != NULL) { ret += sizeof("MHASH_") - 1; } return mutils_strdup(ret); } WIN32DLL_DEFINE __const mutils_word8 *mhash_get_hash_name_static(hashid type) { mutils_word8 *ret = NULL; /* avoid prefix */ MHASH_ALG_LOOP( ret = p->name); if ( ret != NULL) { ret += sizeof("MHASH_") - 1; } return ret; } MHASH mhash_cp(MHASH from) { MHASH ret; ret = (MHASH) mutils_malloc(sizeof(MHASH_INSTANCE)); if (ret == NULL) { return(MHASH_FAILED); } mutils_memcpy(ret, from, sizeof(MHASH_INSTANCE)); /* copy the internal state also */ ret->state = (mutils_word8 *) mutils_malloc(ret->state_size); if (ret->state == NULL) { mutils_free(ret); return(MHASH_FAILED); } mutils_memcpy(ret->state, from->state, ret->state_size); /* copy the key in case of hmac*/ if (ret->hmac_key_size != 0) { ret->hmac_key = (mutils_word8 *) mutils_malloc(ret->hmac_key_size); if (ret == NULL) { mutils_free(ret->state); mutils_free(ret); return(MHASH_FAILED); } mutils_memcpy(ret->hmac_key, from->hmac_key, ret->hmac_key_size); } return ret; } MHASH mhash_init_int(__const hashid type) { MHASH ret; INIT_FUNC func; ret = (MHASH) mutils_malloc(sizeof(MHASH_INSTANCE)); if (ret == NULL) { return MHASH_FAILED; } mutils_memset(ret, 0, sizeof(MHASH_INSTANCE)); ret->algorithm_given = type; ret->state_size = _mhash_get_state_size(type); if (ret->state_size == 0) { mutils_free(ret); return(MHASH_FAILED); } if ( (ret->state = mutils_malloc(ret->state_size)) == NULL) { mutils_free(ret); return(MHASH_FAILED); } func = _mhash_get_init_func( type); if (func != NULL) { func(ret->state); } else { mutils_free(ret->state); mutils_free(ret); return(MHASH_FAILED); } ret->hash_func = _mhash_get_hash_func( type); ret->deinit_func = _mhash_get_deinit_func( type); ret->final_func = _mhash_get_final_func( type); return ret; } /* plaintext should be a multiple of the algorithm's block size */ mutils_boolean mhash(MHASH td, __const void *plaintext, mutils_word32 size) { if (td->hash_func!=NULL) { td->hash_func( td->state, plaintext, size); } return(MUTILS_OK); } WIN32DLL_DEFINE void mhash_deinit(MHASH td, void *result) { if (td->final_func != NULL) { td->final_func( td->state); } if (td->deinit_func != NULL) { td->deinit_func( td->state, result); } if (NULL != td->state) { mutils_free(td->state); } mutils_free(td); return; } WIN32DLL_DEFINE void *mhash_end_m(MHASH td, void *(*hash_malloc) (mutils_word32)) { void *digest; mutils_word32 size; size = mhash_get_block_size( td->algorithm_given); digest = mutils_malloc(size); if (digest==NULL) { return NULL; } mhash_deinit( td, digest); return(digest); } WIN32DLL_DEFINE void *mhash_end(MHASH td) { return(mhash_end_m(td, mutils_malloc)); } WIN32DLL_DEFINE MHASH mhash_init(__const hashid type) { MHASH ret = MHASH_FAILED; ret = mhash_init_int(type); return(ret); } /* HMAC functions */ WIN32DLL_DEFINE mutils_word32 mhash_get_hash_pblock(hashid type) { mutils_word32 ret = 0; MHASH_ALG_LOOP(ret = p->hash_pblock); return(ret); } WIN32DLL_DEFINE mutils_error mhash_hmac_deinit(MHASH td, void *result) { mutils_word8 *opad; mutils_word8 _opad[MAX_BLOCK_SIZE]; MHASH tmptd; mutils_word32 i; mutils_word32 opad_alloc = 0; if (td->hmac_block > MAX_BLOCK_SIZE) { opad = mutils_malloc(td->hmac_block); if (opad == NULL) { return(-MUTILS_SYSTEM_RESOURCE_ERROR); } opad_alloc = 1; } else { opad = _opad; } for (i = 0; i < td->hmac_key_size; i++) { opad[i] = (0x5C) ^ td->hmac_key[i]; } for (; i < td->hmac_block; i++) { opad[i] = (0x5C); } tmptd = mhash_init(td->algorithm_given); mhash(tmptd, opad, td->hmac_block); if (td->final_func != NULL) { td->final_func(td->state); } if (td->deinit_func != NULL) { td->deinit_func(td->state, result); } if (result != NULL) { mhash(tmptd, result, mhash_get_block_size(td->algorithm_given)); } mutils_free(td->state); if (opad_alloc!=0) { mutils_free(opad); } mutils_bzero(td->hmac_key, td->hmac_key_size); mutils_free(td->hmac_key); mutils_free(td); mhash_deinit(tmptd, result); return(MUTILS_OK); } WIN32DLL_DEFINE void *mhash_hmac_end_m(MHASH td, void *(*hash_malloc) (mutils_word32)) { void *digest; digest = hash_malloc(mhash_get_block_size (td->algorithm_given)); if (digest == NULL) { return(NULL); } mhash_hmac_deinit(td, digest); return(digest); } WIN32DLL_DEFINE void *mhash_hmac_end(MHASH td) { return mhash_hmac_end_m(td, mutils_malloc); } WIN32DLL_DEFINE MHASH mhash_hmac_init(__const hashid type, void *key, mutils_word32 keysize, mutils_word32 block) { MHASH ret = MHASH_FAILED; MHASH tmptd; mutils_word8 *ipad; mutils_word8 _ipad[MAX_BLOCK_SIZE]; mutils_word32 i; mutils_boolean ipad_alloc = MUTILS_FALSE; mutils_boolean res; if (block == 0) { block = 64; /* the default for ripemd,md5,sha-1 */ } ret = mhash_init_int(type); if (ret != MHASH_FAILED) { /* Initial hmac calculations */ ret->hmac_block = block; if ( ret->hmac_block > MAX_BLOCK_SIZE) { ipad = mutils_malloc(ret->hmac_block); if (ipad == NULL) { return MHASH_FAILED; } ipad_alloc = MUTILS_TRUE; } else { ipad = _ipad; } if (keysize > ret->hmac_block) { tmptd = mhash_init(type); mhash(tmptd, key, keysize); ret->hmac_key_size = mhash_get_block_size(type); ret->hmac_key = mhash_end(tmptd); } else { ret->hmac_key = mutils_malloc(ret->hmac_block); mutils_bzero(ret->hmac_key, ret->hmac_block); mutils_memcpy(ret->hmac_key, key, keysize); ret->hmac_key_size = ret->hmac_block; } /* IPAD */ for (i = 0; i < ret->hmac_key_size; i++) { ipad[i] = (0x36) ^ ret->hmac_key[i]; } for (; i < ret->hmac_block; i++) { ipad[i] = (0x36); } res = mhash(ret, ipad, ret->hmac_block); if (ipad_alloc == MUTILS_TRUE) { mutils_free(ipad); } } return(ret); } WIN32DLL_DEFINE void mhash_free(void *ptr) { mutils_free(ptr); } /* Saves the state of a hashing algorithm such that it can be restored at some later point in time using mhash_restore_state(). mem_size should contain the size of the given _mem pointer. Otherwise the required size will be copied there. Original version and idea by Blake Stephen */ WIN32DLL_DEFINE mutils_error mhash_save_state_mem(MHASH td, void *_mem, mutils_word32 *mem_size ) { mutils_word32 tot_size; mutils_word32 pos; mutils_word8 *mem = _mem; tot_size = sizeof(td->algorithm_given) + sizeof(td->hmac_key_size) + sizeof(td->hmac_block) + td->hmac_key_size + + sizeof(td->state_size) + td->state_size; if ( *mem_size < tot_size) { *mem_size = tot_size; return(MUTILS_INVALID_INPUT_BUFFER); } if ( mem != NULL) { pos = 0; mutils_memcpy( mem, &td->algorithm_given, sizeof(td->algorithm_given)); pos = sizeof( td->algorithm_given); mutils_memcpy( &mem[pos], &td->hmac_key_size, sizeof(td->hmac_key_size)); pos += sizeof(td->hmac_key_size); mutils_memcpy( &mem[pos], &td->hmac_block, sizeof(td->hmac_block)); pos += sizeof(td->hmac_block); mutils_memcpy( &mem[pos], td->hmac_key, td->hmac_key_size); pos += td->hmac_key_size; mutils_memcpy( &mem[pos], &td->state_size, sizeof(td->state_size)); pos += sizeof(td->state_size); mutils_memcpy( &mem[pos], td->state, td->state_size); pos += td->state_size; } return(MUTILS_OK); } /* Restores the state of a hashing algorithm that was saved using mhash_save_state(). Use like mhash_init. */ WIN32DLL_DEFINE MHASH mhash_restore_state_mem(void* _mem) { mutils_word8 *mem = _mem; hashid algorithm_given; MHASH ret = MHASH_FAILED; mutils_word32 pos; if (mem==NULL) { return(ret); } mutils_memcpy( &algorithm_given, mem, sizeof(algorithm_given)); if ((ret = mhash_init(algorithm_given)) == MHASH_FAILED) { return(ret); } ret->algorithm_given = algorithm_given; pos = sizeof(algorithm_given); mutils_memcpy( &ret->hmac_key_size, &mem[pos], sizeof(ret->hmac_key_size)); pos += sizeof( ret->hmac_key_size); mutils_memcpy( &ret->hmac_block, &mem[pos], sizeof(ret->hmac_block)); pos += sizeof(ret->hmac_block); if (ret->hmac_key_size != 0) { ret->hmac_key = mutils_malloc(ret->hmac_key_size); if (ret->hmac_key == NULL) { goto freeall; } mutils_memcpy( ret->hmac_key, &mem[pos], ret->hmac_key_size); pos += sizeof(ret->hmac_key_size); } mutils_memcpy( &ret->state_size, &mem[pos], sizeof(ret->state_size)); pos += sizeof( ret->state_size); ret->state = mutils_malloc(ret->state_size); if (ret->state==NULL) goto freeall; mutils_memcpy( ret->state, &mem[pos], ret->state_size); pos += ret->state_size; ret->hash_func = _mhash_get_hash_func( algorithm_given); ret->deinit_func = _mhash_get_deinit_func( algorithm_given); ret->final_func = _mhash_get_final_func( algorithm_given); return(ret); freeall: /* This uses too much internals */ mutils_free(ret->state); mutils_free(ret->hmac_key); mutils_free(ret); return(MHASH_FAILED); } #if defined(WIN32) || defined (__CYGWIN__) WIN32DLL_DEFINE int main (void) { /* empty main function to avoid linker error (see cygwin FAQ) */ } #endif