static int compare_d(void *a, unsigned long b) { int ret; LTC_ARGCHK(a != NULL); ret = fp_cmp_d(a, b); switch (ret) { case FP_LT: return LTC_MP_LT; case FP_EQ: return LTC_MP_EQ; case FP_GT: return LTC_MP_GT; } return 0; }
static int tfm_dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh) { fp_int s, priv_key, p, peer_pub; size_t size = 0; int ret; if (dh->pub_key == NULL || dh->g == NULL || dh->priv_key == NULL) return -1; fp_init(&p); BN2mpz(&p, dh->p); fp_init(&peer_pub); BN2mpz(&peer_pub, pub); /* check if peers pubkey is reasonable */ if (fp_isneg(&peer_pub) || fp_cmp(&peer_pub, &p) >= 0 || fp_cmp_d(&peer_pub, 1) <= 0) { fp_zero(&p); fp_zero(&peer_pub); return -1; } fp_init(&priv_key); BN2mpz(&priv_key, dh->priv_key); fp_init(&s); ret = fp_exptmod(&peer_pub, &priv_key, &p, &s); fp_zero(&p); fp_zero(&peer_pub); fp_zero(&priv_key); if (ret != 0) return -1; size = fp_unsigned_bin_size(&s); fp_to_unsigned_bin(&s, shared); fp_zero(&s); return size; }
/** Add two ECC points @param P The point to add @param Q The point to add @param R [out] The destination of the double @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 */ static int tfm_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *Mp) { fp_int t1, t2, x, y, z; fp_digit mp; LTC_ARGCHK(P != NULL); LTC_ARGCHK(Q != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(Mp != NULL); mp = *((fp_digit*)Mp); fp_init(&t1); fp_init(&t2); fp_init(&x); fp_init(&y); fp_init(&z); /* should we dbl instead? */ fp_sub(modulus, Q->y, &t1); if ( (fp_cmp(P->x, Q->x) == FP_EQ) && (Q->z != NULL && fp_cmp(P->z, Q->z) == FP_EQ) && (fp_cmp(P->y, Q->y) == FP_EQ || fp_cmp(P->y, &t1) == FP_EQ)) { return tfm_ecc_projective_dbl_point(P, R, modulus, Mp); } fp_copy(P->x, &x); fp_copy(P->y, &y); fp_copy(P->z, &z); /* if Z is one then these are no-operations */ if (Q->z != NULL) { /* T1 = Z' * Z' */ fp_sqr(Q->z, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* X = X * T1 */ fp_mul(&t1, &x, &x); fp_montgomery_reduce(&x, modulus, mp); /* T1 = Z' * T1 */ fp_mul(Q->z, &t1, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* Y = Y * T1 */ fp_mul(&t1, &y, &y); fp_montgomery_reduce(&y, modulus, mp); } /* T1 = Z*Z */ fp_sqr(&z, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* T2 = X' * T1 */ fp_mul(Q->x, &t1, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T1 = Z * T1 */ fp_mul(&z, &t1, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* T1 = Y' * T1 */ fp_mul(Q->y, &t1, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* Y = Y - T1 */ fp_sub(&y, &t1, &y); if (fp_cmp_d(&y, 0) == FP_LT) { fp_add(&y, modulus, &y); } /* T1 = 2T1 */ fp_add(&t1, &t1, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* T1 = Y + T1 */ fp_add(&t1, &y, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* X = X - T2 */ fp_sub(&x, &t2, &x); if (fp_cmp_d(&x, 0) == FP_LT) { fp_add(&x, modulus, &x); } /* T2 = 2T2 */ fp_add(&t2, &t2, &t2); if (fp_cmp(&t2, modulus) != FP_LT) { fp_sub(&t2, modulus, &t2); } /* T2 = X + T2 */ fp_add(&t2, &x, &t2); if (fp_cmp(&t2, modulus) != FP_LT) { fp_sub(&t2, modulus, &t2); } /* if Z' != 1 */ if (Q->z != NULL) { /* Z = Z * Z' */ fp_mul(&z, Q->z, &z); fp_montgomery_reduce(&z, modulus, mp); } /* Z = Z * X */ fp_mul(&z, &x, &z); fp_montgomery_reduce(&z, modulus, mp); /* T1 = T1 * X */ fp_mul(&t1, &x, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* X = X * X */ fp_sqr(&x, &x); fp_montgomery_reduce(&x, modulus, mp); /* T2 = T2 * x */ fp_mul(&t2, &x, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T1 = T1 * X */ fp_mul(&t1, &x, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* X = Y*Y */ fp_sqr(&y, &x); fp_montgomery_reduce(&x, modulus, mp); /* X = X - T2 */ fp_sub(&x, &t2, &x); if (fp_cmp_d(&x, 0) == FP_LT) { fp_add(&x, modulus, &x); } /* T2 = T2 - X */ fp_sub(&t2, &x, &t2); if (fp_cmp_d(&t2, 0) == FP_LT) { fp_add(&t2, modulus, &t2); } /* T2 = T2 - X */ fp_sub(&t2, &x, &t2); if (fp_cmp_d(&t2, 0) == FP_LT) { fp_add(&t2, modulus, &t2); } /* T2 = T2 * Y */ fp_mul(&t2, &y, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* Y = T2 - T1 */ fp_sub(&t2, &t1, &y); if (fp_cmp_d(&y, 0) == FP_LT) { fp_add(&y, modulus, &y); } /* Y = Y/2 */ if (fp_isodd(&y)) { fp_add(&y, modulus, &y); } fp_div_2(&y, &y); fp_copy(&x, R->x); fp_copy(&y, R->y); fp_copy(&z, R->z); return CRYPT_OK; }
static int tfm_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *Mp) { fp_int t1, t2; fp_digit mp; LTC_ARGCHK(P != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(Mp != NULL); mp = *((fp_digit*)Mp); fp_init(&t1); fp_init(&t2); if (P != R) { fp_copy(P->x, R->x); fp_copy(P->y, R->y); fp_copy(P->z, R->z); } /* t1 = Z * Z */ fp_sqr(R->z, &t1); fp_montgomery_reduce(&t1, modulus, mp); /* Z = Y * Z */ fp_mul(R->z, R->y, R->z); fp_montgomery_reduce(R->z, modulus, mp); /* Z = 2Z */ fp_add(R->z, R->z, R->z); if (fp_cmp(R->z, modulus) != FP_LT) { fp_sub(R->z, modulus, R->z); } /* &t2 = X - T1 */ fp_sub(R->x, &t1, &t2); if (fp_cmp_d(&t2, 0) == FP_LT) { fp_add(&t2, modulus, &t2); } /* T1 = X + T1 */ fp_add(&t1, R->x, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* T2 = T1 * T2 */ fp_mul(&t1, &t2, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T1 = 2T2 */ fp_add(&t2, &t2, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* T1 = T1 + T2 */ fp_add(&t1, &t2, &t1); if (fp_cmp(&t1, modulus) != FP_LT) { fp_sub(&t1, modulus, &t1); } /* Y = 2Y */ fp_add(R->y, R->y, R->y); if (fp_cmp(R->y, modulus) != FP_LT) { fp_sub(R->y, modulus, R->y); } /* Y = Y * Y */ fp_sqr(R->y, R->y); fp_montgomery_reduce(R->y, modulus, mp); /* T2 = Y * Y */ fp_sqr(R->y, &t2); fp_montgomery_reduce(&t2, modulus, mp); /* T2 = T2/2 */ if (fp_isodd(&t2)) { fp_add(&t2, modulus, &t2); } fp_div_2(&t2, &t2); /* Y = Y * X */ fp_mul(R->y, R->x, R->y); fp_montgomery_reduce(R->y, modulus, mp); /* X = T1 * T1 */ fp_sqr(&t1, R->x); fp_montgomery_reduce(R->x, modulus, mp); /* X = X - Y */ fp_sub(R->x, R->y, R->x); if (fp_cmp_d(R->x, 0) == FP_LT) { fp_add(R->x, modulus, R->x); } /* X = X - Y */ fp_sub(R->x, R->y, R->x); if (fp_cmp_d(R->x, 0) == FP_LT) { fp_add(R->x, modulus, R->x); } /* Y = Y - X */ fp_sub(R->y, R->x, R->y); if (fp_cmp_d(R->y, 0) == FP_LT) { fp_add(R->y, modulus, R->y); } /* Y = Y * T1 */ fp_mul(R->y, &t1, R->y); fp_montgomery_reduce(R->y, modulus, mp); /* Y = Y - T2 */ fp_sub(R->y, &t2, R->y); if (fp_cmp_d(R->y, 0) == FP_LT) { fp_add(R->y, modulus, R->y); } return CRYPT_OK; }
static int tfm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) { fp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; int counter, ret, bitsp; if (bits < 789) return -1; bitsp = (bits + 1) / 2; ret = -1; fp_init_multi(&el, &p, &q, &n, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); BN2mpz(&el, e); /* generate p and q so that p != q and bits(pq) ~ bits */ counter = 0; do { BN_GENCB_call(cb, 2, counter++); CHECK(random_num(&p, bitsp), 0); CHECK(fp_find_prime(&p), FP_YES); fp_sub_d(&p, 1, &t1); fp_gcd(&t1, &el, &t2); } while(fp_cmp_d(&t2, 1) != 0); BN_GENCB_call(cb, 3, 0); counter = 0; do { BN_GENCB_call(cb, 2, counter++); CHECK(random_num(&q, bits - bitsp), 0); CHECK(fp_find_prime(&q), FP_YES); if (fp_cmp(&p, &q) == 0) /* don't let p and q be the same */ continue; fp_sub_d(&q, 1, &t1); fp_gcd(&t1, &el, &t2); } while(fp_cmp_d(&t2, 1) != 0); /* make p > q */ if (fp_cmp(&p, &q) < 0) { fp_int c; fp_copy(&p, &c); fp_copy(&q, &p); fp_copy(&c, &q); } BN_GENCB_call(cb, 3, 1); /* calculate n, n = p * q */ fp_mul(&p, &q, &n); /* calculate d, d = 1/e mod (p - 1)(q - 1) */ fp_sub_d(&p, 1, &t1); fp_sub_d(&q, 1, &t2); fp_mul(&t1, &t2, &t3); fp_invmod(&el, &t3, &d); /* calculate dmp1 dmp1 = d mod (p-1) */ fp_mod(&d, &t1, &dmp1); /* calculate dmq1 dmq1 = d mod (q-1) */ fp_mod(&d, &t2, &dmq1); /* calculate iqmp iqmp = 1/q mod p */ fp_invmod(&q, &p, &iqmp); /* fill in RSA key */ rsa->e = mpz2BN(&el); rsa->p = mpz2BN(&p); rsa->q = mpz2BN(&q); rsa->n = mpz2BN(&n); rsa->d = mpz2BN(&d); rsa->dmp1 = mpz2BN(&dmp1); rsa->dmq1 = mpz2BN(&dmq1); rsa->iqmp = mpz2BN(&iqmp); ret = 1; out: fp_zero_multi(&el, &p, &q, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); return ret; }
/* c = 1/a (mod b) for odd b only */ int fp_invmod(fp_int *a, fp_int *b, fp_int *c) { fp_int x, y, u, v, B, D; int neg; /* 2. [modified] b must be odd */ if (fp_iseven (b) == FP_YES) { return fp_invmod_slow(a,b,c); } /* init all our temps */ fp_init(&x); fp_init(&y); fp_init(&u); fp_init(&v); fp_init(&B); fp_init(&D); /* x == modulus, y == value to invert */ fp_copy(b, &x); /* we need y = |a| */ fp_abs(a, &y); /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ fp_copy(&x, &u); fp_copy(&y, &v); fp_set (&D, 1); top: /* 4. while u is even do */ while (fp_iseven (&u) == FP_YES) { /* 4.1 u = u/2 */ fp_div_2 (&u, &u); /* 4.2 if B is odd then */ if (fp_isodd (&B) == FP_YES) { fp_sub (&B, &x, &B); } /* B = B/2 */ fp_div_2 (&B, &B); } /* 5. while v is even do */ while (fp_iseven (&v) == FP_YES) { /* 5.1 v = v/2 */ fp_div_2 (&v, &v); /* 5.2 if D is odd then */ if (fp_isodd (&D) == FP_YES) { /* D = (D-x)/2 */ fp_sub (&D, &x, &D); } /* D = D/2 */ fp_div_2 (&D, &D); } /* 6. if u >= v then */ if (fp_cmp (&u, &v) != FP_LT) { /* u = u - v, B = B - D */ fp_sub (&u, &v, &u); fp_sub (&B, &D, &B); } else { /* v - v - u, D = D - B */ fp_sub (&v, &u, &v); fp_sub (&D, &B, &D); } /* if not zero goto step 4 */ if (fp_iszero (&u) == FP_NO) { goto top; } /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (fp_cmp_d (&v, 1) != FP_EQ) { return FP_VAL; } /* b is now the inverse */ neg = a->sign; while (D.sign == FP_NEG) { fp_add (&D, b, &D); } fp_copy (&D, c); c->sign = neg; return FP_OKAY; }
static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c) { fp_int x, y, u, v, A, B, C, D; int res; /* b cannot be negative */ if (b->sign == FP_NEG || fp_iszero(b) == 1) { return FP_VAL; } /* init temps */ fp_init(&x); fp_init(&y); fp_init(&u); fp_init(&v); fp_init(&A); fp_init(&B); fp_init(&C); fp_init(&D); /* x = a, y = b */ if ((res = fp_mod(a, b, &x)) != FP_OKAY) { return res; } fp_copy(b, &y); /* 2. [modified] if x,y are both even then return an error! */ if (fp_iseven (&x) == 1 && fp_iseven (&y) == 1) { return FP_VAL; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ fp_copy (&x, &u); fp_copy (&y, &v); fp_set (&A, 1); fp_set (&D, 1); top: /* 4. while u is even do */ while (fp_iseven (&u) == 1) { /* 4.1 u = u/2 */ fp_div_2 (&u, &u); /* 4.2 if A or B is odd then */ if (fp_isodd (&A) == 1 || fp_isodd (&B) == 1) { /* A = (A+y)/2, B = (B-x)/2 */ fp_add (&A, &y, &A); fp_sub (&B, &x, &B); } /* A = A/2, B = B/2 */ fp_div_2 (&A, &A); fp_div_2 (&B, &B); } /* 5. while v is even do */ while (fp_iseven (&v) == 1) { /* 5.1 v = v/2 */ fp_div_2 (&v, &v); /* 5.2 if C or D is odd then */ if (fp_isodd (&C) == 1 || fp_isodd (&D) == 1) { /* C = (C+y)/2, D = (D-x)/2 */ fp_add (&C, &y, &C); fp_sub (&D, &x, &D); } /* C = C/2, D = D/2 */ fp_div_2 (&C, &C); fp_div_2 (&D, &D); } /* 6. if u >= v then */ if (fp_cmp (&u, &v) != FP_LT) { /* u = u - v, A = A - C, B = B - D */ fp_sub (&u, &v, &u); fp_sub (&A, &C, &A); fp_sub (&B, &D, &B); } else { /* v - v - u, C = C - A, D = D - B */ fp_sub (&v, &u, &v); fp_sub (&C, &A, &C); fp_sub (&D, &B, &D); } /* if not zero goto step 4 */ if (fp_iszero (&u) == 0) goto top; /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (fp_cmp_d (&v, 1) != FP_EQ) { return FP_VAL; } /* if its too low */ while (fp_cmp_d(&C, 0) == FP_LT) { fp_add(&C, b, &C); } /* too big */ while (fp_cmp_mag(&C, b) != FP_LT) { fp_sub(&C, b, &C); } /* C is now the inverse */ fp_copy(&C, c); return FP_OKAY; }