/* "UH Universal Hashing Library" Copyright ((c)) 2002, Rice University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Rice University (RICE) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. This software is provided by RICE and the contributors on an "as is" basis, without any representations or warranties of any kind, express or implied including, but not limited to, representations or warranties of non-infringement, merchantability or fitness for a particular purpose. In no event shall RICE or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. */ #include "uh_cw.h" #include "uh_internals.h" #include #include struct uh_cw_ctx { char key[UH_AES_KEY_LEN]; UINT32 *rndvector; /* These are needed for the update/final interface */ UINT64 partial_sum; int index; int threshold; }; static UINT32 p32 = ((UINT32)0xFFFFFFFBu); /* 2^32 - 5 */ uh_cw_ctx_t uh_cw_alloc(const char key[UH_AES_KEY_LEN], int threshold) { struct uh_cw_ctx *ctx; uh_aes_int_key aeskey; UINT8 in[UH_AES_BLOCK_LEN], out[UH_AES_BLOCK_LEN]; int i; /* Fail if the threshold is out of bounds */ if (threshold >= (1<<20) || threshold <= 0) return NULL; /* Do all the allocation here */ ctx=(struct uh_cw_ctx *)malloc(sizeof(struct uh_cw_ctx)); if (ctx == NULL) return NULL; /* Must allocate one extra word for terminal '1'. */ ctx->rndvector=(UINT32 *)malloc((threshold+1)*4); if (ctx->rndvector == NULL) { free(ctx); return NULL; } /* Allocation done. Initialize the struct */ ctx->partial_sum = 0; ctx->index=0; ctx->threshold=threshold; memcpy(ctx->key,key,UH_AES_KEY_LEN); /* AES setup for random vector */ uh_aes_setup((const UINT8*)key,aeskey); memset(in, 0, UH_AES_BLOCK_LEN); for(i=0 ; i < threshold+1 ; i++) { if (i % (UH_AES_BLOCK_LEN / 4) == 0) { STORE_UINT32_LITTLE(in,i); uh_aes_encrypt(in,out,aeskey); } ctx->rndvector[i]=(LOAD_UINT32_LITTLE(((UINT32 *)out)+ (i % (UH_AES_BLOCK_LEN / 4))))%p32; } return ctx; } void uh_cw_delete(uh_cw_ctx_t ctx) { if (!ctx) { exit(1); } free (ctx->rndvector); free (ctx); } void uh_cw_reset(uh_cw_ctx_t ctx) { if (!ctx) { exit(1); } ctx->index=0; ctx->partial_sum = 0; } /* Long slow correct technique for generating bytes */ static UINT32 uh_cw_rndgen_slow(uh_cw_ctx_t ctx, long index) { uh_aes_int_key aeskey; UINT8 in[UH_AES_BLOCK_LEN], out[UH_AES_BLOCK_LEN]; if (!ctx) { exit(1); } if (index >= (1<<20)) { exit(1); } /* AES setup for random vector */ uh_aes_setup((const UINT8*)ctx->key,aeskey); memset(in, 0, UH_AES_BLOCK_LEN); STORE_UINT32_LITTLE(in,(index/(UH_AES_BLOCK_LEN / 4))*(UH_AES_BLOCK_LEN / 4)); uh_aes_encrypt(in,out,aeskey); return LOAD_UINT32_LITTLE(((UINT32 *)out)+ (index % (UH_AES_BLOCK_LEN / 4))); } void uh_cw_update(uh_cw_ctx_t ctx, const char *input, long len) { int i=0; if (!ctx) { exit(1); } for (i=0 ; i < len && ctx->index < ctx->threshold ; i++, (ctx->index)++) { ctx->partial_sum += input[i]*((UINT64)ctx->rndvector[ctx->index]); } if (i != len && ctx->index >= ctx->threshold) { /* BUGGO: TODO: Must deal with input thats too long here. */ for ( ; i < len ; i++, (ctx->index)++) ctx->partial_sum += input[i]*((UINT64)uh_cw_rndgen_slow(ctx,ctx->index)); } } unsigned int uh_cw_final(uh_cw_ctx_t ctx) { unsigned int out; UINT64 partial_sum; if (!ctx) { exit(1); } /* We must see if we need to calculate the sentinel. */ if (ctx->index > ctx->threshold) partial_sum = ctx->partial_sum+uh_cw_rndgen_slow(ctx,ctx->index); else { partial_sum = ctx->partial_sum+ctx->rndvector[ctx->index]; } out = partial_sum % p32; uh_cw_reset(ctx); return out; } /* May be invoked in parallel in different threads as long as the input is less than threshold. Otherwise, cannot. */ unsigned int uh_cw(uh_cw_ctx_t ctx, const char *input, long len) { int i=0; UINT64 partial_sum = 0; if (!ctx) { exit(1); } if (len > ctx->threshold) { /* BUGGO: TODO: Must deal with input thats too long here. */ uh_cw_update(ctx,input,len); return uh_cw_final(ctx); } for (i=0 ; i < len ; i++) { partial_sum += input[i]* (UINT64)(ctx->rndvector[i]); } partial_sum += ctx->rndvector[i]; return partial_sum % p32; } /* Unsafe if input is over threshold in length */ unsigned int uh_cw_UNSAFE(uh_cw_ctx_t ctx, const char *input, long len) { int i=0; UINT64 partial_sum = 0; if (!ctx) { exit(1); } for (i=0 ; i < len ; i++) { partial_sum += (input[i])* (UINT64)(ctx->rndvector[i]); } partial_sum += ctx->rndvector[i]; return partial_sum % p32; } void uh_cw_getkey(uh_cw_ctx_t ctx, char *key) { if (!ctx) { exit(1); } if (!key) { exit(1); } memcpy(key,ctx->key,UH_AES_KEY_LEN); }