diff options
Diffstat (limited to 'openssl/engines/ccgost/gosthash.c')
-rw-r--r-- | openssl/engines/ccgost/gosthash.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/openssl/engines/ccgost/gosthash.c b/openssl/engines/ccgost/gosthash.c new file mode 100644 index 000000000..a5c0662ff --- /dev/null +++ b/openssl/engines/ccgost/gosthash.c @@ -0,0 +1,255 @@ +/********************************************************************** + * gosthash.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of GOST R 34.11-94 hash function * + * uses on gost89.c and gost89.h Doesn't need OpenSSL * + **********************************************************************/ +#include <string.h> + +#include "gost89.h" +#include "gosthash.h" + + +/* Use OPENSSL_malloc for memory allocation if compiled with + * -DOPENSSL_BUILD, and libc malloc otherwise + */ +#ifndef MYALLOC +# ifdef OPENSSL_BUILD +# include <openssl/crypto.h> +# define MYALLOC(size) OPENSSL_malloc(size) +# define MYFREE(ptr) OPENSSL_free(ptr) +# else +# define MYALLOC(size) malloc(size) +# define MYFREE(ptr) free(ptr) +# endif +#endif +/* Following functions are various bit meshing routines used in + * GOST R 34.11-94 algorithms */ +static void swap_bytes (byte *w, byte *k) + { + int i,j; + for (i=0;i<4;i++) + for (j=0;j<8;j++) + k[i+4*j]=w[8*i+j]; + + } + +/* was A_A */ +static void circle_xor8 (const byte *w, byte *k) + { + byte buf[8]; + int i; + memcpy(buf,w,8); + memcpy(k,w+8,24); + for(i=0;i<8;i++) + k[i+24]=buf[i]^k[i]; + } + +/* was R_R */ +static void transform_3 (byte *data) + { + unsigned short int acc; + acc=(data[0]^data[2]^data[4]^data[6]^data[24]^data[30])| + ((data[1]^data[3]^data[5]^data[7]^data[25]^data[31])<<8); + memmove(data,data+2,30); + data[30]=acc&0xff; + data[31]=acc>>8; + } + +/* Adds blocks of N bytes modulo 2**(8*n). Returns carry*/ +static int add_blocks(int n,byte *left, const byte *right) + { + int i; + int carry=0; + int sum; + for (i=0;i<n;i++) + { + sum=(int)left[i]+(int)right[i]+carry; + left[i]=sum & 0xff; + carry=sum>>8; + } + return carry; + } + +/* Xor two sequences of bytes */ +static void xor_blocks (byte *result,const byte *a,const byte *b,size_t len) + { + size_t i; + for (i=0;i<len;i++) result[i]=a[i]^b[i]; + } + +/* + * Calculate H(i+1) = Hash(Hi,Mi) + * Where H and M are 32 bytes long + */ +static int hash_step(gost_ctx *c,byte *H,const byte *M) + { + byte U[32],W[32],V[32],S[32],Key[32]; + int i; + /* Compute first key */ + xor_blocks(W,H,M,32); + swap_bytes(W,Key); + /* Encrypt first 8 bytes of H with first key*/ + gost_enc_with_key(c,Key,H,S); + /* Compute second key*/ + circle_xor8(H,U); + circle_xor8(M,V); + circle_xor8(V,V); + xor_blocks(W,U,V,32); + swap_bytes(W,Key); + /* encrypt second 8 bytes of H with second key*/ + gost_enc_with_key(c,Key,H+8,S+8); + /* compute third key */ + circle_xor8(U,U); + U[31]=~U[31]; U[29]=~U[29]; U[28]=~U[28]; U[24]=~U[24]; + U[23]=~U[23]; U[20]=~U[20]; U[18]=~U[18]; U[17]=~U[17]; + U[14]=~U[14]; U[12]=~U[12]; U[10]=~U[10]; U[ 8]=~U[ 8]; + U[ 7]=~U[ 7]; U[ 5]=~U[ 5]; U[ 3]=~U[ 3]; U[ 1]=~U[ 1]; + circle_xor8(V,V); + circle_xor8(V,V); + xor_blocks(W,U,V,32); + swap_bytes(W,Key); + /* encrypt third 8 bytes of H with third key*/ + gost_enc_with_key(c,Key,H+16,S+16); + /* Compute fourth key */ + circle_xor8(U,U); + circle_xor8(V,V); + circle_xor8(V,V); + xor_blocks(W,U,V,32); + swap_bytes(W,Key); + /* Encrypt last 8 bytes with fourth key */ + gost_enc_with_key(c,Key,H+24,S+24); + for (i=0;i<12;i++) + transform_3(S); + xor_blocks(S,S,M,32); + transform_3(S); + xor_blocks(S,S,H,32); + for (i=0;i<61;i++) + transform_3(S); + memcpy(H,S,32); + return 1; + } + +/* Initialize gost_hash ctx - cleans up temporary structures and + * set up substitution blocks + */ +int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block) + { + memset(ctx,0,sizeof(gost_hash_ctx)); + ctx->cipher_ctx = (gost_ctx *)MYALLOC(sizeof(gost_ctx)); + if (!ctx->cipher_ctx) + { + return 0; + } + gost_init(ctx->cipher_ctx,subst_block); + return 1; + } + +/* + * Free cipher CTX if it is dynamically allocated. Do not use + * if cipher ctx is statically allocated as in OpenSSL implementation of + * GOST hash algroritm + * + */ +void done_gost_hash_ctx(gost_hash_ctx *ctx) + { + /* No need to use gost_destroy, because cipher keys are not really + * secret when hashing */ + MYFREE(ctx->cipher_ctx); + } + +/* + * reset state of hash context to begin hashing new message + */ +int start_hash(gost_hash_ctx *ctx) + { + if (!ctx->cipher_ctx) return 0; + memset(&(ctx->H),0,32); + memset(&(ctx->S),0,32); + ctx->len = 0L; + ctx->left=0; + return 1; + } + +/* + * Hash block of arbitrary length + * + * + */ +int hash_block(gost_hash_ctx *ctx,const byte *block, size_t length) + { + const byte *curptr=block; + const byte *barrier=block+(length-32);/* Last byte we can safely hash*/ + if (ctx->left) + { + /*There are some bytes from previous step*/ + unsigned int add_bytes = 32-ctx->left; + if (add_bytes>length) + { + add_bytes = length; + } + memcpy(&(ctx->remainder[ctx->left]),block,add_bytes); + ctx->left+=add_bytes; + if (ctx->left<32) + { + return 1; + } + curptr=block+add_bytes; + hash_step(ctx->cipher_ctx,ctx->H,ctx->remainder); + add_blocks(32,ctx->S,ctx->remainder); + ctx->len+=32; + ctx->left=0; + } + while (curptr<=barrier) + { + hash_step(ctx->cipher_ctx,ctx->H,curptr); + + add_blocks(32,ctx->S,curptr); + ctx->len+=32; + curptr+=32; + } + if (curptr!=block+length) + { + ctx->left=block+length-curptr; + memcpy(ctx->remainder,curptr,ctx->left); + } + return 1; + } + +/* + * Compute hash value from current state of ctx + * state of hash ctx becomes invalid and cannot be used for further + * hashing. + */ +int finish_hash(gost_hash_ctx *ctx,byte *hashval) + { + byte buf[32]; + byte H[32]; + byte S[32]; + ghosthash_len fin_len=ctx->len; + byte *bptr; + memcpy(H,ctx->H,32); + memcpy(S,ctx->S,32); + if (ctx->left) + { + memset(buf,0,32); + memcpy(buf,ctx->remainder,ctx->left); + hash_step(ctx->cipher_ctx,H,buf); + add_blocks(32,S,buf); + fin_len+=ctx->left; + } + memset(buf,0,32); + bptr=buf; + fin_len<<=3; /* Hash length in BITS!!*/ + while(fin_len>0) + { + *(bptr++)=(byte)(fin_len&0xFF); + fin_len>>=8; + }; + hash_step(ctx->cipher_ctx,H,buf); + hash_step(ctx->cipher_ctx,H,S); + memcpy(hashval,H,32); + return 1; + } |