198944Sobrien/********************************************************************** 298944Sobrien * gost_sign.c * 398944Sobrien * Copyright (c) 2005-2006 Cryptocom LTD * 498944Sobrien * This file is distributed under the same license as OpenSSL * 598944Sobrien * * 698944Sobrien * Implementation of GOST R 34.10-94 signature algorithm * 798944Sobrien * for OpenSSL * 898944Sobrien * Requires OpenSSL 0.9.9 for compilation * 998944Sobrien **********************************************************************/ 1098944Sobrien#include <string.h> 1198944Sobrien#include <openssl/rand.h> 1298944Sobrien#include <openssl/bn.h> 1398944Sobrien#include <openssl/dsa.h> 1498944Sobrien#include <openssl/evp.h> 1598944Sobrien#include <openssl/err.h> 1698944Sobrien 1798944Sobrien#include "gost_params.h" 1898944Sobrien#include "gost_lcl.h" 1998944Sobrien#include "e_gost_err.h" 2098944Sobrien 2198944Sobrien#ifdef DEBUG_SIGN 2298944Sobrienvoid dump_signature(const char *message, const unsigned char *buffer, 2398944Sobrien size_t len) 2498944Sobrien{ 2598944Sobrien size_t i; 2698944Sobrien fprintf(stderr, "signature %s Length=%d", message, len); 2798944Sobrien for (i = 0; i < len; i++) { 2898944Sobrien if (i % 16 == 0) 2998944Sobrien fputc('\n', stderr); 3098944Sobrien fprintf(stderr, " %02x", buffer[i]); 3198944Sobrien } 3298944Sobrien fprintf(stderr, "\nEnd of signature\n"); 3398944Sobrien} 3498944Sobrien 3598944Sobrienvoid dump_dsa_sig(const char *message, DSA_SIG *sig) 3698944Sobrien{ 3798944Sobrien fprintf(stderr, "%s\nR=", message); 3898944Sobrien BN_print_fp(stderr, sig->r); 3998944Sobrien fprintf(stderr, "\nS="); 4098944Sobrien BN_print_fp(stderr, sig->s); 4198944Sobrien fprintf(stderr, "\n"); 4298944Sobrien} 4398944Sobrien 4498944Sobrien#else 4598944Sobrien 4698944Sobrien# define dump_signature(a,b,c) 4798944Sobrien# define dump_dsa_sig(a,b) 4898944Sobrien#endif 4998944Sobrien 5098944Sobrien/* 5198944Sobrien * Computes signature and returns it as DSA_SIG structure 5298944Sobrien */ 5398944SobrienDSA_SIG *gost_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) 5498944Sobrien{ 5598944Sobrien BIGNUM *k = NULL, *tmp = NULL, *tmp2 = NULL; 5698944Sobrien DSA_SIG *newsig = NULL, *ret = NULL; 5798944Sobrien BIGNUM *md = hashsum2bn(dgst); 5898944Sobrien /* check if H(M) mod q is zero */ 5998944Sobrien BN_CTX *ctx = BN_CTX_new(); 6098944Sobrien if(!ctx) { 6198944Sobrien GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE); 6298944Sobrien goto err; 6398944Sobrien } 6498944Sobrien BN_CTX_start(ctx); 6598944Sobrien newsig = DSA_SIG_new(); 6698944Sobrien if (!newsig) { 6798944Sobrien GOSTerr(GOST_F_GOST_DO_SIGN, GOST_R_NO_MEMORY); 6898944Sobrien goto err; 6998944Sobrien } 7098944Sobrien tmp = BN_CTX_get(ctx); 7198944Sobrien k = BN_CTX_get(ctx); 7298944Sobrien tmp2 = BN_CTX_get(ctx); 7398944Sobrien if(!tmp || !k || !tmp2) { 7498944Sobrien GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE); 7598944Sobrien goto err; 7698944Sobrien } 7798944Sobrien BN_mod(tmp, md, dsa->q, ctx); 7898944Sobrien if (BN_is_zero(tmp)) { 7998944Sobrien BN_one(md); 8098944Sobrien } 8198944Sobrien do { 8298944Sobrien do { 8398944Sobrien /* 8498944Sobrien * Generate random number k less than q 8598944Sobrien */ 8698944Sobrien BN_rand_range(k, dsa->q); 8798944Sobrien /* generate r = (a^x mod p) mod q */ 8898944Sobrien BN_mod_exp(tmp, dsa->g, k, dsa->p, ctx); 8998944Sobrien if (!(newsig->r)) { 90130803Smarcel newsig->r = BN_new(); 9198944Sobrien if(!newsig->r) { 92130803Smarcel GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE); 93130803Smarcel goto err; 94130803Smarcel } 95130803Smarcel } 96130803Smarcel BN_mod(newsig->r, tmp, dsa->q, ctx); 9798944Sobrien } 9898944Sobrien while (BN_is_zero(newsig->r)); 9998944Sobrien /* generate s = (xr + k(Hm)) mod q */ 10098944Sobrien BN_mod_mul(tmp, dsa->priv_key, newsig->r, dsa->q, ctx); 10198944Sobrien BN_mod_mul(tmp2, k, md, dsa->q, ctx); 10298944Sobrien if (!newsig->s) { 10398944Sobrien newsig->s = BN_new(); 10498944Sobrien if(!newsig->s) { 10598944Sobrien GOSTerr(GOST_F_GOST_DO_SIGN, ERR_R_MALLOC_FAILURE); 10698944Sobrien goto err; 10798944Sobrien } 10898944Sobrien } 10998944Sobrien BN_mod_add(newsig->s, tmp, tmp2, dsa->q, ctx); 11098944Sobrien } 11198944Sobrien while (BN_is_zero(newsig->s)); 11298944Sobrien 11398944Sobrien ret = newsig; 11498944Sobrien err: 11598944Sobrien BN_free(md); 11698944Sobrien if(ctx) { 11798944Sobrien BN_CTX_end(ctx); 11898944Sobrien BN_CTX_free(ctx); 11998944Sobrien } 12098944Sobrien if(!ret && newsig) { 12198944Sobrien DSA_SIG_free(newsig); 12298944Sobrien } 123130803Smarcel return ret; 124130803Smarcel} 12598944Sobrien 12698944Sobrien/* 12798944Sobrien * Packs signature according to Cryptocom rules 12898944Sobrien * and frees up DSA_SIG structure 12998944Sobrien */ 13098944Sobrien/*- 13198944Sobrienint pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, size_t *siglen) 13298944Sobrien { 13398944Sobrien *siglen = 2*order; 13498944Sobrien memset(sig,0,*siglen); 13598944Sobrien store_bignum(s->r, sig,order); 13698944Sobrien store_bignum(s->s, sig + order,order); 137130803Smarcel dump_signature("serialized",sig,*siglen); 138130803Smarcel DSA_SIG_free(s); 139130803Smarcel return 1; 140130803Smarcel } 141130803Smarcel*/ 142130803Smarcel/* 143130803Smarcel * Packs signature according to Cryptopro rules 144130803Smarcel * and frees up DSA_SIG structure 145130803Smarcel */ 146130803Smarcelint pack_sign_cp(DSA_SIG *s, int order, unsigned char *sig, size_t *siglen) 14798944Sobrien{ 14898944Sobrien *siglen = 2 * order; 14998944Sobrien memset(sig, 0, *siglen); 15098944Sobrien store_bignum(s->s, sig, order); 15198944Sobrien store_bignum(s->r, sig + order, order); 15298944Sobrien dump_signature("serialized", sig, *siglen); 15398944Sobrien DSA_SIG_free(s); 15498944Sobrien return 1; 15598944Sobrien} 15698944Sobrien 15798944Sobrien/* 15898944Sobrien * Verifies signature passed as DSA_SIG structure 15998944Sobrien * 16098944Sobrien */ 16198944Sobrien 16298944Sobrienint gost_do_verify(const unsigned char *dgst, int dgst_len, 16398944Sobrien DSA_SIG *sig, DSA *dsa) 16498944Sobrien{ 16598944Sobrien BIGNUM *md = NULL, *tmp = NULL; 16698944Sobrien BIGNUM *q2 = NULL; 16798944Sobrien BIGNUM *u = NULL, *v = NULL, *z1 = NULL, *z2 = NULL; 16898944Sobrien BIGNUM *tmp2 = NULL, *tmp3 = NULL; 16998944Sobrien int ok = 0; 17098944Sobrien BN_CTX *ctx = BN_CTX_new(); 17198944Sobrien if(!ctx) { 17298944Sobrien GOSTerr(GOST_F_GOST_DO_VERIFY, ERR_R_MALLOC_FAILURE); 173130803Smarcel goto err; 174130803Smarcel } 17598944Sobrien 17698944Sobrien BN_CTX_start(ctx); 17798944Sobrien if (BN_cmp(sig->s, dsa->q) >= 1 || BN_cmp(sig->r, dsa->q) >= 1) { 17898944Sobrien GOSTerr(GOST_F_GOST_DO_VERIFY, GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); 17998944Sobrien goto err; 18098944Sobrien } 18198944Sobrien md = hashsum2bn(dgst); 18298944Sobrien 18398944Sobrien tmp = BN_CTX_get(ctx); 18498944Sobrien v = BN_CTX_get(ctx); 18598944Sobrien q2 = BN_CTX_get(ctx); 18698944Sobrien z1 = BN_CTX_get(ctx); 18798944Sobrien z2 = BN_CTX_get(ctx); 18898944Sobrien tmp2 = BN_CTX_get(ctx); 18998944Sobrien tmp3 = BN_CTX_get(ctx); 19098944Sobrien u = BN_CTX_get(ctx); 19198944Sobrien if(!tmp || !v || !q2 || !z1 || !z2 || !tmp2 || !tmp3 || !u) { 19298944Sobrien GOSTerr(GOST_F_GOST_DO_VERIFY, ERR_R_MALLOC_FAILURE); 19398944Sobrien goto err; 19498944Sobrien } 19598944Sobrien 19698944Sobrien BN_mod(tmp, md, dsa->q, ctx); 19798944Sobrien if (BN_is_zero(tmp)) { 19898944Sobrien BN_one(md); 19998944Sobrien } 20098944Sobrien BN_copy(q2, dsa->q); 20198944Sobrien BN_sub_word(q2, 2); 20298944Sobrien BN_mod_exp(v, md, q2, dsa->q, ctx); 20398944Sobrien BN_mod_mul(z1, sig->s, v, dsa->q, ctx); 20498944Sobrien BN_sub(tmp, dsa->q, sig->r); 20598944Sobrien BN_mod_mul(z2, tmp, v, dsa->p, ctx); 20698944Sobrien BN_mod_exp(tmp, dsa->g, z1, dsa->p, ctx); 20798944Sobrien BN_mod_exp(tmp2, dsa->pub_key, z2, dsa->p, ctx); 20898944Sobrien BN_mod_mul(tmp3, tmp, tmp2, dsa->p, ctx); 20998944Sobrien BN_mod(u, tmp3, dsa->q, ctx); 21098944Sobrien ok = (BN_cmp(u, sig->r) == 0); 21198944Sobrien 21298944Sobrien if (!ok) { 21398944Sobrien GOSTerr(GOST_F_GOST_DO_VERIFY, GOST_R_SIGNATURE_MISMATCH); 21498944Sobrien } 21598944Sobrienerr: 21698944Sobrien if(md) BN_free(md); 21798944Sobrien if(ctx) { 21898944Sobrien BN_CTX_end(ctx); 21998944Sobrien BN_CTX_free(ctx); 22098944Sobrien } 22198944Sobrien return ok; 22298944Sobrien} 22398944Sobrien 22498944Sobrien/* 22598944Sobrien * Computes public keys for GOST R 34.10-94 algorithm 22698944Sobrien * 22798944Sobrien */ 22898944Sobrienint gost94_compute_public(DSA *dsa) 22998944Sobrien{ 23098944Sobrien /* Now fill algorithm parameters with correct values */ 23198944Sobrien BN_CTX *ctx; 23298944Sobrien if (!dsa->g) { 23398944Sobrien GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, GOST_R_KEY_IS_NOT_INITALIZED); 23498944Sobrien return 0; 23598944Sobrien } 23698944Sobrien ctx = BN_CTX_new(); 23798944Sobrien if(!ctx) { 23898944Sobrien GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE); 23998944Sobrien return 0; 24098944Sobrien } 24198944Sobrien 242 dsa->pub_key = BN_new(); 243 if(!dsa->pub_key) { 244 GOSTerr(GOST_F_GOST94_COMPUTE_PUBLIC, ERR_R_MALLOC_FAILURE); 245 BN_CTX_free(ctx); 246 return 0; 247 } 248 /* Compute public key y = a^x mod p */ 249 BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx); 250 BN_CTX_free(ctx); 251 return 1; 252} 253 254/* 255 * Fill GOST 94 params, searching them in R3410_paramset array 256 * by nid of paramset 257 * 258 */ 259int fill_GOST94_params(DSA *dsa, int nid) 260{ 261 R3410_params *params = R3410_paramset; 262 while (params->nid != NID_undef && params->nid != nid) 263 params++; 264 if (params->nid == NID_undef) { 265 GOSTerr(GOST_F_FILL_GOST94_PARAMS, GOST_R_UNSUPPORTED_PARAMETER_SET); 266 return 0; 267 } 268#define dump_signature(a,b,c) 269 if (dsa->p) { 270 BN_free(dsa->p); 271 } 272 dsa->p = NULL; 273 BN_dec2bn(&(dsa->p), params->p); 274 if (dsa->q) { 275 BN_free(dsa->q); 276 } 277 dsa->q = NULL; 278 BN_dec2bn(&(dsa->q), params->q); 279 if (dsa->g) { 280 BN_free(dsa->g); 281 } 282 dsa->g = NULL; 283 BN_dec2bn(&(dsa->g), params->a); 284 return 1; 285} 286 287/* 288 * Generate GOST R 34.10-94 keypair 289 * 290 * 291 */ 292int gost_sign_keygen(DSA *dsa) 293{ 294 dsa->priv_key = BN_new(); 295 if(!dsa->priv_key) { 296 GOSTerr(GOST_F_GOST_SIGN_KEYGEN, ERR_R_MALLOC_FAILURE); 297 return 0; 298 } 299 BN_rand_range(dsa->priv_key, dsa->q); 300 return gost94_compute_public(dsa); 301} 302 303/* Unpack signature according to cryptocom rules */ 304/*- 305DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen) 306 { 307 DSA_SIG *s; 308 s = DSA_SIG_new(); 309 if (s == NULL) 310 { 311 GOSTerr(GOST_F_UNPACK_CC_SIGNATURE,GOST_R_NO_MEMORY); 312 return(NULL); 313 } 314 s->r = getbnfrombuf(sig, siglen/2); 315 s->s = getbnfrombuf(sig + siglen/2, siglen/2); 316 return s; 317 } 318*/ 319/* Unpack signature according to cryptopro rules */ 320DSA_SIG *unpack_cp_signature(const unsigned char *sig, size_t siglen) 321{ 322 DSA_SIG *s; 323 324 s = DSA_SIG_new(); 325 if (s == NULL) { 326 GOSTerr(GOST_F_UNPACK_CP_SIGNATURE, GOST_R_NO_MEMORY); 327 return NULL; 328 } 329 s->s = getbnfrombuf(sig, siglen / 2); 330 s->r = getbnfrombuf(sig + siglen / 2, siglen / 2); 331 return s; 332} 333 334/* Convert little-endian byte array into bignum */ 335BIGNUM *hashsum2bn(const unsigned char *dgst) 336{ 337 unsigned char buf[32]; 338 int i; 339 for (i = 0; i < 32; i++) { 340 buf[31 - i] = dgst[i]; 341 } 342 return getbnfrombuf(buf, 32); 343} 344 345/* Convert byte buffer to bignum, skipping leading zeros*/ 346BIGNUM *getbnfrombuf(const unsigned char *buf, size_t len) 347{ 348 while (*buf == 0 && len > 0) { 349 buf++; 350 len--; 351 } 352 if (len) { 353 return BN_bin2bn(buf, len, NULL); 354 } else { 355 BIGNUM *b = BN_new(); 356 BN_zero(b); 357 return b; 358 } 359} 360 361/* 362 * Pack bignum into byte buffer of given size, filling all leading bytes by 363 * zeros 364 */ 365int store_bignum(BIGNUM *bn, unsigned char *buf, int len) 366{ 367 int bytes = BN_num_bytes(bn); 368 if (bytes > len) 369 return 0; 370 memset(buf, 0, len); 371 BN_bn2bin(bn, buf + len - bytes); 372 return 1; 373} 374