static void ecdsa_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs) { struct ecdsa_key *ek = container_of(key, struct ecdsa_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ek->sshk.vt->extra; assert(ek->privateKey); mp_int *z = ecdsa_signing_exponent_from_data(ek->curve, extra, data); /* Generate k between 1 and curve->n, using the same deterministic * k generation system we use for conventional DSA. */ mp_int *k; { unsigned char digest[20]; hash_simple(&ssh_sha1, data, digest); k = dss_gen_k( "ECDSA deterministic k generator", ek->curve->w.G_order, ek->privateKey, digest, sizeof(digest)); } WeierstrassPoint *kG = ecc_weierstrass_multiply(ek->curve->w.G, k); mp_int *x; ecc_weierstrass_get_affine(kG, &x, NULL); ecc_weierstrass_point_free(kG); /* r = kG.x mod order(G) */ mp_int *r = mp_mod(x, ek->curve->w.G_order); mp_free(x); /* s = (z + r * priv)/k mod n */ mp_int *rPriv = mp_modmul(r, ek->privateKey, ek->curve->w.G_order); mp_int *numerator = mp_modadd(z, rPriv, ek->curve->w.G_order); mp_free(z); mp_free(rPriv); mp_int *kInv = mp_invert(k, ek->curve->w.G_order); mp_free(k); mp_int *s = mp_modmul(numerator, kInv, ek->curve->w.G_order); mp_free(numerator); mp_free(kInv); /* Format the output */ put_stringz(bs, ek->sshk.vt->ssh_id); strbuf *substr = strbuf_new(); put_mp_ssh2(substr, r); put_mp_ssh2(substr, s); put_stringsb(bs, substr); mp_free(r); mp_free(s); }
/* * Verify that the public data in an RSA key matches the private * data. We also check the private data itself: we ensure that p > * q and that iqmp really is the inverse of q mod p. */ bool rsa_verify(RSAKey *key) { mp_int *n, *ed, *pm1, *qm1; unsigned ok = 1; /* Preliminary checks: p,q must actually be nonzero. */ if (mp_eq_integer(key->p, 0) | mp_eq_integer(key->q, 0)) return false; /* n must equal pq. */ n = mp_mul(key->p, key->q); ok &= mp_cmp_eq(n, key->modulus); mp_free(n); /* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */ pm1 = mp_copy(key->p); mp_sub_integer_into(pm1, pm1, 1); ed = mp_modmul(key->exponent, key->private_exponent, pm1); mp_free(pm1); ok &= mp_eq_integer(ed, 1); mp_free(ed); qm1 = mp_copy(key->q); mp_sub_integer_into(qm1, qm1, 1); ed = mp_modmul(key->exponent, key->private_exponent, qm1); mp_free(qm1); ok &= mp_eq_integer(ed, 1); mp_free(ed); /* * Ensure p > q. * * I have seen key blobs in the wild which were generated with * p < q, so instead of rejecting the key in this case we * should instead flip them round into the canonical order of * p > q. This also involves regenerating iqmp. */ mp_int *p_new = mp_max(key->p, key->q); mp_int *q_new = mp_min(key->p, key->q); mp_free(key->p); mp_free(key->q); mp_free(key->iqmp); key->p = p_new; key->q = q_new; key->iqmp = mp_invert(key->q, key->p); return ok; }
/*-------------------------------------------------------------------*/ static void convert_to_integer(gmp_poly_t *alg_sqrt, mp_t *n, mp_t *c, signed_mp_t *m1, signed_mp_t *m0, mp_t *res) { /* given the completed square root, apply the homomorphism to convert the polynomial to an integer. We do this by evaluating alg_sqrt at c*m0/m1, with all calculations performed mod n */ uint32 i; mpz_t gmp_n; mp_t m1_pow; mp_t m1_tmp; mp_t m0_tmp; mp_t next_coeff; mpz_init(gmp_n); mp2gmp(n, gmp_n); gmp_poly_mod_q(alg_sqrt, gmp_n, alg_sqrt); mpz_clear(gmp_n); mp_copy(&m1->num, &m1_tmp); if (m1->sign == NEGATIVE) mp_sub(n, &m1_tmp, &m1_tmp); mp_copy(&m1_tmp, &m1_pow); mp_modmul(&m0->num, c, n, &m0_tmp); if (m0->sign == POSITIVE) mp_sub(n, &m0_tmp, &m0_tmp); i = alg_sqrt->degree; gmp2mp(alg_sqrt->coeff[i], res); for (i--; (int32)i >= 0; i--) { mp_modmul(res, &m0_tmp, n, res); gmp2mp(alg_sqrt->coeff[i], &next_coeff); mp_modmul(&next_coeff, &m1_pow, n, &next_coeff); mp_add(res, &next_coeff, res); if (i > 0) mp_modmul(&m1_pow, &m1_tmp, n, &m1_pow); } if (mp_cmp(res, n) > 0) mp_sub(res, n, res); }
static bool ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data) { struct ecdsa_key *ek = container_of(key, struct ecdsa_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ek->sshk.vt->extra; BinarySource src[1]; BinarySource_BARE_INIT_PL(src, sig); /* Check the signature starts with the algorithm name */ if (!ptrlen_eq_string(get_string(src), ek->sshk.vt->ssh_id)) return false; /* Everything else is nested inside a sub-string. Descend into that. */ ptrlen sigstr = get_string(src); if (get_err(src)) return false; BinarySource_BARE_INIT_PL(src, sigstr); /* Extract the signature integers r,s */ mp_int *r = get_mp_ssh2(src); mp_int *s = get_mp_ssh2(src); if (get_err(src)) { mp_free(r); mp_free(s); return false; } /* Basic sanity checks: 0 < r,s < order(G) */ unsigned invalid = 0; invalid |= mp_eq_integer(r, 0); invalid |= mp_eq_integer(s, 0); invalid |= mp_cmp_hs(r, ek->curve->w.G_order); invalid |= mp_cmp_hs(s, ek->curve->w.G_order); /* Get the hash of the signed data, converted to an integer */ mp_int *z = ecdsa_signing_exponent_from_data(ek->curve, extra, data); /* Verify the signature integers against the hash */ mp_int *w = mp_invert(s, ek->curve->w.G_order); mp_int *u1 = mp_modmul(z, w, ek->curve->w.G_order); mp_free(z); mp_int *u2 = mp_modmul(r, w, ek->curve->w.G_order); mp_free(w); WeierstrassPoint *u1G = ecc_weierstrass_multiply(ek->curve->w.G, u1); mp_free(u1); WeierstrassPoint *u2P = ecc_weierstrass_multiply(ek->publicKey, u2); mp_free(u2); WeierstrassPoint *sum = ecc_weierstrass_add_general(u1G, u2P); ecc_weierstrass_point_free(u1G); ecc_weierstrass_point_free(u2P); mp_int *x; ecc_weierstrass_get_affine(sum, &x, NULL); ecc_weierstrass_point_free(sum); mp_divmod_into(x, ek->curve->w.G_order, NULL, x); invalid |= (1 ^ mp_cmp_eq(r, x)); mp_free(x); mp_free(r); mp_free(s); return !invalid; }
static void eddsa_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs) { struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk); const struct ecsign_extra *extra = (const struct ecsign_extra *)ek->sshk.vt->extra; assert(ek->privateKey); /* * EdDSA prescribes a specific method of generating the random * nonce integer for the signature. (A verifier can't tell * whether you followed that method, but it's important to * follow it anyway, because test vectors will want a specific * signature for a given message, and because this preserves * determinism of signatures even if the same signature were * made twice by different software.) */ /* * First, we hash the private key integer (bare, little-endian) * into a hash generating 2*fieldBytes of output. */ unsigned char hash[MAX_HASH_LEN]; ssh_hash *h = ssh_hash_new(extra->hash); for (size_t i = 0; i < ek->curve->fieldBytes; ++i) put_byte(h, mp_get_byte(ek->privateKey, i)); ssh_hash_final(h, hash); /* * The first half of the output hash is converted into an * integer a, by the standard EdDSA transformation. */ mp_int *a = eddsa_exponent_from_hash( make_ptrlen(hash, ek->curve->fieldBytes), ek->curve); /* * The second half of the hash of the private key is hashed again * with the message to be signed, and used as an exponent to * generate the signature point r. */ h = ssh_hash_new(extra->hash); put_data(h, hash + ek->curve->fieldBytes, extra->hash->hlen - ek->curve->fieldBytes); put_datapl(h, data); ssh_hash_final(h, hash); mp_int *log_r_unreduced = mp_from_bytes_le( make_ptrlen(hash, extra->hash->hlen)); mp_int *log_r = mp_mod(log_r_unreduced, ek->curve->e.G_order); mp_free(log_r_unreduced); EdwardsPoint *r = ecc_edwards_multiply(ek->curve->e.G, log_r); /* * Encode r now, because we'll need its encoding for the next * hashing step as well as to write into the actual signature. */ strbuf *r_enc = strbuf_new(); put_epoint(r_enc, r, ek->curve, true); /* omit string header */ ecc_edwards_point_free(r); /* * Compute the hash of (r || public key || message) just as * eddsa_verify does. */ mp_int *H = eddsa_signing_exponent_from_data( ek, extra, ptrlen_from_strbuf(r_enc), data); /* And then s = (log(r) + H*a) mod order(G). */ mp_int *Ha = mp_modmul(H, a, ek->curve->e.G_order); mp_int *s = mp_modadd(log_r, Ha, ek->curve->e.G_order); mp_free(H); mp_free(a); mp_free(Ha); mp_free(log_r); /* Format the output */ put_stringz(bs, ek->sshk.vt->ssh_id); put_uint32(bs, r_enc->len + ek->curve->fieldBytes); put_data(bs, r_enc->u, r_enc->len); strbuf_free(r_enc); for (size_t i = 0; i < ek->curve->fieldBytes; ++i) put_byte(bs, mp_get_byte(s, i)); mp_free(s); }