gost2001.c revision 238384
1238384Sjkim/********************************************************************** 2238384Sjkim * gost2001.c * 3238384Sjkim * Copyright (c) 2005-2006 Cryptocom LTD * 4238384Sjkim * This file is distributed under the same license as OpenSSL * 5238384Sjkim * * 6238384Sjkim * Implementation of GOST R 34.10-2001 * 7238384Sjkim * Requires OpenSSL 0.9.9 for compilation * 8238384Sjkim **********************************************************************/ 9238384Sjkim#include "gost_lcl.h" 10238384Sjkim#include "gost_params.h" 11238384Sjkim#include <string.h> 12238384Sjkim#include <openssl/rand.h> 13238384Sjkim#include <openssl/ecdsa.h> 14238384Sjkim#include <openssl/err.h> 15238384Sjkim#include "e_gost_err.h" 16238384Sjkim#ifdef DEBUG_SIGN 17238384Sjkimextern 18238384Sjkimvoid dump_signature(const char *message,const unsigned char *buffer,size_t len); 19238384Sjkimvoid dump_dsa_sig(const char *message, DSA_SIG *sig); 20238384Sjkim#else 21238384Sjkim 22238384Sjkim#define dump_signature(a,b,c) 23238384Sjkim#define dump_dsa_sig(a,b) 24238384Sjkim#endif 25238384Sjkim 26238384Sjkim/* 27238384Sjkim * Fills EC_KEY structure hidden in the app_data field of DSA structure 28238384Sjkim * with parameter information, extracted from parameter array in 29238384Sjkim * params.c file. 30238384Sjkim * 31238384Sjkim * Also fils DSA->q field with copy of EC_GROUP order field to make 32238384Sjkim * DSA_size function work 33238384Sjkim */ 34238384Sjkimint fill_GOST2001_params(EC_KEY *eckey, int nid) 35238384Sjkim { 36238384Sjkim R3410_2001_params *params = R3410_2001_paramset; 37238384Sjkim EC_GROUP *grp=NULL; 38238384Sjkim BIGNUM *p=NULL,*q=NULL,*a=NULL,*b=NULL,*x=NULL,*y=NULL; 39238384Sjkim EC_POINT *P=NULL; 40238384Sjkim BN_CTX *ctx=BN_CTX_new(); 41238384Sjkim int ok=0; 42238384Sjkim 43238384Sjkim BN_CTX_start(ctx); 44238384Sjkim p=BN_CTX_get(ctx); 45238384Sjkim a=BN_CTX_get(ctx); 46238384Sjkim b=BN_CTX_get(ctx); 47238384Sjkim x=BN_CTX_get(ctx); 48238384Sjkim y=BN_CTX_get(ctx); 49238384Sjkim q=BN_CTX_get(ctx); 50238384Sjkim while (params->nid!=NID_undef && params->nid != nid) params++; 51238384Sjkim if (params->nid == NID_undef) 52238384Sjkim { 53238384Sjkim GOSTerr(GOST_F_FILL_GOST2001_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET); 54238384Sjkim goto err; 55238384Sjkim } 56238384Sjkim BN_hex2bn(&p,params->p); 57238384Sjkim BN_hex2bn(&a,params->a); 58238384Sjkim BN_hex2bn(&b,params->b); 59238384Sjkim 60238384Sjkim grp = EC_GROUP_new_curve_GFp(p,a,b,ctx); 61238384Sjkim 62238384Sjkim P = EC_POINT_new(grp); 63238384Sjkim 64238384Sjkim BN_hex2bn(&x,params->x); 65238384Sjkim BN_hex2bn(&y,params->y); 66238384Sjkim EC_POINT_set_affine_coordinates_GFp(grp,P,x,y,ctx); 67238384Sjkim BN_hex2bn(&q,params->q); 68238384Sjkim#ifdef DEBUG_KEYS 69238384Sjkim fprintf(stderr,"Set params index %d oid %s\nq=", 70238384Sjkim (params-R3410_2001_paramset),OBJ_nid2sn(params->nid)); 71238384Sjkim BN_print_fp(stderr,q); 72238384Sjkim fprintf(stderr,"\n"); 73238384Sjkim#endif 74238384Sjkim 75238384Sjkim EC_GROUP_set_generator(grp,P,q,NULL); 76238384Sjkim EC_GROUP_set_curve_name(grp,params->nid); 77238384Sjkim 78238384Sjkim EC_KEY_set_group(eckey,grp); 79238384Sjkim ok=1; 80238384Sjkim err: 81238384Sjkim EC_POINT_free(P); 82238384Sjkim EC_GROUP_free(grp); 83238384Sjkim BN_CTX_end(ctx); 84238384Sjkim BN_CTX_free(ctx); 85238384Sjkim return ok; 86238384Sjkim } 87238384Sjkim 88238384Sjkim 89238384Sjkim/* 90238384Sjkim * Computes gost2001 signature as DSA_SIG structure 91238384Sjkim * 92238384Sjkim * 93238384Sjkim */ 94238384SjkimDSA_SIG *gost2001_do_sign(const unsigned char *dgst,int dlen, EC_KEY *eckey) 95238384Sjkim { 96238384Sjkim DSA_SIG *newsig = NULL; 97238384Sjkim BIGNUM *md = hashsum2bn(dgst); 98238384Sjkim BIGNUM *order = NULL; 99238384Sjkim const EC_GROUP *group; 100238384Sjkim const BIGNUM *priv_key; 101238384Sjkim BIGNUM *r=NULL,*s=NULL,*X=NULL,*tmp=NULL,*tmp2=NULL, *k=NULL,*e=NULL; 102238384Sjkim EC_POINT *C=NULL; 103238384Sjkim BN_CTX *ctx = BN_CTX_new(); 104238384Sjkim BN_CTX_start(ctx); 105238384Sjkim OPENSSL_assert(dlen==32); 106238384Sjkim newsig=DSA_SIG_new(); 107238384Sjkim if (!newsig) 108238384Sjkim { 109238384Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_NO_MEMORY); 110238384Sjkim goto err; 111238384Sjkim } 112238384Sjkim group = EC_KEY_get0_group(eckey); 113238384Sjkim order=BN_CTX_get(ctx); 114238384Sjkim EC_GROUP_get_order(group,order,ctx); 115238384Sjkim priv_key = EC_KEY_get0_private_key(eckey); 116238384Sjkim e = BN_CTX_get(ctx); 117238384Sjkim BN_mod(e,md,order,ctx); 118238384Sjkim#ifdef DEBUG_SIGN 119238384Sjkim fprintf(stderr,"digest as bignum="); 120238384Sjkim BN_print_fp(stderr,md); 121238384Sjkim fprintf(stderr,"\ndigest mod q="); 122238384Sjkim BN_print_fp(stderr,e); 123238384Sjkim fprintf(stderr,"\n"); 124238384Sjkim#endif 125238384Sjkim if (BN_is_zero(e)) 126238384Sjkim { 127238384Sjkim BN_one(e); 128238384Sjkim } 129238384Sjkim k =BN_CTX_get(ctx); 130238384Sjkim C=EC_POINT_new(group); 131238384Sjkim do 132238384Sjkim { 133238384Sjkim do 134238384Sjkim { 135238384Sjkim if (!BN_rand_range(k,order)) 136238384Sjkim { 137238384Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); 138238384Sjkim DSA_SIG_free(newsig); 139238384Sjkim newsig = NULL; 140238384Sjkim goto err; 141238384Sjkim } 142238384Sjkim if (!EC_POINT_mul(group,C,k,NULL,NULL,ctx)) 143238384Sjkim { 144238384Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB); 145238384Sjkim DSA_SIG_free(newsig); 146238384Sjkim newsig = NULL; 147238384Sjkim goto err; 148238384Sjkim } 149238384Sjkim if (!X) X=BN_CTX_get(ctx); 150238384Sjkim if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx)) 151238384Sjkim { 152238384Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB); 153238384Sjkim DSA_SIG_free(newsig); 154238384Sjkim newsig = NULL; 155238384Sjkim goto err; 156238384Sjkim } 157238384Sjkim if (!r) r=BN_CTX_get(ctx); 158238384Sjkim BN_nnmod(r,X,order,ctx); 159238384Sjkim } 160238384Sjkim while (BN_is_zero(r)); 161238384Sjkim /* s = (r*priv_key+k*e) mod order */ 162238384Sjkim if (!tmp) tmp = BN_CTX_get(ctx); 163238384Sjkim BN_mod_mul(tmp,priv_key,r,order,ctx); 164238384Sjkim if (!tmp2) tmp2 = BN_CTX_get(ctx); 165238384Sjkim BN_mod_mul(tmp2,k,e,order,ctx); 166238384Sjkim if (!s) s=BN_CTX_get(ctx); 167238384Sjkim BN_mod_add(s,tmp,tmp2,order,ctx); 168238384Sjkim } 169238384Sjkim while (BN_is_zero(s)); 170238384Sjkim 171238384Sjkim newsig->s=BN_dup(s); 172238384Sjkim newsig->r=BN_dup(r); 173238384Sjkim err: 174238384Sjkim BN_CTX_end(ctx); 175238384Sjkim BN_CTX_free(ctx); 176238384Sjkim EC_POINT_free(C); 177238384Sjkim BN_free(md); 178238384Sjkim return newsig; 179238384Sjkim } 180238384Sjkim/* 181238384Sjkim * Verifies gost 2001 signature 182238384Sjkim * 183238384Sjkim */ 184238384Sjkimint gost2001_do_verify(const unsigned char *dgst,int dgst_len, 185238384Sjkim DSA_SIG *sig, EC_KEY *ec) 186238384Sjkim { 187238384Sjkim BN_CTX *ctx=BN_CTX_new(); 188238384Sjkim const EC_GROUP *group = EC_KEY_get0_group(ec); 189238384Sjkim BIGNUM *order; 190238384Sjkim BIGNUM *md = NULL,*e=NULL,*R=NULL,*v=NULL,*z1=NULL,*z2=NULL; 191238384Sjkim BIGNUM *X=NULL,*tmp=NULL; 192238384Sjkim EC_POINT *C = NULL; 193238384Sjkim const EC_POINT *pub_key=NULL; 194238384Sjkim int ok=0; 195238384Sjkim 196238384Sjkim BN_CTX_start(ctx); 197238384Sjkim order = BN_CTX_get(ctx); 198238384Sjkim e = BN_CTX_get(ctx); 199238384Sjkim z1 = BN_CTX_get(ctx); 200238384Sjkim z2 = BN_CTX_get(ctx); 201238384Sjkim tmp = BN_CTX_get(ctx); 202238384Sjkim X= BN_CTX_get(ctx); 203238384Sjkim R=BN_CTX_get(ctx); 204238384Sjkim v=BN_CTX_get(ctx); 205238384Sjkim 206238384Sjkim EC_GROUP_get_order(group,order,ctx); 207238384Sjkim pub_key = EC_KEY_get0_public_key(ec); 208238384Sjkim if (BN_is_zero(sig->s) || BN_is_zero(sig->r) || 209238384Sjkim (BN_cmp(sig->s,order)>=1) || (BN_cmp(sig->r,order)>=1)) 210238384Sjkim { 211238384Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); 212238384Sjkim goto err; 213238384Sjkim 214238384Sjkim } 215238384Sjkim md = hashsum2bn(dgst); 216238384Sjkim 217238384Sjkim BN_mod(e,md,order,ctx); 218238384Sjkim#ifdef DEBUG_SIGN 219238384Sjkim fprintf(stderr,"digest as bignum: "); 220238384Sjkim BN_print_fp(stderr,md); 221238384Sjkim fprintf(stderr,"\ndigest mod q: "); 222238384Sjkim BN_print_fp(stderr,e); 223238384Sjkim#endif 224238384Sjkim if (BN_is_zero(e)) BN_one(e); 225238384Sjkim v=BN_mod_inverse(v,e,order,ctx); 226238384Sjkim BN_mod_mul(z1,sig->s,v,order,ctx); 227238384Sjkim BN_sub(tmp,order,sig->r); 228238384Sjkim BN_mod_mul(z2,tmp,v,order,ctx); 229238384Sjkim#ifdef DEBUG_SIGN 230238384Sjkim fprintf(stderr,"\nInverted digest value: "); 231238384Sjkim BN_print_fp(stderr,v); 232238384Sjkim fprintf(stderr,"\nz1: "); 233238384Sjkim BN_print_fp(stderr,z1); 234238384Sjkim fprintf(stderr,"\nz2: "); 235238384Sjkim BN_print_fp(stderr,z2); 236238384Sjkim#endif 237238384Sjkim C = EC_POINT_new(group); 238238384Sjkim if (!EC_POINT_mul(group,C,z1,pub_key,z2,ctx)) 239238384Sjkim { 240238384Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB); 241238384Sjkim goto err; 242238384Sjkim } 243238384Sjkim if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx)) 244238384Sjkim { 245238384Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB); 246238384Sjkim goto err; 247238384Sjkim } 248238384Sjkim BN_mod(R,X,order,ctx); 249238384Sjkim#ifdef DEBUG_SIGN 250238384Sjkim fprintf(stderr,"\nX="); 251238384Sjkim BN_print_fp(stderr,X); 252238384Sjkim fprintf(stderr,"\nX mod q="); 253238384Sjkim BN_print_fp(stderr,R); 254238384Sjkim fprintf(stderr,"\n"); 255238384Sjkim#endif 256238384Sjkim if (BN_cmp(R,sig->r)!=0) 257238384Sjkim { 258238384Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH); 259238384Sjkim } 260238384Sjkim else 261238384Sjkim { 262238384Sjkim ok = 1; 263238384Sjkim } 264238384Sjkim err: 265238384Sjkim EC_POINT_free(C); 266238384Sjkim BN_CTX_end(ctx); 267238384Sjkim BN_CTX_free(ctx); 268238384Sjkim BN_free(md); 269238384Sjkim return ok; 270238384Sjkim } 271238384Sjkim/* 272238384Sjkim * Computes GOST R 34.10-2001 public key 273238384Sjkim * 274238384Sjkim * 275238384Sjkim */ 276238384Sjkimint gost2001_compute_public(EC_KEY *ec) 277238384Sjkim { 278238384Sjkim const EC_GROUP *group = EC_KEY_get0_group(ec); 279238384Sjkim EC_POINT *pub_key=NULL; 280238384Sjkim const BIGNUM *priv_key=NULL; 281238384Sjkim BN_CTX *ctx=NULL; 282238384Sjkim int ok=0; 283238384Sjkim 284238384Sjkim if (!group) 285238384Sjkim { 286238384Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITIALIZED); 287238384Sjkim return 0; 288238384Sjkim } 289238384Sjkim ctx=BN_CTX_new(); 290238384Sjkim BN_CTX_start(ctx); 291238384Sjkim if (!(priv_key=EC_KEY_get0_private_key(ec))) 292238384Sjkim { 293238384Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB); 294238384Sjkim goto err; 295238384Sjkim } 296238384Sjkim 297238384Sjkim pub_key = EC_POINT_new(group); 298238384Sjkim if (!EC_POINT_mul(group,pub_key,priv_key,NULL,NULL,ctx)) 299238384Sjkim { 300238384Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB); 301238384Sjkim goto err; 302238384Sjkim } 303238384Sjkim if (!EC_KEY_set_public_key(ec,pub_key)) 304238384Sjkim { 305238384Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB); 306238384Sjkim goto err; 307238384Sjkim } 308238384Sjkim ok = 256; 309238384Sjkim err: 310238384Sjkim BN_CTX_end(ctx); 311238384Sjkim EC_POINT_free(pub_key); 312238384Sjkim BN_CTX_free(ctx); 313238384Sjkim return ok; 314238384Sjkim } 315238384Sjkim/* 316238384Sjkim * 317238384Sjkim * Generates GOST R 34.10-2001 keypair 318238384Sjkim * 319238384Sjkim * 320238384Sjkim */ 321238384Sjkimint gost2001_keygen(EC_KEY *ec) 322238384Sjkim { 323238384Sjkim BIGNUM *order = BN_new(),*d=BN_new(); 324238384Sjkim const EC_GROUP *group = EC_KEY_get0_group(ec); 325238384Sjkim EC_GROUP_get_order(group,order,NULL); 326238384Sjkim 327238384Sjkim do 328238384Sjkim { 329238384Sjkim if (!BN_rand_range(d,order)) 330238384Sjkim { 331238384Sjkim GOSTerr(GOST_F_GOST2001_KEYGEN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); 332238384Sjkim BN_free(d); 333238384Sjkim BN_free(order); 334238384Sjkim return 0; 335238384Sjkim } 336238384Sjkim } 337238384Sjkim while (BN_is_zero(d)); 338238384Sjkim EC_KEY_set_private_key(ec,d); 339238384Sjkim BN_free(d); 340238384Sjkim BN_free(order); 341238384Sjkim return gost2001_compute_public(ec); 342238384Sjkim } 343238384Sjkim 344