/* The secret integers s0 and s1 must be in the range 0 < s < n for some n, and must be relatively prime to that n. We know a priori that n is of the form 2**k * p for some small integer k and prime p. Therefore, it suffices to choose a random integer in the range [0, n/2), multiply by two and add one (enforcing oddness), and then reject values which are divisible by p. */ static BIGNUM * random_s(const BIGNUM *n, const BIGNUM *p, BN_CTX *c) { BIGNUM h, m, *r; BN_init(&h); BN_init(&m); FAILZ(r = BN_new()); FAILZ(BN_copy(&h, n)); FAILZ(BN_rshift1(&h, &h)); do { FAILZ(BN_rand_range(r, &h)); FAILZ(BN_lshift1(r, r)); FAILZ(BN_add(r, r, BN_value_one())); FAILZ(BN_nnmod(&m, r, p, c)); } while (BN_is_zero(&m)); BN_clear(&h); BN_clear(&m); return r; fail: BN_clear(&h); BN_clear(&m); if (r) BN_clear_free(r); return 0; }
int MKEM_decode_message(const MKEM *kp, uint8_t *secret, const uint8_t *message) { int use_curve0 = !(message[0] & kp->params->curve_bit); const EC_GROUP *ca = use_curve0 ? kp->params->c0 : kp->params->c1; const BIGNUM *sa = use_curve0 ? kp->s0 : kp->s1; EC_POINT *q = 0, *r = 0; uint8_t *unpadded = 0; BIGNUM x, y; size_t mlen = kp->params->msgsize; int rv; if (!kp->s0 || !kp->s1) /* secret key not available */ return -1; BN_init(&x); BN_init(&y); FAILZ(q = EC_POINT_new(ca)); FAILZ(r = EC_POINT_new(ca)); FAILZ(unpadded = malloc(mlen + 1)); /* Copy the message, erase the padding bits, and put an 0x02 byte on the front so we can use EC_POINT_oct2point to recover the y-coordinate. */ unpadded[0] = 0x02; unpadded[1] = (message[0] & ~(kp->params->pad_mask|kp->params->curve_bit)); memcpy(&unpadded[2], &message[1], mlen - 1); FAILZ(EC_POINT_oct2point(ca, q, unpadded, mlen + 1, kp->params->ctx)); FAILZ(EC_POINT_mul(ca, r, 0, q, sa, kp->params->ctx)); FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, q, &x, &y, kp->params->ctx)); if (bn2bin_padhi(&x, secret, mlen) != mlen) goto fail; FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, r, &x, &y, kp->params->ctx)); if (bn2bin_padhi(&x, secret + mlen, mlen) != mlen) goto fail; rv = 0; done: if (unpadded) { memset(unpadded, 0, mlen + 1); free(unpadded); } if (q) EC_POINT_clear_free(q); if (r) EC_POINT_clear_free(r); BN_clear(&x); BN_clear(&y); return rv; fail: rv = -1; memset(secret, 0, mlen * 2); goto done; }
/** * Validates the format of the boot signature block, and checks that * the length in authenticated attributes matches the actual length of * the image. * @param bs The boot signature block to validate * @param length The actual length of the boot image without the signature */ static int validate_signature_block(const BootSignature *bs, uint64_t length) { BIGNUM expected; BIGNUM value; int rc = -1; if (!bs) { return -1; } BN_init(&expected); BN_init(&value); /* Confirm that formatVersion matches our supported version */ if (!BN_set_word(&expected, FORMAT_VERSION)) { ERR_print_errors(g_error); goto vsb_done; } ASN1_INTEGER_to_BN(bs->formatVersion, &value); if (BN_cmp(&expected, &value) != 0) { printf("Unsupported signature version\n"); goto vsb_done; } BN_clear(&expected); BN_clear(&value); /* Confirm that the length of the image matches with the length in the authenticated attributes */ length = htobe64(length); BN_bin2bn((const unsigned char *) &length, sizeof(length), &expected); ASN1_INTEGER_to_BN(bs->authenticatedAttributes->length, &value); if (BN_cmp(&expected, &value) != 0) { printf("Image length doesn't match signature attributes\n"); goto vsb_done; } rc = 0; vsb_done: BN_free(&expected); BN_free(&value); return rc; }
/** * Generate a prime number * * The internal CPRNG is seeded using the provided seed value. * * @param prime Pointer for storage of prime number * @param s Secret to share * @param bits Bit size of prime * @param rngSeed Seed value for CPRNG * @param rngSeedLength Length of Seed value for CPRNG * */ static int generatePrime(BIGNUM *prime, const BIGNUM *s, const int bits, unsigned char *rngSeed, const unsigned int rngSeedLength) { int max_rounds = 1000; // Seed the RNG RAND_seed(rngSeed, rngSeedLength); // Clear the prime value BN_clear(prime); do { // Generate random prime #if OPENSSL_VERSION_NUMBER >= 0x00908000L /* last parm is BN_GENCB which is null in our case */ BN_generate_prime_ex(prime, bits, 1, NULL, NULL, NULL); #else BN_generate_prime(prime, bits, 1, NULL, NULL, NULL, NULL ); #endif } while ((BN_ucmp(prime, s) == -1) && (max_rounds-- > 0)); // If prime < s or not reached 1000 tries if (max_rounds > 0) return 0; else return -1; // We could not find a prime number }
int dh_gen_key(DH *dh, int need) { int pbits; const BIGNUM *p, *pub_key, *priv_key; DH_get0_pqg(dh, &p, NULL, NULL); if (need < 0 || p == NULL || (pbits = BN_num_bits(p)) <= 0 || need > INT_MAX / 2 || 2 * need > pbits) return SSH_ERR_INVALID_ARGUMENT; if (need < 256) need = 256; /* * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), * so double requested need here. */ DH_set_length(dh, MIN(need * 2, pbits - 1)); if (DH_generate_key(dh) == 0) { return SSH_ERR_LIBCRYPTO_ERROR; } DH_get0_key(dh, &pub_key, &priv_key); if (!dh_pub_is_valid(dh, pub_key)) { #if 0 BN_clear(priv_key); #endif return SSH_ERR_LIBCRYPTO_ERROR; } return 0; }
BIGNUM * BN_bin2bn(const void *s, int len, BIGNUM *bn) { heim_integer *hi = (void *)bn; if (len < 0) return NULL; if (hi == NULL) { hi = (heim_integer *)BN_new(); if (hi == NULL) return NULL; } if (hi->data) BN_clear((BIGNUM *)hi); hi->negative = 0; hi->data = malloc(len); if (hi->data == NULL && len != 0) { if (bn == NULL) BN_free((BIGNUM *)hi); return NULL; } hi->length = len; memcpy(hi->data, s, len); return (BIGNUM *)hi; }
CHECK_RETVAL_BOOL \ static BOOLEAN selfTestGeneralOps1( void ) { BIGNUM a; /* Simple tests that don't need the support of higher-level routines like importBignum() */ BN_init( &a ); if( !BN_zero( &a ) ) return( FALSE ); if( !BN_is_zero( &a ) || BN_is_one( &a ) ) return( FALSE ); if( !BN_is_word( &a, 0 ) || BN_is_word( &a, 1 ) ) return( FALSE ); if( BN_is_odd( &a ) ) return( FALSE ); if( BN_get_word( &a ) != 0 ) return( FALSE ); if( !BN_one( &a ) ) return( FALSE ); if( BN_is_zero( &a ) || !BN_is_one( &a ) ) return( FALSE ); if( BN_is_word( &a, 0 ) || !BN_is_word( &a, 1 ) ) return( FALSE ); if( !BN_is_odd( &a ) ) return( FALSE ); if( BN_num_bytes( &a ) != 1 ) return( FALSE ); if( BN_get_word( &a ) != 1 ) return( FALSE ); BN_clear( &a ); return( TRUE ); }
int BN_rand(BIGNUM *bn, int bits, int top, int bottom) { size_t len = (bits + 7) / 8; heim_integer *i = (heim_integer *)bn; BN_clear(bn); i->negative = 0; i->data = malloc(len); if (i->data == NULL && len != 0) return 0; i->length = len; if (RAND_bytes(i->data, i->length) != 1) { free(i->data); i->data = NULL; return 0; } { size_t j = len * 8; while(j > bits) { BN_clear_bit(bn, j - 1); j--; } } if (top == -1) { ; } else if (top == 0 && bits > 0) { BN_set_bit(bn, bits - 1); } else if (top == 1 && bits > 1) { BN_set_bit(bn, bits - 1); BN_set_bit(bn, bits - 2); } else { BN_clear(bn); return 0; } if (bottom && bits > 0) BN_set_bit(bn, 0); return 1; }
void vg_exec_context_consolidate_key(vg_exec_context_t *vxcp) { if (vxcp->vxc_delta) { BN_clear(&vxcp->vxc_bntmp); BN_set_word(&vxcp->vxc_bntmp, vxcp->vxc_delta); BN_add(&vxcp->vxc_bntmp2, EC_KEY_get0_private_key(vxcp->vxc_key), &vxcp->vxc_bntmp); vg_set_privkey(&vxcp->vxc_bntmp2, vxcp->vxc_key); vxcp->vxc_delta = 0; } }
static void vg_prefix_range_sum(vg_prefix_t *vp, BIGNUM *result, BIGNUM *tmp1) { vg_prefix_t *startp; startp = vp; BN_clear(result); do { BN_sub(tmp1, vp->vp_high, vp->vp_low); BN_add(result, result, tmp1); vp = vp->vp_sibling; } while (vp && (vp != startp)); }
int BN_uadd(BIGNUM *res, const BIGNUM *a, const BIGNUM *b) { const heim_integer *ai = (const heim_integer *)a; const heim_integer *bi = (const heim_integer *)b; const unsigned char *ap, *bp; unsigned char *cp; heim_integer ci; int carry = 0; ssize_t len; if (ai->negative && bi->negative) return 0; if (ai->length < bi->length) { const heim_integer *si = bi; bi = ai; ai = si; } ci.negative = 0; ci.length = ai->length + 1; ci.data = malloc(ci.length); if (ci.data == NULL) return 0; ap = &((const unsigned char *)ai->data)[ai->length - 1]; bp = &((const unsigned char *)bi->data)[bi->length - 1]; cp = &((unsigned char *)ci.data)[ci.length - 1]; for (len = bi->length; len > 0; len--) { carry = *ap + *bp + carry; *cp = carry & 0xff; carry = (carry & ~0xff) ? 1 : 0; ap--; bp--; cp--; } for (len = ai->length - bi->length; len > 0; len--) { carry = *ap + carry; *cp = carry & 0xff; carry = (carry & ~0xff) ? 1 : 0; ap--; cp--; } if (!carry) memmove(cp, cp + 1, --ci.length); else *cp = carry; BN_clear(res); *((heim_integer *)res) = ci; return 1; }
void BN_CTX_end(BN_CTX *c) { const size_t prev = c->stack.val[c->stack.used - 1]; size_t i; if (c->stack.used == 0) abort(); for (i = prev; i < c->bn.used; i++) BN_clear(c->bn.val[i]); c->stack.used--; c->bn.used = prev; }
/** * Generate a prime number * * The internal CPRNG is seeded using the provided seed value. * For the bit size of the generated prime the following condition holds: * * num_bits(prime) > max(2^r, num_bits(n + 1)) * * r equals the number of bits needed to encode the secret. * * @param prime Pointer for storage of prime number * @param s Secret to share * @param n Maximum number of shares * @param rngSeed Seed value for CPRNG * */ static void generatePrime(BIGNUM *prime, const BIGNUM *s, const unsigned int n, char *rngSeed) { int bits = 0; // Seed the RNG RAND_seed(rngSeed, sizeof(rngSeed)); // Determine minimum number of bits for prime >= max(2^r, n + 1) bits = BN_num_bits_word(n + 1) > BN_num_bits(s) ? (BN_num_bits_word(n + 1)) : (BN_num_bits(s)); // Clear the prime value BN_clear(prime); // Generate random prime BN_generate_prime(prime, bits, 1, NULL, NULL, NULL, NULL ); }
int MKEM_generate_message(const MKEM *kp, uint8_t *secret, uint8_t *message) { BIGNUM u; uint8_t pad; int rv = -1; BN_init(&u); if (BN_rand_range(&u, kp->params->maxu) && BN_add(&u, &u, BN_value_one()) && RAND_bytes(&pad, 1) && !MKEM_generate_message_u(kp, &u, pad, secret, message)) rv = 0; BN_clear(&u); return rv; }
static void BN_POOL_reset(BN_POOL *p) { BN_POOL_ITEM *item = p->head; while (item) { unsigned int loop = 0; BIGNUM *bn = item->vals; while (loop++ < BN_CTX_POOL_SIZE) { if (bn->d) BN_clear(bn); bn++; } item = item->next; } p->current = p->head; p->used = 0; }
static void vg_prefix_context_clear_all_patterns(vg_context_t *vcp) { vg_prefix_context_t *vcpp = (vg_prefix_context_t *) vcp; vg_prefix_t *vp; unsigned long npfx_left = 0; while (!avl_root_empty(&vcpp->vcp_avlroot)) { vp = avl_item_entry(vcpp->vcp_avlroot.ar_root, vg_prefix_t, vp_item); vg_prefix_delete(&vcpp->vcp_avlroot, vp); npfx_left++; } assert(npfx_left == vcpp->base.vc_npatterns); vcpp->base.vc_npatterns = 0; vcpp->base.vc_npatterns_start = 0; vcpp->base.vc_found = 0; BN_clear(&vcpp->vcp_difficulty); }
double vg_prefix_get_difficulty(int addrtype, const char *pattern) { BN_CTX *bnctx; BIGNUM result, bntmp; BIGNUM *ranges[4]; char *dbuf; int ret; double diffret = 0.0; bnctx = BN_CTX_new(); BN_init(&result); BN_init(&bntmp); ret = get_prefix_ranges(addrtype, pattern, ranges, bnctx); if (ret == 0) { BN_sub(&bntmp, ranges[1], ranges[0]); BN_add(&result, &result, &bntmp); if (ranges[2]) { BN_sub(&bntmp, ranges[3], ranges[2]); BN_add(&result, &result, &bntmp); } free_ranges(ranges); BN_clear(&bntmp); BN_set_bit(&bntmp, 192); BN_div(&result, NULL, &bntmp, &result, bnctx); dbuf = BN_bn2dec(&result); diffret = strtod(dbuf, NULL); OPENSSL_free(dbuf); } BN_clear_free(&result); BN_clear_free(&bntmp); BN_CTX_free(bnctx); return diffret; }
static void vg_prefix_context_next_difficulty(vg_prefix_context_t *vcpp, BIGNUM *bntmp, BIGNUM *bntmp2, BN_CTX *bnctx) { char *dbuf; BN_clear(bntmp); BN_set_bit(bntmp, 192); BN_div(bntmp2, NULL, bntmp, &vcpp->vcp_difficulty, bnctx); dbuf = BN_bn2dec(bntmp2); if (vcpp->base.vc_verbose > 0) { if (vcpp->base.vc_npatterns > 1) fprintf(stderr, "Next match difficulty: %s (%ld prefixes)\n", dbuf, vcpp->base.vc_npatterns); else fprintf(stderr, "Difficulty: %s\n", dbuf); } vcpp->base.vc_chance = atof(dbuf); OPENSSL_free(dbuf); }
void BN_CTX_clear( BN_CTX *bnCTX ) { BN_POOL_ITEM *item = bnCTX->pool.head; /* Reset the bignum pool */ while( item != NULL ) { unsigned int loop = 0; BIGNUM *bn = item->vals; while( loop++ < BN_CTX_POOL_SIZE ) { if( bn->d != NULL ) BN_clear( bn ); bn++; } item = item->next; } bnCTX->pool.current = bnCTX->pool.head; bnCTX->pool.used = 0; /* Reset the pool stack */ bnCTX->stack.depth = 0; }
int MKEM_generate_message_u(const MKEM *kp, const BIGNUM *uraw, uint8_t pad, uint8_t *secret, uint8_t *message) { BIGNUM u, x, y; int use_curve0 = (BN_cmp(uraw, kp->params->n0) < 0); const EC_GROUP *ca; const EC_POINT *ga; const EC_POINT *pa; EC_POINT *q = 0, *r = 0; size_t mlen = kp->params->msgsize; int rv; BN_init(&u); BN_init(&x); BN_init(&y); if (use_curve0) { ca = kp->params->c0; ga = kp->params->g0; pa = kp->p0; FAILZ(BN_copy(&u, uraw)); } else { ca = kp->params->c1; ga = kp->params->g1; pa = kp->p1; FAILZ(BN_sub(&u, uraw, kp->params->n0)); FAILZ(BN_add(&u, &u, BN_value_one())); } FAILZ(q = EC_POINT_new(ca)); FAILZ(r = EC_POINT_new(ca)); FAILZ(EC_POINT_mul(ca, q, 0, ga, &u, kp->params->ctx)); FAILZ(EC_POINT_mul(ca, r, 0, pa, &u, kp->params->ctx)); FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, q, &x, &y, kp->params->ctx)); if (bn2bin_padhi(&x, message, mlen) != mlen) goto fail; if (message[0] & (kp->params->pad_mask|kp->params->curve_bit)) /* see below */ goto fail; memcpy(secret, message, mlen); FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, r, &x, &y, kp->params->ctx)); if (bn2bin_padhi(&x, secret + mlen, mlen) != mlen) goto fail; /* K high bits of the message will be zero. Fill in the high K-1 of them with random bits from the pad, and use the lowest bit to identify the curve in use. That bit will have a bias on the order of 2^{-d/2} where d is the bit-degree of the curve; 2^{-81} for the only curve presently implemented. This is acceptably small since an elliptic curve of d bits gives only about d/2 bits of security anyway, and is much better than allowing a timing attack via the recipient having to attempt point decompression twice for curve 1 but only once for curve 0 (or, alternatively, doubling the time required for all decryptions). */ pad &= kp->params->pad_mask; pad |= (use_curve0 ? 0 : kp->params->curve_bit); message[0] |= pad; rv = 0; done: BN_clear(&u); BN_clear(&x); BN_clear(&y); if (q) EC_POINT_clear_free(q); if (r) EC_POINT_clear_free(r); return rv; fail: memset(message, 0, mlen); memset(secret, 0, mlen * 2); rv = -1; goto done; }
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; }
CHECK_RETVAL_BOOL \ static BOOLEAN selfTestGeneralOps2( void ) { BIGNUM a; int status; /* More complex tests that need higher-level routines like importBignum(), run after the tests of components of importBignum() have concluded */ BN_init( &a ); #if BN_BITS2 == 64 status = importBignum( &a, "\x01\x00\x00\x00\x00\x00\x00\x00\x00", 9, 1, 128, NULL, KEYSIZE_CHECK_NONE ); #else status = importBignum( &a, "\x01\x00\x00\x00\x00", 5, 1, 128, NULL, KEYSIZE_CHECK_NONE ); #endif /* 64- vs 32-bit */ if( cryptStatusError( status ) ) return( FALSE ); if( BN_is_zero( &a ) || BN_is_one( &a ) ) return( FALSE ); if( BN_is_word( &a, 0 ) || BN_is_word( &a, 1 ) ) return( FALSE ); if( BN_is_odd( &a ) ) return( FALSE ); if( BN_get_word( &a ) != BN_NAN ) return( FALSE ); if( BN_num_bytes( &a ) != ( BN_BITS2 / 8 ) + 1 ) return( FALSE ); if( BN_num_bits( &a ) != BN_BITS2 + 1 ) return( FALSE ); if( !BN_is_bit_set( &a, BN_BITS2 ) ) return( FALSE ); if( BN_is_bit_set( &a, 17 ) || !BN_set_bit( &a, 17 ) || \ !BN_is_bit_set( &a, 17 ) ) return( FALSE ); #if BN_BITS2 == 64 status = importBignum( &a, "\x01\x00\x00\x00\x00\x00\x00\x00\x01", 9, 1, 128, NULL, KEYSIZE_CHECK_NONE ); #else status = importBignum( &a, "\x01\x00\x00\x00\x01", 5, 1, 128, NULL, KEYSIZE_CHECK_NONE ); #endif /* 64- vs 32-bit */ if( cryptStatusError( status ) ) return( FALSE ); if( BN_is_zero( &a ) || BN_is_one( &a ) ) return( FALSE ); if( BN_is_word( &a, 0 ) || BN_is_word( &a, 1 ) ) return( FALSE ); if( !BN_is_odd( &a ) ) return( FALSE ); if( BN_num_bytes( &a ) != ( BN_BITS2 / 8 ) + 1 ) return( FALSE ); if( BN_get_word( &a ) != BN_NAN ) return( FALSE ); if( BN_num_bits( &a ) != BN_BITS2 + 1 ) return( FALSE ); if( !BN_is_bit_set( &a, BN_BITS2 ) ) return( FALSE ); if( BN_is_bit_set( &a, BN_BITS2 + 27 ) || \ !BN_set_bit( &a, BN_BITS2 + 27 ) || \ !BN_is_bit_set( &a, BN_BITS2 + 27 ) ) return( FALSE ); /* Setting a bit off the end of a bignum extends its size, which is why the following value doesn't match the one from a few lines earlier */ if( BN_num_bytes( &a ) != ( BN_BITS2 / 8 ) + 4 ) return( FALSE ); /* The bit index for indexing bits is zero-based (since 1 == 1 << 0) but for counting bits is one-based, which is why the following comparison looks wrong. Yet another one of OpenSSL's many booby-traps */ if( BN_num_bits( &a ) != BN_BITS2 + 28 ) return( FALSE ); BN_clear( &a ); return( TRUE ); }
/* * 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; }
void BN_free(BIGNUM *bn) { BN_clear(bn); free(bn); }
static int test_BN_bit(void) { BIGNUM *bn; int ret = 0; bn = BN_new(); /* test setting and getting of "word" */ if (!BN_set_word(bn, 1)) return 1; if (!BN_is_bit_set(bn, 0)) ret += 1; if (!BN_is_bit_set(bn, 0)) ret += 1; if (!BN_set_word(bn, 2)) return 1; if (!BN_is_bit_set(bn, 1)) ret += 1; if (!BN_set_word(bn, 3)) return 1; if (!BN_is_bit_set(bn, 0)) ret += 1; if (!BN_is_bit_set(bn, 1)) ret += 1; if (!BN_set_word(bn, 0x100)) return 1; if (!BN_is_bit_set(bn, 8)) ret += 1; if (!BN_set_word(bn, 0x1000)) return 1; if (!BN_is_bit_set(bn, 12)) ret += 1; /* test bitsetting */ if (!BN_set_word(bn, 1)) return 1; if (!BN_set_bit(bn, 1)) return 1; if (BN_get_word(bn) != 3) return 1; if (!BN_clear_bit(bn, 0)) return 1; if (BN_get_word(bn) != 2) return 1; /* test bitsetting past end of current end */ BN_clear(bn); if (!BN_set_bit(bn, 12)) return 1; if (BN_get_word(bn) != 0x1000) return 1; /* test bit and byte counting functions */ if (BN_num_bits(bn) != 13) return 1; if (BN_num_bytes(bn) != 2) return 1; BN_free(bn); return ret; }
/* * Refer to FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test. * OR C.3.1 Miller-Rabin Probabilistic Primality Test (if enhanced is zero). * The Step numbers listed in the code refer to the enhanced case. * * if enhanced is set, then status returns one of the following: * BN_PRIMETEST_PROBABLY_PRIME * BN_PRIMETEST_COMPOSITE_WITH_FACTOR * BN_PRIMETEST_COMPOSITE_NOT_POWER_OF_PRIME * if enhanced is zero, then status returns either * BN_PRIMETEST_PROBABLY_PRIME or * BN_PRIMETEST_COMPOSITE * * returns 0 if there was an error, otherwise it returns 1. */ int bn_miller_rabin_is_prime(const BIGNUM *w, int iterations, BN_CTX *ctx, BN_GENCB *cb, int enhanced, int *status) { int i, j, a, ret = 0; BIGNUM *g, *w1, *w3, *x, *m, *z, *b; BN_MONT_CTX *mont = NULL; /* w must be odd */ if (!BN_is_odd(w)) return 0; BN_CTX_start(ctx); g = BN_CTX_get(ctx); w1 = BN_CTX_get(ctx); w3 = BN_CTX_get(ctx); x = BN_CTX_get(ctx); m = BN_CTX_get(ctx); z = BN_CTX_get(ctx); b = BN_CTX_get(ctx); if (!(b != NULL /* w1 := w - 1 */ && BN_copy(w1, w) && BN_sub_word(w1, 1) /* w3 := w - 3 */ && BN_copy(w3, w) && BN_sub_word(w3, 3))) goto err; /* check w is larger than 3, otherwise the random b will be too small */ if (BN_is_zero(w3) || BN_is_negative(w3)) goto err; /* (Step 1) Calculate largest integer 'a' such that 2^a divides w-1 */ a = 1; while (!BN_is_bit_set(w1, a)) a++; /* (Step 2) m = (w-1) / 2^a */ if (!BN_rshift(m, w1, a)) goto err; /* Montgomery setup for computations mod a */ mont = BN_MONT_CTX_new(); if (mont == NULL || !BN_MONT_CTX_set(mont, w, ctx)) goto err; if (iterations == BN_prime_checks) iterations = BN_prime_checks_for_size(BN_num_bits(w)); /* (Step 4) */ for (i = 0; i < iterations; ++i) { /* (Step 4.1) obtain a Random string of bits b where 1 < b < w-1 */ if (!BN_priv_rand_range(b, w3) || !BN_add_word(b, 2)) /* 1 < b < w-1 */ goto err; if (enhanced) { /* (Step 4.3) */ if (!BN_gcd(g, b, w, ctx)) goto err; /* (Step 4.4) */ if (!BN_is_one(g)) { *status = BN_PRIMETEST_COMPOSITE_WITH_FACTOR; ret = 1; goto err; } } /* (Step 4.5) z = b^m mod w */ if (!BN_mod_exp_mont(z, b, m, w, ctx, mont)) goto err; /* (Step 4.6) if (z = 1 or z = w-1) */ if (BN_is_one(z) || BN_cmp(z, w1) == 0) goto outer_loop; /* (Step 4.7) for j = 1 to a-1 */ for (j = 1; j < a ; ++j) { /* (Step 4.7.1 - 4.7.2) x = z. z = x^2 mod w */ if (!BN_copy(x, z) || !BN_mod_mul(z, x, x, w, ctx)) goto err; /* (Step 4.7.3) */ if (BN_cmp(z, w1) == 0) goto outer_loop; /* (Step 4.7.4) */ if (BN_is_one(z)) goto composite; } /* At this point z = b^((w-1)/2) mod w */ /* (Steps 4.8 - 4.9) x = z, z = x^2 mod w */ if (!BN_copy(x, z) || !BN_mod_mul(z, x, x, w, ctx)) goto err; /* (Step 4.10) */ if (BN_is_one(z)) goto composite; /* (Step 4.11) x = b^(w-1) mod w */ if (!BN_copy(x, z)) goto err; composite: if (enhanced) { /* (Step 4.1.2) g = GCD(x-1, w) */ if (!BN_sub_word(x, 1) || !BN_gcd(g, x, w, ctx)) goto err; /* (Steps 4.1.3 - 4.1.4) */ if (BN_is_one(g)) *status = BN_PRIMETEST_COMPOSITE_NOT_POWER_OF_PRIME; else *status = BN_PRIMETEST_COMPOSITE_WITH_FACTOR; } else { *status = BN_PRIMETEST_COMPOSITE; } ret = 1; goto err; outer_loop: ; /* (Step 4.1.5) */ if (!BN_GENCB_call(cb, 1, i)) goto err; } /* (Step 5) */ *status = BN_PRIMETEST_PROBABLY_PRIME; ret = 1; err: BN_clear(g); BN_clear(w1); BN_clear(w3); BN_clear(x); BN_clear(m); BN_clear(z); BN_clear(b); BN_CTX_end(ctx); BN_MONT_CTX_free(mont); return ret; }
void tests(void) { #ifndef USING_WOLFSSL struct bitmap *b; BIGNUM *bn; size_t len; int i, j, k, n; u_char bbuf[1024], bnbuf[1024]; int r; #else struct bitmap *b; BIGNUM *bn; #endif TEST_START("bitmap_new"); b = bitmap_new(); ASSERT_PTR_NE(b, NULL); bn = BN_new(); ASSERT_PTR_NE(bn, NULL); TEST_DONE(); TEST_START("bitmap_set_bit / bitmap_test_bit"); #ifndef USING_WOLFSSL for (i = -1; i < NTESTS; i++) { for (j = -1; j < NTESTS; j++) { for (k = -1; k < NTESTS; k++) { bitmap_zero(b); /* wolfSSL does not have support for BN_clear at this time */ BN_clear(bn); test_subtest_info("set %d/%d/%d", i, j, k); /* Set bits */ if (i >= 0) { ASSERT_INT_EQ(bitmap_set_bit(b, i), 0); ASSERT_INT_EQ(BN_set_bit(bn, i), 1); } if (j >= 0) { ASSERT_INT_EQ(bitmap_set_bit(b, j), 0); ASSERT_INT_EQ(BN_set_bit(bn, j), 1); } if (k >= 0) { ASSERT_INT_EQ(bitmap_set_bit(b, k), 0); ASSERT_INT_EQ(BN_set_bit(bn, k), 1); } /* Check perfect match between bitmap and bn */ test_subtest_info("match %d/%d/%d", i, j, k); for (n = 0; n < NTESTS; n++) { ASSERT_INT_EQ(BN_is_bit_set(bn, n), bitmap_test_bit(b, n)); } /* Test length calculations */ test_subtest_info("length %d/%d/%d", i, j, k); ASSERT_INT_EQ(BN_num_bits(bn), (int)bitmap_nbits(b)); ASSERT_INT_EQ(BN_num_bytes(bn), (int)bitmap_nbytes(b)); /* Test serialisation */ test_subtest_info("serialise %d/%d/%d", i, j, k); len = bitmap_nbytes(b); memset(bbuf, 0xfc, sizeof(bbuf)); ASSERT_INT_EQ(bitmap_to_string(b, bbuf, sizeof(bbuf)), 0); for (n = len; n < (int)sizeof(bbuf); n++) ASSERT_U8_EQ(bbuf[n], 0xfc); r = BN_bn2bin(bn, bnbuf); ASSERT_INT_GE(r, 0); ASSERT_INT_EQ(r, (int)len); ASSERT_MEM_EQ(bbuf, bnbuf, len); /* Test deserialisation */ test_subtest_info("deserialise %d/%d/%d", i, j, k); bitmap_zero(b); ASSERT_INT_EQ(bitmap_from_string(b, bnbuf, len), 0); for (n = 0; n < NTESTS; n++) { ASSERT_INT_EQ(BN_is_bit_set(bn, n), bitmap_test_bit(b, n)); } /* Test clearing bits */ test_subtest_info("clear %d/%d/%d", i, j, k); for (n = 0; n < NTESTS; n++) { ASSERT_INT_EQ(bitmap_set_bit(b, n), 0); ASSERT_INT_EQ(BN_set_bit(bn, n), 1); } if (i >= 0) { bitmap_clear_bit(b, i); /* wolfSSL does not have support for BN_clear_bit at this time */ BN_clear_bit(bn, i); } if (j >= 0) { bitmap_clear_bit(b, j); /* wolfSSL does not have support for BN_clear_bit at this time */ BN_clear_bit(bn, j); } if (k >= 0) { bitmap_clear_bit(b, k); /* wolfSSL does not have support for BN_clear_bit at this time */ BN_clear_bit(bn, k); } for (n = 0; n < NTESTS; n++) { ASSERT_INT_EQ(BN_is_bit_set(bn, n), bitmap_test_bit(b, n)); } } } } #endif /* USING_WOLFSSL */ bitmap_free(b); BN_free(bn); TEST_DONE(); }
BigNum (BigNum const& other) : num (BN_new ()) { if (BN_copy (num, other.num) == nullptr) BN_clear (num); }