int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) { unsigned char *B = NULL, *D = NULL, *I = NULL, *p = NULL, *Ai = NULL; int Slen, Plen, Ilen, Ijlen; int i, j, u, v; int ret = 0; BIGNUM *Ij = NULL, *Bpl1 = NULL; /* These hold Ij and B + 1 */ EVP_MD_CTX *ctx = NULL; #ifdef OPENSSL_DEBUG_KEYGEN unsigned char *tmpout = out; int tmpn = n; #endif ctx = EVP_MD_CTX_new(); if (ctx == NULL) goto err; #ifdef OPENSSL_DEBUG_KEYGEN fprintf(stderr, "KEYGEN DEBUG\n"); fprintf(stderr, "ID %d, ITER %d\n", id, iter); fprintf(stderr, "Password (length %d):\n", passlen); h__dump(pass, passlen); fprintf(stderr, "Salt (length %d):\n", saltlen); h__dump(salt, saltlen); #endif v = EVP_MD_block_size(md_type); u = EVP_MD_size(md_type); if (u < 0 || v <= 0) goto err; D = OPENSSL_malloc(v); Ai = OPENSSL_malloc(u); B = OPENSSL_malloc(v + 1); Slen = v * ((saltlen + v - 1) / v); if (passlen) Plen = v * ((passlen + v - 1) / v); else Plen = 0; Ilen = Slen + Plen; I = OPENSSL_malloc(Ilen); Ij = BN_new(); Bpl1 = BN_new(); if (D == NULL || Ai == NULL || B == NULL || I == NULL || Ij == NULL || Bpl1 == NULL) goto err; for (i = 0; i < v; i++) D[i] = id; p = I; for (i = 0; i < Slen; i++) *p++ = salt[i % saltlen]; for (i = 0; i < Plen; i++) *p++ = pass[i % passlen]; for (;;) { if (!EVP_DigestInit_ex(ctx, md_type, NULL) || !EVP_DigestUpdate(ctx, D, v) || !EVP_DigestUpdate(ctx, I, Ilen) || !EVP_DigestFinal_ex(ctx, Ai, NULL)) goto err; for (j = 1; j < iter; j++) { if (!EVP_DigestInit_ex(ctx, md_type, NULL) || !EVP_DigestUpdate(ctx, Ai, u) || !EVP_DigestFinal_ex(ctx, Ai, NULL)) goto err; } memcpy(out, Ai, min(n, u)); if (u >= n) { #ifdef OPENSSL_DEBUG_KEYGEN fprintf(stderr, "Output KEY (length %d)\n", tmpn); h__dump(tmpout, tmpn); #endif ret = 1; goto end; } n -= u; out += u; for (j = 0; j < v; j++) B[j] = Ai[j % u]; /* Work out B + 1 first then can use B as tmp space */ if (!BN_bin2bn(B, v, Bpl1)) goto err; if (!BN_add_word(Bpl1, 1)) goto err; for (j = 0; j < Ilen; j += v) { if (!BN_bin2bn(I + j, v, Ij)) goto err; if (!BN_add(Ij, Ij, Bpl1)) goto err; if (!BN_bn2bin(Ij, B)) goto err; Ijlen = BN_num_bytes(Ij); /* If more than 2^(v*8) - 1 cut off MSB */ if (Ijlen > v) { if (!BN_bn2bin(Ij, B)) goto err; memcpy(I + j, B + 1, v); #ifndef PKCS12_BROKEN_KEYGEN /* If less than v bytes pad with zeroes */ } else if (Ijlen < v) { memset(I + j, 0, v - Ijlen); if (!BN_bn2bin(Ij, I + j + v - Ijlen)) goto err; #endif } else if (!BN_bn2bin(Ij, I + j)) goto err; } } err: PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_MALLOC_FAILURE); end: OPENSSL_free(Ai); OPENSSL_free(B); OPENSSL_free(D); OPENSSL_free(I); BN_free(Ij); BN_free(Bpl1); EVP_MD_CTX_free(ctx); return ret; }
int BN_X931_derive_prime_ex(BIGNUM *p, BIGNUM *p1, BIGNUM *p2, const BIGNUM *Xp, const BIGNUM *Xp1, const BIGNUM *Xp2, const BIGNUM *e, BN_CTX *ctx, BN_GENCB *cb) { int ret = 0; BIGNUM *t, *p1p2, *pm1; /* Only even e supported */ if (!BN_is_odd(e)) return 0; BN_CTX_start(ctx); if (!p1) p1 = BN_CTX_get(ctx); if (!p2) p2 = BN_CTX_get(ctx); t = BN_CTX_get(ctx); p1p2 = BN_CTX_get(ctx); pm1 = BN_CTX_get(ctx); if (!bn_x931_derive_pi(p1, Xp1, ctx, cb)) goto err; if (!bn_x931_derive_pi(p2, Xp2, ctx, cb)) goto err; if (!BN_mul(p1p2, p1, p2, ctx)) goto err; /* First set p to value of Rp */ if (!BN_mod_inverse(p, p2, p1, ctx)) goto err; if (!BN_mul(p, p, p2, ctx)) goto err; if (!BN_mod_inverse(t, p1, p2, ctx)) goto err; if (!BN_mul(t, t, p1, ctx)) goto err; if (!BN_sub(p, p, t)) goto err; if (p->neg && !BN_add(p, p, p1p2)) goto err; /* p now equals Rp */ if (!BN_mod_sub(p, p, Xp, p1p2, ctx)) goto err; if (!BN_add(p, p, Xp)) goto err; /* p now equals Yp0 */ for (;;) { int i = 1; BN_GENCB_call(cb, 0, i++); if (!BN_copy(pm1, p)) goto err; if (!BN_sub_word(pm1, 1)) goto err; if (!BN_gcd(t, pm1, e, ctx)) goto err; if (BN_is_one(t) /* * X9.31 specifies 8 MR and 1 Lucas test or any prime test * offering similar or better guarantees 50 MR is considerably * better. */ && BN_is_prime_fasttest_ex(p, 50, ctx, 1, cb)) break; if (!BN_add(p, p, p1p2)) goto err; } BN_GENCB_call(cb, 3, 0); ret = 1; err: BN_CTX_end(ctx); return ret; }
int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) { unsigned char *B, *D, *I, *p, *Ai; int Slen, Plen, Ilen, Ijlen; int i, j, u, v; int ret = 0; BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */ EVP_MD_CTX ctx; #if 0 if (!pass) { PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_PASSED_NULL_PARAMETER); return 0; } #endif EVP_MD_CTX_init(&ctx); v = EVP_MD_block_size(md_type); u = EVP_MD_size(md_type); if (u < 0) return 0; D = malloc(v); Ai = malloc(u); B = malloc(v + 1); Slen = v * ((saltlen + v - 1) / v); if (passlen) Plen = v * ((passlen + v - 1)/v); else Plen = 0; Ilen = Slen + Plen; I = malloc(Ilen); Ij = BN_new(); Bpl1 = BN_new(); if (!D || !Ai || !B || !I || !Ij || !Bpl1) goto err; for (i = 0; i < v; i++) D[i] = id; p = I; for (i = 0; i < Slen; i++) *p++ = salt[i % saltlen]; for (i = 0; i < Plen; i++) *p++ = pass[i % passlen]; for (;;) { if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || !EVP_DigestUpdate(&ctx, D, v) || !EVP_DigestUpdate(&ctx, I, Ilen) || !EVP_DigestFinal_ex(&ctx, Ai, NULL)) goto err; for (j = 1; j < iter; j++) { if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || !EVP_DigestUpdate(&ctx, Ai, u) || !EVP_DigestFinal_ex(&ctx, Ai, NULL)) goto err; } memcpy (out, Ai, min (n, u)); if (u >= n) { ret = 1; goto end; } n -= u; out += u; for (j = 0; j < v; j++) B[j] = Ai[j % u]; /* Work out B + 1 first then can use B as tmp space */ if (!BN_bin2bn (B, v, Bpl1)) goto err; if (!BN_add_word (Bpl1, 1)) goto err; for (j = 0; j < Ilen; j += v) { if (!BN_bin2bn(I + j, v, Ij)) goto err; if (!BN_add(Ij, Ij, Bpl1)) goto err; if (!BN_bn2bin(Ij, B)) goto err; Ijlen = BN_num_bytes (Ij); /* If more than 2^(v*8) - 1 cut off MSB */ if (Ijlen > v) { if (!BN_bn2bin (Ij, B)) goto err; memcpy (I + j, B + 1, v); #ifndef PKCS12_BROKEN_KEYGEN /* If less than v bytes pad with zeroes */ } else if (Ijlen < v) { memset(I + j, 0, v - Ijlen); if (!BN_bn2bin(Ij, I + j + v - Ijlen)) goto err; #endif } else if (!BN_bn2bin (Ij, I + j)) goto err; } } err: PKCS12err(PKCS12_F_PKCS12_KEY_GEN_UNI, ERR_R_MALLOC_FAILURE); end: free(Ai); free(B); free(D); free(I); BN_free(Ij); BN_free(Bpl1); EVP_MD_CTX_cleanup(&ctx); return ret; }
/* solves ax == 1 (mod n) */ BIGNUM *BN_mod_inverse(BIGNUM *in, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) { BIGNUM *A,*B,*X,*Y,*M,*D,*R=NULL; BIGNUM *T,*ret=NULL; int sign; bn_check_top(a); bn_check_top(n); BN_CTX_start(ctx); A = BN_CTX_get(ctx); B = BN_CTX_get(ctx); X = BN_CTX_get(ctx); D = BN_CTX_get(ctx); M = BN_CTX_get(ctx); Y = BN_CTX_get(ctx); if (Y == NULL) goto err; if (in == NULL) R=BN_new(); else R=in; if (R == NULL) goto err; if (!BN_zero(X)) goto err; if (!BN_one(Y)) goto err; if (BN_copy(A,a) == NULL) goto err; if (BN_copy(B,n) == NULL) goto err; sign=1; while (!BN_is_zero(B)) { if (!BN_div(D,M,A,B,ctx)) goto err; T=A; A=B; B=M; /* T has a struct, M does not */ if (!BN_mul(T,D,X,ctx)) goto err; if (!BN_add(T,T,Y)) goto err; M=Y; Y=X; X=T; sign= -sign; } if (sign < 0) { if (!BN_sub(Y,n,Y)) goto err; } if (BN_is_one(A)) { if (!BN_mod(R,Y,n,ctx)) goto err; } else { BNerr(BN_F_BN_MOD_INVERSE,BN_R_NO_INVERSE); goto err; } ret=R; err: if ((ret == NULL) && (in == NULL)) BN_free(R); BN_CTX_end(ctx); return(ret); }
/* * Find the bignum ranges that produce a given prefix. */ static int get_prefix_ranges(int addrtype, const char *pfx, BIGNUM **result, BN_CTX *bnctx) { int i, p, c; int zero_prefix = 0; int check_upper = 0; int b58pow, b58ceil, b58top = 0; int ret = -1; BIGNUM bntarg, bnceil, bnfloor; BIGNUM bnbase; BIGNUM *bnap, *bnbp, *bntp; BIGNUM *bnhigh = NULL, *bnlow = NULL, *bnhigh2 = NULL, *bnlow2 = NULL; BIGNUM bntmp, bntmp2; BN_init(&bntarg); BN_init(&bnceil); BN_init(&bnfloor); BN_init(&bnbase); BN_init(&bntmp); BN_init(&bntmp2); BN_set_word(&bnbase, 58); p = strlen(pfx); for (i = 0; i < p; i++) { c = vg_b58_reverse_map[(int)pfx[i]]; if (c == -1) { fprintf(stderr, "Invalid character '%c' in prefix '%s'\n", pfx[i], pfx); goto out; } if (i == zero_prefix) { if (c == 0) { /* Add another zero prefix */ zero_prefix++; if (zero_prefix > 19) { fprintf(stderr, "Prefix '%s' is too long\n", pfx); goto out; } continue; } /* First non-zero character */ b58top = c; BN_set_word(&bntarg, c); } else { BN_set_word(&bntmp2, c); BN_mul(&bntmp, &bntarg, &bnbase, bnctx); BN_add(&bntarg, &bntmp, &bntmp2); } } /* Power-of-two ceiling and floor values based on leading 1s */ BN_clear(&bntmp); BN_set_bit(&bntmp, 200 - (zero_prefix * 8)); BN_sub(&bnceil, &bntmp, BN_value_one()); BN_set_bit(&bnfloor, 192 - (zero_prefix * 8)); bnlow = BN_new(); bnhigh = BN_new(); if (b58top) { /* * If a non-zero was given in the prefix, find the * numeric boundaries of the prefix. */ BN_copy(&bntmp, &bnceil); bnap = &bntmp; bnbp = &bntmp2; b58pow = 0; while (BN_cmp(bnap, &bnbase) > 0) { b58pow++; BN_div(bnbp, NULL, bnap, &bnbase, bnctx); bntp = bnap; bnap = bnbp; bnbp = bntp; } b58ceil = BN_get_word(bnap); if ((b58pow - (p - zero_prefix)) < 6) { /* * Do not allow the prefix to constrain the * check value, this is ridiculous. */ fprintf(stderr, "Prefix '%s' is too long\n", pfx); goto out; } BN_set_word(&bntmp2, b58pow - (p - zero_prefix)); BN_exp(&bntmp, &bnbase, &bntmp2, bnctx); BN_mul(bnlow, &bntmp, &bntarg, bnctx); BN_sub(&bntmp2, &bntmp, BN_value_one()); BN_add(bnhigh, bnlow, &bntmp2); if (b58top <= b58ceil) { /* Fill out the upper range too */ check_upper = 1; bnlow2 = BN_new(); bnhigh2 = BN_new(); BN_mul(bnlow2, bnlow, &bnbase, bnctx); BN_mul(&bntmp2, bnhigh, &bnbase, bnctx); BN_set_word(&bntmp, 57); BN_add(bnhigh2, &bntmp2, &bntmp); /* * Addresses above the ceiling will have one * fewer "1" prefix in front than we require. */ if (BN_cmp(&bnceil, bnlow2) < 0) { /* High prefix is above the ceiling */ check_upper = 0; BN_free(bnhigh2); bnhigh2 = NULL; BN_free(bnlow2); bnlow2 = NULL; } else if (BN_cmp(&bnceil, bnhigh2) < 0) /* High prefix is partly above the ceiling */ BN_copy(bnhigh2, &bnceil); /* * Addresses below the floor will have another * "1" prefix in front instead of our target. */ if (BN_cmp(&bnfloor, bnhigh) >= 0) { /* Low prefix is completely below the floor */ assert(check_upper); check_upper = 0; BN_free(bnhigh); bnhigh = bnhigh2; bnhigh2 = NULL; BN_free(bnlow); bnlow = bnlow2; bnlow2 = NULL; } else if (BN_cmp(&bnfloor, bnlow) > 0) { /* Low prefix is partly below the floor */ BN_copy(bnlow, &bnfloor); } } } else { BN_copy(bnhigh, &bnceil); BN_clear(bnlow); } /* Limit the prefix to the address type */ BN_clear(&bntmp); BN_set_word(&bntmp, addrtype); BN_lshift(&bntmp2, &bntmp, 192); if (check_upper) { if (BN_cmp(&bntmp2, bnhigh2) > 0) { check_upper = 0; BN_free(bnhigh2); bnhigh2 = NULL; BN_free(bnlow2); bnlow2 = NULL; } else if (BN_cmp(&bntmp2, bnlow2) > 0) BN_copy(bnlow2, &bntmp2); } if (BN_cmp(&bntmp2, bnhigh) > 0) { if (!check_upper) goto not_possible; check_upper = 0; BN_free(bnhigh); bnhigh = bnhigh2; bnhigh2 = NULL; BN_free(bnlow); bnlow = bnlow2; bnlow2 = NULL; } else if (BN_cmp(&bntmp2, bnlow) > 0) { BN_copy(bnlow, &bntmp2); } BN_set_word(&bntmp, addrtype + 1); BN_lshift(&bntmp2, &bntmp, 192); if (check_upper) { if (BN_cmp(&bntmp2, bnlow2) < 0) { check_upper = 0; BN_free(bnhigh2); bnhigh2 = NULL; BN_free(bnlow2); bnlow2 = NULL; } else if (BN_cmp(&bntmp2, bnhigh2) < 0) BN_copy(bnlow2, &bntmp2); } if (BN_cmp(&bntmp2, bnlow) < 0) { if (!check_upper) goto not_possible; check_upper = 0; BN_free(bnhigh); bnhigh = bnhigh2; bnhigh2 = NULL; BN_free(bnlow); bnlow = bnlow2; bnlow2 = NULL; } else if (BN_cmp(&bntmp2, bnhigh) < 0) { BN_copy(bnhigh, &bntmp2); } /* Address ranges are complete */ assert(check_upper || ((bnlow2 == NULL) && (bnhigh2 == NULL))); result[0] = bnlow; result[1] = bnhigh; result[2] = bnlow2; result[3] = bnhigh2; bnlow = NULL; bnhigh = NULL; bnlow2 = NULL; bnhigh2 = NULL; ret = 0; if (0) { not_possible: ret = -2; } out: BN_clear_free(&bntarg); BN_clear_free(&bnceil); BN_clear_free(&bnfloor); BN_clear_free(&bnbase); BN_clear_free(&bntmp); BN_clear_free(&bntmp2); if (bnhigh) BN_free(bnhigh); if (bnlow) BN_free(bnlow); if (bnhigh2) BN_free(bnhigh2); if (bnlow2) BN_free(bnlow2); return ret; }
bigint& bigint::operator += ( const bigint& a ){ bigint tmp(*this); BN_add( tmp.n, n, a.n ); std::swap(*this,tmp); return *this; }
static struct wpabuf * eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) { struct wpabuf *req = NULL; BIGNUM *mask = NULL, *x = NULL, *y = NULL; u8 *scalar = NULL, *element = NULL; u16 offset; wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request"); if (((data->private_value = BN_new()) == NULL) || ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || ((data->my_scalar = BN_new()) == NULL) || ((mask = BN_new()) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation " "fail"); goto fin; } BN_rand_range(data->private_value, data->grp->order); BN_rand_range(mask, data->grp->order); BN_add(data->my_scalar, data->private_value, mask); BN_mod(data->my_scalar, data->my_scalar, data->grp->order, data->bnctx); if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, data->grp->pwe, mask, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation " "fail"); eap_pwd_state(data, FAILURE); goto fin; } if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion " "fail"); goto fin; } BN_free(mask); if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation " "fail"); goto fin; } if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, data->my_element, x, y, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " "fail"); goto fin; } if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); goto fin; } /* * bignums occupy as little memory as possible so one that is * sufficiently smaller than the prime or order might need pre-pending * with zeros. */ os_memset(scalar, 0, BN_num_bytes(data->grp->order)); os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); offset = BN_num_bytes(data->grp->order) - BN_num_bytes(data->my_scalar); BN_bn2bin(data->my_scalar, scalar + offset); offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); BN_bn2bin(x, element + offset); offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, 1 + (2 * BN_num_bytes(data->grp->prime)) + BN_num_bytes(data->grp->order), EAP_CODE_REQUEST, id); if (req == NULL) goto fin; wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH); /* We send the element as (x,y) followed by the scalar */ wpabuf_put_data(req, element, (2 * BN_num_bytes(data->grp->prime))); wpabuf_put_data(req, scalar, BN_num_bytes(data->grp->order)); fin: os_free(scalar); os_free(element); BN_free(x); BN_free(y); if (req == NULL) eap_pwd_state(data, FAILURE); return req; }
int dsa_builtin_paramgen(DSA *ret, size_t bits, size_t qbits, const EVP_MD *evpmd, const unsigned char *seed_in, size_t seed_len, int *counter_ret, unsigned long *h_ret, BN_GENCB *cb) { int ok=0; unsigned char seed[SHA256_DIGEST_LENGTH]; unsigned char md[SHA256_DIGEST_LENGTH]; unsigned char buf[SHA256_DIGEST_LENGTH],buf2[SHA256_DIGEST_LENGTH]; BIGNUM *r0,*W,*X,*c,*test; BIGNUM *g=NULL,*q=NULL,*p=NULL; BN_MONT_CTX *mont=NULL; int i, k, n=0, m=0, qsize = qbits >> 3; int counter=0; int r=0; BN_CTX *ctx=NULL; unsigned int h=2; if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH && qsize != SHA256_DIGEST_LENGTH) /* invalid q size */ return 0; if (evpmd == NULL) /* use SHA1 as default */ evpmd = EVP_sha1(); if (bits < 512) bits = 512; bits = (bits+63)/64*64; /* NB: seed_len == 0 is special case: copy generated seed to * seed_in if it is not NULL. */ if (seed_len && (seed_len < (size_t)qsize)) seed_in = NULL; /* seed buffer too small -- ignore */ if (seed_len > (size_t)qsize) seed_len = qsize; /* App. 2.2 of FIPS PUB 186 allows larger SEED, * but our internal buffers are restricted to 160 bits*/ if (seed_in != NULL) memcpy(seed, seed_in, seed_len); if ((ctx=BN_CTX_new()) == NULL) goto err; if ((mont=BN_MONT_CTX_new()) == NULL) goto err; BN_CTX_start(ctx); r0 = BN_CTX_get(ctx); g = BN_CTX_get(ctx); W = BN_CTX_get(ctx); q = BN_CTX_get(ctx); X = BN_CTX_get(ctx); c = BN_CTX_get(ctx); p = BN_CTX_get(ctx); test = BN_CTX_get(ctx); if (!BN_lshift(test,BN_value_one(),bits-1)) goto err; for (;;) { for (;;) /* find q */ { int seed_is_random; /* step 1 */ if(!BN_GENCB_call(cb, 0, m++)) goto err; if (!seed_len) { RAND_pseudo_bytes(seed, qsize); seed_is_random = 1; } else { seed_is_random = 0; seed_len=0; /* use random seed if 'seed_in' turns out to be bad*/ } memcpy(buf , seed, qsize); memcpy(buf2, seed, qsize); /* precompute "SEED + 1" for step 7: */ for (i = qsize-1; i >= 0; i--) { buf[i]++; if (buf[i] != 0) break; } /* step 2 */ EVP_Digest(seed, qsize, md, NULL, evpmd, NULL); EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL); for (i = 0; i < qsize; i++) md[i]^=buf2[i]; /* step 3 */ md[0] |= 0x80; md[qsize-1] |= 0x01; if (!BN_bin2bn(md, qsize, q)) goto err; /* step 4 */ r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, seed_is_random, cb); if (r > 0) break; if (r != 0) goto err; /* do a callback call */ /* step 5 */ } if(!BN_GENCB_call(cb, 2, 0)) goto err; if(!BN_GENCB_call(cb, 3, 0)) goto err; /* step 6 */ counter=0; /* "offset = 2" */ n=(bits-1)/160; for (;;) { if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) goto err; /* step 7 */ BN_zero(W); /* now 'buf' contains "SEED + offset - 1" */ for (k=0; k<=n; k++) { /* obtain "SEED + offset + k" by incrementing: */ for (i = qsize-1; i >= 0; i--) { buf[i]++; if (buf[i] != 0) break; } EVP_Digest(buf, qsize, md ,NULL, evpmd, NULL); /* step 8 */ if (!BN_bin2bn(md, qsize, r0)) goto err; if (!BN_lshift(r0,r0,(qsize << 3)*k)) goto err; if (!BN_add(W,W,r0)) goto err; } /* more of step 8 */ if (!BN_mask_bits(W,bits-1)) goto err; if (!BN_copy(X,W)) goto err; if (!BN_add(X,X,test)) goto err; /* step 9 */ if (!BN_lshift1(r0,q)) goto err; if (!BN_mod(c,X,r0,ctx)) goto err; if (!BN_sub(r0,c,BN_value_one())) goto err; if (!BN_sub(p,X,r0)) goto err; /* step 10 */ if (BN_cmp(p,test) >= 0) { /* step 11 */ r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb); if (r > 0) goto end; /* found it */ if (r != 0) goto err; } /* step 13 */ counter++; /* "offset = offset + n + 1" */ /* step 14 */ if (counter >= 4096) break; } } end: if(!BN_GENCB_call(cb, 2, 1)) goto err; /* We now need to generate g */ /* Set r0=(p-1)/q */ if (!BN_sub(test,p,BN_value_one())) goto err; if (!BN_div(r0,NULL,test,q,ctx)) goto err; if (!BN_set_word(test,h)) goto err; if (!BN_MONT_CTX_set(mont,p,ctx)) goto err; for (;;) { /* g=test^r0%p */ if (!BN_mod_exp_mont(g,test,r0,p,ctx,mont)) goto err; if (!BN_is_one(g)) break; if (!BN_add(test,test,BN_value_one())) goto err; h++; } if(!BN_GENCB_call(cb, 3, 1)) goto err; ok=1; err: if (ok) { if(ret->p) BN_free(ret->p); if(ret->q) BN_free(ret->q); if(ret->g) BN_free(ret->g); ret->p=BN_dup(p); ret->q=BN_dup(q); ret->g=BN_dup(g); if (ret->p == NULL || ret->q == NULL || ret->g == NULL) { ok=0; goto err; } if (counter_ret != NULL) *counter_ret=counter; if (h_ret != NULL) *h_ret=h; } if(ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } if (mont != NULL) BN_MONT_CTX_free(mont); return ok; }
DSA *DSA_generate_parameters(int bits, unsigned char *seed_in, int seed_len, int *counter_ret, unsigned long *h_ret, void (*callback)(int, int, void *), void *cb_arg) { int ok=0; unsigned char seed[SHA_DIGEST_LENGTH]; unsigned char md[SHA_DIGEST_LENGTH]; unsigned char buf[SHA_DIGEST_LENGTH],buf2[SHA_DIGEST_LENGTH]; BIGNUM *r0,*W,*X,*c,*test; BIGNUM *g=NULL,*q=NULL,*p=NULL; BN_MONT_CTX *mont=NULL; int k,n=0,i,b,m=0; int counter=0; int r=0; BN_CTX *ctx=NULL,*ctx2=NULL,*ctx3=NULL; unsigned int h=2; DSA *ret=NULL; if (bits < 512) bits=512; bits=(bits+63)/64*64; if (seed_len < 20) seed_in = NULL; /* seed buffer too small -- ignore */ if (seed_len > 20) seed_len = 20; /* App. 2.2 of FIPS PUB 186 allows larger SEED, * but our internal buffers are restricted to 160 bits*/ if ((seed_in != NULL) && (seed_len == 20)) memcpy(seed,seed_in,seed_len); if ((ctx=BN_CTX_new()) == NULL) goto err; if ((ctx2=BN_CTX_new()) == NULL) goto err; if ((ctx3=BN_CTX_new()) == NULL) goto err; if ((ret=DSA_new()) == NULL) goto err; if ((mont=BN_MONT_CTX_new()) == NULL) goto err; BN_CTX_start(ctx2); r0 = BN_CTX_get(ctx2); g = BN_CTX_get(ctx2); W = BN_CTX_get(ctx2); q = BN_CTX_get(ctx2); X = BN_CTX_get(ctx2); c = BN_CTX_get(ctx2); p = BN_CTX_get(ctx2); test = BN_CTX_get(ctx2); if (test == NULL) goto err; if (!BN_lshift(test,BN_value_one(),bits-1)) goto err; for (;;) { for (;;) /* find q */ { int seed_is_random; /* step 1 */ if (callback != NULL) callback(0,m++,cb_arg); if (!seed_len) { RAND_pseudo_bytes(seed,SHA_DIGEST_LENGTH); seed_is_random = 1; } else { seed_is_random = 0; seed_len=0; /* use random seed if 'seed_in' turns out to be bad*/ } memcpy(buf,seed,SHA_DIGEST_LENGTH); memcpy(buf2,seed,SHA_DIGEST_LENGTH); /* precompute "SEED + 1" for step 7: */ for (i=SHA_DIGEST_LENGTH-1; i >= 0; i--) { buf[i]++; if (buf[i] != 0) break; } /* step 2 */ EVP_Digest(seed,SHA_DIGEST_LENGTH,md,NULL,HASH, NULL); EVP_Digest(buf,SHA_DIGEST_LENGTH,buf2,NULL,HASH, NULL); for (i=0; i<SHA_DIGEST_LENGTH; i++) md[i]^=buf2[i]; /* step 3 */ md[0]|=0x80; md[SHA_DIGEST_LENGTH-1]|=0x01; if (!BN_bin2bn(md,SHA_DIGEST_LENGTH,q)) goto err; /* step 4 */ r = BN_is_prime_fasttest(q, DSS_prime_checks, callback, ctx3, cb_arg, seed_is_random); if (r > 0) break; if (r != 0) goto err; /* do a callback call */ /* step 5 */ } if (callback != NULL) callback(2,0,cb_arg); if (callback != NULL) callback(3,0,cb_arg); /* step 6 */ counter=0; /* "offset = 2" */ n=(bits-1)/160; b=(bits-1)-n*160; for (;;) { if (callback != NULL && counter != 0) callback(0,counter,cb_arg); /* step 7 */ if (!BN_zero(W)) goto err; /* now 'buf' contains "SEED + offset - 1" */ for (k=0; k<=n; k++) { /* obtain "SEED + offset + k" by incrementing: */ for (i=SHA_DIGEST_LENGTH-1; i >= 0; i--) { buf[i]++; if (buf[i] != 0) break; } EVP_Digest(buf,SHA_DIGEST_LENGTH,md,NULL,HASH, NULL); /* step 8 */ if (!BN_bin2bn(md,SHA_DIGEST_LENGTH,r0)) goto err; if (!BN_lshift(r0,r0,160*k)) goto err; if (!BN_add(W,W,r0)) goto err; } /* more of step 8 */ if (!BN_mask_bits(W,bits-1)) goto err; if (!BN_copy(X,W)) goto err; if (!BN_add(X,X,test)) goto err; /* step 9 */ if (!BN_lshift1(r0,q)) goto err; if (!BN_mod(c,X,r0,ctx)) goto err; if (!BN_sub(r0,c,BN_value_one())) goto err; if (!BN_sub(p,X,r0)) goto err; /* step 10 */ if (BN_cmp(p,test) >= 0) { /* step 11 */ r = BN_is_prime_fasttest(p, DSS_prime_checks, callback, ctx3, cb_arg, 1); if (r > 0) goto end; /* found it */ if (r != 0) goto err; } /* step 13 */ counter++; /* "offset = offset + n + 1" */ /* step 14 */ if (counter >= 4096) break; } } end: if (callback != NULL) callback(2,1,cb_arg); /* We now need to generate g */ /* Set r0=(p-1)/q */ if (!BN_sub(test,p,BN_value_one())) goto err; if (!BN_div(r0,NULL,test,q,ctx)) goto err; if (!BN_set_word(test,h)) goto err; if (!BN_MONT_CTX_set(mont,p,ctx)) goto err; for (;;) { /* g=test^r0%p */ if (!BN_mod_exp_mont(g,test,r0,p,ctx,mont)) goto err; if (!BN_is_one(g)) break; if (!BN_add(test,test,BN_value_one())) goto err; h++; } if (callback != NULL) callback(3,1,cb_arg); ok=1; err: if (!ok) { if (ret != NULL) DSA_free(ret); } else { ret->p=BN_dup(p); ret->q=BN_dup(q); ret->g=BN_dup(g); if (ret->p == NULL || ret->q == NULL || ret->g == NULL) { ok=0; goto err; } if ((m > 1) && (seed_in != NULL)) memcpy(seed_in,seed,20); if (counter_ret != NULL) *counter_ret=counter; if (h_ret != NULL) *h_ret=h; } if (ctx != NULL) BN_CTX_free(ctx); if (ctx2 != NULL) { BN_CTX_end(ctx2); BN_CTX_free(ctx2); } if (ctx3 != NULL) BN_CTX_free(ctx3); if (mont != NULL) BN_MONT_CTX_free(mont); return(ok?ret:NULL); }
static void eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData, const u8 *payload, size_t payload_len) { EC_POINT *K = NULL, *point = NULL; BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL; u16 offset; u8 *ptr, *scalar = NULL, *element = NULL; size_t prime_len, order_len; if (data->state != PWD_Commit_Req) { ret->ignore = TRUE; goto fin; } prime_len = BN_num_bytes(data->grp->prime); order_len = BN_num_bytes(data->grp->order); if (payload_len != 2 * prime_len + order_len) { wpa_printf(MSG_INFO, "EAP-pwd: Unexpected Commit payload length %u (expected %u)", (unsigned int) payload_len, (unsigned int) (2 * prime_len + order_len)); goto fin; } if (((data->private_value = BN_new()) == NULL) || ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || ((cofactor = BN_new()) == NULL) || ((data->my_scalar = BN_new()) == NULL) || ((mask = BN_new()) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail"); goto fin; } if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor " "for curve"); goto fin; } if (BN_rand_range(data->private_value, data->grp->order) != 1 || BN_rand_range(mask, data->grp->order) != 1 || BN_add(data->my_scalar, data->private_value, mask) != 1 || BN_mod(data->my_scalar, data->my_scalar, data->grp->order, data->bnctx) != 1) { wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get randomness"); goto fin; } if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, data->grp->pwe, mask, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation " "fail"); eap_pwd_state(data, FAILURE); goto fin; } if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); goto fin; } BN_clear_free(mask); if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail"); goto fin; } /* process the request */ if (((data->server_scalar = BN_new()) == NULL) || ((data->k = BN_new()) == NULL) || ((K = EC_POINT_new(data->grp->group)) == NULL) || ((point = EC_POINT_new(data->grp->group)) == NULL) || ((data->server_element = EC_POINT_new(data->grp->group)) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " "fail"); goto fin; } /* element, x then y, followed by scalar */ ptr = (u8 *) payload; BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); ptr += BN_num_bytes(data->grp->prime); BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); ptr += BN_num_bytes(data->grp->prime); BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar); if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, data->server_element, x, y, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " "fail"); goto fin; } /* check to ensure server's element is not in a small sub-group */ if (BN_cmp(cofactor, BN_value_one())) { if (!EC_POINT_mul(data->grp->group, point, NULL, data->server_element, cofactor, NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " "server element by order!\n"); goto fin; } if (EC_POINT_is_at_infinity(data->grp->group, point)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): server element " "is at infinity!\n"); goto fin; } } /* compute the shared key, k */ if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, data->server_scalar, data->bnctx)) || (!EC_POINT_add(data->grp->group, K, K, data->server_element, data->bnctx)) || (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, data->bnctx))) { wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " "fail"); goto fin; } /* ensure that the shared key isn't in a small sub-group */ if (BN_cmp(cofactor, BN_value_one())) { if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " "shared key point by order"); goto fin; } } /* * This check is strictly speaking just for the case above where * co-factor > 1 but it was suggested that even though this is probably * never going to happen it is a simple and safe check "just to be * sure" so let's be safe. */ if (EC_POINT_is_at_infinity(data->grp->group, K)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " "infinity!\n"); goto fin; } if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, NULL, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " "shared secret from point"); goto fin; } /* now do the response */ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, data->my_element, x, y, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); goto fin; } if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail"); goto fin; } /* * bignums occupy as little memory as possible so one that is * sufficiently smaller than the prime or order might need pre-pending * with zeros. */ os_memset(scalar, 0, BN_num_bytes(data->grp->order)); os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); offset = BN_num_bytes(data->grp->order) - BN_num_bytes(data->my_scalar); BN_bn2bin(data->my_scalar, scalar + offset); offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); BN_bn2bin(x, element + offset); offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) + 2 * BN_num_bytes(data->grp->prime)); if (data->outbuf == NULL) goto fin; /* we send the element as (x,y) follwed by the scalar */ wpabuf_put_data(data->outbuf, element, 2 * BN_num_bytes(data->grp->prime)); wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); fin: os_free(scalar); os_free(element); BN_clear_free(x); BN_clear_free(y); BN_clear_free(cofactor); EC_POINT_clear_free(K); EC_POINT_clear_free(point); if (data->outbuf == NULL) eap_pwd_state(data, FAILURE); else eap_pwd_state(data, PWD_Confirm_Req); }
int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) { if (!BN_add(r, a, b)) return 0; return BN_nnmod(r, r, m, ctx); }
static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd, const BIGNUM *rem, BN_CTX *ctx) { int i, ret = 0; BIGNUM *t1, *qadd, *q; bits--; BN_CTX_start(ctx); t1 = BN_CTX_get(ctx); q = BN_CTX_get(ctx); qadd = BN_CTX_get(ctx); if (qadd == NULL) { goto err; } if (!BN_rshift1(qadd, padd)) { goto err; } if (!BN_rand(q, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD)) { goto err; } /* we need ((rnd-rem) % add) == 0 */ if (!BN_mod(t1, q, qadd, ctx)) { goto err; } if (!BN_sub(q, q, t1)) { goto err; } if (rem == NULL) { if (!BN_add_word(q, 1)) { goto err; } } else { if (!BN_rshift1(t1, rem)) { goto err; } if (!BN_add(q, q, t1)) { goto err; } } /* we now have a random number 'rand' to test. */ if (!BN_lshift1(p, q)) { goto err; } if (!BN_add_word(p, 1)) { goto err; } loop: for (i = 1; i < NUMPRIMES; i++) { /* check that p and q are prime */ /* check that for p and q * gcd(p-1,primes) == 1 (except for 2) */ BN_ULONG pmod = BN_mod_word(p, (BN_ULONG)primes[i]); BN_ULONG qmod = BN_mod_word(q, (BN_ULONG)primes[i]); if (pmod == (BN_ULONG)-1 || qmod == (BN_ULONG)-1) { goto err; } if (pmod == 0 || qmod == 0) { if (!BN_add(p, p, padd)) { goto err; } if (!BN_add(q, q, qadd)) { goto err; } goto loop; } } ret = 1; err: BN_CTX_end(ctx); return ret; }
static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { assert(ctx != NULL); assert(rsa->n != NULL); assert(rsa->e != NULL); assert(rsa->d != NULL); assert(rsa->p != NULL); assert(rsa->q != NULL); assert(rsa->dmp1 != NULL); assert(rsa->dmq1 != NULL); assert(rsa->iqmp != NULL); BIGNUM *r1, *m1, *vrfy; BIGNUM local_dmp1, local_dmq1, local_c, local_r1; BIGNUM *dmp1, *dmq1, *c, *pr1; int ret = 0; size_t i, num_additional_primes = 0; if (rsa->additional_primes != NULL) { num_additional_primes = sk_RSA_additional_prime_num(rsa->additional_primes); } BN_CTX_start(ctx); r1 = BN_CTX_get(ctx); m1 = BN_CTX_get(ctx); vrfy = BN_CTX_get(ctx); if (r1 == NULL || m1 == NULL || vrfy == NULL) { goto err; } { BIGNUM local_p, local_q; BIGNUM *p = NULL, *q = NULL; /* Make sure BN_mod_inverse in Montgomery intialization uses the * BN_FLG_CONSTTIME flag. */ BN_init(&local_p); p = &local_p; BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); BN_init(&local_q); q = &local_q; BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME); if (!BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, p, ctx) || !BN_MONT_CTX_set_locked(&rsa->mont_q, &rsa->lock, q, ctx)) { goto err; } } if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx)) { goto err; } /* compute I mod q */ c = &local_c; BN_with_flags(c, I, BN_FLG_CONSTTIME); if (!BN_mod(r1, c, rsa->q, ctx)) { goto err; } /* compute r1^dmq1 mod q */ dmq1 = &local_dmq1; BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime(m1, r1, dmq1, rsa->q, ctx, rsa->mont_q)) { goto err; } /* compute I mod p */ c = &local_c; BN_with_flags(c, I, BN_FLG_CONSTTIME); if (!BN_mod(r1, c, rsa->p, ctx)) { goto err; } /* compute r1^dmp1 mod p */ dmp1 = &local_dmp1; BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime(r0, r1, dmp1, rsa->p, ctx, rsa->mont_p)) { goto err; } if (!BN_sub(r0, r0, m1)) { goto err; } /* This will help stop the size of r0 increasing, which does * affect the multiply if it optimised for a power of 2 size */ if (BN_is_negative(r0)) { if (!BN_add(r0, r0, rsa->p)) { goto err; } } if (!BN_mul(r1, r0, rsa->iqmp, ctx)) { goto err; } /* Turn BN_FLG_CONSTTIME flag on before division operation */ pr1 = &local_r1; BN_with_flags(pr1, r1, BN_FLG_CONSTTIME); if (!BN_mod(r0, pr1, rsa->p, ctx)) { goto err; } /* If p < q it is occasionally possible for the correction of * adding 'p' if r0 is negative above to leave the result still * negative. This can break the private key operations: the following * second correction should *always* correct this rare occurrence. * This will *never* happen with OpenSSL generated keys because * they ensure p > q [steve] */ if (BN_is_negative(r0)) { if (!BN_add(r0, r0, rsa->p)) { goto err; } } if (!BN_mul(r1, r0, rsa->q, ctx)) { goto err; } if (!BN_add(r0, r1, m1)) { goto err; } for (i = 0; i < num_additional_primes; i++) { /* multi-prime RSA. */ BIGNUM local_exp, local_prime; BIGNUM *exp = &local_exp, *prime = &local_prime; RSA_additional_prime *ap = sk_RSA_additional_prime_value(rsa->additional_primes, i); BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME); BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME); /* c will already point to a BIGNUM with the correct flags. */ if (!BN_mod(r1, c, prime, ctx)) { goto err; } if (!BN_MONT_CTX_set_locked(&ap->mont, &rsa->lock, prime, ctx) || !BN_mod_exp_mont_consttime(m1, r1, exp, prime, ctx, ap->mont)) { goto err; } BN_set_flags(m1, BN_FLG_CONSTTIME); if (!BN_sub(m1, m1, r0) || !BN_mul(m1, m1, ap->coeff, ctx) || !BN_mod(m1, m1, prime, ctx) || (BN_is_negative(m1) && !BN_add(m1, m1, prime)) || !BN_mul(m1, m1, ap->r, ctx) || !BN_add(r0, r0, m1)) { goto err; } } ret = 1; err: BN_CTX_end(ctx); return ret; }
int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) { int retn=0; #ifdef MONT_WORD BIGNUM *n,*r; BN_ULONG *ap,*np,*rp,n0,v,*nrp; int al,nl,max,i,x,ri; BN_CTX_start(ctx); if ((r = BN_CTX_get(ctx)) == NULL) goto err; if (!BN_copy(r,a)) goto err; n= &(mont->N); ap=a->d; /* mont->ri is the size of mont->N in bits (rounded up to the word size) */ al=ri=mont->ri/BN_BITS2; nl=n->top; if ((al == 0) || (nl == 0)) { r->top=0; return(1); } max=(nl+al+1); /* allow for overflow (no?) XXX */ if (bn_wexpand(r,max) == NULL) goto err; if (bn_wexpand(ret,max) == NULL) goto err; r->neg=a->neg^n->neg; np=n->d; rp=r->d; nrp= &(r->d[nl]); /* clear the top words of T */ #if 1 for (i=r->top; i<max; i++) /* memset? XXX */ r->d[i]=0; #else memset(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG)); #endif r->top=max; n0=mont->n0; #ifdef BN_COUNT fprintf(stderr,"word BN_from_montgomery %d * %d\n",nl,nl); #endif for (i=0; i<nl; i++) { #ifdef __TANDEM { long long t1; long long t2; long long t3; t1 = rp[0] * (n0 & 0177777); t2 = 037777600000l; t2 = n0 & t2; t3 = rp[0] & 0177777; t2 = (t3 * t2) & BN_MASK2; t1 = t1 + t2; v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1); } #else v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2); #endif nrp++; rp++; if (((nrp[-1]+=v)&BN_MASK2) >= v) continue; else { if (((++nrp[0])&BN_MASK2) != 0) continue; if (((++nrp[1])&BN_MASK2) != 0) continue; for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ; } } bn_fix_top(r); /* mont->ri will be a multiple of the word size */ #if 0 BN_rshift(ret,r,mont->ri); #else ret->neg = r->neg; x=ri; rp=ret->d; ap= &(r->d[x]); if (r->top < x) al=0; else al=r->top-x; ret->top=al; al-=4; for (i=0; i<al; i+=4) { BN_ULONG t1,t2,t3,t4; t1=ap[i+0]; t2=ap[i+1]; t3=ap[i+2]; t4=ap[i+3]; rp[i+0]=t1; rp[i+1]=t2; rp[i+2]=t3; rp[i+3]=t4; } al+=4; for (; i<al; i++) rp[i]=ap[i]; #endif #else /* !MONT_WORD */ BIGNUM *t1,*t2; BN_CTX_start(ctx); t1 = BN_CTX_get(ctx); t2 = BN_CTX_get(ctx); if (t1 == NULL || t2 == NULL) goto err; if (!BN_copy(t1,a)) goto err; BN_mask_bits(t1,mont->ri); if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err; BN_mask_bits(t2,mont->ri); if (!BN_mul(t1,t2,&mont->N,ctx)) goto err; if (!BN_add(t2,a,t1)) goto err; if (!BN_rshift(ret,t2,mont->ri)) goto err; #endif /* MONT_WORD */ if (BN_ucmp(ret, &(mont->N)) >= 0) { if (!BN_usub(ret,ret,&(mont->N))) goto err; } retn=1; err: BN_CTX_end(ctx); return(retn); }
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, const unsigned char *dgst, int dlen) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; EC_POINT *tmp_point=NULL; const EC_GROUP *group; int ret = 0; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_MALLOC_FAILURE); return 0; } } else ctx = ctx_in; k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ order = BN_new(); X = BN_new(); if (!k || !r || !order || !X) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); goto err; } if ((tmp_point = EC_POINT_new(group)) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (!EC_GROUP_get_order(group, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } do { /* get random k */ do #ifndef OPENSSL_NO_SHA512 if (dgst != NULL) { if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey), dgst, dlen, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } else #endif { if (!BN_rand_range(k, order)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } while (BN_is_zero(k)); /* We do not want timing information to leak the length of k, * so we compute G*k using an equivalent scalar of fixed * bit-length. */ if (!BN_add(k, k, order)) goto err; if (BN_num_bits(k) <= BN_num_bits(order)) if (!BN_add(k, k, order)) goto err; /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else /* NID_X9_62_characteristic_two_field */ { if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp_point, X, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(r, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); /* compute the inverse of k */ if (EC_GROUP_get_mont_data(group) != NULL) { /* We want inverse in constant time, therefore we utilize the * fact order must be prime and use Fermats Little Theorem * instead. */ if (!BN_set_word(X, 2) ) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } if (!BN_mod_sub(X, order, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } BN_set_flags(X, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime(k, k, X, order, ctx, EC_GROUP_get_mont_data(group))) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } else { if (!BN_mod_inverse(k, k, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } /* clear old values if necessary */ if (*rp != NULL) BN_clear_free(*rp); if (*kinvp != NULL) BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; *kinvp = k; ret = 1; err: if (!ret) { if (k != NULL) BN_clear_free(k); if (r != NULL) BN_clear_free(r); } if (ctx_in == NULL) BN_CTX_free(ctx); if (order != NULL) BN_free(order); if (tmp_point != NULL) EC_POINT_free(tmp_point); if (X) BN_clear_free(X); return(ret); }
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ECDSAerror(ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { ECDSAerror(ERR_R_MALLOC_FAILURE); return 0; } } else ctx = ctx_in; k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ order = BN_new(); X = BN_new(); if (!k || !r || !order || !X) { ECDSAerror(ERR_R_MALLOC_FAILURE); goto err; } if ((tmp_point = EC_POINT_new(group)) == NULL) { ECDSAerror(ERR_R_EC_LIB); goto err; } if (!EC_GROUP_get_order(group, order, ctx)) { ECDSAerror(ERR_R_EC_LIB); goto err; } do { /* get random k */ do if (!BN_rand_range(k, order)) { ECDSAerror(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } while (BN_is_zero(k)); /* We do not want timing information to leak the length of k, * so we compute G*k using an equivalent scalar of fixed * bit-length. */ if (!BN_add(k, k, order)) goto err; if (BN_num_bits(k) <= BN_num_bits(order)) if (!BN_add(k, k, order)) goto err; BN_set_flags(k, BN_FLG_CONSTTIME); /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ECDSAerror(ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) { ECDSAerror(ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else /* NID_X9_62_characteristic_two_field */ { if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp_point, X, NULL, ctx)) { ECDSAerror(ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(r, X, order, ctx)) { ECDSAerror(ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); /* compute the inverse of k */ if (!BN_mod_inverse_ct(k, k, order, ctx)) { ECDSAerror(ERR_R_BN_LIB); goto err; } /* clear old values if necessary */ BN_clear_free(*rp); BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; *kinvp = k; ret = 1; err: if (!ret) { BN_clear_free(k); BN_clear_free(r); } if (ctx_in == NULL) BN_CTX_free(ctx); BN_free(order); EC_POINT_free(tmp_point); BN_clear_free(X); return (ret); }
bigint bigint::operator + ( const bigint& a )const { bigint tmp(*this); BN_add( tmp.n, n, a.n ); return tmp; }
static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, const uint8_t *digest, size_t digest_len) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *kinv = NULL, *r = NULL, *tmp = NULL; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); return 0; } } else { ctx = ctx_in; } k = BN_new(); kinv = BN_new(); // this value is later returned in *kinvp r = BN_new(); // this value is later returned in *rp tmp = BN_new(); if (k == NULL || kinv == NULL || r == NULL || tmp == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); goto err; } tmp_point = EC_POINT_new(group); if (tmp_point == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } const BIGNUM *order = EC_GROUP_get0_order(group); // Check that the size of the group order is FIPS compliant (FIPS 186-4 // B.5.2). if (BN_num_bits(order) < 160) { OPENSSL_PUT_ERROR(ECDSA, EC_R_INVALID_GROUP_ORDER); goto err; } do { // If possible, we'll include the private key and message digest in the k // generation. The |digest| argument is only empty if |ECDSA_sign_setup| is // being used. if (eckey->fixed_k != NULL) { if (!BN_copy(k, eckey->fixed_k)) { goto err; } } else if (digest_len > 0) { do { if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey), digest, digest_len, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } while (BN_is_zero(k)); } else if (!BN_rand_range_ex(k, 1, order)) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } // Compute the inverse of k. The order is a prime, so use Fermat's Little // Theorem. Note |ec_group_get_order_mont| may return NULL but // |bn_mod_inverse_prime| allows this. if (!bn_mod_inverse_prime(kinv, k, order, ctx, ec_group_get_order_mont(group))) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } // We do not want timing information to leak the length of k, // so we compute G*k using an equivalent scalar of fixed // bit-length. if (!BN_add(k, k, order)) { goto err; } if (BN_num_bits(k) <= BN_num_bits(order)) { if (!BN_add(k, k, order)) { goto err; } } // compute r the x-coordinate of generator * k if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, tmp, NULL, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } if (!BN_nnmod(r, tmp, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); // clear old values if necessary BN_clear_free(*rp); BN_clear_free(*kinvp); // save the pre-computed values *rp = r; *kinvp = kinv; ret = 1; err: BN_clear_free(k); if (!ret) { BN_clear_free(kinv); BN_clear_free(r); } if (ctx_in == NULL) { BN_CTX_free(ctx); } EC_POINT_free(tmp_point); BN_clear_free(tmp); return ret; }
static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { BIGNUM *r1,*m1,*vrfy; BIGNUM local_dmp1,local_dmq1,local_c,local_r1; BIGNUM *dmp1,*dmq1,*c,*pr1; int ret=0; BN_CTX_start(ctx); r1 = BN_CTX_get(ctx); m1 = BN_CTX_get(ctx); vrfy = BN_CTX_get(ctx); { BIGNUM local_p, local_q; BIGNUM *p = NULL, *q = NULL; /* Make sure BN_mod_inverse in Montgomery intialization uses the * BN_FLG_CONSTTIME flag (unless RSA_FLAG_NO_CONSTTIME is set) */ if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { BN_init(&local_p); p = &local_p; BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); BN_init(&local_q); q = &local_q; BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME); } else { p = rsa->p; q = rsa->q; } if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) { if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_p, CRYPTO_LOCK_RSA, p, ctx)) goto err; if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_q, CRYPTO_LOCK_RSA, q, ctx)) goto err; } } if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n, ctx)) goto err; /* compute I mod q */ if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { c = &local_c; BN_with_flags(c, I, BN_FLG_CONSTTIME); if (!BN_mod(r1,c,rsa->q,ctx)) goto err; } else { if (!BN_mod(r1,I,rsa->q,ctx)) goto err; } /* compute r1^dmq1 mod q */ if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { dmq1 = &local_dmq1; BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME); } else dmq1 = rsa->dmq1; if (!rsa->meth->bn_mod_exp(m1,r1,dmq1,rsa->q,ctx, rsa->_method_mod_q)) goto err; /* compute I mod p */ if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { c = &local_c; BN_with_flags(c, I, BN_FLG_CONSTTIME); if (!BN_mod(r1,c,rsa->p,ctx)) goto err; } else { if (!BN_mod(r1,I,rsa->p,ctx)) goto err; } /* compute r1^dmp1 mod p */ if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { dmp1 = &local_dmp1; BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME); } else dmp1 = rsa->dmp1; if (!rsa->meth->bn_mod_exp(r0,r1,dmp1,rsa->p,ctx, rsa->_method_mod_p)) goto err; if (!BN_sub(r0,r0,m1)) goto err; /* This will help stop the size of r0 increasing, which does * affect the multiply if it optimised for a power of 2 size */ if (BN_is_negative(r0)) if (!BN_add(r0,r0,rsa->p)) goto err; if (!BN_mul(r1,r0,rsa->iqmp,ctx)) goto err; /* Turn BN_FLG_CONSTTIME flag on before division operation */ if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { pr1 = &local_r1; BN_with_flags(pr1, r1, BN_FLG_CONSTTIME); } else pr1 = r1; if (!BN_mod(r0,pr1,rsa->p,ctx)) goto err; /* If p < q it is occasionally possible for the correction of * adding 'p' if r0 is negative above to leave the result still * negative. This can break the private key operations: the following * second correction should *always* correct this rare occurrence. * This will *never* happen with OpenSSL generated keys because * they ensure p > q [steve] */ if (BN_is_negative(r0)) if (!BN_add(r0,r0,rsa->p)) goto err; if (!BN_mul(r1,r0,rsa->q,ctx)) goto err; if (!BN_add(r0,r1,m1)) goto err; if (rsa->e && rsa->n) { if (!rsa->meth->bn_mod_exp(vrfy,r0,rsa->e,rsa->n,ctx,rsa->_method_mod_n)) goto err; /* If 'I' was greater than (or equal to) rsa->n, the operation * will be equivalent to using 'I mod n'. However, the result of * the verify will *always* be less than 'n' so we don't check * for absolute equality, just congruency. */ if (!BN_sub(vrfy, vrfy, I)) goto err; if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) goto err; if (BN_is_negative(vrfy)) if (!BN_add(vrfy, vrfy, rsa->n)) goto err; if (!BN_is_zero(vrfy)) { /* 'I' and 'vrfy' aren't congruent mod n. Don't leak * miscalculated CRT output, just do a raw (slower) * mod_exp and return that instead. */ BIGNUM local_d; BIGNUM *d = NULL; if (!(rsa->flags & RSA_FLAG_NO_CONSTTIME)) { d = &local_d; BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); } else d = rsa->d; if (!rsa->meth->bn_mod_exp(r0,I,d,rsa->n,ctx, rsa->_method_mod_n)) goto err; } } ret=1; err: BN_CTX_end(ctx); return(ret); }
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift,i,j,loop; BIGNUM *tmp,wnum,*snum,*sdiv,*res; BN_ULONG *resp,*wnump; BN_ULONG d0,d1; int num_n,div_n; bn_check_top(num); bn_check_top(divisor); if (BN_is_zero(divisor)) { BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); return(0); } if (BN_ucmp(num,divisor) < 0) { if (rm != NULL) { if (BN_copy(rm,num) == NULL) return(0); } if (dv != NULL) BN_zero(dv); return(1); } BN_CTX_start(ctx); tmp=BN_CTX_get(ctx); snum=BN_CTX_get(ctx); sdiv=BN_CTX_get(ctx); if (dv == NULL) res=BN_CTX_get(ctx); else res=dv; if (sdiv==NULL || res == NULL) goto err; tmp->neg=0; /* First we normalise the numbers */ norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err; sdiv->neg=0; norm_shift+=BN_BITS2; if (!(BN_lshift(snum,num,norm_shift))) goto err; snum->neg=0; div_n=sdiv->top; num_n=snum->top; loop=num_n-div_n; /* Lets setup a 'window' into snum * This is the part that corresponds to the current * 'area' being divided */ BN_init(&wnum); wnum.d= &(snum->d[loop]); wnum.top= div_n; wnum.dmax= snum->dmax+1; /* a bit of a lie */ /* Get the top 2 words of sdiv */ /* i=sdiv->top; */ d0=sdiv->d[div_n-1]; d1=(div_n == 1)?0:sdiv->d[div_n-2]; /* pointer to the 'top' of snum */ wnump= &(snum->d[num_n-1]); /* Setup to 'res' */ res->neg= (num->neg^divisor->neg); if (!bn_wexpand(res,(loop+1))) goto err; res->top=loop; resp= &(res->d[loop-1]); /* space for temp */ if (!bn_wexpand(tmp,(div_n+1))) goto err; if (BN_ucmp(&wnum,sdiv) >= 0) { if (!BN_usub(&wnum,&wnum,sdiv)) goto err; *resp=1; res->d[res->top-1]=1; } else res->top--; resp--; for (i=0; i<loop-1; i++) { BN_ULONG q,l0; #if defined(BN_DIV3W) && !defined(NO_ASM) BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG); q=bn_div_3_words(wnump,d1,d0); #else BN_ULONG n0,n1,rem=0; n0=wnump[0]; n1=wnump[-1]; if (n0 == d0) q=BN_MASK2; else /* n0 < d0 */ { #ifdef BN_LLONG BN_ULLONG t2; #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0); #else q=bn_div_words(n0,n1,d0); #endif #ifndef REMAINDER_IS_ALREADY_CALCULATED /* * rem doesn't have to be BN_ULLONG. The least we * know it's less that d0, isn't it? */ rem=(n1-q*d0)&BN_MASK2; #endif t2=(BN_ULLONG)d1*q; for (;;) { if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2])) break; q--; rem += d0; if (rem < d0) break; /* don't let rem overflow */ t2 -= d1; } #else /* !BN_LLONG */ BN_ULONG t2l,t2h,ql,qh; q=bn_div_words(n0,n1,d0); #ifndef REMAINDER_IS_ALREADY_CALCULATED rem=(n1-q*d0)&BN_MASK2; #endif #ifdef BN_UMULT_HIGH t2l = d1 * q; t2h = BN_UMULT_HIGH(d1,q); #else t2l=LBITS(d1); t2h=HBITS(d1); ql =LBITS(q); qh =HBITS(q); mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ #endif for (;;) { if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) break; q--; rem += d0; if (rem < d0) break; /* don't let rem overflow */ if (t2l < d1) t2h--; t2l -= d1; } #endif /* !BN_LLONG */ } #endif /* !BN_DIV3W */ l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); wnum.d--; wnum.top++; tmp->d[div_n]=l0; for (j=div_n+1; j>0; j--) if (tmp->d[j-1]) break; tmp->top=j; j=wnum.top; if (!BN_sub(&wnum,&wnum,tmp)) goto err; snum->top=snum->top+wnum.top-j; if (wnum.neg) { q--; j=wnum.top; if (!BN_add(&wnum,&wnum,sdiv)) goto err; snum->top+=wnum.top-j; } *(resp--)=q; wnump--; } if (rm != NULL) { BN_rshift(rm,snum,norm_shift); rm->neg=num->neg; } BN_CTX_end(ctx); return(1); err: BN_CTX_end(ctx); return(0); }
static int RSA_eay_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { BIGNUM *r1,*m1,*vrfy; BIGNUM local_dmp1, local_dmq1; BIGNUM *dmp1, *dmq1; int ret=0; BN_CTX_start(ctx); r1 = BN_CTX_get(ctx); m1 = BN_CTX_get(ctx); vrfy = BN_CTX_get(ctx); MONT_HELPER(rsa, ctx, p, rsa->flags & RSA_FLAG_CACHE_PRIVATE, goto err); MONT_HELPER(rsa, ctx, q, rsa->flags & RSA_FLAG_CACHE_PRIVATE, goto err); MONT_HELPER(rsa, ctx, n, rsa->flags & RSA_FLAG_CACHE_PUBLIC, goto err); if (!BN_mod(r1,I,rsa->q,ctx)) goto err; if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME)) { dmq1 = &local_dmq1; BN_with_flags(dmq1, rsa->dmq1, BN_FLG_EXP_CONSTTIME); } else dmq1 = rsa->dmq1; if (!rsa->meth->bn_mod_exp(m1,r1,dmq1,rsa->q,ctx, rsa->_method_mod_q)) goto err; if (!BN_mod(r1,I,rsa->p,ctx)) goto err; if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME)) { dmp1 = &local_dmp1; BN_with_flags(dmp1, rsa->dmp1, BN_FLG_EXP_CONSTTIME); } else dmp1 = rsa->dmp1; if (!rsa->meth->bn_mod_exp(r0,r1,dmp1,rsa->p,ctx, rsa->_method_mod_p)) goto err; if (!BN_sub(r0,r0,m1)) goto err; /* This will help stop the size of r0 increasing, which does * affect the multiply if it optimised for a power of 2 size */ if (BN_is_negative(r0)) if (!BN_add(r0,r0,rsa->p)) goto err; if (!BN_mul(r1,r0,rsa->iqmp,ctx)) goto err; if (!BN_mod(r0,r1,rsa->p,ctx)) goto err; /* If p < q it is occasionally possible for the correction of * adding 'p' if r0 is negative above to leave the result still * negative. This can break the private key operations: the following * second correction should *always* correct this rare occurrence. * This will *never* happen with OpenSSL generated keys because * they ensure p > q [steve] */ if (BN_is_negative(r0)) if (!BN_add(r0,r0,rsa->p)) goto err; if (!BN_mul(r1,r0,rsa->q,ctx)) goto err; if (!BN_add(r0,r1,m1)) goto err; if (rsa->e && rsa->n) { if (!rsa->meth->bn_mod_exp(vrfy,r0,rsa->e,rsa->n,ctx,rsa->_method_mod_n)) goto err; /* If 'I' was greater than (or equal to) rsa->n, the operation * will be equivalent to using 'I mod n'. However, the result of * the verify will *always* be less than 'n' so we don't check * for absolute equality, just congruency. */ if (!BN_sub(vrfy, vrfy, I)) goto err; if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) goto err; if (BN_is_negative(vrfy)) if (!BN_add(vrfy, vrfy, rsa->n)) goto err; if (!BN_is_zero(vrfy)) { /* 'I' and 'vrfy' aren't congruent mod n. Don't leak * miscalculated CRT output, just do a raw (slower) * mod_exp and return that instead. */ BIGNUM local_d; BIGNUM *d = NULL; if (!(rsa->flags & RSA_FLAG_NO_EXP_CONSTTIME)) { d = &local_d; BN_with_flags(d, rsa->d, BN_FLG_EXP_CONSTTIME); } else d = rsa->d; if (!rsa->meth->bn_mod_exp(r0,I,d,rsa->n,ctx, rsa->_method_mod_n)) goto err; } } ret=1; err: BN_CTX_end(ctx); return(ret); }
static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd, const BIGNUM *rem, BN_CTX *ctx) { int i, ret = 0; BIGNUM *t1, *qadd, *q; bits--; BN_CTX_start(ctx); t1 = BN_CTX_get(ctx); q = BN_CTX_get(ctx); qadd = BN_CTX_get(ctx); if (qadd == NULL) goto err; if (!BN_rshift1(qadd, padd)) goto err; if (!BN_rand(q, bits, 0, 1)) goto err; /* we need ((rnd-rem) % add) == 0 */ if (!BN_mod(t1, q, qadd, ctx)) goto err; if (!BN_sub(q, q, t1)) goto err; if (rem == NULL) { if (!BN_add_word(q, 1)) goto err; } else { if (!BN_rshift1(t1, rem)) goto err; if (!BN_add(q, q, t1)) goto err; } /* we now have a random number 'rand' to test. */ if (!BN_lshift1(p, q)) goto err; if (!BN_add_word(p, 1)) goto err; loop: for (i = 1; i < NUMPRIMES; i++) { /* check that p and q are prime */ /* * check that for p and q gcd(p-1,primes) == 1 (except for 2) */ if ((BN_mod_word(p, (BN_ULONG)primes[i]) == 0) || (BN_mod_word(q, (BN_ULONG)primes[i]) == 0)) { if (!BN_add(p, p, padd)) goto err; if (!BN_add(q, q, qadd)) goto err; goto loop; } } ret = 1; err: BN_CTX_end(ctx); bn_check_top(p); return (ret); }
static int vg_prefix_context_add_patterns(vg_context_t *vcp, const char ** const patterns, int npatterns) { vg_prefix_context_t *vcpp = (vg_prefix_context_t *) vcp; prefix_case_iter_t caseiter; vg_prefix_t *vp, *vp2; BN_CTX *bnctx; BIGNUM bntmp, bntmp2, bntmp3; BIGNUM *ranges[4]; int ret = 0; int i, impossible = 0; int case_impossible; unsigned long npfx; char *dbuf; bnctx = BN_CTX_new(); BN_init(&bntmp); BN_init(&bntmp2); BN_init(&bntmp3); npfx = 0; for (i = 0; i < npatterns; i++) { if (!vcpp->vcp_caseinsensitive) { vp = NULL; ret = get_prefix_ranges(vcpp->base.vc_addrtype, patterns[i], ranges, bnctx); if (!ret) { vp = vg_prefix_add_ranges(&vcpp->vcp_avlroot, patterns[i], ranges, NULL); } } else { /* Case-enumerate the prefix */ if (!prefix_case_iter_init(&caseiter, patterns[i])) { fprintf(stderr, "Prefix '%s' is too long\n", patterns[i]); continue; } if (caseiter.ci_nbits > 16) { fprintf(stderr, "WARNING: Prefix '%s' has " "2^%d case-varied derivatives\n", patterns[i], caseiter.ci_nbits); } case_impossible = 0; vp = NULL; do { ret = get_prefix_ranges(vcpp->base.vc_addrtype, caseiter.ci_prefix, ranges, bnctx); if (ret == -2) { case_impossible++; ret = 0; continue; } if (ret) break; vp2 = vg_prefix_add_ranges(&vcpp->vcp_avlroot, patterns[i], ranges, vp); if (!vp2) { ret = -1; break; } if (!vp) vp = vp2; } while (prefix_case_iter_next(&caseiter)); if (!vp && case_impossible) ret = -2; if (ret && vp) { vg_prefix_delete(&vcpp->vcp_avlroot, vp); vp = NULL; } } if (ret == -2) { fprintf(stderr, "Prefix '%s' not possible\n", patterns[i]); impossible++; } if (!vp) continue; npfx++; /* Determine the probability of finding a match */ vg_prefix_range_sum(vp, &bntmp, &bntmp2); BN_add(&bntmp2, &vcpp->vcp_difficulty, &bntmp); BN_copy(&vcpp->vcp_difficulty, &bntmp2); if (vcp->vc_verbose > 1) { BN_clear(&bntmp2); BN_set_bit(&bntmp2, 192); BN_div(&bntmp3, NULL, &bntmp2, &bntmp, bnctx); dbuf = BN_bn2dec(&bntmp3); fprintf(stderr, "Prefix difficulty: %20s %s\n", dbuf, patterns[i]); OPENSSL_free(dbuf); } } vcpp->base.vc_npatterns += npfx; vcpp->base.vc_npatterns_start += npfx; if (!npfx && impossible) { const char *ats = "bitcoin", *bw = "\"1\""; switch (vcpp->base.vc_addrtype) { case 5: ats = "bitcoin script"; bw = "\"3\""; break; case 111: ats = "testnet"; bw = "\"m\" or \"n\""; break; case 52: ats = "namecoin"; bw = "\"M\" or \"N\""; break; default: break; } fprintf(stderr, "Hint: valid %s addresses begin with %s\n", ats, bw); } if (npfx) vg_prefix_context_next_difficulty(vcpp, &bntmp, &bntmp2, bnctx); ret = (npfx != 0); BN_clear_free(&bntmp); BN_clear_free(&bntmp2); BN_clear_free(&bntmp3); BN_CTX_free(bnctx); return ret; }
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; int order_bits; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); return 0; } } else ctx = ctx_in; k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ order = BN_new(); X = BN_new(); if (!k || !r || !order || !X) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); goto err; } if ((tmp_point = EC_POINT_new(group)) == NULL) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (!EC_GROUP_get_order(group, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } /* Preallocate space */ order_bits = BN_num_bits(order); if (!BN_set_bit(k, order_bits) || !BN_set_bit(r, order_bits) || !BN_set_bit(X, order_bits)) goto err; do { /* get random k */ do if (!BN_rand_range(k, order)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } while (BN_is_zero(k)) ; /* * We do not want timing information to leak the length of k, so we * compute G*k using an equivalent scalar of fixed bit-length. * * We unconditionally perform both of these additions to prevent a * small timing information leakage. We then choose the sum that is * one bit longer than the order. This guarantees the code * path used in the constant time implementations elsewhere. * * TODO: revisit the BN_copy aiming for a memory access agnostic * conditional copy. */ if (!BN_add(r, k, order) || !BN_add(X, r, order) || !BN_copy(k, BN_num_bits(r) > order_bits ? r : X)) goto err; /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp (group, tmp_point, X, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else { /* NID_X9_62_characteristic_two_field */ if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp_point, X, NULL, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(r, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); /* compute the inverse of k */ if (EC_GROUP_get_mont_data(group) != NULL) { /* * We want inverse in constant time, therefore we utilize the fact * order must be prime and use Fermats Little Theorem instead. */ if (!BN_set_word(X, 2)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } if (!BN_mod_sub(X, order, X, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } BN_set_flags(X, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime (k, k, X, order, ctx, EC_GROUP_get_mont_data(group))) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } else { if (!BN_mod_inverse(k, k, order, ctx)) { ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } /* clear old values if necessary */ if (*rp != NULL) BN_clear_free(*rp); if (*kinvp != NULL) BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; *kinvp = k; ret = 1; err: if (!ret) { if (k != NULL) BN_clear_free(k); if (r != NULL) BN_clear_free(r); } if (ctx_in == NULL) BN_CTX_free(ctx); if (order != NULL) BN_free(order); if (tmp_point != NULL) EC_POINT_free(tmp_point); if (X) BN_clear_free(X); return (ret); }
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields // recid selects which key is recovered // if check is non-zero, additional checks are performed int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) { if (!eckey) return 0; int ret = 0; BN_CTX *ctx = NULL; BIGNUM *x = NULL; BIGNUM *e = NULL; BIGNUM *order = NULL; BIGNUM *sor = NULL; BIGNUM *eor = NULL; BIGNUM *field = NULL; EC_POINT *R = NULL; EC_POINT *O = NULL; EC_POINT *Q = NULL; BIGNUM *rr = NULL; BIGNUM *zero = NULL; int n = 0; int i = recid / 2; const EC_GROUP *group = EC_KEY_get0_group(eckey); if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } BN_CTX_start(ctx); order = BN_CTX_get(ctx); if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } x = BN_CTX_get(ctx); if (!BN_copy(x, order)) { ret=-1; goto err; } if (!BN_mul_word(x, i)) { ret=-1; goto err; } if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } field = BN_CTX_get(ctx); if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } if (BN_cmp(x, field) >= 0) { ret=0; goto err; } if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } if (check) { if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } } if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } n = EC_GROUP_get_degree(group); e = BN_CTX_get(ctx); if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); zero = BN_CTX_get(ctx); if (!BN_zero(zero)) { ret=-1; goto err; } if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } rr = BN_CTX_get(ctx); if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } sor = BN_CTX_get(ctx); if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } eor = BN_CTX_get(ctx); if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } ret = 1; err: if (ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } if (R != NULL) EC_POINT_free(R); if (O != NULL) EC_POINT_free(O); if (Q != NULL) EC_POINT_free(Q); return ret; }
/* Out: bytes_B, len_B. * * On failure, bytes_B will be set to NULL and len_B will be set to 0 */ struct SRPVerifier * srp_verifier_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * bytes_s, int len_s, const unsigned char * bytes_v, int len_v, const unsigned char * bytes_A, int len_A, const unsigned char ** bytes_B, int * len_B, const char * n_hex, const char * g_hex ) { BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); BIGNUM *v = BN_bin2bn(bytes_v, len_v, NULL); BIGNUM *A = BN_bin2bn(bytes_A, len_A, NULL); BIGNUM *u = 0; BIGNUM *B = BN_new(); BIGNUM *S = BN_new(); BIGNUM *b = BN_new(); BIGNUM *k = 0; BIGNUM *tmp1 = BN_new(); BIGNUM *tmp2 = BN_new(); BN_CTX *ctx = BN_CTX_new(); int ulen = strlen(username) + 1; NGConstant *ng = new_ng( ng_type, n_hex, g_hex ); struct SRPVerifier * ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) ); init_random(); /* Only happens once */ ver->username = (char *) malloc( ulen ); ver->hash_alg = alg; ver->ng = ng; memcpy( (char*)ver->username, username, ulen ); ver->authenticated = 0; /* SRP-6a safety check */ BN_mod(tmp1, A, ng->N, ctx); if ( !BN_is_zero(tmp1) ) { BN_rand(b, 256, -1, 0); k = H_nn(alg, ng->N, ng->g); /* B = kv + g^b */ BN_mul(tmp1, k, v, ctx); BN_mod_exp(tmp2, ng->g, b, ng->N, ctx); BN_add(B, tmp1, tmp2); u = H_nn(alg, A, B); /* S = (A *(v^u)) ^ b */ BN_mod_exp(tmp1, v, u, ng->N, ctx); BN_mul(tmp2, A, tmp1, ctx); BN_mod_exp(S, tmp2, b, ng->N, ctx); hash_num(alg, S, ver->session_key); calculate_M( alg, ng, ver->M, username, s, A, B, ver->session_key ); calculate_H_AMK( alg, ver->H_AMK, A, ver->M, ver->session_key ); *len_B = BN_num_bytes(B); *bytes_B = (const unsigned char *) malloc( *len_B ); BN_bn2bin( B, (unsigned char *) *bytes_B ); ver->bytes_B = *bytes_B; } else { *len_B = 0; *bytes_B = NULL; } BN_free(s); BN_free(v); BN_free(A); if (u) BN_free(u); if (k) BN_free(k); BN_free(B); BN_free(S); BN_free(b); BN_free(tmp1); BN_free(tmp2); BN_CTX_free(ctx); return ver; }
static void eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) { BIGNUM *mask = NULL, *x = NULL, *y = NULL; u8 *scalar = NULL, *element = NULL; u16 offset; wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request"); /* * if we're fragmenting then we already have an commit request, just * return */ if (data->out_frag_pos) return; if (((data->private_value = BN_new()) == NULL) || ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || ((data->my_scalar = BN_new()) == NULL) || ((mask = BN_new()) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation " "fail"); goto fin; } if (BN_rand_range(data->private_value, data->grp->order) != 1 || BN_rand_range(mask, data->grp->order) != 1 || BN_add(data->my_scalar, data->private_value, mask) != 1 || BN_mod(data->my_scalar, data->my_scalar, data->grp->order, data->bnctx) != 1) { wpa_printf(MSG_INFO, "EAP-pwd (server): unable to get randomness"); goto fin; } if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, data->grp->pwe, mask, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation " "fail"); eap_pwd_state(data, FAILURE); goto fin; } if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion " "fail"); goto fin; } BN_clear_free(mask); if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation " "fail"); goto fin; } if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, data->my_element, x, y, data->bnctx)) { wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " "fail"); goto fin; } if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == NULL)) { wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); goto fin; } /* * bignums occupy as little memory as possible so one that is * sufficiently smaller than the prime or order might need pre-pending * with zeros. */ os_memset(scalar, 0, BN_num_bytes(data->grp->order)); os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); offset = BN_num_bytes(data->grp->order) - BN_num_bytes(data->my_scalar); BN_bn2bin(data->my_scalar, scalar + offset); offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); BN_bn2bin(x, element + offset); offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) + BN_num_bytes(data->grp->order)); if (data->outbuf == NULL) goto fin; /* We send the element as (x,y) followed by the scalar */ wpabuf_put_data(data->outbuf, element, 2 * BN_num_bytes(data->grp->prime)); wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order)); fin: os_free(scalar); os_free(element); BN_clear_free(x); BN_clear_free(y); if (data->outbuf == NULL) eap_pwd_state(data, FAILURE); }
/* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */ void srp_user_process_challenge( struct SRPUser * usr, const unsigned char * bytes_s, int len_s, const unsigned char * bytes_B, int len_B, const unsigned char ** bytes_M, int * len_M ) { BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); BIGNUM *B = BN_bin2bn(bytes_B, len_B, NULL); BIGNUM *u = 0; BIGNUM *x = 0; BIGNUM *k = 0; BIGNUM *v = BN_new(); BIGNUM *tmp1 = BN_new(); BIGNUM *tmp2 = BN_new(); BIGNUM *tmp3 = BN_new(); BN_CTX *ctx = BN_CTX_new(); u = H_nn(usr->hash_alg, usr->A, B); x = calculate_x( usr->hash_alg, s, usr->username, usr->password, usr->password_len ); k = H_nn(usr->hash_alg, usr->ng->N, usr->ng->g); /* SRP-6a safety check */ if ( !BN_is_zero(B) && !BN_is_zero(u) ) { BN_mod_exp(v, usr->ng->g, x, usr->ng->N, ctx); /* S = (B - k*(g^x)) ^ (a + ux) */ BN_mul(tmp1, u, x, ctx); BN_add(tmp2, usr->a, tmp1); /* tmp2 = (a + ux) */ BN_mod_exp(tmp1, usr->ng->g, x, usr->ng->N, ctx); BN_mul(tmp3, k, tmp1, ctx); /* tmp3 = k*(g^x) */ BN_sub(tmp1, B, tmp3); /* tmp1 = (B - K*(g^x)) */ BN_mod_exp(usr->S, tmp1, tmp2, usr->ng->N, ctx); hash_num(usr->hash_alg, usr->S, usr->session_key); calculate_M( usr->hash_alg, usr->ng, usr->M, usr->username, s, usr->A, B, usr->session_key ); calculate_H_AMK( usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key ); *bytes_M = usr->M; if (len_M) *len_M = hash_length( usr->hash_alg ); } else { *bytes_M = NULL; if (len_M) *len_M = 0; } BN_free(s); BN_free(B); BN_free(u); BN_free(x); BN_free(k); BN_free(v); BN_free(tmp1); BN_free(tmp2); BN_free(tmp3); BN_CTX_free(ctx); }
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; int ret = 0; if (a == b) return EC_POINT_dbl(group, r, a, ctx); if (EC_POINT_is_at_infinity(group, a)) return EC_POINT_copy(r, b); if (EC_POINT_is_at_infinity(group, b)) return EC_POINT_copy(r, a); field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); n4 = BN_CTX_get(ctx); n5 = BN_CTX_get(ctx); n6 = BN_CTX_get(ctx); if (n6 == NULL) goto end; /* * Note that in this function we must not read components of 'a' or 'b' * once we have written the corresponding components of 'r'. ('r' might * be one of 'a' or 'b'.) */ /* n1, n2 */ if (b->Z_is_one) { if (!BN_copy(n1, a->X)) goto end; if (!BN_copy(n2, a->Y)) goto end; /* n1 = X_a */ /* n2 = Y_a */ } else { if (!field_sqr(group, n0, b->Z, ctx)) goto end; if (!field_mul(group, n1, a->X, n0, ctx)) goto end; /* n1 = X_a * Z_b^2 */ if (!field_mul(group, n0, n0, b->Z, ctx)) goto end; if (!field_mul(group, n2, a->Y, n0, ctx)) goto end; /* n2 = Y_a * Z_b^3 */ } /* n3, n4 */ if (a->Z_is_one) { if (!BN_copy(n3, b->X)) goto end; if (!BN_copy(n4, b->Y)) goto end; /* n3 = X_b */ /* n4 = Y_b */ } else { if (!field_sqr(group, n0, a->Z, ctx)) goto end; if (!field_mul(group, n3, b->X, n0, ctx)) goto end; /* n3 = X_b * Z_a^2 */ if (!field_mul(group, n0, n0, a->Z, ctx)) goto end; if (!field_mul(group, n4, b->Y, n0, ctx)) goto end; /* n4 = Y_b * Z_a^3 */ } /* n5, n6 */ if (!BN_mod_sub_quick(n5, n1, n3, p)) goto end; if (!BN_mod_sub_quick(n6, n2, n4, p)) goto end; /* n5 = n1 - n3 */ /* n6 = n2 - n4 */ if (BN_is_zero(n5)) { if (BN_is_zero(n6)) { /* a is the same point as b */ BN_CTX_end(ctx); ret = EC_POINT_dbl(group, r, a, ctx); ctx = NULL; goto end; } else { /* a is the inverse of b */ BN_zero(r->Z); r->Z_is_one = 0; ret = 1; goto end; } } /* 'n7', 'n8' */ if (!BN_mod_add_quick(n1, n1, n3, p)) goto end; if (!BN_mod_add_quick(n2, n2, n4, p)) goto end; /* 'n7' = n1 + n3 */ /* 'n8' = n2 + n4 */ /* Z_r */ if (a->Z_is_one && b->Z_is_one) { if (!BN_copy(r->Z, n5)) goto end; } else { if (a->Z_is_one) { if (!BN_copy(n0, b->Z)) goto end; } else if (b->Z_is_one) { if (!BN_copy(n0, a->Z)) goto end; } else { if (!field_mul(group, n0, a->Z, b->Z, ctx)) goto end; } if (!field_mul(group, r->Z, n0, n5, ctx)) goto end; } r->Z_is_one = 0; /* Z_r = Z_a * Z_b * n5 */ /* X_r */ if (!field_sqr(group, n0, n6, ctx)) goto end; if (!field_sqr(group, n4, n5, ctx)) goto end; if (!field_mul(group, n3, n1, n4, ctx)) goto end; if (!BN_mod_sub_quick(r->X, n0, n3, p)) goto end; /* X_r = n6^2 - n5^2 * 'n7' */ /* 'n9' */ if (!BN_mod_lshift1_quick(n0, r->X, p)) goto end; if (!BN_mod_sub_quick(n0, n3, n0, p)) goto end; /* n9 = n5^2 * 'n7' - 2 * X_r */ /* Y_r */ if (!field_mul(group, n0, n0, n6, ctx)) goto end; if (!field_mul(group, n5, n4, n5, ctx)) goto end; /* now n5 is n5^3 */ if (!field_mul(group, n1, n2, n5, ctx)) goto end; if (!BN_mod_sub_quick(n0, n0, n1, p)) goto end; if (BN_is_odd(n0)) if (!BN_add(n0, n0, p)) goto end; /* now 0 <= n0 < 2*p, and n0 is even */ if (!BN_rshift1(r->Y, n0)) goto end; /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ ret = 1; end: if (ctx) /* otherwise we already called BN_CTX_end */ BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
/* * Computes gost_ec signature as DSA_SIG structure * */ DSA_SIG *gost_ec_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey) { DSA_SIG *newsig = NULL, *ret = NULL; BIGNUM *md = NULL; BIGNUM *order = NULL; const EC_GROUP *group; const BIGNUM *priv_key; BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k = NULL, *e = NULL; EC_POINT *C = NULL; BN_CTX *ctx; OPENSSL_assert(dgst != NULL && eckey != NULL); if (!(ctx = BN_CTX_new())) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE); return NULL; } BN_CTX_start(ctx); OPENSSL_assert(dlen == 32 || dlen == 64); md = hashsum2bn(dgst, dlen); newsig = DSA_SIG_new(); if (!newsig || !md) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE); goto err; } group = EC_KEY_get0_group(eckey); if (!group) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR); goto err; } order = BN_CTX_get(ctx); if (!order || !EC_GROUP_get_order(group, order, ctx)) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR); goto err; } priv_key = EC_KEY_get0_private_key(eckey); if (!priv_key) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR); goto err; } e = BN_CTX_get(ctx); if (!e || !BN_mod(e, md, order, ctx)) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR); goto err; } #ifdef DEBUG_SIGN fprintf(stderr, "digest as bignum="); BN_print_fp(stderr, md); fprintf(stderr, "\ndigest mod q="); BN_print_fp(stderr, e); fprintf(stderr, "\n"); #endif if (BN_is_zero(e)) { BN_one(e); } k = BN_CTX_get(ctx); C = EC_POINT_new(group); if (!k || !C) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE); goto err; } do { do { if (!BN_rand_range(k, order)) { GOSTerr(GOST_F_GOST_EC_SIGN, GOST_R_RNG_ERROR); goto err; } /* * To avoid timing information leaking the length of k, * compute C*k using an equivalent scalar of fixed bit-length */ if (!BN_add(k, k, order) || (BN_num_bits(k) <= BN_num_bits(order) && !BN_add(k, k, order))) { goto err; } if (!EC_POINT_mul(group, C, k, NULL, NULL, ctx)) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_EC_LIB); goto err; } if (!X) X = BN_CTX_get(ctx); if (!r) r = BN_CTX_get(ctx); if (!X || !r) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE); goto err; } if (!EC_POINT_get_affine_coordinates_GFp(group, C, X, NULL, ctx)) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_EC_LIB); goto err; } if (!BN_nnmod(r, X, order, ctx)) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR); goto err; } } while (BN_is_zero(r)); /* s = (r*priv_key+k*e) mod order */ if (!tmp) tmp = BN_CTX_get(ctx); if (!tmp2) tmp2 = BN_CTX_get(ctx); if (!s) s = BN_CTX_get(ctx); if (!tmp || !tmp2 || !s) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE); goto err; } if (!BN_mod_mul(tmp, priv_key, r, order, ctx) || !BN_mod_mul(tmp2, k, e, order, ctx) || !BN_mod_add(s, tmp, tmp2, order, ctx)) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR); goto err; } } while (BN_is_zero(s)); newsig->s = BN_dup(s); newsig->r = BN_dup(r); if (!newsig->s || !newsig->r) { GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE); goto err; } ret = newsig; err: BN_CTX_end(ctx); BN_CTX_free(ctx); if (C) EC_POINT_free(C); if (md) BN_free(md); if (!ret && newsig) { DSA_SIG_free(newsig); } return ret; }