int EVP_PKEY_set_std_dp(EVP_PKEY *key, int stnd_dp) { DH *dh = NULL; EC_KEY *ec = NULL; if (!key) { log_err("Invalid arguments"); return 0; } /* Generate key from standardized domain parameters */ switch(stnd_dp) { case 0: case 1: case 2: if (!init_dh(&dh, stnd_dp)) return 0; EVP_PKEY_set1_DH(key, dh); /* Decrement reference count */ DH_free(dh); break; case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: if (!init_ecdh(&ec, stnd_dp)) return 0; EVP_PKEY_set1_EC_KEY(key, ec); /* Decrement reference count */ EC_KEY_free(ec); break; default: log_err("Invalid arguments"); return 0; } return 1; }
int EVP_PKEY_set_keys(EVP_PKEY *evp_pkey, const unsigned char *privkey, size_t privkey_len, const unsigned char *pubkey, size_t pubkey_len, BN_CTX *bn_ctx) { EC_KEY *ec_key = NULL; DH *dh = NULL; EC_POINT *ec_point = NULL; BIGNUM *bn = NULL, *dh_pub_key, *dh_priv_key; int ok = 0; const EC_GROUP *group; check(evp_pkey, "Invalid arguments"); switch (EVP_PKEY_base_id(evp_pkey)) { case EVP_PKEY_EC: ec_key = EVP_PKEY_get1_EC_KEY(evp_pkey); if (!ec_key) goto err; group = EC_KEY_get0_group(ec_key); if (pubkey) { ec_point = EC_POINT_new(group); if (!ec_point || !EC_POINT_oct2point(group, ec_point, pubkey, pubkey_len, bn_ctx) || !EC_KEY_set_public_key(ec_key, ec_point)) goto err; } if (privkey) { bn = BN_bin2bn(privkey, privkey_len, bn); if (!bn || !EC_KEY_set_private_key(ec_key, bn)) goto err; } if (!EVP_PKEY_set1_EC_KEY(evp_pkey, ec_key)) goto err; break; case EVP_PKEY_DH: dh = EVP_PKEY_get1_DH(evp_pkey); if (!dh) goto err; if (pubkey) { dh_pub_key = BN_bin2bn(pubkey, pubkey_len, NULL); if (!dh_pub_key || !DH_set0_key(dh, dh_pub_key, NULL)) goto err; } if (privkey) { dh_priv_key = BN_bin2bn(privkey, privkey_len, NULL); if (!dh_priv_key || !DH_set0_key(dh, NULL, dh_priv_key)) goto err; } if (!EVP_PKEY_set1_DH(evp_pkey, dh)) goto err; break; default: log_err("Unknown type of key"); goto err; break; } ok = 1; err: if (bn) BN_clear_free(bn); if (ec_key) EC_KEY_free(ec_key); if (dh) DH_free(dh); if (ec_point) EC_POINT_clear_free(ec_point); return ok; }
EVP_PKEY * EVP_PKEY_dup(EVP_PKEY *key) { EVP_PKEY *out = NULL; DH *dh_in = NULL, *dh_out = NULL; EC_KEY *ec_in = NULL, *ec_out = NULL; RSA *rsa_in = NULL, *rsa_out = NULL; check(key, "Invalid arguments"); out = EVP_PKEY_new(); if (!out) goto err; switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_DH: dh_in = EVP_PKEY_get1_DH(key); if (!dh_in) goto err; dh_out = DHparams_dup_with_q(dh_in); if (!dh_out) goto err; EVP_PKEY_set1_DH(out, dh_out); DH_free(dh_out); DH_free(dh_in); break; case EVP_PKEY_EC: ec_in = EVP_PKEY_get1_EC_KEY(key); if (!ec_in) goto err; ec_out = EC_KEY_dup(ec_in); if (!ec_out) goto err; EVP_PKEY_set1_EC_KEY(out, ec_out); EC_KEY_free(ec_out); EC_KEY_free(ec_in); break; case EVP_PKEY_RSA: rsa_in = EVP_PKEY_get1_RSA(key); if (!rsa_in) goto err; rsa_out = RSAPrivateKey_dup(rsa_in); if (!rsa_out) goto err; EVP_PKEY_set1_RSA(out, rsa_out); RSA_free(rsa_out); RSA_free(rsa_in); break; default: log_err("Unknown protocol"); goto err; } return out; err: if (dh_in) DH_free(dh_in); if (ec_in) EC_KEY_free(ec_in); if (rsa_in) RSA_free(rsa_in); return NULL; }
ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ DH *dh_params = NULL; int mpint; /* 0 or 4 */ { ERL_NIF_TERM head, tail; BIGNUM *dh_p = NULL, *dh_g = NULL, *priv_key_in = NULL; unsigned long len = 0; if (!(get_bn_from_bin(env, argv[0], &priv_key_in) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) || !enif_get_ulong(env, argv[3], &len) /* Load dh_params with values to use by the generator. Mem mgmnt transfered from dh_p etc to dh_params */ || !(dh_params = DH_new()) || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) ) { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } if (len) { if (len < BN_num_bits(dh_p)) DH_set_length(dh_params, len); else { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } } } #ifdef HAS_EVP_PKEY_CTX { EVP_PKEY_CTX *ctx; EVP_PKEY *dhkey, *params; int success; params = EVP_PKEY_new(); success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */ DH_free(dh_params); /* ...dh_params (and params) must be freed */ if (!success) return atom_error; ctx = EVP_PKEY_CTX_new(params, NULL); EVP_PKEY_free(params); if (!ctx) { return atom_error; } if (!EVP_PKEY_keygen_init(ctx)) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } dhkey = EVP_PKEY_new(); if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */ /*... generated key is written to ppkey." (=last arg) */ /* EVP_PKEY_CTX_free(ctx); */ /* EVP_PKEY_free(dhkey); */ return atom_error; } dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */ EVP_PKEY_free(dhkey); if (!dh_params) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } EVP_PKEY_CTX_free(ctx); } #else if (!DH_generate_key(dh_params)) return atom_error; #endif { unsigned char *pub_ptr, *prv_ptr; int pub_len, prv_len; ERL_NIF_TERM ret_pub, ret_prv; const BIGNUM *pub_key_gen, *priv_key_gen; DH_get0_key(dh_params, &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. "The values point to the internal representation of the public key and private key values. This memory should not be freed directly." says man */ pub_len = BN_num_bytes(pub_key_gen); prv_len = BN_num_bytes(priv_key_gen); pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); if (mpint) { put_int32(pub_ptr, pub_len); pub_ptr += 4; put_int32(prv_ptr, prv_len); prv_ptr += 4; } BN_bn2bin(pub_key_gen, pub_ptr); BN_bn2bin(priv_key_gen, prv_ptr); ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); DH_free(dh_params); return enif_make_tuple2(env, ret_pub, ret_prv); } }
int dh_gm_compute_key(PACE_CTX * ctx, const BUF_MEM * s, const BUF_MEM * in, BN_CTX *bn_ctx) { int ret = 0; BUF_MEM * mem_h = NULL; BIGNUM * bn_s = NULL, *bn_h = NULL, *bn_g = NULL; DH *static_key = NULL, *ephemeral_key = NULL; check(ctx && ctx->static_key && s && ctx->ka_ctx, "Invalid arguments"); BN_CTX_start(bn_ctx); static_key = EVP_PKEY_get1_DH(ctx->static_key); if (!static_key) goto err; /* Convert nonce to BIGNUM */ bn_s = BN_bin2bn((unsigned char *) s->data, s->length, bn_s); if (!bn_s) goto err; /* complete the DH and convert the result to a BIGNUM */ mem_h = dh_compute_key(ctx->static_key, in, bn_ctx); if (!mem_h) goto err; bn_h = BN_bin2bn((unsigned char *) mem_h->data, mem_h->length, bn_h); if (!bn_h) goto err; /* Initialize ephemeral parameters with parameters from the static key */ ephemeral_key = DHparams_dup_with_q(static_key); if (!ephemeral_key) goto err; /* map to new generator */ bn_g = BN_CTX_get(bn_ctx); if (!bn_g || /* bn_g = g^s mod p */ !BN_mod_exp(bn_g, static_key->g, bn_s, static_key->p, bn_ctx) || /* ephemeral_key->g = bn_g * h mod p = g^s * h mod p */ !BN_mod_mul(ephemeral_key->g, bn_g, bn_h, static_key->p, bn_ctx)) goto err; /* Copy ephemeral key to context structure */ if (!EVP_PKEY_set1_DH(ctx->ka_ctx->key, ephemeral_key)) goto err; ret = 1; err: if (mem_h) { OPENSSL_cleanse(mem_h->data, mem_h->max); BUF_MEM_free(mem_h); } if (bn_h) BN_clear_free(bn_h); if (bn_s) BN_clear_free(bn_s); /* 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; }
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; }