ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ BIGNUM *other_pub_key = NULL, *dh_p = NULL, *dh_g = NULL; DH *dh_priv = DH_new(); /* Check the arguments and get my private key (dh_priv), the peer's public key (other_pub_key), the parameters p & q */ { BIGNUM *dummy_pub_key = NULL, *priv_key = NULL; ERL_NIF_TERM head, tail; if (!get_bn_from_bin(env, argv[0], &other_pub_key) || !get_bn_from_bin(env, argv[1], &priv_key) || !enif_get_list_cell(env, argv[2], &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) /* Note: DH_set0_key() does not allow setting only the * private key, although DH_compute_key() does not use the * public key. Work around this limitation by setting * the public key to a copy of the private key. */ || !(dummy_pub_key = BN_dup(priv_key)) || !DH_set0_key(dh_priv, dummy_pub_key, priv_key) || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g) ) { if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (other_pub_key) BN_free(other_pub_key); if (dummy_pub_key) BN_free(dummy_pub_key); if (priv_key) BN_free(priv_key); return enif_make_badarg(env); } } { ErlNifBinary ret_bin; int size; enif_alloc_binary(DH_size(dh_priv), &ret_bin); size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); BN_free(other_pub_key); DH_free(dh_priv); if (size<=0) { enif_release_binary(&ret_bin); return atom_error; } if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size); return enif_make_binary(env, &ret_bin); } }
static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (ModulusSize, PublicExponent) */ int modulus_bits; BIGNUM *pub_exp, *three; RSA *rsa; int success; ERL_NIF_TERM result; BN_GENCB *intr_cb; #ifndef HAVE_OPAQUE_BN_GENCB BN_GENCB intr_cb_buf; #endif if (!enif_get_int(env, argv[0], &modulus_bits) || modulus_bits < 256) { return enif_make_badarg(env); } if (!get_bn_from_bin(env, argv[1], &pub_exp)) { return enif_make_badarg(env); } /* Make sure the public exponent is large enough (at least 3). * Without this, RSA_generate_key_ex() can run forever. */ three = BN_new(); BN_set_word(three, 3); success = BN_cmp(pub_exp, three); BN_free(three); if (success < 0) { BN_free(pub_exp); return enif_make_badarg(env); } /* For large keys, prime generation can take many seconds. Set up * the callback which we use to test whether the process has been * interrupted. */ #ifdef HAVE_OPAQUE_BN_GENCB intr_cb = BN_GENCB_new(); #else intr_cb = &intr_cb_buf; #endif BN_GENCB_set(intr_cb, check_erlang_interrupt, env); rsa = RSA_new(); success = RSA_generate_key_ex(rsa, modulus_bits, pub_exp, intr_cb); BN_free(pub_exp); #ifdef HAVE_OPAQUE_BN_GENCB BN_GENCB_free(intr_cb); #endif if (!success) { RSA_free(rsa); return atom_error; } result = put_rsa_private_key(env, rsa); RSA_free(rsa); return result; }
int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) { /* key=[E,N] */ ERL_NIF_TERM head, tail; BIGNUM *e, *n; if (!enif_get_list_cell(env, key, &head, &tail) || !get_bn_from_bin(env, head, &e) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &n) || !enif_is_empty_list(env, tail)) { return 0; } (void) RSA_set0_key(rsa, n, e, NULL); return 1; }
ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Range) */ BIGNUM *bn_range, *bn_rand; ERL_NIF_TERM ret; if(!get_bn_from_bin(env, argv[0], &bn_range)) { return enif_make_badarg(env); } bn_rand = BN_new(); if (BN_rand_range(bn_rand, bn_range) != 1) { ret = atom_false; } else { ret = bin_from_bn(env, bn_rand); } BN_free(bn_rand); BN_free(bn_range); return ret; }
int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) { /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */ ERL_NIF_TERM head, tail; BIGNUM *e, *n, *d; BIGNUM *p, *q; BIGNUM *dmp1, *dmq1, *iqmp; if (!enif_get_list_cell(env, key, &head, &tail) || !get_bn_from_bin(env, head, &e) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &n) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &d)) { return 0; } (void) RSA_set0_key(rsa, n, e, d); if (enif_is_empty_list(env, tail)) { return 1; } if (!enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &q) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dmp1) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dmq1) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &iqmp) || !enif_is_empty_list(env, tail)) { return 0; } (void) RSA_set0_factors(rsa, p, q); (void) RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp); return 1; }
ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Base,Exponent,Modulo,bin_hdr) */ BIGNUM *bn_base = NULL, *bn_exponent = NULL, *bn_modulo = NULL, *bn_result = NULL; BN_CTX *bn_ctx = NULL; unsigned char* ptr; int dlen; unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */ unsigned extra_byte; ERL_NIF_TERM ret; ASSERT(argc == 4); if (!get_bn_from_bin(env, argv[0], &bn_base)) goto bad_arg; if (!get_bn_from_bin(env, argv[1], &bn_exponent)) goto bad_arg; if (!get_bn_from_bin(env, argv[2], &bn_modulo)) goto bad_arg; if (!enif_get_uint(env, argv[3], &bin_hdr)) goto bad_arg; if (bin_hdr != 0 && bin_hdr != 4) goto bad_arg; if ((bn_result = BN_new()) == NULL) goto err; if ((bn_ctx = BN_CTX_new()) == NULL) goto err; if (!BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx)) goto err; dlen = BN_num_bytes(bn_result); if (dlen < 0 || dlen > INT_MAX / 8) goto bad_arg; extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen * 8 - 1); if ((ptr = enif_make_new_binary(env, bin_hdr + extra_byte + (unsigned int)dlen, &ret)) == NULL) goto err; if (bin_hdr) { put_uint32(ptr, extra_byte + (unsigned int)dlen); ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */ ptr += bin_hdr + extra_byte; } BN_bn2bin(bn_result, ptr); goto done; bad_arg: err: ret = enif_make_badarg(env); done: if (bn_base) BN_free(bn_base); if (bn_exponent) BN_free(bn_exponent); if (bn_modulo) BN_free(bn_modulo); if (bn_result) BN_free(bn_result); if (bn_ctx) BN_CTX_free(bn_ctx); return ret; }
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); } }