diff options
Diffstat (limited to 'lib/crypto/c_src/evp.c')
| -rw-r--r-- | lib/crypto/c_src/evp.c | 164 | 
1 files changed, 164 insertions, 0 deletions
diff --git a/lib/crypto/c_src/evp.c b/lib/crypto/c_src/evp.c new file mode 100644 index 0000000000..3bf66bfffe --- /dev/null +++ b/lib/crypto/c_src/evp.c @@ -0,0 +1,164 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010-2018. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + */ + +#include "evp.h" + +ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +    /*    (Curve, PeerBin, MyBin) */ +{ +#ifdef HAVE_ED_CURVE_DH +    ERL_NIF_TERM ret; +    int type; +    EVP_PKEY_CTX *ctx = NULL; +    ErlNifBinary peer_bin, my_bin, key_bin; +    EVP_PKEY *peer_key = NULL, *my_key = NULL; +    size_t max_size; +    int key_bin_alloc = 0; + +    ASSERT(argc == 3); + +    if (argv[0] == atom_x25519) +        type = EVP_PKEY_X25519; +    else if (argv[0] == atom_x448) +        type = EVP_PKEY_X448; +    else +        goto bad_arg; + +    if (!enif_inspect_binary(env, argv[1], &peer_bin)) +        goto bad_arg; +    if (!enif_inspect_binary(env, argv[2], &my_bin)) +        goto bad_arg; + +    if ((my_key = EVP_PKEY_new_raw_private_key(type, NULL, my_bin.data, my_bin.size)) == NULL) +        goto err; +    if ((ctx = EVP_PKEY_CTX_new(my_key, NULL)) == NULL) +        goto err; + +    if (EVP_PKEY_derive_init(ctx) != 1) +        goto err; + +    if ((peer_key = EVP_PKEY_new_raw_public_key(type, NULL, peer_bin.data, peer_bin.size)) == NULL) +        goto err; +    if (EVP_PKEY_derive_set_peer(ctx, peer_key) != 1) +        goto err; + +    if (EVP_PKEY_derive(ctx, NULL, &max_size) != 1) +        goto err; + +    if (!enif_alloc_binary(max_size, &key_bin)) +        goto err; +    key_bin_alloc = 1; +    if (EVP_PKEY_derive(ctx, key_bin.data, &key_bin.size) != 1) +        goto err; + +    if (key_bin.size < max_size) { +        if (!enif_realloc_binary(&key_bin, (size_t)key_bin.size)) +            goto err; +    } + +    ret = enif_make_binary(env, &key_bin); +    key_bin_alloc = 0; +    goto done; + + bad_arg: + err: +    if (key_bin_alloc) +        enif_release_binary(&key_bin); +    ret = enif_make_badarg(env); + + done: +    if (my_key) +        EVP_PKEY_free(my_key); +    if (peer_key) +        EVP_PKEY_free(peer_key); +    if (ctx) +        EVP_PKEY_CTX_free(ctx); + +    return ret; + +#else +    return atom_notsup; +#endif +} + +ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +/* (Curve) */ +{ +#ifdef HAVE_ED_CURVE_DH +    int type; +    EVP_PKEY_CTX *ctx = NULL; +    EVP_PKEY *pkey = NULL; +    ERL_NIF_TERM ret_pub, ret_prv, ret; +    size_t key_len; +    unsigned char *out_pub = NULL, *out_priv = NULL; + +    ASSERT(argc == 1); + +    if (argv[0] == atom_x25519) +        type = EVP_PKEY_X25519; +    else if (argv[0] == atom_x448) +        type = EVP_PKEY_X448; +    else +        goto bad_arg; + +    if ((ctx = EVP_PKEY_CTX_new_id(type, NULL)) == NULL) +        goto bad_arg; + +    if (EVP_PKEY_keygen_init(ctx) != 1) +        goto err; +    if (EVP_PKEY_keygen(ctx, &pkey) != 1) +        goto err; + +    if (EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len) != 1) +        goto err; +    if ((out_pub = enif_make_new_binary(env, key_len, &ret_pub)) == NULL) +        goto err; +    if (EVP_PKEY_get_raw_public_key(pkey, out_pub, &key_len) != 1) +        goto err; + +    if (EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len) != 1) +        goto err; +    if ((out_priv = enif_make_new_binary(env, key_len, &ret_prv)) == NULL) +        goto err; +    if (EVP_PKEY_get_raw_private_key(pkey, out_priv, &key_len) != 1) +        goto err; + +    ret = enif_make_tuple2(env, ret_pub, ret_prv); +    goto done; + + bad_arg: +    ret = enif_make_badarg(env); +    goto done; + + err: +    ret = atom_error; + + done: +    if (pkey) +        EVP_PKEY_free(pkey); +    if (ctx) +        EVP_PKEY_CTX_free(ctx); +    return ret; + +#else +    return atom_notsup; +#endif +} +  | 
