int DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer) { mp_int w, u1, u2, v, r, s; int ret = 0; if (mp_init_multi(&w, &u1, &u2, &v, &r, &s) != MP_OKAY) return MP_INIT_E; /* set r and s from signature */ if (mp_read_unsigned_bin(&r, sig, DSA_HALF_SIZE) != MP_OKAY || mp_read_unsigned_bin(&s, sig + DSA_HALF_SIZE, DSA_HALF_SIZE) != MP_OKAY) ret = MP_READ_E; /* sanity checks */ /* put H into u1 from sha digest */ if (ret == 0 && mp_read_unsigned_bin(&u1,digest,SHA_DIGEST_SIZE) != MP_OKAY) ret = MP_READ_E; /* w = s invmod q */ if (ret == 0 && mp_invmod(&s, &key->q, &w) != MP_OKAY) ret = MP_INVMOD_E; /* u1 = (H * w) % q */ if (ret == 0 && mp_mulmod(&u1, &w, &key->q, &u1) != MP_OKAY) ret = MP_MULMOD_E; /* u2 = (r * w) % q */ if (ret == 0 && mp_mulmod(&r, &w, &key->q, &u2) != MP_OKAY) ret = MP_MULMOD_E; /* verify v = ((g^u1 * y^u2) mod p) mod q */ if (ret == 0 && mp_exptmod(&key->g, &u1, &key->p, &u1) != MP_OKAY) ret = MP_EXPTMOD_E; if (ret == 0 && mp_exptmod(&key->y, &u2, &key->p, &u2) != MP_OKAY) ret = MP_EXPTMOD_E; if (ret == 0 && mp_mulmod(&u1, &u2, &key->p, &v) != MP_OKAY) ret = MP_MULMOD_E; if (ret == 0 && mp_mod(&v, &key->q, &v) != MP_OKAY) ret = MP_MULMOD_E; /* do they match */ if (ret == 0 && mp_cmp(&r, &v) == MP_EQ) *answer = 1; else *answer = 0; mp_clear(&s); mp_clear(&r); mp_clear(&u1); mp_clear(&u2); mp_clear(&w); mp_clear(&v); return ret; }
/* d = a * b (mod c) */ int mp_mulmod_montgomery (mp_int * a, mp_int * b, mp_int * c, mp_int * d) { int res; mp_int R; mp_digit mp; /* initialize R */ if ((res = mp_init(&R)) != MP_OKAY) { printf("Error initializing the number. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* get normalizzation */ if ((res = mp_montgomery_calc_normalization(&R,c)) != MP_OKAY) { printf("Error getting norm. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* get mp value */ if ((res = mp_montgomery_setup(c, &mp)) != MP_OKAY) { printf("Error setting up montgomery. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* normalize ‘a’ so now a is equal to aR */ if ((res = mp_mulmod(a, &R, c, a)) != MP_OKAY) { printf("Error computing aR. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* normalize ‘b’ so now a is equal to bR */ if ((res = mp_mulmod(b, &R, c, b)) != MP_OKAY) { printf("Error computing aR. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* compute a * b in Montgomery domain */ if ((res = mp_mul(a, b, d)) != MP_OKAY) { printf("Error multiplying. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* now reduce ‘d’ back down to d = a*b*R^2 * R^-1 == a*b*R */ if ((res = mp_montgomery_reduce(d, c, mp)) != MP_OKAY) { printf("Error reducing. %s", mp_error_to_string(res)); return EXIT_FAILURE; } /* now reduce ‘d’ back down to d = a*b*R * R^-1 == a*b */ if ((res = mp_montgomery_reduce(d, c, mp)) != MP_OKAY) { printf("Error reducing. %s", mp_error_to_string(res)); return EXIT_FAILURE; } mp_clear (&R); return res; }
/** Verify a DSA signature @param r DSA "r" parameter @param s DSA "s" parameter @param hash The hash that was signed @param hashlen The length of the hash that was signed @param stat [out] The result of the signature verification, 1==valid, 0==invalid @param key The corresponding public DH key @return CRYPT_OK if successful (even if the signature is invalid) */ int dsa_verify_hash_raw( mp_int *r, mp_int *s, const unsigned char *hash, unsigned long hashlen, int *stat, dsa_key *key) { mp_int w, v, u1, u2; int err; LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid signature */ *stat = 0; /* init our variables */ if ((err = mp_init_multi(&w, &v, &u1, &u2, NULL)) != MP_OKAY) { return mpi_to_ltc_error(err); } /* neither r or s can be null or >q*/ if (mp_iszero(r) == MP_YES || mp_iszero(s) == MP_YES || mp_cmp(r, &key->q) != MP_LT || mp_cmp(s, &key->q) != MP_LT) { err = CRYPT_INVALID_PACKET; goto done; } /* w = 1/s mod q */ if ((err = mp_invmod(s, &key->q, &w)) != MP_OKAY) { goto error; } /* u1 = m * w mod q */ if ((err = mp_read_unsigned_bin(&u1, (unsigned char *)hash, hashlen)) != MP_OKAY) { goto error; } if ((err = mp_mulmod(&u1, &w, &key->q, &u1)) != MP_OKAY) { goto error; } /* u2 = r*w mod q */ if ((err = mp_mulmod(r, &w, &key->q, &u2)) != MP_OKAY) { goto error; } /* v = g^u1 * y^u2 mod p mod q */ if ((err = mp_exptmod(&key->g, &u1, &key->p, &u1)) != MP_OKAY) { goto error; } if ((err = mp_exptmod(&key->y, &u2, &key->p, &u2)) != MP_OKAY) { goto error; } if ((err = mp_mulmod(&u1, &u2, &key->p, &v)) != MP_OKAY) { goto error; } if ((err = mp_mod(&v, &key->q, &v)) != MP_OKAY) { goto error; } /* if r = v then we're set */ if (mp_cmp(r, &v) == MP_EQ) { *stat = 1; } err = CRYPT_OK; goto done; error : err = mpi_to_ltc_error(err); done : mp_clear_multi(&w, &v, &u1, &u2, NULL); return err; }
/** Verify a DSA signature @param r DSA "r" parameter @param s DSA "s" parameter @param hash The hash that was signed @param hashlen The length of the hash that was signed @param stat [out] The result of the signature verification, 1==valid, 0==invalid @param key The corresponding public DH key @return CRYPT_OK if successful (even if the signature is invalid) */ int dsa_verify_hash_raw( void *r, void *s, const unsigned char *hash, unsigned long hashlen, int *stat, dsa_key *key) { void *w, *v, *u1, *u2; int err; LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid signature */ *stat = 0; /* init our variables */ if ((err = mp_init_multi(&w, &v, &u1, &u2, NULL)) != CRYPT_OK) { return err; } /* neither r or s can be null or >q*/ if (mp_iszero(r) == LTC_MP_YES || mp_iszero(s) == LTC_MP_YES || mp_cmp(r, key->q) != LTC_MP_LT || mp_cmp(s, key->q) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; goto error; } /* w = 1/s mod q */ if ((err = mp_invmod(s, key->q, w)) != CRYPT_OK) { goto error; } /* u1 = m * w mod q */ if ((err = mp_read_unsigned_bin(u1, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(u1, w, key->q, u1)) != CRYPT_OK) { goto error; } /* u2 = r*w mod q */ if ((err = mp_mulmod(r, w, key->q, u2)) != CRYPT_OK) { goto error; } /* v = g^u1 * y^u2 mod p mod q */ if ((err = mp_exptmod(key->g, u1, key->p, u1)) != CRYPT_OK) { goto error; } if ((err = mp_exptmod(key->y, u2, key->p, u2)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(u1, u2, key->p, v)) != CRYPT_OK) { goto error; } if ((err = mp_mod(v, key->q, v)) != CRYPT_OK) { goto error; } /* if r = v then we're set */ if (mp_cmp(r, v) == LTC_MP_EQ) { *stat = 1; } err = CRYPT_OK; error: mp_clear_multi(w, v, u1, u2, NULL); return err; }
/* ** RSA Private key operation using CRT. */ static SECStatus rsa_PrivateKeyOpCRTNoCheck(RSAPrivateKey *key, mp_int *m, mp_int *c) { mp_int p, q, d_p, d_q, qInv; mp_int m1, m2, h, ctmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&d_p) = 0; MP_DIGITS(&d_q) = 0; MP_DIGITS(&qInv) = 0; MP_DIGITS(&m1) = 0; MP_DIGITS(&m2) = 0; MP_DIGITS(&h) = 0; MP_DIGITS(&ctmp) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&d_p) ); CHECK_MPI_OK( mp_init(&d_q) ); CHECK_MPI_OK( mp_init(&qInv) ); CHECK_MPI_OK( mp_init(&m1) ); CHECK_MPI_OK( mp_init(&m2) ); CHECK_MPI_OK( mp_init(&h) ); CHECK_MPI_OK( mp_init(&ctmp) ); /* copy private key parameters into mp integers */ SECITEM_TO_MPINT(key->prime1, &p); /* p */ SECITEM_TO_MPINT(key->prime2, &q); /* q */ SECITEM_TO_MPINT(key->exponent1, &d_p); /* d_p = d mod (p-1) */ SECITEM_TO_MPINT(key->exponent2, &d_q); /* d_q = d mod (q-1) */ SECITEM_TO_MPINT(key->coefficient, &qInv); /* qInv = q**-1 mod p */ /* 1. m1 = c**d_p mod p */ CHECK_MPI_OK( mp_mod(c, &p, &ctmp) ); CHECK_MPI_OK( mp_exptmod(&ctmp, &d_p, &p, &m1) ); /* 2. m2 = c**d_q mod q */ CHECK_MPI_OK( mp_mod(c, &q, &ctmp) ); CHECK_MPI_OK( mp_exptmod(&ctmp, &d_q, &q, &m2) ); /* 3. h = (m1 - m2) * qInv mod p */ CHECK_MPI_OK( mp_submod(&m1, &m2, &p, &h) ); CHECK_MPI_OK( mp_mulmod(&h, &qInv, &p, &h) ); /* 4. m = m2 + h * q */ CHECK_MPI_OK( mp_mul(&h, &q, m) ); CHECK_MPI_OK( mp_add(m, &m2, m) ); cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&d_p); mp_clear(&d_q); mp_clear(&qInv); mp_clear(&m1); mp_clear(&m2); mp_clear(&h); mp_clear(&ctmp); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
static int mulmod(void *a, void *b, void *c, void *d) { LTC_ARGCHK(a != NULL); LTC_ARGCHK(b != NULL); LTC_ARGCHK(c != NULL); LTC_ARGCHK(d != NULL); return mpi_to_ltc_error(mp_mulmod(a,b,c,d)); }
/** * bignum_mulmod - d = a * b (mod c) * @a: Bignum from bignum_init() * @b: Bignum from bignum_init() * @c: Bignum from bignum_init(); modulus * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) * Returns: 0 on success, -1 on failure */ int bignum_mulmod(const struct bignum *a, const struct bignum *b, const struct bignum *c, struct bignum *d) { if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) != MP_OKAY) { wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); return -1; } return 0; }
int _dsa_verify_hash (mp_int *r, mp_int *s, mp_int *hash, mp_int *keyG, mp_int *keyP, mp_int *keyQ, mp_int *keyY) { mp_int w, v, u1, u2; int ret; MP_OP(mp_init_multi(&w, &v, &u1, &u2, NULL)); // neither r or s can be 0 or >q if (mp_iszero(r) == MP_YES || mp_iszero(s) == MP_YES || mp_cmp(r, keyQ) != MP_LT || mp_cmp(s, keyQ) != MP_LT) { ret = -1; goto error; } // w = 1/s mod q MP_OP(mp_invmod(s, keyQ, &w)); // u1 = m * w mod q MP_OP(mp_mulmod(hash, &w, keyQ, &u1)); // u2 = r*w mod q MP_OP(mp_mulmod(r, &w, keyQ, &u2)); // v = g^u1 * y^u2 mod p mod q MP_OP(mp_exptmod(keyG, &u1, keyP, &u1)); MP_OP(mp_exptmod(keyY, &u2, keyP, &u2)); MP_OP(mp_mulmod(&u1, &u2, keyP, &v)); MP_OP(mp_mod(&v, keyQ, &v)); // if r = v then we're set ret = 0; if (mp_cmp(r, &v) == MP_EQ) ret = 1; error: mp_clear_multi(&w, &v, &u1, &u2, NULL); return ret; }
int ltc_ecc_is_point(const ltc_ecc_set_type *dp, void *x, void *y) { void *prime, *a, *b, *t1, *t2; int err; if ((err = mp_init_multi(&prime, &a, &b, &t1, &t2, NULL)) != CRYPT_OK) { return err; } /* load prime, a and b */ if ((err = mp_read_radix(prime, dp->prime, 16)) != CRYPT_OK) goto cleanup; if ((err = mp_read_radix(b, dp->B, 16)) != CRYPT_OK) goto cleanup; if ((err = mp_read_radix(a, dp->A, 16)) != CRYPT_OK) goto cleanup; /* compute y^2 */ if ((err = mp_sqr(y, t1)) != CRYPT_OK) goto cleanup; /* compute x^3 */ if ((err = mp_sqr(x, t2)) != CRYPT_OK) goto cleanup; if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) goto cleanup; if ((err = mp_mul(x, t2, t2)) != CRYPT_OK) goto cleanup; /* compute y^2 - x^3 */ if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) goto cleanup; /* compute y^2 - x^3 - a*x */ if ((err = mp_submod(prime, a, prime, t2)) != CRYPT_OK) goto cleanup; if ((err = mp_mulmod(t2, x, prime, t2)) != CRYPT_OK) goto cleanup; if ((err = mp_addmod(t1, t2, prime, t1)) != CRYPT_OK) goto cleanup; /* adjust range (0, prime) */ while (mp_cmp_d(t1, 0) == LTC_MP_LT) { if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) goto cleanup; } while (mp_cmp(t1, prime) != LTC_MP_LT) { if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) goto cleanup; } /* compare to b */ if (mp_cmp(t1, b) != LTC_MP_EQ) { err = CRYPT_INVALID_PACKET; } else { err = CRYPT_OK; } cleanup: mp_clear_multi(prime, b, t1, t2, NULL); return err; }
/* Divides two field elements. If a is NULL, then returns the inverse of * b. */ mp_err ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r, const GFMethod *meth) { mp_err res = MP_OKAY; mp_int t; /* If a is NULL, then return the inverse of b, otherwise return a/b. */ if (a == NULL) { return mp_invmod(b, &meth->irr, r); } else { /* MPI doesn't support divmod, so we implement it using invmod and * mulmod. */ MP_CHECKOK(mp_init(&t)); MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); MP_CHECKOK(mp_mulmod(a, &t, &meth->irr, r)); CLEANUP: mp_clear(&t); return res; } }
/* Tests a point p in Modified Jacobian coordinates, comparing against the * expected affine result (x, y). */ mp_err testJmPoint(ecfp_jm_pt * r, mp_int *x, mp_int *y, ECGroup *ecgroup) { char s[1000]; mp_int rx, ry, rz, raz4, test; mp_err res = MP_OKAY; /* Initialization */ MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&rz) = 0; MP_DIGITS(&raz4) = 0; MP_DIGITS(&test) = 0; MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(mp_init(&raz4)); MP_CHECKOK(mp_init(&test)); /* Convert to integer */ ecfp_fp2i(&rx, r->x, ecgroup); ecfp_fp2i(&ry, r->y, ecgroup); ecfp_fp2i(&rz, r->z, ecgroup); ecfp_fp2i(&raz4, r->az4, ecgroup); /* Verify raz4 = rz^4 * a */ mp_sqrmod(&rz, &ecgroup->meth->irr, &test); mp_sqrmod(&test, &ecgroup->meth->irr, &test); mp_mulmod(&test, &ecgroup->curvea, &ecgroup->meth->irr, &test); if (mp_cmp(&test, &raz4) != 0) { printf(" Error: a*z^4 not valid\n"); MP_CHECKOK(mp_toradix(&ecgroup->curvea, s, 16)); printf("a %s\n", s); MP_CHECKOK(mp_toradix(&rz, s, 16)); printf("rz %s\n", s); MP_CHECKOK(mp_toradix(&raz4, s, 16)); printf("raz4 %s\n", s); res = MP_NO; goto CLEANUP; } /* convert result R to affine coordinates */ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup); /* Compare against expected result */ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) { printf(" Error: Modified Jacobian Floating Point Incorrect.\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf("floating point result\nrx %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf("ry %s\n", s); MP_CHECKOK(mp_toradix(x, s, 16)); printf("integer result\nx %s\n", s); MP_CHECKOK(mp_toradix(y, s, 16)); printf("y %s\n", s); res = MP_NO; goto CLEANUP; } CLEANUP: mp_clear(&rx); mp_clear(&ry); mp_clear(&rz); mp_clear(&raz4); mp_clear(&test); return res; }
/* Tests a point p in Chudnovsky Jacobian coordinates, comparing against * the expected affine result (x, y). */ mp_err testChudPoint(ecfp_chud_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup) { char s[1000]; mp_int rx, ry, rz, rz2, rz3, test; mp_err res = MP_OKAY; /* Initialization */ MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&rz) = 0; MP_DIGITS(&rz2) = 0; MP_DIGITS(&rz3) = 0; MP_DIGITS(&test) = 0; MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_init(&rz3)); MP_CHECKOK(mp_init(&test)); /* Convert to integers */ ecfp_fp2i(&rx, p->x, ecgroup); ecfp_fp2i(&ry, p->y, ecgroup); ecfp_fp2i(&rz, p->z, ecgroup); ecfp_fp2i(&rz2, p->z2, ecgroup); ecfp_fp2i(&rz3, p->z3, ecgroup); /* Verify z2, z3 are valid */ mp_sqrmod(&rz, &ecgroup->meth->irr, &test); if (mp_cmp(&test, &rz2) != 0) { printf(" Error: rzp2 not valid\n"); res = MP_NO; goto CLEANUP; } mp_mulmod(&test, &rz, &ecgroup->meth->irr, &test); if (mp_cmp(&test, &rz3) != 0) { printf(" Error: rzp2 not valid\n"); res = MP_NO; goto CLEANUP; } /* convert result R to affine coordinates */ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup); /* Compare against expected result */ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) { printf(" Error: Chudnovsky Floating Point Incorrect.\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf("floating point result\nrx %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf("ry %s\n", s); MP_CHECKOK(mp_toradix(x, s, 16)); printf("integer result\nx %s\n", s); MP_CHECKOK(mp_toradix(y, s, 16)); printf("y %s\n", s); res = MP_NO; goto CLEANUP; } CLEANUP: mp_clear(&rx); mp_clear(&ry); mp_clear(&rz); mp_clear(&rz2); mp_clear(&rz3); mp_clear(&test); return res; }
/** Compute an RSA modular exponentiation @param in The input data to send into RSA @param inlen The length of the input (octets) @param out [out] The destination @param outlen [in/out] The max size and resulting size of the output @param which Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC @param key The RSA key to use @return CRYPT_OK if successful */ int rsa_exptmod(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int which, rsa_key *key) { void *tmp, *tmpa, *tmpb; unsigned long x; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* is the key of the right type for the operation? */ if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) { return CRYPT_PK_NOT_PRIVATE; } /* must be a private or public operation */ if (which != PK_PRIVATE && which != PK_PUBLIC) { return CRYPT_PK_INVALID_TYPE; } /* init and copy into tmp */ if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != CRYPT_OK) { return err; } if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto error; } /* sanity check on the input */ if (mp_cmp(key->N, tmp) == LTC_MP_LT) { err = CRYPT_PK_INVALID_SIZE; goto error; } /* are we using the private exponent and is the key optimized? */ if (which == PK_PRIVATE) { /* tmpa = tmp^dP mod p */ if ((err = mp_exptmod(tmp, key->dP, key->p, tmpa)) != CRYPT_OK) { goto error; } /* tmpb = tmp^dQ mod q */ if ((err = mp_exptmod(tmp, key->dQ, key->q, tmpb)) != CRYPT_OK) { goto error; } /* tmp = (tmpa - tmpb) * qInv (mod p) */ if ((err = mp_sub(tmpa, tmpb, tmp)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(tmp, key->qP, key->p, tmp)) != CRYPT_OK) { goto error; } /* tmp = tmpb + q * tmp */ if ((err = mp_mul(tmp, key->q, tmp)) != CRYPT_OK) { goto error; } if ((err = mp_add(tmp, tmpb, tmp)) != CRYPT_OK) { goto error; } } else { /* exptmod it */ if ((err = mp_exptmod(tmp, key->e, key->N, tmp)) != CRYPT_OK) { goto error; } } /* read it back */ x = (unsigned long)mp_unsigned_bin_size(key->N); if (x > *outlen) { *outlen = x; err = CRYPT_BUFFER_OVERFLOW; goto error; } /* this should never happen ... */ if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) { err = CRYPT_ERROR; goto error; } *outlen = x; /* convert it */ zeromem(out, x); if ((err = mp_to_unsigned_bin(tmp, out+(x-mp_unsigned_bin_size(tmp)))) != CRYPT_OK) { goto error; } /* clean up and return */ err = CRYPT_OK; error: mp_clear_multi(tmp, tmpa, tmpb, NULL); return err; }
int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) { mp_int M[TAB_SIZE], res; mp_digit buf, mp; int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; /* use a pointer to the reduction algorithm. This allows us to use * one of many reduction algorithms without modding the guts of * the code with if statements everywhere. */ int (*redux)(mp_int*,mp_int*,mp_digit); /* find window size */ x = mp_count_bits (X); if (x <= 7) { winsize = 2; } else if (x <= 36) { winsize = 3; } else if (x <= 140) { winsize = 4; } else if (x <= 450) { winsize = 5; } else if (x <= 1303) { winsize = 6; } else if (x <= 3529) { winsize = 7; } else { winsize = 8; } #ifdef MP_LOW_MEM if (winsize > 5) { winsize = 5; } #endif /* init M array */ /* init first cell */ if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) { return err; } /* now init the second half of the array */ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) { for (y = 1<<(winsize-1); y < x; y++) { mp_clear (&M[y]); } mp_clear(&M[1]); return err; } } /* determine and setup reduction code */ if (redmode == 0) { #ifdef BN_MP_MONTGOMERY_SETUP_C /* now setup montgomery */ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { goto LBL_M; } #else err = MP_VAL; goto LBL_M; #endif /* automatically pick the comba one if available (saves quite a few calls/ifs) */ #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C if ((((P->used * 2) + 1) < MP_WARRAY) && (P->used < (1 << ((CHAR_BIT * sizeof(mp_word)) - (2 * DIGIT_BIT))))) { redux = fast_mp_montgomery_reduce; } else #endif { #ifdef BN_MP_MONTGOMERY_REDUCE_C /* use slower baseline Montgomery method */ redux = mp_montgomery_reduce; #else err = MP_VAL; goto LBL_M; #endif } } else if (redmode == 1) { #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) /* setup DR reduction for moduli of the form B**k - b */ mp_dr_setup(P, &mp); redux = mp_dr_reduce; #else err = MP_VAL; goto LBL_M; #endif } else { #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) /* setup DR reduction for moduli of the form 2**k - b */ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { goto LBL_M; } redux = mp_reduce_2k; #else err = MP_VAL; goto LBL_M; #endif } /* setup result */ if ((err = mp_init_size (&res, P->alloc)) != MP_OKAY) { goto LBL_M; } /* create M table * * * The first half of the table is not computed though accept for M[0] and M[1] */ if (redmode == 0) { #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C /* now we need R mod m */ if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { goto LBL_RES; } /* now set M[1] to G * R mod m */ if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { goto LBL_RES; } #else err = MP_VAL; goto LBL_RES; #endif } else { mp_set(&res, 1); if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { goto LBL_RES; } } /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { goto LBL_RES; } for (x = 0; x < (winsize - 1); x++) { if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { goto LBL_RES; } } /* create upper table */ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&M[x], P, mp)) != MP_OKAY) { goto LBL_RES; } } /* set initial mode and bit cnt */ mode = 0; bitcnt = 1; buf = 0; digidx = X->used - 1; bitcpy = 0; bitbuf = 0; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { /* if digidx == -1 we are out of digits so break */ if (digidx == -1) { break; } /* read next digit and reset bitcnt */ buf = X->dp[digidx--]; bitcnt = (int)DIGIT_BIT; } /* grab the next msb from the exponent */ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; buf <<= (mp_digit)1; /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ if ((mode == 0) && (y == 0)) { continue; } /* if the bit is zero and mode == 1 then we square */ if ((mode == 1) && (y == 0)) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } continue; } /* else we add it to the window */ bitbuf |= (y << (winsize - ++bitcpy)); mode = 2; if (bitcpy == winsize) { /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } /* then multiply */ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } /* empty window and reset */ bitcpy = 0; bitbuf = 0; mode = 1; } } /* if bits remain then square/multiply */ if ((mode == 2) && (bitcpy > 0)) { /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr (&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } /* get next bit of the window */ bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { /* then multiply */ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux (&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } } } if (redmode == 0) { /* fixup result if Montgomery reduction is used * recall that any value in a Montgomery system is * actually multiplied by R mod n. So we have * to reduce one more time to cancel out the factor * of R. */ if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } /* swap res with Y */ mp_exch (&res, Y); err = MP_OKAY; LBL_RES:mp_clear (&res); LBL_M: mp_clear(&M[1]); for (x = 1<<(winsize-1); x < (1 << winsize); x++) { mp_clear (&M[x]); } return err; }
static SECStatus dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest, const unsigned char *kb) { mp_int p, q, g; /* PQG parameters */ mp_int x, k; /* private key & pseudo-random integer */ mp_int r, s; /* tuple (r, s) is signature) */ mp_err err = MP_OKAY; SECStatus rv = SECSuccess; unsigned int dsa_subprime_len, dsa_signature_len, offset; SECItem localDigest; unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; /* FIPS-compliance dictates that digest is a SHA hash. */ /* Check args. */ if (!key || !signature || !digest) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } dsa_subprime_len = PQG_GetLength(&key->params.subPrime); dsa_signature_len = dsa_subprime_len*2; if ((signature->len < dsa_signature_len) || (digest->len > HASH_LENGTH_MAX) || (digest->len < SHA1_LENGTH)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* DSA accepts digests not equal to dsa_subprime_len, if the * digests are greater, then they are truncated to the size of * dsa_subprime_len, using the left most bits. If they are less * then they are padded on the left.*/ PORT_Memset(localDigestData, 0, dsa_subprime_len); offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0; PORT_Memcpy(localDigestData+offset, digest->data, dsa_subprime_len - offset); localDigest.data = localDigestData; localDigest.len = dsa_subprime_len; /* Initialize MPI integers. */ MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&g) = 0; MP_DIGITS(&x) = 0; MP_DIGITS(&k) = 0; MP_DIGITS(&r) = 0; MP_DIGITS(&s) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&g) ); CHECK_MPI_OK( mp_init(&x) ); CHECK_MPI_OK( mp_init(&k) ); CHECK_MPI_OK( mp_init(&r) ); CHECK_MPI_OK( mp_init(&s) ); /* ** Convert stored PQG and private key into MPI integers. */ SECITEM_TO_MPINT(key->params.prime, &p); SECITEM_TO_MPINT(key->params.subPrime, &q); SECITEM_TO_MPINT(key->params.base, &g); SECITEM_TO_MPINT(key->privateValue, &x); OCTETS_TO_MPINT(kb, &k, dsa_subprime_len); /* ** FIPS 186-1, Section 5, Step 1 ** ** r = (g**k mod p) mod q */ CHECK_MPI_OK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */ CHECK_MPI_OK( mp_mod(&r, &q, &r) ); /* r = r mod q */ /* ** FIPS 186-1, Section 5, Step 2 ** ** s = (k**-1 * (HASH(M) + x*r)) mod q */ SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */ CHECK_MPI_OK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */ CHECK_MPI_OK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */ CHECK_MPI_OK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */ CHECK_MPI_OK( mp_mulmod(&s, &k, &q, &s) ); /* s = s * k mod q */ /* ** verify r != 0 and s != 0 ** mentioned as optional in FIPS 186-1. */ if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); rv = SECFailure; goto cleanup; } /* ** Step 4 ** ** Signature is tuple (r, s) */ err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len); if (err < 0) goto cleanup; err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len, dsa_subprime_len); if (err < 0) goto cleanup; err = MP_OKAY; signature->len = dsa_signature_len; cleanup: PORT_Memset(localDigestData, 0, DSA_MAX_SUBPRIME_LEN); mp_clear(&p); mp_clear(&q); mp_clear(&g); mp_clear(&x); mp_clear(&k); mp_clear(&r); mp_clear(&s); if (err) { translate_mpi_error(err); rv = SECFailure; } return rv; }
/* ** Checks the signature on the given digest using the key provided. */ SECStatus ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, const SECItem *digest) { SECStatus rv = SECFailure; #ifndef NSS_DISABLE_ECC mp_int r_, s_; /* tuple (r', s') is received signature) */ mp_int c, u1, u2, v; /* intermediate values used in verification */ mp_int x1; mp_int n; mp_err err = MP_OKAY; ECParams *ecParams = NULL; SECItem pointC = { siBuffer, NULL, 0 }; int slen; /* length in bytes of a half signature (r or s) */ int flen; /* length in bytes of the field size */ unsigned olen; /* length in bytes of the base point order */ unsigned obits; /* length in bits of the base point order */ #if EC_DEBUG char mpstr[256]; printf("ECDSA verification called\n"); #endif /* Initialize MPI integers. */ /* must happen before the first potential call to cleanup */ MP_DIGITS(&r_) = 0; MP_DIGITS(&s_) = 0; MP_DIGITS(&c) = 0; MP_DIGITS(&u1) = 0; MP_DIGITS(&u2) = 0; MP_DIGITS(&x1) = 0; MP_DIGITS(&v) = 0; MP_DIGITS(&n) = 0; /* Check args */ if (!key || !signature || !digest) { PORT_SetError(SEC_ERROR_INVALID_ARGS); goto cleanup; } ecParams = &(key->ecParams); flen = (ecParams->fieldID.size + 7) >> 3; olen = ecParams->order.len; if (signature->len == 0 || signature->len%2 != 0 || signature->len > 2*olen) { PORT_SetError(SEC_ERROR_INPUT_LEN); goto cleanup; } slen = signature->len/2; SECITEM_AllocItem(NULL, &pointC, 2*flen + 1); if (pointC.data == NULL) goto cleanup; CHECK_MPI_OK( mp_init(&r_) ); CHECK_MPI_OK( mp_init(&s_) ); CHECK_MPI_OK( mp_init(&c) ); CHECK_MPI_OK( mp_init(&u1) ); CHECK_MPI_OK( mp_init(&u2) ); CHECK_MPI_OK( mp_init(&x1) ); CHECK_MPI_OK( mp_init(&v) ); CHECK_MPI_OK( mp_init(&n) ); /* ** Convert received signature (r', s') into MPI integers. */ CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) ); CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) ); /* ** ANSI X9.62, Section 5.4.2, Steps 1 and 2 ** ** Verify that 0 < r' < n and 0 < s' < n */ SECITEM_TO_MPINT(ecParams->order, &n); if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); goto cleanup; /* will return rv == SECFailure */ } /* ** ANSI X9.62, Section 5.4.2, Step 3 ** ** c = (s')**-1 mod n */ CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */ /* ** ANSI X9.62, Section 5.4.2, Step 4 ** ** u1 = ((HASH(M')) * c) mod n */ SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */ /* In the definition of EC signing, digests are truncated * to the length of n in bits. * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) ); if (digest->len*8 > obits) { /* u1 = HASH(M') */ mpl_rsh(&u1,&u1,digest->len*8 - obits); } #if EC_DEBUG mp_todecimal(&r_, mpstr); printf("r_: %s (dec)\n", mpstr); mp_todecimal(&s_, mpstr); printf("s_: %s (dec)\n", mpstr); mp_todecimal(&c, mpstr); printf("c : %s (dec)\n", mpstr); mp_todecimal(&u1, mpstr); printf("digest: %s (dec)\n", mpstr); #endif CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */ /* ** ANSI X9.62, Section 5.4.2, Step 4 ** ** u2 = ((r') * c) mod n */ CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) ); /* ** ANSI X9.62, Section 5.4.3, Step 1 ** ** Compute u1*G + u2*Q ** Here, A = u1.G B = u2.Q and C = A + B ** If the result, C, is the point at infinity, reject the signature */ if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) != SECSuccess) { rv = SECFailure; goto cleanup; } if (ec_point_at_infinity(&pointC)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); rv = SECFailure; goto cleanup; } CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) ); /* ** ANSI X9.62, Section 5.4.4, Step 2 ** ** v = x1 mod n */ CHECK_MPI_OK( mp_mod(&x1, &n, &v) ); #if EC_DEBUG mp_todecimal(&r_, mpstr); printf("r_: %s (dec)\n", mpstr); mp_todecimal(&v, mpstr); printf("v : %s (dec)\n", mpstr); #endif /* ** ANSI X9.62, Section 5.4.4, Step 3 ** ** Verification: v == r' */ if (mp_cmp(&v, &r_)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); rv = SECFailure; /* Signature failed to verify. */ } else { rv = SECSuccess; /* Signature verified. */ } #if EC_DEBUG mp_todecimal(&u1, mpstr); printf("u1: %s (dec)\n", mpstr); mp_todecimal(&u2, mpstr); printf("u2: %s (dec)\n", mpstr); mp_tohex(&x1, mpstr); printf("x1: %s\n", mpstr); mp_todecimal(&v, mpstr); printf("v : %s (dec)\n", mpstr); #endif cleanup: mp_clear(&r_); mp_clear(&s_); mp_clear(&c); mp_clear(&u1); mp_clear(&u2); mp_clear(&x1); mp_clear(&v); mp_clear(&n); if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } #if EC_DEBUG printf("ECDSA verification %s\n", (rv == SECSuccess) ? "succeeded" : "failed"); #endif #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); #endif /* NSS_DISABLE_ECC */ return rv; }
/** Verify an ECC signature @param sig The signature to verify @param siglen The length of the signature (octets) @param hash The hash (message digest) that was signed @param hashlen The length of the hash (octets) @param stat Result of signature, 1==valid, 0==invalid @param key The corresponding public ECC key @return CRYPT_OK if successful (even if the signature is not valid) */ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int *stat, ecc_key *key) { ecc_point *mG, *mQ; void *r, *s, *v, *w, *u1, *u2, *e, *p, *m; void *mp; int err; LTC_ARGCHK(sig != NULL); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid signature */ *stat = 0; mp = NULL; /* is the IDX valid ? */ if (ltc_ecc_is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } /* allocate ints */ if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != CRYPT_OK) { return CRYPT_MEM; } /* allocate points */ mG = ltc_ecc_new_point(); mQ = ltc_ecc_new_point(); if (mQ == NULL || mG == NULL) { err = CRYPT_MEM; goto error; } /* parse header */ if ((err = der_decode_sequence_multi(sig, siglen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; } /* get the order */ if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } /* get the modulus */ if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } /* check for zero */ if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; goto error; } /* read hash */ if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, (int)hashlen)) != CRYPT_OK) { goto error; } /* w = s^-1 mod n */ if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; } /* u1 = ew */ if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; } /* u2 = rw */ if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } /* find mG and mQ */ if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } /* compute u1*mG + u2*mQ = mG */ if (ltc_mp.ecc_mul2add == NULL) { if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK) { goto error; } if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK) { goto error; } /* find the montgomery mp */ if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } /* add them */ if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK) { goto error; } /* reduce */ if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } } else { /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m)) != CRYPT_OK) { goto error; } } /* v = X_x1 mod n */ if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } /* does v == r */ if (mp_cmp(v, r) == LTC_MP_EQ) { *stat = 1; } /* clear up and return */ err = CRYPT_OK; error: ltc_ecc_del_point(mG); ltc_ecc_del_point(mQ); mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL); if (mp != NULL) { mp_montgomery_free(mp); } return err; }
/** Sign a message digest @param in The message digest to sign @param inlen The length of the digest @param out [out] The destination for the signature @param outlen [in/out] The max size and resulting size of the signature @param prng An active PRNG state @param wprng The index of the PRNG you wish to use @param key A private ECC key @return CRYPT_OK if successful */ int ecc_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int wprng, ecc_key *key) { ecc_key pubkey; void *r, *s, *e, *p; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* is this a private key? */ if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* is the IDX valid ? */ if (ltc_ecc_is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } /* get the hash and load it as a bignum into 'e' */ /* init the bignums */ if ((err = mp_init_multi(&r, &s, &p, &e, NULL)) != CRYPT_OK) { ecc_free(&pubkey); goto LBL_ERR; } if ((err = mp_read_radix(p, (char *)ltc_ecc_sets[key->idx].order, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto error; } /* make up a key and export the public copy */ for (;;) { if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { return err; } /* find r = x1 mod n */ if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r)) { ecc_free(&pubkey); } else { /* find s = (e + xr)/k */ if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/k */ if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */ if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e + xr */ if ((err = mp_mod(s, p, s)) != CRYPT_OK) { goto error; } /* s = e + xr */ if ((err = mp_mulmod(s, pubkey.k, p, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */ if (mp_iszero(s)) { ecc_free(&pubkey); } else { break; } } } /* store as SEQUENCE { r, s -- integer } */ err = der_encode_sequence_multi(out, outlen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL); goto LBL_ERR; error: LBL_ERR: mp_clear_multi(r, s, p, e, NULL); ecc_free(&pubkey); return err; }
/* Computes the ECDSA signature (a concatenation of two values r and s) * on the digest using the given key and the random value kb (used in * computing s). */ SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag) { SECStatus rv = SECFailure; mp_int x1; mp_int d, k; /* private key, random integer */ mp_int r, s; /* tuple (r, s) is the signature */ mp_int n; mp_err err = MP_OKAY; ECParams *ecParams = NULL; SECItem kGpoint = { siBuffer, NULL, 0}; int flen = 0; /* length in bytes of the field size */ unsigned olen; /* length in bytes of the base point order */ #if EC_DEBUG char mpstr[256]; #endif /* Initialize MPI integers. */ /* must happen before the first potential call to cleanup */ MP_DIGITS(&x1) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&k) = 0; MP_DIGITS(&r) = 0; MP_DIGITS(&s) = 0; MP_DIGITS(&n) = 0; /* Check args */ if (!key || !signature || !digest || !kb || (kblen < 0)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); goto cleanup; } ecParams = &(key->ecParams); flen = (ecParams->fieldID.size + 7) >> 3; olen = ecParams->order.len; if (signature->data == NULL) { /* a call to get the signature length only */ goto finish; } if (signature->len < 2*olen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); rv = SECBufferTooSmall; goto cleanup; } CHECK_MPI_OK( mp_init(&x1, kmflag) ); CHECK_MPI_OK( mp_init(&d, kmflag) ); CHECK_MPI_OK( mp_init(&k, kmflag) ); CHECK_MPI_OK( mp_init(&r, kmflag) ); CHECK_MPI_OK( mp_init(&s, kmflag) ); CHECK_MPI_OK( mp_init(&n, kmflag) ); SECITEM_TO_MPINT( ecParams->order, &n ); SECITEM_TO_MPINT( key->privateValue, &d ); CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) ); /* Make sure k is in the interval [1, n-1] */ if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) { #if EC_DEBUG printf("k is outside [1, n-1]\n"); mp_tohex(&k, mpstr); printf("k : %s \n", mpstr); mp_tohex(&n, mpstr); printf("n : %s \n", mpstr); #endif PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* * Using an equivalent exponent of fixed length (same as n or 1 bit less * than n) to keep the kG timing relatively constant. * * Note that this is an extra step on top of the approach defined in * ANSI X9.62 so as to make a fixed length K. */ CHECK_MPI_OK( mp_add(&k, &n, &k) ); CHECK_MPI_OK( mp_div_2(&k, &k) ); /* ** ANSI X9.62, Section 5.3.2, Step 2 ** ** Compute kG */ kGpoint.len = 2*flen + 1; kGpoint.data = PORT_Alloc(2*flen + 1, kmflag); if ((kGpoint.data == NULL) || (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag) != SECSuccess)) goto cleanup; /* ** ANSI X9.62, Section 5.3.3, Step 1 ** ** Extract the x co-ordinate of kG into x1 */ CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, (mp_size) flen) ); /* ** ANSI X9.62, Section 5.3.3, Step 2 ** ** r = x1 mod n NOTE: n is the order of the curve */ CHECK_MPI_OK( mp_mod(&x1, &n, &r) ); /* ** ANSI X9.62, Section 5.3.3, Step 3 ** ** verify r != 0 */ if (mp_cmp_z(&r) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** ANSI X9.62, Section 5.3.3, Step 4 ** ** s = (k**-1 * (HASH(M) + d*r)) mod n */ SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */ /* In the definition of EC signing, digests are truncated * to the length of n in bits. * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ if (digest->len*8 > (unsigned int)ecParams->fieldID.size) { mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size); } #if EC_DEBUG mp_todecimal(&n, mpstr); printf("n : %s (dec)\n", mpstr); mp_todecimal(&d, mpstr); printf("d : %s (dec)\n", mpstr); mp_tohex(&x1, mpstr); printf("x1: %s\n", mpstr); mp_todecimal(&s, mpstr); printf("digest: %s (decimal)\n", mpstr); mp_todecimal(&r, mpstr); printf("r : %s (dec)\n", mpstr); mp_tohex(&r, mpstr); printf("r : %s\n", mpstr); #endif CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */ CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */ CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */ CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */ #if EC_DEBUG mp_todecimal(&s, mpstr); printf("s : %s (dec)\n", mpstr); mp_tohex(&s, mpstr); printf("s : %s\n", mpstr); #endif /* ** ANSI X9.62, Section 5.3.3, Step 5 ** ** verify s != 0 */ if (mp_cmp_z(&s) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** ** Signature is tuple (r, s) */ CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) ); CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) ); finish: signature->len = 2*olen; rv = SECSuccess; err = MP_OKAY; cleanup: mp_clear(&x1); mp_clear(&d); mp_clear(&k); mp_clear(&r); mp_clear(&s); mp_clear(&n); if (kGpoint.data) { PORT_ZFree(kGpoint.data, 2*flen + 1); } if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } #if EC_DEBUG printf("ECDSA signing with seed %s\n", (rv == SECSuccess) ? "succeeded" : "failed"); #endif return rv; }
SECStatus RSA_PrivateKeyCheck(const RSAPrivateKey *key) { mp_int p, q, n, psub1, qsub1, e, d, d_p, d_q, qInv, res; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&n) = 0; MP_DIGITS(&psub1)= 0; MP_DIGITS(&qsub1)= 0; MP_DIGITS(&e) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&d_p) = 0; MP_DIGITS(&d_q) = 0; MP_DIGITS(&qInv) = 0; MP_DIGITS(&res) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&psub1)); CHECK_MPI_OK( mp_init(&qsub1)); CHECK_MPI_OK( mp_init(&e) ); CHECK_MPI_OK( mp_init(&d) ); CHECK_MPI_OK( mp_init(&d_p) ); CHECK_MPI_OK( mp_init(&d_q) ); CHECK_MPI_OK( mp_init(&qInv) ); CHECK_MPI_OK( mp_init(&res) ); if (!key->modulus.data || !key->prime1.data || !key->prime2.data || !key->publicExponent.data || !key->privateExponent.data || !key->exponent1.data || !key->exponent2.data || !key->coefficient.data) { /*call RSA_PopulatePrivateKey first, if the application wishes to * recover these parameters */ err = MP_BADARG; goto cleanup; } SECITEM_TO_MPINT(key->modulus, &n); SECITEM_TO_MPINT(key->prime1, &p); SECITEM_TO_MPINT(key->prime2, &q); SECITEM_TO_MPINT(key->publicExponent, &e); SECITEM_TO_MPINT(key->privateExponent, &d); SECITEM_TO_MPINT(key->exponent1, &d_p); SECITEM_TO_MPINT(key->exponent2, &d_q); SECITEM_TO_MPINT(key->coefficient, &qInv); /* p > q */ if (mp_cmp(&p, &q) <= 0) { rv = SECFailure; goto cleanup; } #define VERIFY_MPI_EQUAL(m1, m2) \ if (mp_cmp(m1, m2) != 0) { \ rv = SECFailure; \ goto cleanup; \ } #define VERIFY_MPI_EQUAL_1(m) \ if (mp_cmp_d(m, 1) != 0) { \ rv = SECFailure; \ goto cleanup; \ } /* * The following errors cannot be recovered from. */ /* n == p * q */ CHECK_MPI_OK( mp_mul(&p, &q, &res) ); VERIFY_MPI_EQUAL(&res, &n); /* gcd(e, p-1) == 1 */ CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); CHECK_MPI_OK( mp_gcd(&e, &psub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* gcd(e, q-1) == 1 */ CHECK_MPI_OK( mp_sub_d(&q, 1, &qsub1) ); CHECK_MPI_OK( mp_gcd(&e, &qsub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* d*e == 1 mod p-1 */ CHECK_MPI_OK( mp_mulmod(&d, &e, &psub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* d*e == 1 mod q-1 */ CHECK_MPI_OK( mp_mulmod(&d, &e, &qsub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* * The following errors can be recovered from. However, the purpose of this * function is to check consistency, so they are not. */ /* d_p == d mod p-1 */ CHECK_MPI_OK( mp_mod(&d, &psub1, &res) ); VERIFY_MPI_EQUAL(&res, &d_p); /* d_q == d mod q-1 */ CHECK_MPI_OK( mp_mod(&d, &qsub1, &res) ); VERIFY_MPI_EQUAL(&res, &d_q); /* q * q**-1 == 1 mod p */ CHECK_MPI_OK( mp_mulmod(&q, &qInv, &p, &res) ); VERIFY_MPI_EQUAL_1(&res); cleanup: mp_clear(&n); mp_clear(&p); mp_clear(&q); mp_clear(&psub1); mp_clear(&qsub1); mp_clear(&e); mp_clear(&d); mp_clear(&d_p); mp_clear(&d_q); mp_clear(&qInv); mp_clear(&res); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* ** Perform a raw private-key operation ** Length of input and output buffers are equal to key's modulus len. */ static SECStatus rsa_PrivateKeyOp(RSAPrivateKey *key, unsigned char *output, const unsigned char *input, PRBool check) { unsigned int modLen; unsigned int offset; SECStatus rv = SECSuccess; mp_err err; mp_int n, c, m; mp_int f, g; if (!key || !output || !input) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* check input out of range (needs to be in range [0..n-1]) */ modLen = rsa_modulusLen(&key->modulus); offset = (key->modulus.data[0] == 0) ? 1 : 0; /* may be leading 0 */ if (memcmp(input, key->modulus.data + offset, modLen) >= 0) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } MP_DIGITS(&n) = 0; MP_DIGITS(&c) = 0; MP_DIGITS(&m) = 0; MP_DIGITS(&f) = 0; MP_DIGITS(&g) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&c) ); CHECK_MPI_OK( mp_init(&m) ); CHECK_MPI_OK( mp_init(&f) ); CHECK_MPI_OK( mp_init(&g) ); SECITEM_TO_MPINT(key->modulus, &n); OCTETS_TO_MPINT(input, &c, modLen); /* If blinding, compute pre-image of ciphertext by multiplying by ** blinding factor */ if (nssRSAUseBlinding) { CHECK_SEC_OK( get_blinding_params(key, &n, modLen, &f, &g) ); /* c' = c*f mod n */ CHECK_MPI_OK( mp_mulmod(&c, &f, &n, &c) ); } /* Do the private key operation m = c**d mod n */ if ( key->prime1.len == 0 || key->prime2.len == 0 || key->exponent1.len == 0 || key->exponent2.len == 0 || key->coefficient.len == 0) { CHECK_SEC_OK( rsa_PrivateKeyOpNoCRT(key, &m, &c, &n, modLen) ); } else if (check) { CHECK_SEC_OK( rsa_PrivateKeyOpCRTCheckedPubKey(key, &m, &c) ); } else { CHECK_SEC_OK( rsa_PrivateKeyOpCRTNoCheck(key, &m, &c) ); } /* If blinding, compute post-image of plaintext by multiplying by ** blinding factor */ if (nssRSAUseBlinding) { /* m = m'*g mod n */ CHECK_MPI_OK( mp_mulmod(&m, &g, &n, &m) ); } err = mp_to_fixlen_octets(&m, output, modLen); if (err >= 0) err = MP_OKAY; cleanup: mp_clear(&n); mp_clear(&c); mp_clear(&m); mp_clear(&f); mp_clear(&g); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
int main(int argc, char *argv[]) { int ix; mp_int a, b, c, m; mp_digit r; if(argc < 4) { fprintf(stderr, "Usage: %s <a> <b> <m>\n", argv[0]); return 1; } printf("Test 4: Modular arithmetic\n\n"); mp_init(&a); mp_init(&b); mp_init(&m); mp_read_radix(&a, argv[1], 10); mp_read_radix(&b, argv[2], 10); mp_read_radix(&m, argv[3], 10); printf("a = "); mp_print(&a, stdout); fputc('\n', stdout); printf("b = "); mp_print(&b, stdout); fputc('\n', stdout); printf("m = "); mp_print(&m, stdout); fputc('\n', stdout); mp_init(&c); printf("\nc = a (mod m)\n"); mp_mod(&a, &m, &c); printf("c = "); mp_print(&c, stdout); fputc('\n', stdout); printf("\nc = b (mod m)\n"); mp_mod(&b, &m, &c); printf("c = "); mp_print(&c, stdout); fputc('\n', stdout); printf("\nc = b (mod 1853)\n"); mp_mod_d(&b, 1853, &r); printf("c = %04X\n", r); printf("\nc = (a + b) mod m\n"); mp_addmod(&a, &b, &m, &c); printf("c = "); mp_print(&c, stdout); fputc('\n', stdout); printf("\nc = (a - b) mod m\n"); mp_submod(&a, &b, &m, &c); printf("c = "); mp_print(&c, stdout); fputc('\n', stdout); printf("\nc = (a * b) mod m\n"); mp_mulmod(&a, &b, &m, &c); printf("c = "); mp_print(&c, stdout); fputc('\n', stdout); printf("\nc = (a ** b) mod m\n"); mp_exptmod(&a, &b, &m, &c); printf("c = "); mp_print(&c, stdout); fputc('\n', stdout); printf("\nIn-place modular squaring test:\n"); for(ix = 0; ix < 5; ix++) { printf("a = (a * a) mod m a = "); mp_sqrmod(&a, &m, &a); mp_print(&a, stdout); fputc('\n', stdout); } mp_clear(&c); mp_clear(&m); mp_clear(&b); mp_clear(&a); return 0; }
/* signature is caller-supplied buffer of at least 20 bytes. ** On input, signature->len == size of buffer to hold signature. ** digest->len == size of digest. */ SECStatus DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature, const SECItem *digest) { /* FIPS-compliance dictates that digest is a SHA hash. */ mp_int p, q, g; /* PQG parameters */ mp_int r_, s_; /* tuple (r', s') is received signature) */ mp_int u1, u2, v, w; /* intermediate values used in verification */ mp_int y; /* public key */ mp_err err; int dsa_subprime_len, dsa_signature_len, offset; SECItem localDigest; unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; SECStatus verified = SECFailure; /* Check args. */ if (!key || !signature || !digest ) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } dsa_subprime_len = PQG_GetLength(&key->params.subPrime); dsa_signature_len = dsa_subprime_len*2; if ((signature->len != dsa_signature_len) || (digest->len > HASH_LENGTH_MAX) || (digest->len < SHA1_LENGTH)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* DSA accepts digests not equal to dsa_subprime_len, if the * digests are greater, than they are truncated to the size of * dsa_subprime_len, using the left most bits. If they are less * then they are padded on the left.*/ PORT_Memset(localDigestData, 0, dsa_subprime_len); offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0; PORT_Memcpy(localDigestData+offset, digest->data, dsa_subprime_len - offset); localDigest.data = localDigestData; localDigest.len = dsa_subprime_len; /* Initialize MPI integers. */ MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&g) = 0; MP_DIGITS(&y) = 0; MP_DIGITS(&r_) = 0; MP_DIGITS(&s_) = 0; MP_DIGITS(&u1) = 0; MP_DIGITS(&u2) = 0; MP_DIGITS(&v) = 0; MP_DIGITS(&w) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&g) ); CHECK_MPI_OK( mp_init(&y) ); CHECK_MPI_OK( mp_init(&r_) ); CHECK_MPI_OK( mp_init(&s_) ); CHECK_MPI_OK( mp_init(&u1) ); CHECK_MPI_OK( mp_init(&u2) ); CHECK_MPI_OK( mp_init(&v) ); CHECK_MPI_OK( mp_init(&w) ); /* ** Convert stored PQG and public key into MPI integers. */ SECITEM_TO_MPINT(key->params.prime, &p); SECITEM_TO_MPINT(key->params.subPrime, &q); SECITEM_TO_MPINT(key->params.base, &g); SECITEM_TO_MPINT(key->publicValue, &y); /* ** Convert received signature (r', s') into MPI integers. */ OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len); OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len); /* ** Verify that 0 < r' < q and 0 < s' < q */ if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) { /* err is zero here. */ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); goto cleanup; /* will return verified == SECFailure */ } /* ** FIPS 186-1, Section 6, Step 1 ** ** w = (s')**-1 mod q */ CHECK_MPI_OK( mp_invmod(&s_, &q, &w) ); /* w = (s')**-1 mod q */ /* ** FIPS 186-1, Section 6, Step 2 ** ** u1 = ((Hash(M')) * w) mod q */ SECITEM_TO_MPINT(localDigest, &u1); /* u1 = HASH(M') */ CHECK_MPI_OK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */ /* ** FIPS 186-1, Section 6, Step 3 ** ** u2 = ((r') * w) mod q */ CHECK_MPI_OK( mp_mulmod(&r_, &w, &q, &u2) ); /* ** FIPS 186-1, Section 6, Step 4 ** ** v = ((g**u1 * y**u2) mod p) mod q */ CHECK_MPI_OK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */ CHECK_MPI_OK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */ CHECK_MPI_OK( mp_mulmod(&g, &y, &p, &v) ); /* v = g * y mod p */ CHECK_MPI_OK( mp_mod(&v, &q, &v) ); /* v = v mod q */ /* ** Verification: v == r' */ if (mp_cmp(&v, &r_)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); verified = SECFailure; /* Signature failed to verify. */ } else { verified = SECSuccess; /* Signature verified. */ } cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&g); mp_clear(&y); mp_clear(&r_); mp_clear(&s_); mp_clear(&u1); mp_clear(&u2); mp_clear(&v); mp_clear(&w); if (err) { translate_mpi_error(err); } return verified; }
/* Tests point addition in Modified Jacobian + Chudnovsky Jacobian -> * Modified Jacobian coordinates. */ mp_err testPointAddJmChud(ECGroup *ecgroup) { mp_err res; mp_int rx2, ry2, ix, iy, iz, test, pz, paz4, qx, qy, qz; ecfp_chud_pt q; ecfp_jm_pt p, r; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&qx) = 0; MP_DIGITS(&qy) = 0; MP_DIGITS(&qz) = 0; MP_DIGITS(&pz) = 0; MP_DIGITS(&paz4) = 0; MP_DIGITS(&iz) = 0; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&ix) = 0; MP_DIGITS(&iy) = 0; MP_DIGITS(&iz) = 0; MP_DIGITS(&test) = 0; MP_CHECKOK(mp_init(&qx)); MP_CHECKOK(mp_init(&qy)); MP_CHECKOK(mp_init(&qz)); MP_CHECKOK(mp_init(&pz)); MP_CHECKOK(mp_init(&paz4)); MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&ix)); MP_CHECKOK(mp_init(&iy)); MP_CHECKOK(mp_init(&iz)); MP_CHECKOK(mp_init(&test)); /* Test Modified Jacobian form addition */ /* Set p */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); /* paz4 = az^4 */ MP_CHECKOK(mp_set_int(&pz, 5)); mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4); mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4); mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4); ecfp_i2fp(p.z, &pz, ecgroup); ecfp_i2fp(p.az4, &paz4, ecgroup); /* Set q */ MP_CHECKOK(mp_set_int(&qz, 105)); ecfp_i2fp(q.x, &ecgroup->geny, ecgroup); ecfp_i2fp(q.y, &ecgroup->genx, ecgroup); ecfp_i2fp(q.z, &qz, ecgroup); mp_sqrmod(&qz, &ecgroup->meth->irr, &test); ecfp_i2fp(q.z2, &test, ecgroup); mp_mulmod(&test, &qz, &ecgroup->meth->irr, &test); ecfp_i2fp(q.z3, &test, ecgroup); /* Do calculation */ group->pt_add_jm_chud(&p, &q, &r, group); /* Calculate addition to compare against */ ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy, ecgroup); ec_GFp_pt_add_jac_aff(&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy, &ix, &iy, &iz, ecgroup); ec_GFp_pt_jac2aff(&ix, &iy, &iz, &rx2, &ry2, ecgroup); MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf (" Test Passed - Point Addition - Modified & Chudnovsky Jacobian\n"); else printf ("TEST FAILED - Point Addition - Modified & Chudnovsky Jacobian\n"); mp_clear(&qx); mp_clear(&qy); mp_clear(&qz); mp_clear(&pz); mp_clear(&paz4); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&ix); mp_clear(&iy); mp_clear(&iz); mp_clear(&test); return res; }
/* Tests point doubling in Modified Jacobian coordinates */ mp_err testPointDoubleJm(ECGroup *ecgroup) { mp_err res; mp_int pz, paz4, rx2, ry2, rz2, raz4; ecfp_jm_pt p, r; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&pz) = 0; MP_DIGITS(&paz4) = 0; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&rz2) = 0; MP_DIGITS(&raz4) = 0; MP_CHECKOK(mp_init(&pz)); MP_CHECKOK(mp_init(&paz4)); MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_init(&raz4)); /* Set p */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); /* paz4 = az^4 */ MP_CHECKOK(mp_set_int(&pz, 5)); mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4); mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4); mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4); ecfp_i2fp(p.z, &pz, ecgroup); ecfp_i2fp(p.az4, &paz4, ecgroup); group->pt_dbl_jm(&p, &r, group); M_TimeOperation(group->pt_dbl_jm(&p, &r, group), 100000); /* Calculate doubling to compare against */ ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2, &rz2, ecgroup); ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup); /* Do comparison and check az^4 */ MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Point Doubling - Modified Jacobian\n"); else printf("TEST FAILED - Point Doubling - Modified Jacobian\n"); mp_clear(&pz); mp_clear(&paz4); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&rz2); mp_clear(&raz4); return res; }
static int RsaFunction(const byte* in, word32 inLen, byte* out, word32* outLen, int type, RsaKey* key) { #define ERROR_OUT(x) { ret = x; goto done;} mp_int tmp; int ret = 0; word32 keyLen, len; if (mp_init(&tmp) != MP_OKAY) return MP_INIT_E; if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY) ERROR_OUT(MP_READ_E); if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) { #ifdef RSA_LOW_MEM /* half as much memory but twice as slow */ if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY) ERROR_OUT(MP_EXPTMOD_E); #else #define INNER_ERROR_OUT(x) { ret = x; goto inner_done; } mp_int tmpa, tmpb; if (mp_init(&tmpa) != MP_OKAY) ERROR_OUT(MP_INIT_E); if (mp_init(&tmpb) != MP_OKAY) { mp_clear(&tmpa); ERROR_OUT(MP_INIT_E); } /* tmpa = tmp^dP mod p */ if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY) INNER_ERROR_OUT(MP_EXPTMOD_E); /* tmpb = tmp^dQ mod q */ if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY) INNER_ERROR_OUT(MP_EXPTMOD_E); /* tmp = (tmpa - tmpb) * qInv (mod p) */ if (mp_sub(&tmpa, &tmpb, &tmp) != MP_OKAY) INNER_ERROR_OUT(MP_SUB_E); if (mp_mulmod(&tmp, &key->u, &key->p, &tmp) != MP_OKAY) INNER_ERROR_OUT(MP_MULMOD_E); /* tmp = tmpb + q * tmp */ if (mp_mul(&tmp, &key->q, &tmp) != MP_OKAY) INNER_ERROR_OUT(MP_MUL_E); if (mp_add(&tmp, &tmpb, &tmp) != MP_OKAY) INNER_ERROR_OUT(MP_ADD_E); inner_done: mp_clear(&tmpa); mp_clear(&tmpb); if (ret != 0) return ret; #endif /* RSA_LOW_MEM */ } else if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) { if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY) ERROR_OUT(MP_EXPTMOD_E); } else ERROR_OUT(RSA_WRONG_TYPE_E); keyLen = mp_unsigned_bin_size(&key->n); if (keyLen > *outLen) ERROR_OUT(RSA_BUFFER_E); len = mp_unsigned_bin_size(&tmp); /* pad front w/ zeros to match key length */ while (len < keyLen) { *out++ = 0x00; len++; } *outLen = keyLen; /* convert */ if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY) ERROR_OUT(MP_TO_E); done: mp_clear(&tmp); return ret; }
/* Computes the ECDSA signature (a concatenation of two values r and s) * on the digest using the given key and the random value kb (used in * computing s). */ SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, const SECItem *digest, const unsigned char *kb, const int kblen) { SECStatus rv = SECFailure; #ifndef NSS_DISABLE_ECC mp_int x1; mp_int d, k; /* private key, random integer */ mp_int r, s; /* tuple (r, s) is the signature */ mp_int n; mp_err err = MP_OKAY; ECParams *ecParams = NULL; SECItem kGpoint = { siBuffer, NULL, 0}; int flen = 0; /* length in bytes of the field size */ unsigned olen; /* length in bytes of the base point order */ unsigned obits; /* length in bits of the base point order */ #if EC_DEBUG char mpstr[256]; #endif /* Initialize MPI integers. */ /* must happen before the first potential call to cleanup */ MP_DIGITS(&x1) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&k) = 0; MP_DIGITS(&r) = 0; MP_DIGITS(&s) = 0; MP_DIGITS(&n) = 0; /* Check args */ if (!key || !signature || !digest || !kb || (kblen < 0)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); goto cleanup; } ecParams = &(key->ecParams); flen = (ecParams->fieldID.size + 7) >> 3; olen = ecParams->order.len; if (signature->data == NULL) { /* a call to get the signature length only */ goto finish; } if (signature->len < 2*olen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); goto cleanup; } CHECK_MPI_OK( mp_init(&x1) ); CHECK_MPI_OK( mp_init(&d) ); CHECK_MPI_OK( mp_init(&k) ); CHECK_MPI_OK( mp_init(&r) ); CHECK_MPI_OK( mp_init(&s) ); CHECK_MPI_OK( mp_init(&n) ); SECITEM_TO_MPINT( ecParams->order, &n ); SECITEM_TO_MPINT( key->privateValue, &d ); CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) ); /* Make sure k is in the interval [1, n-1] */ if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) { #if EC_DEBUG printf("k is outside [1, n-1]\n"); mp_tohex(&k, mpstr); printf("k : %s \n", mpstr); mp_tohex(&n, mpstr); printf("n : %s \n", mpstr); #endif PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** We do not want timing information to leak the length of k, ** so we compute k*G using an equivalent scalar of fixed ** bit-length. ** Fix based on patch for ECDSA timing attack in the paper ** by Billy Bob Brumley and Nicola Tuveri at ** http://eprint.iacr.org/2011/232 ** ** How do we convert k to a value of a fixed bit-length? ** k starts off as an integer satisfying 0 <= k < n. Hence, ** n <= k+n < 2n, which means k+n has either the same number ** of bits as n or one more bit than n. If k+n has the same ** number of bits as n, the second addition ensures that the ** final value has exactly one more bit than n. Thus, we ** always end up with a value that exactly one more bit than n. */ CHECK_MPI_OK( mp_add(&k, &n, &k) ); if (mpl_significant_bits(&k) <= mpl_significant_bits(&n)) { CHECK_MPI_OK( mp_add(&k, &n, &k) ); } /* ** ANSI X9.62, Section 5.3.2, Step 2 ** ** Compute kG */ kGpoint.len = 2*flen + 1; kGpoint.data = PORT_Alloc(2*flen + 1); if ((kGpoint.data == NULL) || (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess)) goto cleanup; /* ** ANSI X9.62, Section 5.3.3, Step 1 ** ** Extract the x co-ordinate of kG into x1 */ CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, (mp_size) flen) ); /* ** ANSI X9.62, Section 5.3.3, Step 2 ** ** r = x1 mod n NOTE: n is the order of the curve */ CHECK_MPI_OK( mp_mod(&x1, &n, &r) ); /* ** ANSI X9.62, Section 5.3.3, Step 3 ** ** verify r != 0 */ if (mp_cmp_z(&r) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** ANSI X9.62, Section 5.3.3, Step 4 ** ** s = (k**-1 * (HASH(M) + d*r)) mod n */ SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */ /* In the definition of EC signing, digests are truncated * to the length of n in bits. * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) ); if (digest->len*8 > obits) { mpl_rsh(&s,&s,digest->len*8 - obits); } #if EC_DEBUG mp_todecimal(&n, mpstr); printf("n : %s (dec)\n", mpstr); mp_todecimal(&d, mpstr); printf("d : %s (dec)\n", mpstr); mp_tohex(&x1, mpstr); printf("x1: %s\n", mpstr); mp_todecimal(&s, mpstr); printf("digest: %s (decimal)\n", mpstr); mp_todecimal(&r, mpstr); printf("r : %s (dec)\n", mpstr); mp_tohex(&r, mpstr); printf("r : %s\n", mpstr); #endif CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */ CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */ CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */ CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */ #if EC_DEBUG mp_todecimal(&s, mpstr); printf("s : %s (dec)\n", mpstr); mp_tohex(&s, mpstr); printf("s : %s\n", mpstr); #endif /* ** ANSI X9.62, Section 5.3.3, Step 5 ** ** verify s != 0 */ if (mp_cmp_z(&s) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** ** Signature is tuple (r, s) */ CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) ); CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) ); finish: signature->len = 2*olen; rv = SECSuccess; err = MP_OKAY; cleanup: mp_clear(&x1); mp_clear(&d); mp_clear(&k); mp_clear(&r); mp_clear(&s); mp_clear(&n); if (kGpoint.data) { PORT_ZFree(kGpoint.data, 2*flen + 1); } if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } #if EC_DEBUG printf("ECDSA signing with seed %s\n", (rv == SECSuccess) ? "succeeded" : "failed"); #endif #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); #endif /* NSS_DISABLE_ECC */ return rv; }
/** Double an ECC point @param P The point to double @param R [out] The destination of the double @param a ECC curve parameter a (if NULL we assume a == -3) @param modulus The modulus of the field the ECC curve is in @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success */ int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *a, void *modulus, void *mp) { void *t1, *t2; int err; LTC_ARGCHK(P != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(mp != NULL); if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) { return err; } if (P != R) { if ((err = mp_copy(P->x, R->x)) != CRYPT_OK) { goto done; } if ((err = mp_copy(P->y, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_copy(P->z, R->z)) != CRYPT_OK) { goto done; } } /* t1 = Z * Z */ if ((err = mp_sqr(R->z, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* Z = Y * Z */ if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK) { goto done; } /* Z = 2Z */ if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK) { goto done; } if (mp_cmp(R->z, modulus) != LTC_MP_LT) { if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK) { goto done; } } if (a == NULL) { /* special case for a == -3 (slightly faster than general case) */ /* T2 = X - T1 */ if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK) { goto done; } if (mp_cmp_d(t2, 0) == LTC_MP_LT) { if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; } } /* T1 = X + T1 */ if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T2 = T1 * T2 */ if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = 2T2 */ if ((err = mp_add(t2, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T1 = T1 + T2 */ if ((err = mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } } else { /* T2 = T1 * T1 */ if ((err = mp_sqr(t1, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = T2 * a */ if ((err = mp_mulmod(t2, a, modulus, t1)) != CRYPT_OK) { goto done; } /* T2 = X * X */ if ((err = mp_sqr(R->x, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = T2 + T1 */ if ((err = mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T1 = T2 + T1 */ if ((err = mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T1 = T2 + T1 */ if ((err = mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } } /* Y = 2Y */ if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK) { goto done; } if (mp_cmp(R->y, modulus) != LTC_MP_LT) { if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK) { goto done; } } /* Y = Y * Y */ if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; } /* T2 = Y * Y */ if ((err = mp_sqr(R->y, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T2 = T2/2 */ if (mp_isodd(t2)) { if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; } } if ((err = mp_div_2(t2, t2)) != CRYPT_OK) { goto done; } /* Y = Y * X */ if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; } /* X = T1 * T1 */ if ((err = mp_sqr(t1, R->x)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK) { goto done; } /* X = X - Y */ if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->x, 0) == LTC_MP_LT) { if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; } } /* X = X - Y */ if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->x, 0) == LTC_MP_LT) { if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; } } /* Y = Y - X */ if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->y, 0) == LTC_MP_LT) { if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; } } /* Y = Y * T1 */ if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; } /* Y = Y - T2 */ if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->y, 0) == LTC_MP_LT) { if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; } } err = CRYPT_OK; done: mp_clear_multi(t1, t2, NULL); return err; }
/** Sign a hash with DSA @param in The hash to sign @param inlen The length of the hash to sign @param r The "r" integer of the signature (caller must initialize with mp_init() first) @param s The "s" integer of the signature (caller must initialize with mp_init() first) @param prng An active PRNG state @param wprng The index of the PRNG desired @param key A private DSA key @return CRYPT_OK if successful */ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, void *r, void *s, prng_state *prng, int wprng, dsa_key *key) { void *k, *kinv, *tmp; unsigned char *buf; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(key != NULL); if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* check group order size */ if (key->qord >= MDSA_MAX_GROUP) { return CRYPT_INVALID_ARG; } buf = XMALLOC(MDSA_MAX_GROUP); if (buf == NULL) { return CRYPT_MEM; } /* Init our temps */ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } retry: do { /* gen random k */ if (prng_descriptor[wprng].read(buf, key->qord, prng) != (unsigned long)key->qord) { err = CRYPT_ERROR_READPRNG; goto error; } /* read k */ if ((err = mp_read_unsigned_bin(k, buf, key->qord)) != CRYPT_OK) { goto error; } /* k > 1 ? */ if (mp_cmp_d(k, 1) != LTC_MP_GT) { goto retry; } /* test gcd */ if ((err = mp_gcd(k, key->q, tmp)) != CRYPT_OK) { goto error; } } while (mp_cmp_d(tmp, 1) != LTC_MP_EQ); /* now find 1/k mod q */ if ((err = mp_invmod(k, key->q, kinv)) != CRYPT_OK) { goto error; } /* now find r = g^k mod p mod q */ if ((err = mp_exptmod(key->g, k, key->p, r)) != CRYPT_OK) { goto error; } if ((err = mp_mod(r, key->q, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r) == LTC_MP_YES) { goto retry; } /* now find s = (in + xr)/k mod q */ if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; } if ((err = mp_mul(key->x, r, s)) != CRYPT_OK) { goto error; } if ((err = mp_add(s, tmp, s)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(s, kinv, key->q, s)) != CRYPT_OK) { goto error; } if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; error: mp_clear_multi(k, kinv, tmp, NULL); ERRBUF: #ifdef LTC_CLEAN_STACK zeromem(buf, MDSA_MAX_GROUP); #endif XFREE(buf); return err; }
int DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng) { mp_int k, kInv, r, s, H; int ret = 0, sz; byte buffer[DSA_HALF_SIZE]; if (mp_init_multi(&k, &kInv, &r, &s, &H, 0) != MP_OKAY) return MP_INIT_E; sz = min(sizeof(buffer), mp_unsigned_bin_size(&key->q)); /* generate k */ RNG_GenerateBlock(rng, buffer, sz); buffer[0] |= 0x0C; if (mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY) ret = MP_READ_E; if (mp_cmp_d(&k, 1) != MP_GT) ret = MP_CMP_E; /* inverse k mod q */ if (ret == 0 && mp_invmod(&k, &key->q, &kInv) != MP_OKAY) ret = MP_INVMOD_E; /* generate r, r = (g exp k mod p) mod q */ if (ret == 0 && mp_exptmod(&key->g, &k, &key->p, &r) != MP_OKAY) ret = MP_EXPTMOD_E; if (ret == 0 && mp_mod(&r, &key->q, &r) != MP_OKAY) ret = MP_MOD_E; /* generate H from sha digest */ if (ret == 0 && mp_read_unsigned_bin(&H, digest,SHA_DIGEST_SIZE) != MP_OKAY) ret = MP_READ_E; /* generate s, s = (kInv * (H + x*r)) % q */ if (ret == 0 && mp_mul(&key->x, &r, &s) != MP_OKAY) ret = MP_MUL_E; if (ret == 0 && mp_add(&s, &H, &s) != MP_OKAY) ret = MP_ADD_E; if (ret == 0 && mp_mulmod(&s, &kInv, &key->q, &s) != MP_OKAY) ret = MP_MULMOD_E; /* write out */ if (ret == 0) { int rSz = mp_unsigned_bin_size(&r); int sSz = mp_unsigned_bin_size(&s); if (rSz == DSA_HALF_SIZE - 1) { out[0] = 0; out++; } if (mp_to_unsigned_bin(&r, out) != MP_OKAY) ret = MP_TO_E; else { if (sSz == DSA_HALF_SIZE - 1) { out[rSz] = 0; out++; } ret = mp_to_unsigned_bin(&s, out + rSz); } } mp_clear(&H); mp_clear(&s); mp_clear(&r); mp_clear(&kInv); mp_clear(&k); return ret; }