BIGNUM * DH_get_order(const DH *dh, BN_CTX *ctx) { BIGNUM *order = NULL, *bn = NULL; const BIGNUM *p, *g; check(dh && ctx, "Invalid argument"); BN_CTX_start(ctx); DH_get0_pqg(dh, &p, NULL, &g); /* suppose the order of g is q-1 */ order = DH_get_q(dh, ctx); bn = BN_CTX_get(ctx); if (!bn || !order || !BN_sub_word(order, 1) || !BN_mod_exp(bn, g, order, p, ctx)) goto err; if (BN_cmp(bn, BN_value_one()) != 0) { /* if bn != 1, then q-1 is not the order of g, but p-1 should be */ if (!BN_sub(order, p, BN_value_one()) || !BN_mod_exp(bn, g, order, p, ctx)) goto err; check(BN_cmp(bn, BN_value_one()) == 0, "Unable to get order"); } BN_CTX_end(ctx); return order; err: if (order) BN_clear_free(order); BN_CTX_end(ctx); return NULL; }
int dh_im_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in, BN_CTX *bn_ctx) { int ret = 0; BUF_MEM * x_mem = NULL; BIGNUM * x_bn = NULL, *a = NULL, *p_1 = NULL, *q = NULL; DH *static_key = NULL, *ephemeral_key = NULL; check((ctx && in && ctx->ka_ctx), "Invalid arguments"); if (in->length < (size_t) EVP_CIPHER_key_length(ctx->ka_ctx->cipher) || !ctx->static_key) goto err; BN_CTX_start(bn_ctx); static_key = EVP_PKEY_get1_DH(ctx->static_key); if (!static_key) goto err; /* Initialize ephemeral parameters with parameters from the static key */ ephemeral_key = DHparams_dup_with_q(static_key); if (!ephemeral_key) goto err; /* Perform the actual mapping */ x_mem = cipher_no_pad(ctx->ka_ctx, NULL, in, s, 1); if (!x_mem) goto err; x_bn = BN_bin2bn((unsigned char *) x_mem->data, x_mem->length, x_bn); a = BN_CTX_get(bn_ctx); q = DH_get_q(static_key, bn_ctx); p_1 = BN_dup(static_key->p); if (!x_bn || !a || !q || !p_1 || /* p_1 = p-1 */ !BN_sub_word(p_1, 1) || /* a = p-1 / q */ !BN_div(a, NULL, p_1, q, bn_ctx) || /* g~ = x^a mod p */ !BN_mod_exp(ephemeral_key->g, x_bn, a, static_key->p, bn_ctx)) goto err; /* check if g~ != 1 */ check((!BN_is_one(ephemeral_key->g)), "Bad DH generator"); /* Copy ephemeral key to context structure */ if (!EVP_PKEY_set1_DH(ctx->ka_ctx->key, ephemeral_key)) goto err; ret = 1; err: if (q) BN_clear_free(q); if (p_1) BN_clear_free(p_1); if (x_bn) BN_clear_free(x_bn); if (x_mem) BUF_MEM_free(x_mem); /* Decrement reference count, keys are still available via PACE_CTX */ if (static_key) DH_free(static_key); if (ephemeral_key) DH_free(ephemeral_key); BN_CTX_end(bn_ctx); return ret; }