/* Generate a random secret scalar k with an order of p At the beginning this was identical to the code is in elgamal.c. Later imporved by mmr. Further simplified by wk. */ static gcry_mpi_t gen_k (gcry_mpi_t p, int security_level) { gcry_mpi_t k; unsigned int nbits; nbits = mpi_get_nbits (p); k = mpi_snew (nbits); if (DBG_CIPHER) log_debug ("choosing a random k of %u bits\n", nbits); gcry_mpi_randomize (k, nbits, security_level); mpi_mod (k, k, p); /* k = k mod p */ return k; }
/* Compute the public key from the the context EC. Obviously a requirement is that the secret key is available in EC. On success Q is returned; on error NULL. If Q is NULL a newly allocated point is returned. If G or D are given they override the values taken from EC. */ mpi_point_t _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec, mpi_point_t G, gcry_mpi_t d) { if (!G) G = ec->G; if (!d) d = ec->d; if (!d || !G || !ec->p || !ec->a) return NULL; if (ec->model == MPI_EC_TWISTEDEDWARDS && !ec->b) return NULL; if (ec->dialect == ECC_DIALECT_ED25519 && (ec->flags & PUBKEY_FLAG_EDDSA)) { gcry_mpi_t a; unsigned char *digest; if (_gcry_ecc_eddsa_compute_h_d (&digest, d, ec)) return NULL; a = mpi_snew (0); _gcry_mpi_set_buffer (a, digest, 32, 0); xfree (digest); /* And finally the public key. */ if (!Q) Q = mpi_point_new (0); if (Q) _gcry_mpi_ec_mul_point (Q, a, G, ec); mpi_free (a); } else { if (!Q) Q = mpi_point_new (0); if (Q) _gcry_mpi_ec_mul_point (Q, d, G, ec); } return Q; }
/* 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; }
/** * _gcry_ecc_eddsa_genkey - EdDSA version of the key generation. * * @sk: A struct to receive the secret key. * @E: Parameters of the curve. * @ctx: Elliptic curve computation context. * @flags: Flags controlling aspects of the creation. * * Return: An error code. * * The only @flags bit used by this function is %PUBKEY_FLAG_TRANSIENT * to use a faster RNG. */ gpg_err_code_t _gcry_ecc_eddsa_genkey (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, int flags) { gpg_err_code_t rc; int b = 256/8; /* The only size we currently support. */ gcry_mpi_t a, x, y; mpi_point_struct Q; gcry_random_level_t random_level; char *dbuf; size_t dlen; gcry_buffer_t hvec[1]; unsigned char *hash_d = NULL; point_init (&Q); memset (hvec, 0, sizeof hvec); if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) random_level = GCRY_STRONG_RANDOM; else random_level = GCRY_VERY_STRONG_RANDOM; a = mpi_snew (0); x = mpi_new (0); y = mpi_new (0); /* Generate a secret. */ hash_d = xtrymalloc_secure (2*b); if (!hash_d) { rc = gpg_error_from_syserror (); goto leave; } dlen = b; dbuf = _gcry_random_bytes_secure (dlen, random_level); /* Compute the A value. */ hvec[0].data = dbuf; hvec[0].len = dlen; rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1); if (rc) goto leave; sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8); dbuf = NULL; reverse_buffer (hash_d, 32); /* Only the first half of the hash. */ hash_d[0] = (hash_d[0] & 0x7f) | 0x40; hash_d[31] &= 0xf8; _gcry_mpi_set_buffer (a, hash_d, 32, 0); xfree (hash_d); hash_d = NULL; /* log_printmpi ("ecgen a", a); */ /* Compute Q. */ _gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx); if (DBG_CIPHER) log_printpnt ("ecgen pk", &Q, ctx); /* Copy the stuff to the key structures. */ sk->E.model = E->model; sk->E.dialect = E->dialect; sk->E.p = mpi_copy (E->p); sk->E.a = mpi_copy (E->a); sk->E.b = mpi_copy (E->b); point_init (&sk->E.G); point_set (&sk->E.G, &E->G); sk->E.n = mpi_copy (E->n); point_init (&sk->Q); point_set (&sk->Q, &Q); leave: point_free (&Q); _gcry_mpi_release (a); _gcry_mpi_release (x); _gcry_mpi_release (y); xfree (hash_d); return rc; }