gost2001.c revision 280304
1238384Sjkim/********************************************************************** 2238384Sjkim * gost2001.c * 3238384Sjkim * Copyright (c) 2005-2006 Cryptocom LTD * 4238384Sjkim * This file is distributed under the same license as OpenSSL * 5238384Sjkim * * 6280304Sjkim * 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 17280304Sjkimextern 18280304Sjkimvoid dump_signature(const char *message, const unsigned char *buffer, 19280304Sjkim size_t len); 20238384Sjkimvoid dump_dsa_sig(const char *message, DSA_SIG *sig); 21238384Sjkim#else 22238384Sjkim 23280304Sjkim# define dump_signature(a,b,c) 24280304Sjkim# define dump_dsa_sig(a,b) 25238384Sjkim#endif 26238384Sjkim 27238384Sjkim/* 28238384Sjkim * Fills EC_KEY structure hidden in the app_data field of DSA structure 29238384Sjkim * with parameter information, extracted from parameter array in 30238384Sjkim * params.c file. 31238384Sjkim * 32238384Sjkim * Also fils DSA->q field with copy of EC_GROUP order field to make 33238384Sjkim * DSA_size function work 34280304Sjkim */ 35238384Sjkimint fill_GOST2001_params(EC_KEY *eckey, int nid) 36280304Sjkim{ 37280304Sjkim R3410_2001_params *params = R3410_2001_paramset; 38280304Sjkim EC_GROUP *grp = NULL; 39280304Sjkim BIGNUM *p = NULL, *q = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL; 40280304Sjkim EC_POINT *P = NULL; 41280304Sjkim BN_CTX *ctx = BN_CTX_new(); 42280304Sjkim int ok = 0; 43238384Sjkim 44280304Sjkim BN_CTX_start(ctx); 45280304Sjkim p = BN_CTX_get(ctx); 46280304Sjkim a = BN_CTX_get(ctx); 47280304Sjkim b = BN_CTX_get(ctx); 48280304Sjkim x = BN_CTX_get(ctx); 49280304Sjkim y = BN_CTX_get(ctx); 50280304Sjkim q = BN_CTX_get(ctx); 51280304Sjkim while (params->nid != NID_undef && params->nid != nid) 52280304Sjkim params++; 53280304Sjkim if (params->nid == NID_undef) { 54280304Sjkim GOSTerr(GOST_F_FILL_GOST2001_PARAMS, 55280304Sjkim GOST_R_UNSUPPORTED_PARAMETER_SET); 56280304Sjkim goto err; 57280304Sjkim } 58280304Sjkim BN_hex2bn(&p, params->p); 59280304Sjkim BN_hex2bn(&a, params->a); 60280304Sjkim BN_hex2bn(&b, params->b); 61238384Sjkim 62280304Sjkim grp = EC_GROUP_new_curve_GFp(p, a, b, ctx); 63280304Sjkim 64280304Sjkim P = EC_POINT_new(grp); 65280304Sjkim 66280304Sjkim BN_hex2bn(&x, params->x); 67280304Sjkim BN_hex2bn(&y, params->y); 68280304Sjkim EC_POINT_set_affine_coordinates_GFp(grp, P, x, y, ctx); 69280304Sjkim BN_hex2bn(&q, params->q); 70238384Sjkim#ifdef DEBUG_KEYS 71280304Sjkim fprintf(stderr, "Set params index %d oid %s\nq=", 72280304Sjkim (params - R3410_2001_paramset), OBJ_nid2sn(params->nid)); 73280304Sjkim BN_print_fp(stderr, q); 74280304Sjkim fprintf(stderr, "\n"); 75280304Sjkim#endif 76238384Sjkim 77280304Sjkim EC_GROUP_set_generator(grp, P, q, NULL); 78280304Sjkim EC_GROUP_set_curve_name(grp, params->nid); 79238384Sjkim 80280304Sjkim EC_KEY_set_group(eckey, grp); 81280304Sjkim ok = 1; 82280304Sjkim err: 83280304Sjkim EC_POINT_free(P); 84280304Sjkim EC_GROUP_free(grp); 85280304Sjkim BN_CTX_end(ctx); 86280304Sjkim BN_CTX_free(ctx); 87280304Sjkim return ok; 88280304Sjkim} 89238384Sjkim 90238384Sjkim/* 91280304Sjkim * Computes gost2001 signature as DSA_SIG structure 92238384Sjkim * 93238384Sjkim * 94280304Sjkim */ 95280304SjkimDSA_SIG *gost2001_do_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey) 96280304Sjkim{ 97280304Sjkim DSA_SIG *newsig = NULL; 98280304Sjkim BIGNUM *md = hashsum2bn(dgst); 99280304Sjkim BIGNUM *order = NULL; 100280304Sjkim const EC_GROUP *group; 101280304Sjkim const BIGNUM *priv_key; 102280304Sjkim BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k = 103280304Sjkim NULL, *e = NULL; 104280304Sjkim EC_POINT *C = NULL; 105280304Sjkim BN_CTX *ctx = BN_CTX_new(); 106280304Sjkim BN_CTX_start(ctx); 107280304Sjkim OPENSSL_assert(dlen == 32); 108280304Sjkim newsig = DSA_SIG_new(); 109280304Sjkim if (!newsig) { 110280304Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN, GOST_R_NO_MEMORY); 111280304Sjkim goto err; 112280304Sjkim } 113280304Sjkim group = EC_KEY_get0_group(eckey); 114280304Sjkim order = BN_CTX_get(ctx); 115280304Sjkim EC_GROUP_get_order(group, order, ctx); 116280304Sjkim priv_key = EC_KEY_get0_private_key(eckey); 117280304Sjkim e = BN_CTX_get(ctx); 118280304Sjkim BN_mod(e, md, order, ctx); 119238384Sjkim#ifdef DEBUG_SIGN 120280304Sjkim fprintf(stderr, "digest as bignum="); 121280304Sjkim BN_print_fp(stderr, md); 122280304Sjkim fprintf(stderr, "\ndigest mod q="); 123280304Sjkim BN_print_fp(stderr, e); 124280304Sjkim fprintf(stderr, "\n"); 125280304Sjkim#endif 126280304Sjkim if (BN_is_zero(e)) { 127280304Sjkim BN_one(e); 128280304Sjkim } 129280304Sjkim k = BN_CTX_get(ctx); 130280304Sjkim C = EC_POINT_new(group); 131280304Sjkim do { 132280304Sjkim do { 133280304Sjkim if (!BN_rand_range(k, order)) { 134280304Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN, 135280304Sjkim GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); 136280304Sjkim DSA_SIG_free(newsig); 137280304Sjkim newsig = NULL; 138280304Sjkim goto err; 139280304Sjkim } 140280304Sjkim if (!EC_POINT_mul(group, C, k, NULL, NULL, ctx)) { 141280304Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB); 142280304Sjkim DSA_SIG_free(newsig); 143280304Sjkim newsig = NULL; 144280304Sjkim goto err; 145280304Sjkim } 146280304Sjkim if (!X) 147280304Sjkim X = BN_CTX_get(ctx); 148280304Sjkim if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) { 149280304Sjkim GOSTerr(GOST_F_GOST2001_DO_SIGN, ERR_R_EC_LIB); 150280304Sjkim DSA_SIG_free(newsig); 151280304Sjkim newsig = NULL; 152280304Sjkim goto err; 153280304Sjkim } 154280304Sjkim if (!r) 155280304Sjkim r = BN_CTX_get(ctx); 156280304Sjkim BN_nnmod(r, X, order, ctx); 157280304Sjkim } 158280304Sjkim while (BN_is_zero(r)); 159280304Sjkim /* s = (r*priv_key+k*e) mod order */ 160280304Sjkim if (!tmp) 161280304Sjkim tmp = BN_CTX_get(ctx); 162280304Sjkim BN_mod_mul(tmp, priv_key, r, order, ctx); 163280304Sjkim if (!tmp2) 164280304Sjkim tmp2 = BN_CTX_get(ctx); 165280304Sjkim BN_mod_mul(tmp2, k, e, order, ctx); 166280304Sjkim if (!s) 167280304Sjkim s = BN_CTX_get(ctx); 168280304Sjkim BN_mod_add(s, tmp, tmp2, order, ctx); 169280304Sjkim } 170280304Sjkim while (BN_is_zero(s)); 171238384Sjkim 172280304Sjkim newsig->s = BN_dup(s); 173280304Sjkim newsig->r = BN_dup(r); 174280304Sjkim err: 175280304Sjkim BN_CTX_end(ctx); 176280304Sjkim BN_CTX_free(ctx); 177280304Sjkim EC_POINT_free(C); 178280304Sjkim BN_free(md); 179280304Sjkim return newsig; 180280304Sjkim} 181280304Sjkim 182238384Sjkim/* 183238384Sjkim * Verifies gost 2001 signature 184238384Sjkim * 185280304Sjkim */ 186280304Sjkimint gost2001_do_verify(const unsigned char *dgst, int dgst_len, 187280304Sjkim DSA_SIG *sig, EC_KEY *ec) 188280304Sjkim{ 189280304Sjkim BN_CTX *ctx = BN_CTX_new(); 190280304Sjkim const EC_GROUP *group = EC_KEY_get0_group(ec); 191280304Sjkim BIGNUM *order; 192280304Sjkim BIGNUM *md = NULL, *e = NULL, *R = NULL, *v = NULL, *z1 = NULL, *z2 = 193280304Sjkim NULL; 194280304Sjkim BIGNUM *X = NULL, *tmp = NULL; 195280304Sjkim EC_POINT *C = NULL; 196280304Sjkim const EC_POINT *pub_key = NULL; 197280304Sjkim int ok = 0; 198238384Sjkim 199280304Sjkim BN_CTX_start(ctx); 200280304Sjkim order = BN_CTX_get(ctx); 201280304Sjkim e = BN_CTX_get(ctx); 202280304Sjkim z1 = BN_CTX_get(ctx); 203280304Sjkim z2 = BN_CTX_get(ctx); 204280304Sjkim tmp = BN_CTX_get(ctx); 205280304Sjkim X = BN_CTX_get(ctx); 206280304Sjkim R = BN_CTX_get(ctx); 207280304Sjkim v = BN_CTX_get(ctx); 208238384Sjkim 209280304Sjkim EC_GROUP_get_order(group, order, ctx); 210280304Sjkim pub_key = EC_KEY_get0_public_key(ec); 211280304Sjkim if (BN_is_zero(sig->s) || BN_is_zero(sig->r) || 212280304Sjkim (BN_cmp(sig->s, order) >= 1) || (BN_cmp(sig->r, order) >= 1)) { 213280304Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY, 214280304Sjkim GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); 215280304Sjkim goto err; 216238384Sjkim 217280304Sjkim } 218280304Sjkim md = hashsum2bn(dgst); 219280304Sjkim 220280304Sjkim BN_mod(e, md, order, ctx); 221238384Sjkim#ifdef DEBUG_SIGN 222280304Sjkim fprintf(stderr, "digest as bignum: "); 223280304Sjkim BN_print_fp(stderr, md); 224280304Sjkim fprintf(stderr, "\ndigest mod q: "); 225280304Sjkim BN_print_fp(stderr, e); 226280304Sjkim#endif 227280304Sjkim if (BN_is_zero(e)) 228280304Sjkim BN_one(e); 229280304Sjkim v = BN_mod_inverse(v, e, order, ctx); 230280304Sjkim BN_mod_mul(z1, sig->s, v, order, ctx); 231280304Sjkim BN_sub(tmp, order, sig->r); 232280304Sjkim BN_mod_mul(z2, tmp, v, order, ctx); 233238384Sjkim#ifdef DEBUG_SIGN 234280304Sjkim fprintf(stderr, "\nInverted digest value: "); 235280304Sjkim BN_print_fp(stderr, v); 236280304Sjkim fprintf(stderr, "\nz1: "); 237280304Sjkim BN_print_fp(stderr, z1); 238280304Sjkim fprintf(stderr, "\nz2: "); 239280304Sjkim BN_print_fp(stderr, z2); 240280304Sjkim#endif 241280304Sjkim C = EC_POINT_new(group); 242280304Sjkim if (!EC_POINT_mul(group, C, z1, pub_key, z2, ctx)) { 243280304Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB); 244280304Sjkim goto err; 245280304Sjkim } 246280304Sjkim if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) { 247280304Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY, ERR_R_EC_LIB); 248280304Sjkim goto err; 249280304Sjkim } 250280304Sjkim BN_mod(R, X, order, ctx); 251238384Sjkim#ifdef DEBUG_SIGN 252280304Sjkim fprintf(stderr, "\nX="); 253280304Sjkim BN_print_fp(stderr, X); 254280304Sjkim fprintf(stderr, "\nX mod q="); 255280304Sjkim BN_print_fp(stderr, R); 256280304Sjkim fprintf(stderr, "\n"); 257280304Sjkim#endif 258280304Sjkim if (BN_cmp(R, sig->r) != 0) { 259280304Sjkim GOSTerr(GOST_F_GOST2001_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH); 260280304Sjkim } else { 261280304Sjkim ok = 1; 262280304Sjkim } 263280304Sjkim err: 264280304Sjkim EC_POINT_free(C); 265280304Sjkim BN_CTX_end(ctx); 266280304Sjkim BN_CTX_free(ctx); 267280304Sjkim BN_free(md); 268280304Sjkim return ok; 269280304Sjkim} 270280304Sjkim 271238384Sjkim/* 272238384Sjkim * Computes GOST R 34.10-2001 public key 273238384Sjkim * 274238384Sjkim * 275280304Sjkim */ 276280304Sjkimint gost2001_compute_public(EC_KEY *ec) 277280304Sjkim{ 278280304Sjkim const EC_GROUP *group = EC_KEY_get0_group(ec); 279280304Sjkim EC_POINT *pub_key = NULL; 280280304Sjkim const BIGNUM *priv_key = NULL; 281280304Sjkim BN_CTX *ctx = NULL; 282280304Sjkim int ok = 0; 283238384Sjkim 284280304Sjkim if (!group) { 285280304Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, 286280304Sjkim GOST_R_KEY_IS_NOT_INITIALIZED); 287280304Sjkim return 0; 288280304Sjkim } 289280304Sjkim ctx = BN_CTX_new(); 290280304Sjkim BN_CTX_start(ctx); 291280304Sjkim if (!(priv_key = EC_KEY_get0_private_key(ec))) { 292280304Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB); 293280304Sjkim goto err; 294280304Sjkim } 295238384Sjkim 296280304Sjkim pub_key = EC_POINT_new(group); 297280304Sjkim if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) { 298280304Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB); 299280304Sjkim goto err; 300280304Sjkim } 301280304Sjkim if (!EC_KEY_set_public_key(ec, pub_key)) { 302280304Sjkim GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC, ERR_R_EC_LIB); 303280304Sjkim goto err; 304280304Sjkim } 305280304Sjkim ok = 256; 306280304Sjkim err: 307280304Sjkim BN_CTX_end(ctx); 308280304Sjkim EC_POINT_free(pub_key); 309280304Sjkim BN_CTX_free(ctx); 310280304Sjkim return ok; 311280304Sjkim} 312280304Sjkim 313238384Sjkim/* 314280304Sjkim * 315238384Sjkim * Generates GOST R 34.10-2001 keypair 316238384Sjkim * 317238384Sjkim * 318280304Sjkim */ 319238384Sjkimint gost2001_keygen(EC_KEY *ec) 320280304Sjkim{ 321280304Sjkim BIGNUM *order = BN_new(), *d = BN_new(); 322280304Sjkim const EC_GROUP *group = EC_KEY_get0_group(ec); 323280304Sjkim EC_GROUP_get_order(group, order, NULL); 324238384Sjkim 325280304Sjkim do { 326280304Sjkim if (!BN_rand_range(d, order)) { 327280304Sjkim GOSTerr(GOST_F_GOST2001_KEYGEN, 328280304Sjkim GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); 329280304Sjkim BN_free(d); 330280304Sjkim BN_free(order); 331280304Sjkim return 0; 332280304Sjkim } 333280304Sjkim } 334280304Sjkim while (BN_is_zero(d)); 335280304Sjkim EC_KEY_set_private_key(ec, d); 336280304Sjkim BN_free(d); 337280304Sjkim BN_free(order); 338280304Sjkim return gost2001_compute_public(ec); 339280304Sjkim} 340