diff options
Diffstat (limited to 'openssl/engines/ccgost/gost_sign.c')
-rw-r--r-- | openssl/engines/ccgost/gost_sign.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/openssl/engines/ccgost/gost_sign.c b/openssl/engines/ccgost/gost_sign.c new file mode 100644 index 000000000..409565435 --- /dev/null +++ b/openssl/engines/ccgost/gost_sign.c @@ -0,0 +1,321 @@ +/********************************************************************** + * gost_sign.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of GOST R 34.10-94 signature algorithm * + * for OpenSSL * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include <string.h> +#include <openssl/rand.h> +#include <openssl/bn.h> +#include <openssl/dsa.h> +#include <openssl/evp.h> + +#include "gost_params.h" +#include "gost_lcl.h" +#include "e_gost_err.h" + +#ifdef DEBUG_SIGN +void dump_signature(const char *message,const unsigned char *buffer,size_t len) + { + size_t i; + fprintf(stderr,"signature %s Length=%d",message,len); + for (i=0; i<len; i++) + { + if (i% 16 ==0) fputc('\n',stderr); + fprintf (stderr," %02x",buffer[i]); + } + fprintf(stderr,"\nEnd of signature\n"); + } + +void dump_dsa_sig(const char *message, DSA_SIG *sig) + { + fprintf(stderr,"%s\nR=",message); + BN_print_fp(stderr,sig->r); + fprintf(stderr,"\nS="); + BN_print_fp(stderr,sig->s); + fprintf(stderr,"\n"); + } + +#else + +#define dump_signature(a,b,c) +#define dump_dsa_sig(a,b) +#endif + +/* + * Computes signature and returns it as DSA_SIG structure + */ +DSA_SIG *gost_do_sign(const unsigned char *dgst,int dlen, DSA *dsa) + { + BIGNUM *k=NULL,*tmp=NULL,*tmp2=NULL; + DSA_SIG *newsig = DSA_SIG_new(); + BIGNUM *md = hashsum2bn(dgst); + /* check if H(M) mod q is zero */ + BN_CTX *ctx=BN_CTX_new(); + BN_CTX_start(ctx); + if (!newsig) + { + GOSTerr(GOST_F_GOST_DO_SIGN,GOST_R_NO_MEMORY); + goto err; + } + tmp=BN_CTX_get(ctx); + k = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + BN_mod(tmp,md,dsa->q,ctx); + if (BN_is_zero(tmp)) + { + BN_one(md); + } + do + { + do + { + /*Generate random number k less than q*/ + BN_rand_range(k,dsa->q); + /* generate r = (a^x mod p) mod q */ + BN_mod_exp(tmp,dsa->g, k, dsa->p,ctx); + if (!(newsig->r)) newsig->r=BN_new(); + BN_mod(newsig->r,tmp,dsa->q,ctx); + } + while (BN_is_zero(newsig->r)); + /* generate s = (xr + k(Hm)) mod q */ + BN_mod_mul(tmp,dsa->priv_key,newsig->r,dsa->q,ctx); + BN_mod_mul(tmp2,k,md,dsa->q,ctx); + if (!newsig->s) newsig->s=BN_new(); + BN_mod_add(newsig->s,tmp,tmp2,dsa->q,ctx); + } + while (BN_is_zero(newsig->s)); + err: + BN_free(md); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return newsig; + } + + +/* + * Packs signature according to Cryptocom rules + * and frees up DSA_SIG structure + */ +/* +int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, size_t *siglen) + { + *siglen = 2*order; + memset(sig,0,*siglen); + store_bignum(s->r, sig,order); + store_bignum(s->s, sig + order,order); + dump_signature("serialized",sig,*siglen); + DSA_SIG_free(s); + return 1; + } +*/ +/* + * Packs signature according to Cryptopro rules + * and frees up DSA_SIG structure + */ +int pack_sign_cp(DSA_SIG *s,int order,unsigned char *sig, size_t *siglen) + { + *siglen = 2*order; + memset(sig,0,*siglen); + store_bignum(s->s, sig, order); + store_bignum(s->r, sig+order,order); + dump_signature("serialized",sig,*siglen); + DSA_SIG_free(s); + return 1; + } + +/* + * Verifies signature passed as DSA_SIG structure + * + */ + +int gost_do_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa) + { + BIGNUM *md, *tmp=NULL; + BIGNUM *q2=NULL; + BIGNUM *u=NULL,*v=NULL,*z1=NULL,*z2=NULL; + BIGNUM *tmp2=NULL,*tmp3=NULL; + int ok; + BN_CTX *ctx = BN_CTX_new(); + + BN_CTX_start(ctx); + if (BN_cmp(sig->s,dsa->q)>=1|| + BN_cmp(sig->r,dsa->q)>=1) + { + GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); + return 0; + } + md=hashsum2bn(dgst); + + tmp=BN_CTX_get(ctx); + v=BN_CTX_get(ctx); + q2=BN_CTX_get(ctx); + z1=BN_CTX_get(ctx); + z2=BN_CTX_get(ctx); + tmp2=BN_CTX_get(ctx); + tmp3=BN_CTX_get(ctx); + u = BN_CTX_get(ctx); + + BN_mod(tmp,md,dsa->q,ctx); + if (BN_is_zero(tmp)) + { + BN_one(md); + } + BN_copy(q2,dsa->q); + BN_sub_word(q2,2); + BN_mod_exp(v,md,q2,dsa->q,ctx); + BN_mod_mul(z1,sig->s,v,dsa->q,ctx); + BN_sub(tmp,dsa->q,sig->r); + BN_mod_mul(z2,tmp,v,dsa->p,ctx); + BN_mod_exp(tmp,dsa->g,z1,dsa->p,ctx); + BN_mod_exp(tmp2,dsa->pub_key,z2,dsa->p,ctx); + BN_mod_mul(tmp3,tmp,tmp2,dsa->p,ctx); + BN_mod(u,tmp3,dsa->q,ctx); + ok= BN_cmp(u,sig->r); + + BN_free(md); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + if (ok!=0) + { + GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH); + } + return (ok==0); + } + +/* + * Computes public keys for GOST R 34.10-94 algorithm + * + */ +int gost94_compute_public(DSA *dsa) + { + /* Now fill algorithm parameters with correct values */ + BN_CTX *ctx = BN_CTX_new(); + if (!dsa->g) + { + GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITALIZED); + return 0; + } + /* Compute public key y = a^x mod p */ + dsa->pub_key=BN_new(); + BN_mod_exp(dsa->pub_key, dsa->g,dsa->priv_key,dsa->p,ctx); + BN_CTX_free(ctx); + return 1; + } + +/* + * Fill GOST 94 params, searching them in R3410_paramset array + * by nid of paramset + * + */ +int fill_GOST94_params(DSA *dsa,int nid) + { + R3410_params *params=R3410_paramset; + while (params->nid!=NID_undef && params->nid !=nid) params++; + if (params->nid == NID_undef) + { + GOSTerr(GOST_F_FILL_GOST94_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET); + return 0; + } +#define dump_signature(a,b,c) + if (dsa->p) { BN_free(dsa->p); } + dsa->p=NULL; + BN_dec2bn(&(dsa->p),params->p); + if (dsa->q) { BN_free(dsa->q); } + dsa->q=NULL; + BN_dec2bn(&(dsa->q),params->q); + if (dsa->g) { BN_free(dsa->g); } + dsa->g=NULL; + BN_dec2bn(&(dsa->g),params->a); + return 1; + } + +/* + * Generate GOST R 34.10-94 keypair + * + * + */ +int gost_sign_keygen(DSA *dsa) + { + dsa->priv_key = BN_new(); + BN_rand_range(dsa->priv_key,dsa->q); + return gost94_compute_public( dsa); + } + +/* Unpack signature according to cryptocom rules */ +/* +DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen) + { + DSA_SIG *s; + s = DSA_SIG_new(); + if (s == NULL) + { + GOSTerr(GOST_F_UNPACK_CC_SIGNATURE,GOST_R_NO_MEMORY); + return(NULL); + } + s->r = getbnfrombuf(sig, siglen/2); + s->s = getbnfrombuf(sig + siglen/2, siglen/2); + return s; + } +*/ +/* Unpack signature according to cryptopro rules */ +DSA_SIG *unpack_cp_signature(const unsigned char *sig,size_t siglen) + { + DSA_SIG *s; + + s = DSA_SIG_new(); + if (s == NULL) + { + GOSTerr(GOST_F_UNPACK_CP_SIGNATURE,GOST_R_NO_MEMORY); + return NULL; + } + s->s = getbnfrombuf(sig , siglen/2); + s->r = getbnfrombuf(sig + siglen/2, siglen/2); + return s; + } + +/* Convert little-endian byte array into bignum */ +BIGNUM *hashsum2bn(const unsigned char *dgst) + { + unsigned char buf[32]; + int i; + for (i=0;i<32;i++) + { + buf[31-i]=dgst[i]; + } + return getbnfrombuf(buf,32); + } + +/* Convert byte buffer to bignum, skipping leading zeros*/ +BIGNUM *getbnfrombuf(const unsigned char *buf,size_t len) + { + while (*buf==0&&len>0) + { + buf++; len--; + } + if (len) + { + return BN_bin2bn(buf,len,NULL); + } + else + { + BIGNUM *b=BN_new(); + BN_zero(b); + return b; + } + } + +/* Pack bignum into byte buffer of given size, filling all leading bytes + * by zeros */ +int store_bignum(BIGNUM *bn, unsigned char *buf,int len) + { + int bytes = BN_num_bytes(bn); + if (bytes>len) return 0; + memset(buf,0,len); + BN_bn2bin(bn,buf+len-bytes); + return 1; + } |