/* * Return the signature struct (r,s) from the message hash. The caller * must have allocated R and S. */ static gpg_err_code_t sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s) { gpg_err_code_t err = 0; gcry_mpi_t k, dr, sum, k_1, x; mpi_point_t I; mpi_ec_t ctx; k = NULL; dr = mpi_alloc (0); sum = mpi_alloc (0); k_1 = mpi_alloc (0); x = mpi_alloc (0); point_init (&I); mpi_set_ui (s, 0); mpi_set_ui (r, 0); ctx = _gcry_mpi_ec_init (skey->E.p, skey->E.a); while (!mpi_cmp_ui (s, 0)) /* s == 0 */ { while (!mpi_cmp_ui (r, 0)) /* r == 0 */ { /* Note, that we are guaranteed to enter this loop at least once because r has been intialized to 0. We can't use a do_while because we want to keep the value of R even if S has to be recomputed. */ mpi_free (k); k = gen_k (skey->E.n, GCRY_STRONG_RANDOM); _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) { if (DBG_CIPHER) log_debug ("ecc sign: Failed to get affine coordinates\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } mpi_mod (r, x, skey->E.n); /* r = x mod n */ } mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ mpi_addm (sum, input, dr, skey->E.n); /* sum = hash + (d*r) mod n */ mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */ mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */ } leave: _gcry_mpi_ec_free (ctx); point_free (&I); mpi_free (x); mpi_free (k_1); mpi_free (sum); mpi_free (dr); mpi_free (k); return err; }
static void do_encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ) { MPI k; /* Note: maybe we should change the interface, so that it * is possible to check that input is < p and return an * error code. */ k = gen_k( pkey->p, 1 ); mpi_powm( a, pkey->g, k, pkey->p ); /* b = (y^k * input) mod p * = ((y^k mod p) * (input mod p)) mod p * and because input is < p * = ((y^k mod p) * input) mod p */ mpi_powm( b, pkey->y, k, pkey->p ); mpi_mulm( b, b, input, pkey->p ); #if 0 if( DBG_CIPHER ) { log_mpidump("elg encrypted y= ", pkey->y); log_mpidump("elg encrypted p= ", pkey->p); log_mpidump("elg encrypted k= ", k); log_mpidump("elg encrypted M= ", input); log_mpidump("elg encrypted a= ", a); log_mpidump("elg encrypted b= ", b); } #endif mpi_free(k); }
/**************** * To check the validity of the value, recalculate the correspondence * between the public value and the secret one. */ static int check_secret_key (ECC_secret_key * sk) { mpi_point_t Q; gcry_mpi_t y_2, y2 = mpi_alloc (0); mpi_ec_t ctx; /* ?primarity test of 'p' */ /* (...) //!! */ /* G in E(F_p) */ y_2 = gen_y_2 (sk->E.G.x, &sk->E); /* y^2=x^3+a*x+b */ mpi_mulm (y2, sk->E.G.y, sk->E.G.y, sk->E.p); /* y^2=y*y */ if (mpi_cmp (y_2, y2)) { if (DBG_CIPHER) log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n"); return (1); } /* G != PaI */ if (!mpi_cmp_ui (sk->E.G.z, 0)) { if (DBG_CIPHER) log_debug ("Bad check: 'G' cannot be Point at Infinity!\n"); return (1); } point_init (&Q); ctx = _gcry_mpi_ec_init (sk->E.p, sk->E.a); _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx); if (mpi_cmp_ui (Q.z, 0)) { if (DBG_CIPHER) log_debug ("check_secret_key: E is not a curve of order n\n"); point_free (&Q); _gcry_mpi_ec_free (ctx); return 1; } /* pubkey cannot be PaI */ if (!mpi_cmp_ui (sk->Q.z, 0)) { if (DBG_CIPHER) log_debug ("Bad check: Q can not be a Point at Infinity!\n"); _gcry_mpi_ec_free (ctx); return (1); } /* pubkey = [d]G over E */ _gcry_mpi_ec_mul_point (&Q, sk->d, &sk->E.G, ctx); if ((Q.x == sk->Q.x) && (Q.y == sk->Q.y) && (Q.z == sk->Q.z)) { if (DBG_CIPHER) log_debug ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); _gcry_mpi_ec_free (ctx); return (1); } _gcry_mpi_ec_free (ctx); point_free (&Q); return 0; }
static void do_mulm(void) { if( stackidx < 3 ) { fputs("stack underflow\n", stderr); return; } mpi_mulm( stack[stackidx-3], stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] ); stackidx -= 2; }
/**************** * Returns true if the signature composed of A and B is valid. */ static int verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) { int rc; gcry_mpi_t t1; gcry_mpi_t t2; gcry_mpi_t base[4]; gcry_mpi_t ex[4]; if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) ) return 0; /* assertion 0 < a < p failed */ t1 = mpi_alloc( mpi_get_nlimbs(a) ); t2 = mpi_alloc( mpi_get_nlimbs(a) ); #if 0 /* t1 = (y^a mod p) * (a^b mod p) mod p */ gcry_mpi_powm( t1, pkey->y, a, pkey->p ); gcry_mpi_powm( t2, a, b, pkey->p ); mpi_mulm( t1, t1, t2, pkey->p ); /* t2 = g ^ input mod p */ gcry_mpi_powm( t2, pkey->g, input, pkey->p ); rc = !mpi_cmp( t1, t2 ); #elif 0 /* t1 = (y^a mod p) * (a^b mod p) mod p */ base[0] = pkey->y; ex[0] = a; base[1] = a; ex[1] = b; base[2] = NULL; ex[2] = NULL; mpi_mulpowm( t1, base, ex, pkey->p ); /* t2 = g ^ input mod p */ gcry_mpi_powm( t2, pkey->g, input, pkey->p ); rc = !mpi_cmp( t1, t2 ); #else /* t1 = g ^ - input * y ^ a * a ^ b mod p */ mpi_invm(t2, pkey->g, pkey->p ); base[0] = t2 ; ex[0] = input; base[1] = pkey->y; ex[1] = a; base[2] = a; ex[2] = b; base[3] = NULL; ex[3] = NULL; mpi_mulpowm( t1, base, ex, pkey->p ); rc = !mpi_cmp_ui( t1, 1 ); #endif mpi_free(t1); mpi_free(t2); return rc; }
/**************** * Solve the right side of the equation that defines a curve. */ static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base) { gcry_mpi_t three, x_3, axb, y; three = mpi_alloc_set_ui (3); x_3 = mpi_new (0); axb = mpi_new (0); y = mpi_new (0); mpi_powm (x_3, x, three, base->p); mpi_mulm (axb, base->a, x, base->p); mpi_addm (axb, axb, base->b, base->p); mpi_addm (y, x_3, axb, base->p); mpi_free (x_3); mpi_free (axb); mpi_free (three); return y; /* The quadratic value of the coordinate if it exist. */ }
static void decrypt(gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, ELG_secret_key *skey ) { gcry_mpi_t t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) ); /* output = b/(a^x) mod p */ gcry_mpi_powm( t1, a, skey->x, skey->p ); mpi_invm( t1, t1, skey->p ); mpi_mulm( output, b, t1, skey->p ); #if 0 if( DBG_CIPHER ) { log_mpidump("elg decrypted x= ", skey->x); log_mpidump("elg decrypted p= ", skey->p); log_mpidump("elg decrypted a= ", a); log_mpidump("elg decrypted b= ", b); log_mpidump("elg decrypted M= ", output); } #endif mpi_free(t1); }
static void sign(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey ) { gcry_mpi_t k; gcry_mpi_t t = mpi_alloc( mpi_get_nlimbs(a) ); gcry_mpi_t inv = mpi_alloc( mpi_get_nlimbs(a) ); gcry_mpi_t p_1 = mpi_copy(skey->p); /* * b = (t * inv) mod (p-1) * b = (t * inv(k,(p-1),(p-1)) mod (p-1) * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1) * */ mpi_sub_ui(p_1, p_1, 1); k = gen_k( skey->p, 0 /* no small K ! */ ); gcry_mpi_powm( a, skey->g, k, skey->p ); mpi_mul(t, skey->x, a ); mpi_subm(t, input, t, p_1 ); mpi_invm(inv, k, p_1 ); mpi_mulm(b, t, inv, p_1 ); #if 0 if( DBG_CIPHER ) { log_mpidump("elg sign p= ", skey->p); log_mpidump("elg sign g= ", skey->g); log_mpidump("elg sign y= ", skey->y); log_mpidump("elg sign x= ", skey->x); log_mpidump("elg sign k= ", k); log_mpidump("elg sign M= ", input); log_mpidump("elg sign a= ", a); log_mpidump("elg sign b= ", b); } #endif mpi_free(k); mpi_free(t); mpi_free(inv); mpi_free(p_1); }
/**************** * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M */ int mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m) { int rc = -ENOMEM; int k; /* number of elements */ int t; /* bit size of largest exponent */ int i, j, idx; MPI *G = NULL; /* table with precomputed values of size 2^k */ MPI tmp = NULL; for(k=0; basearray[k]; k++ ) ; if (!k) { printk("mpi_mulpowm: assert(k) failed\n"); BUG(); } for(t=0, i=0; (tmp=exparray[i]); i++ ) { j = mpi_get_nbits(tmp); if( j > t ) t = j; } if (i!=k) { printk("mpi_mulpowm: assert(i==k) failed\n"); BUG(); } if (!t) { printk("mpi_mulpowm: assert(t) failed\n"); BUG(); } if (k>=10) { printk("mpi_mulpowm: assert(k<10) failed\n"); BUG(); } //daveti: hack //G = kzalloc( (1<<k) * sizeof *G, GFP_KERNEL ); G = kzalloc( (1<<k) * sizeof *G, GFP_ATOMIC ); if (!G) goto nomem; /* and calculate */ tmp = mpi_alloc( mpi_get_nlimbs(m)+1 ); if (!tmp) goto nomem; if (mpi_set_ui( res, 1 ) < 0) goto nomem; for(i = 1; i <= t; i++ ) { if (mpi_mulm(tmp, res, res, m ) < 0) goto nomem; idx = build_index( exparray, k, i, t ); if (!(idx >= 0 && idx < (1<<k))) { printk("mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed\n"); BUG(); } if( !G[idx] ) { if( !idx ) { G[0] = mpi_alloc_set_ui( 1 ); if (!G[0]) goto nomem; } else { for(j=0; j < k; j++ ) { if( (idx & (1<<j) ) ) { if( !G[idx] ) { if (mpi_copy( &G[idx], basearray[j] ) < 0) goto nomem; } else { if (mpi_mulm(G[idx],G[idx],basearray[j],m) < 0) goto nomem; } } } if( !G[idx] ) { G[idx] = mpi_alloc(0); if (!G[idx]) goto nomem; } } } if (mpi_mulm(res, tmp, G[idx], m ) < 0) goto nomem; } rc = 0; nomem: /* cleanup */ mpi_free(tmp); for(i=0; i < (1<<k); i++ ) mpi_free(G[i]); kfree(G); return rc; }
static void ec_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { #if 0 /* NOTE: This code works only for limb sizes of 32 bit. */ mpi_limb_t *wp, *sp; if (ctx->nist_nbits == 192) { mpi_mul (w, u, v); mpi_resize (w, 12); wp = w->d; sp = ctx->s[0]->d; sp[0*2+0] = wp[0*2+0]; sp[0*2+1] = wp[0*2+1]; sp[1*2+0] = wp[1*2+0]; sp[1*2+1] = wp[1*2+1]; sp[2*2+0] = wp[2*2+0]; sp[2*2+1] = wp[2*2+1]; sp = ctx->s[1]->d; sp[0*2+0] = wp[3*2+0]; sp[0*2+1] = wp[3*2+1]; sp[1*2+0] = wp[3*2+0]; sp[1*2+1] = wp[3*2+1]; sp[2*2+0] = 0; sp[2*2+1] = 0; sp = ctx->s[2]->d; sp[0*2+0] = 0; sp[0*2+1] = 0; sp[1*2+0] = wp[4*2+0]; sp[1*2+1] = wp[4*2+1]; sp[2*2+0] = wp[4*2+0]; sp[2*2+1] = wp[4*2+1]; sp = ctx->s[3]->d; sp[0*2+0] = wp[5*2+0]; sp[0*2+1] = wp[5*2+1]; sp[1*2+0] = wp[5*2+0]; sp[1*2+1] = wp[5*2+1]; sp[2*2+0] = wp[5*2+0]; sp[2*2+1] = wp[5*2+1]; ctx->s[0]->nlimbs = 6; ctx->s[1]->nlimbs = 6; ctx->s[2]->nlimbs = 6; ctx->s[3]->nlimbs = 6; mpi_add (ctx->c, ctx->s[0], ctx->s[1]); mpi_add (ctx->c, ctx->c, ctx->s[2]); mpi_add (ctx->c, ctx->c, ctx->s[3]); while ( mpi_cmp (ctx->c, ctx->p ) >= 0 ) mpi_sub ( ctx->c, ctx->c, ctx->p ); mpi_set (w, ctx->c); } else if (ctx->nist_nbits == 384) { int i; mpi_mul (w, u, v); mpi_resize (w, 24); wp = w->d; #define NEXT(a) do { ctx->s[(a)]->nlimbs = 12; \ sp = ctx->s[(a)]->d; \ i = 0; } while (0) #define X(a) do { sp[i++] = wp[(a)];} while (0) #define X0(a) do { sp[i++] = 0; } while (0) NEXT(0); X(0);X(1);X(2);X(3);X(4);X(5);X(6);X(7);X(8);X(9);X(10);X(11); NEXT(1); X0();X0();X0();X0();X(21);X(22);X(23);X0();X0();X0();X0();X0(); NEXT(2); X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);X(21);X(22);X(23); NEXT(3); X(21);X(22);X(23);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20); NEXT(4); X0();X(23);X0();X(20);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19); NEXT(5); X0();X0();X0();X0();X(20);X(21);X(22);X(23);X0();X0();X0();X0(); NEXT(6); X(20);X0();X0();X(21);X(22);X(23);X0();X0();X0();X0();X0();X0(); NEXT(7); X(23);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);X(21);X(22); NEXT(8); X0();X(20);X(21);X(22);X(23);X0();X0();X0();X0();X0();X0();X0(); NEXT(9); X0();X0();X0();X(23);X(23);X0();X0();X0();X0();X0();X0();X0(); #undef X0 #undef X #undef NEXT mpi_add (ctx->c, ctx->s[0], ctx->s[1]); mpi_add (ctx->c, ctx->c, ctx->s[1]); mpi_add (ctx->c, ctx->c, ctx->s[2]); mpi_add (ctx->c, ctx->c, ctx->s[3]); mpi_add (ctx->c, ctx->c, ctx->s[4]); mpi_add (ctx->c, ctx->c, ctx->s[5]); mpi_add (ctx->c, ctx->c, ctx->s[6]); mpi_sub (ctx->c, ctx->c, ctx->s[7]); mpi_sub (ctx->c, ctx->c, ctx->s[8]); mpi_sub (ctx->c, ctx->c, ctx->s[9]); while ( mpi_cmp (ctx->c, ctx->p ) >= 0 ) mpi_sub ( ctx->c, ctx->c, ctx->p ); while ( ctx->c->sign ) mpi_add ( ctx->c, ctx->c, ctx->p ); mpi_set (w, ctx->c); } else #endif /*0*/ mpi_mulm (w, u, v, ctx->p); }
/* * Check if R and S verifies INPUT. */ static gpg_err_code_t verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s) { gpg_err_code_t err = 0; gcry_mpi_t h, h1, h2, x, y; mpi_point_t Q, Q1, Q2; mpi_ec_t ctx; if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ h = mpi_alloc (0); h1 = mpi_alloc (0); h2 = mpi_alloc (0); x = mpi_alloc (0); y = mpi_alloc (0); point_init (&Q); point_init (&Q1); point_init (&Q2); ctx = _gcry_mpi_ec_init (pkey->E.p, pkey->E.a); /* h = s^(-1) (mod n) */ mpi_invm (h, s, pkey->E.n); /* log_mpidump (" h", h); */ /* h1 = hash * s^(-1) (mod n) */ mpi_mulm (h1, input, h, pkey->E.n); /* log_mpidump (" h1", h1); */ /* Q1 = [ hash * s^(-1) ]G */ _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx); /* log_mpidump ("Q1.x", Q1.x); */ /* log_mpidump ("Q1.y", Q1.y); */ /* log_mpidump ("Q1.z", Q1.z); */ /* h2 = r * s^(-1) (mod n) */ mpi_mulm (h2, r, h, pkey->E.n); /* log_mpidump (" h2", h2); */ /* Q2 = [ r * s^(-1) ]Q */ _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx); /* log_mpidump ("Q2.x", Q2.x); */ /* log_mpidump ("Q2.y", Q2.y); */ /* log_mpidump ("Q2.z", Q2.z); */ /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */ _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); /* log_mpidump (" Q.x", Q.x); */ /* log_mpidump (" Q.y", Q.y); */ /* log_mpidump (" Q.z", Q.z); */ if (!mpi_cmp_ui (Q.z, 0)) { if (DBG_CIPHER) log_debug ("ecc verify: Rejected\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx)) { if (DBG_CIPHER) log_debug ("ecc verify: Failed to get affine coordinates\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ if (mpi_cmp (x, r)) /* x != r */ { if (DBG_CIPHER) { log_mpidump (" x", x); log_mpidump (" y", y); log_mpidump (" r", r); log_mpidump (" s", s); log_debug ("ecc verify: Not verified\n"); } err = GPG_ERR_BAD_SIGNATURE; goto leave; } if (DBG_CIPHER) log_debug ("ecc verify: Accepted\n"); leave: _gcry_mpi_ec_free (ctx); point_free (&Q2); point_free (&Q1); point_free (&Q); mpi_free (y); mpi_free (x); mpi_free (h2); mpi_free (h1); mpi_free (h); return err; }
/* Compute an ECDSA signature. * Return the signature struct (r,s) from the message hash. The caller * must have allocated R and S. */ gpg_err_code_t _gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s, int flags, int hashalgo) { gpg_err_code_t err = 0; int extraloops = 0; gcry_mpi_t k, dr, sum, k_1, x; mpi_point_struct I; gcry_mpi_t hash; const void *abuf; unsigned int abits, qbits; mpi_ec_t ctx; if (DBG_CIPHER) log_mpidump ("ecdsa sign hash ", input ); qbits = mpi_get_nbits (skey->E.n); /* Convert the INPUT into an MPI if needed. */ if (mpi_is_opaque (input)) { abuf = gcry_mpi_get_opaque (input, &abits); err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL)); if (err) return err; if (abits > qbits) gcry_mpi_rshift (hash, hash, abits - qbits); } else hash = input; k = NULL; dr = mpi_alloc (0); sum = mpi_alloc (0); k_1 = mpi_alloc (0); x = mpi_alloc (0); point_init (&I); ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, skey->E.p, skey->E.a, skey->E.b); /* Two loops to avoid R or S are zero. This is more of a joke than a real demand because the probability of them being zero is less than any hardware failure. Some specs however require it. */ do { do { mpi_free (k); k = NULL; if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) { /* Use Pornin's method for deterministic DSA. If this flag is set, it is expected that HASH is an opaque MPI with the to be signed hash. That hash is also used as h1 from 3.2.a. */ if (!mpi_is_opaque (input)) { err = GPG_ERR_CONFLICT; goto leave; } abuf = gcry_mpi_get_opaque (input, &abits); err = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d, abuf, (abits+7)/8, hashalgo, extraloops); if (err) goto leave; extraloops++; } else k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) { if (DBG_CIPHER) log_debug ("ecc sign: Failed to get affine coordinates\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } mpi_mod (r, x, skey->E.n); /* r = x mod n */ } while (!mpi_cmp_ui (r, 0)); mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ mpi_addm (sum, hash, dr, skey->E.n); /* sum = hash + (d*r) mod n */ mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */ mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */ } while (!mpi_cmp_ui (s, 0)); if (DBG_CIPHER) { log_mpidump ("ecdsa sign result r ", r); log_mpidump ("ecdsa sign result s ", s); } leave: _gcry_mpi_ec_free (ctx); point_free (&I); mpi_free (x); mpi_free (k_1); mpi_free (sum); mpi_free (dr); mpi_free (k); if (hash != input) mpi_free (hash); return err; }
/* Verify an ECDSA signature. * Check if R and S verifies INPUT. */ gpg_err_code_t _gcry_ecc_ecdsa_verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s) { gpg_err_code_t err = 0; gcry_mpi_t h, h1, h2, x; mpi_point_struct Q, Q1, Q2; mpi_ec_t ctx; if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ h = mpi_alloc (0); h1 = mpi_alloc (0); h2 = mpi_alloc (0); x = mpi_alloc (0); point_init (&Q); point_init (&Q1); point_init (&Q2); ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, pkey->E.p, pkey->E.a, pkey->E.b); /* h = s^(-1) (mod n) */ mpi_invm (h, s, pkey->E.n); /* h1 = hash * s^(-1) (mod n) */ mpi_mulm (h1, input, h, pkey->E.n); /* Q1 = [ hash * s^(-1) ]G */ _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx); /* h2 = r * s^(-1) (mod n) */ mpi_mulm (h2, r, h, pkey->E.n); /* Q2 = [ r * s^(-1) ]Q */ _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx); /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */ _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); if (!mpi_cmp_ui (Q.z, 0)) { if (DBG_CIPHER) log_debug ("ecc verify: Rejected\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx)) { if (DBG_CIPHER) log_debug ("ecc verify: Failed to get affine coordinates\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ if (mpi_cmp (x, r)) /* x != r */ { if (DBG_CIPHER) { log_mpidump (" x", x); log_mpidump (" r", r); log_mpidump (" s", s); } err = GPG_ERR_BAD_SIGNATURE; goto leave; } leave: _gcry_mpi_ec_free (ctx); point_free (&Q2); point_free (&Q1); point_free (&Q); mpi_free (x); mpi_free (h2); mpi_free (h1); mpi_free (h); return err; }
/* Compute an EdDSA signature. See: * [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja * Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security * signatures. Journal of Cryptographic Engineering 2 (2012), 77-89. * Document ID: a1a62a2f76d23f65d622484ddd09caf8. * URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. * * Despite that this function requires the specification of a hash * algorithm, we only support what has been specified by the paper. * This may change in the future. Note that we don't check the used * curve; the user is responsible to use Ed25519. * * Return the signature struct (r,s) from the message hash. The caller * must have allocated R_R and S. */ gpg_err_code_t _gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk) { int rc; mpi_ec_t ctx = NULL; int b; unsigned int tmp; unsigned char *digest; gcry_buffer_t hvec[3]; const void *mbuf; size_t mlen; unsigned char *rawmpi = NULL; unsigned int rawmpilen; unsigned char *encpk = NULL; /* Encoded public key. */ unsigned int encpklen; mpi_point_struct I; /* Intermediate value. */ mpi_point_struct Q; /* Public key. */ gcry_mpi_t a, x, y, r; memset (hvec, 0, sizeof hvec); if (!mpi_is_opaque (input)) return GPG_ERR_INV_DATA; /* Initialize some helpers. */ point_init (&I); point_init (&Q); a = mpi_snew (0); x = mpi_new (0); y = mpi_new (0); r = mpi_new (0); ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0, skey->E.p, skey->E.a, skey->E.b); b = (ctx->nbits+7)/8; if (b != 256/8) return GPG_ERR_INTERNAL; /* We only support 256 bit. */ rc = _gcry_ecc_eddsa_compute_h_d (&digest, skey->d, ctx); if (rc) goto leave; _gcry_mpi_set_buffer (a, digest, 32, 0); /* Compute the public key if it has not been supplied as optional parameter. */ if (pk) { rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen); if (rc) goto leave; if (DBG_CIPHER) log_printhex ("* e_pk", encpk, encpklen); if (!_gcry_mpi_ec_curve_point (&Q, ctx)) { rc = GPG_ERR_BROKEN_PUBKEY; goto leave; } } else { _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx); rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, 0, &encpk, &encpklen); if (rc) goto leave; if (DBG_CIPHER) log_printhex (" e_pk", encpk, encpklen); } /* Compute R. */ mbuf = mpi_get_opaque (input, &tmp); mlen = (tmp +7)/8; if (DBG_CIPHER) log_printhex (" m", mbuf, mlen); hvec[0].data = digest; hvec[0].off = 32; hvec[0].len = 32; hvec[1].data = (char*)mbuf; hvec[1].len = mlen; rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); if (rc) goto leave; reverse_buffer (digest, 64); if (DBG_CIPHER) log_printhex (" r", digest, 64); _gcry_mpi_set_buffer (r, digest, 64, 0); _gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx); if (DBG_CIPHER) log_printpnt (" r", &I, ctx); /* Convert R into affine coordinates and apply encoding. */ rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, 0, &rawmpi, &rawmpilen); if (rc) goto leave; if (DBG_CIPHER) log_printhex (" e_r", rawmpi, rawmpilen); /* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */ hvec[0].data = rawmpi; /* (this is R) */ hvec[0].off = 0; hvec[0].len = rawmpilen; hvec[1].data = encpk; hvec[1].off = 0; hvec[1].len = encpklen; hvec[2].data = (char*)mbuf; hvec[2].off = 0; hvec[2].len = mlen; rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); if (rc) goto leave; /* No more need for RAWMPI thus we now transfer it to R_R. */ mpi_set_opaque (r_r, rawmpi, rawmpilen*8); rawmpi = NULL; reverse_buffer (digest, 64); if (DBG_CIPHER) log_printhex (" H(R+)", digest, 64); _gcry_mpi_set_buffer (s, digest, 64, 0); mpi_mulm (s, s, a, skey->E.n); mpi_addm (s, s, r, skey->E.n); rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen); if (rc) goto leave; if (DBG_CIPHER) log_printhex (" e_s", rawmpi, rawmpilen); mpi_set_opaque (s, rawmpi, rawmpilen*8); rawmpi = NULL; rc = 0; leave: _gcry_mpi_release (a); _gcry_mpi_release (x); _gcry_mpi_release (y); _gcry_mpi_release (r); xfree (digest); _gcry_mpi_ec_free (ctx); point_free (&I); point_free (&Q); xfree (encpk); xfree (rawmpi); return rc; }
/* Recover X from Y and SIGN (which actually is a parity bit). */ gpg_err_code_t _gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) { gpg_err_code_t rc = 0; gcry_mpi_t u, v, v3, t; static gcry_mpi_t p58, seven; if (ec->dialect != ECC_DIALECT_ED25519) return GPG_ERR_NOT_IMPLEMENTED; if (!p58) p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD"); if (!seven) seven = mpi_set_ui (NULL, 7); u = mpi_new (0); v = mpi_new (0); v3 = mpi_new (0); t = mpi_new (0); /* Compute u and v */ /* u = y^2 */ mpi_mulm (u, y, y, ec->p); /* v = b*y^2 */ mpi_mulm (v, ec->b, u, ec->p); /* u = y^2-1 */ mpi_sub_ui (u, u, 1); /* v = b*y^2+1 */ mpi_add_ui (v, v, 1); /* Compute sqrt(u/v) */ /* v3 = v^3 */ mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); /* t = v3 * v3 * u * v = u * v^7 */ mpi_powm (t, v, seven, ec->p); mpi_mulm (t, t, u, ec->p); /* t = t^((p-5)/8) = (u * v^7)^((p-5)/8) */ mpi_powm (t, t, p58, ec->p); /* x = t * u * v^3 = (u * v^3) * (u * v^7)^((p-5)/8) */ mpi_mulm (t, t, u, ec->p); mpi_mulm (x, t, v3, ec->p); /* Adjust if needed. */ /* t = v * x^2 */ mpi_mulm (t, x, x, ec->p); mpi_mulm (t, t, v, ec->p); /* -t == u ? x = x * sqrt(-1) */ mpi_neg (t, t); if (!mpi_cmp (t, u)) { static gcry_mpi_t m1; /* Fixme: this is not thread-safe. */ if (!m1) m1 = scanval ("2B8324804FC1DF0B2B4D00993DFBD7A7" "2F431806AD2FE478C4EE1B274A0EA0B0"); mpi_mulm (x, x, m1, ec->p); /* t = v * x^2 */ mpi_mulm (t, x, x, ec->p); mpi_mulm (t, t, v, ec->p); /* -t == u ? x = x * sqrt(-1) */ mpi_neg (t, t); if (!mpi_cmp (t, u)) rc = GPG_ERR_INV_OBJ; } /* Choose the desired square root according to parity */ if (mpi_test_bit (x, 0) != !!sign) mpi_sub (x, ec->p, x); mpi_free (t); mpi_free (v3); mpi_free (v); mpi_free (u); return rc; }
int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI m) { int rc = -ENOMEM; int k; /* */ int t; /* */ int i, j, idx; MPI *G = NULL; /* */ MPI tmp = NULL; for (k = 0; basearray[k]; k++) ; if (!k) { pr_emerg("mpi_mulpowm: assert(k) failed\n"); BUG(); } for (t = 0, i = 0; (tmp = exparray[i]); i++) { j = mpi_get_nbits(tmp); if (j > t) t = j; } if (i != k) { pr_emerg("mpi_mulpowm: assert(i==k) failed\n"); BUG(); } if (!t) { pr_emerg("mpi_mulpowm: assert(t) failed\n"); BUG(); } if (k >= 10) { pr_emerg("mpi_mulpowm: assert(k<10) failed\n"); BUG(); } G = kzalloc((1 << k) * sizeof *G, GFP_KERNEL); if (!G) goto err_out; /* */ tmp = mpi_alloc(mpi_get_nlimbs(m) + 1); if (!tmp) goto nomem; if (mpi_set_ui(res, 1) < 0) goto nomem; for (i = 1; i <= t; i++) { if (mpi_mulm(tmp, res, res, m) < 0) goto nomem; idx = build_index(exparray, k, i, t); if (!(idx >= 0 && idx < (1 << k))) { pr_emerg("mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed\n"); BUG(); } if (!G[idx]) { if (!idx) { G[0] = mpi_alloc_set_ui(1); if (!G[0]) goto nomem; } else { for (j = 0; j < k; j++) { if ((idx & (1 << j))) { if (!G[idx]) { if (mpi_copy (&G[idx], basearray[j]) < 0) goto nomem; } else { if (mpi_mulm (G[idx], G[idx], basearray[j], m) < 0) goto nomem; } } } if (!G[idx]) { G[idx] = mpi_alloc(0); if (!G[idx]) goto nomem; } } } if (mpi_mulm(res, tmp, G[idx], m) < 0) goto nomem; } rc = 0; nomem: /* */ mpi_free(tmp); for (i = 0; i < (1 << k); i++) mpi_free(G[i]); kfree(G); err_out: return rc; }