aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto/c_src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto/c_src')
-rw-r--r--lib/crypto/c_src/Makefile.in41
-rw-r--r--lib/crypto/c_src/crypto.c1514
-rw-r--r--lib/crypto/c_src/crypto_callback.c24
3 files changed, 1426 insertions, 153 deletions
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index a20ddff05c..8c92b5ba1b 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -70,6 +70,10 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN)
CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o
CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o
NIF_MAKEFILE = $(PRIVDIR)/Makefile
+CRYPTO_STATIC_OBJS = $(OBJDIR)/crypto_static$(TYPEMARKER).o\
+ $(OBJDIR)/crypto_callback_static$(TYPEMARKER).o
+
+NIF_ARCHIVE = $(LIBDIR)/crypto$(TYPEMARKER).a
ifeq ($(findstring win32,$(TARGET)), win32)
NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll
@@ -97,7 +101,24 @@ CALLBACK_OBJS =
CALLBACK_LIB =
endif
+ifeq ($(USING_VC),yes)
+AR_OUT=-out:
+AR_FLAGS=
+else
+AR_OUT=
+ifeq ($(V),0)
+AR_FLAGS=rc
+else
+AR_FLAGS=rcv
+endif
+endif
+
+ifndef RANLIB
+RANLIB=true
+endif
+
ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES)
+ALL_STATIC_CFLAGS = $(DED_STATIC_CFLAGS) $(INCLUDES)
# ----------------------------------------------------
# Targets
@@ -105,7 +126,14 @@ ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES)
_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
+ifneq ($(findstring ose,$(TARGET)),ose)
debug opt valgrind: $(NIF_LIB) $(CALLBACK_LIB)
+else
+# Do not build dynamic files on OSE
+debug opt valgrind:
+endif
+
+static_lib: $(NIF_ARCHIVE)
$(OBJDIR)/%$(TYPEMARKER).o: %.c
$(V_at)$(INSTALL_DIR) $(OBJDIR)
@@ -115,6 +143,14 @@ $(LIBDIR)/crypto$(TYPEMARKER).so: $(CRYPTO_OBJS)
$(V_at)$(INSTALL_DIR) $(LIBDIR)
$(V_LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB)
+$(OBJDIR)/%_static$(TYPEMARKER).o: %.c
+ $(V_at)$(INSTALL_DIR) $(OBJDIR)
+ $(V_CC) -c -o $@ $(ALL_STATIC_CFLAGS) $<
+
+$(LIBDIR)/crypto$(TYPEMARKER).a: $(CRYPTO_STATIC_OBJS)
+ $(V_AR) $(AR_FLAGS) $(AR_OUT)$@ $(CRYPTO_STATIC_OBJS)
+ $(V_RANLIB) $@
+
$(LIBDIR)/crypto$(TYPEMARKER).dll: $(CRYPTO_OBJS)
$(V_at)$(INSTALL_DIR) $(LIBDIR)
$(V_LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(CRYPTO_OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME)
@@ -145,8 +181,11 @@ else
rm -f $(LIBDIR)/crypto_callback.valgrind.so
endif
rm -f $(OBJDIR)/crypto.o
+ rm -f $(OBJDIR)/crypto_static.o
rm -f $(OBJDIR)/crypto.debug.o
+ rm -f $(OBJDIR)/crypto_static.debug.o
rm -f $(OBJDIR)/crypto.valgrind.o
+ rm -f $(OBJDIR)/crypto_static.valgrind.o
rm -f $(OBJDIR)/crypto_callback.o
rm -f $(OBJDIR)/crypto_callback.debug.o
rm -f $(OBJDIR)/crypto_callback.valgrind.o
@@ -163,12 +202,14 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/priv/obj"
$(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
$(INSTALL_DATA) $(NIF_MAKEFILE) "$(RELSYSDIR)/priv/obj"
+ifneq ($(findstring ose,$(TARGET)),ose)
$(INSTALL_PROGRAM) $(CRYPTO_OBJS) "$(RELSYSDIR)/priv/obj"
$(INSTALL_PROGRAM) $(NIF_LIB) "$(RELSYSDIR)/priv/lib"
ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
$(INSTALL_PROGRAM) $(CALLBACK_OBJS) "$(RELSYSDIR)/priv/obj"
$(INSTALL_PROGRAM) $(CALLBACK_LIB) "$(RELSYSDIR)/priv/lib"
endif
+endif
release_docs_spec:
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index e77e5fb8f0..26e2486dc2 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -74,6 +74,25 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090803fL
+# define HAVE_AES_IGE
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
+
+
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -129,6 +148,19 @@
(s)[3] = (char)((i) & 0xff);\
}
+/* This shall correspond to the similar macro in crypto.erl */
+/* Current value is: erlang:system_info(context_reductions) * 10 */
+#define MAX_BYTES_TO_NIF 20000
+
+#define CONSUME_REDS(NifEnv, Ibin) \
+do { \
+ int _cost = ((Ibin).size * 100) / MAX_BYTES_TO_NIF;\
+ if (_cost) { \
+ (void) enif_consume_timeslice((NifEnv), \
+ (_cost > 100) ? 100 : _cost); \
+ } \
+ } while (0)
+
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
@@ -136,6 +168,7 @@ static void unload(ErlNifEnv* env, void* priv_data);
/* The NIFs: */
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -182,6 +215,7 @@ static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -191,10 +225,11 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -207,14 +242,24 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
+static void init_algorithms_types(ErlNifEnv*);
static void init_digest_types(ErlNifEnv* env);
static void hmac_md5(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
@@ -242,11 +287,17 @@ static void hmac_sha512(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
#endif
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
static ErlNifFunc nif_funcs[] = {
{"info_lib", 0, info_lib},
+ {"algorithms", 0, algorithms},
{"md5", 1, md5},
{"md5_init", 0, md5_init},
{"md5_update", 2, md5_update},
@@ -294,6 +345,7 @@ static ErlNifFunc nif_funcs[] = {
{"des_ecb_crypt", 3, des_ecb_crypt},
{"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt},
{"des_ede3_cfb_crypt_nif", 6, des_ede3_cfb_crypt_nif},
+ {"aes_cfb_8_crypt", 4, aes_cfb_8_crypt},
{"aes_cfb_128_crypt", 4, aes_cfb_128_crypt},
{"aes_ctr_encrypt", 3, aes_ctr_encrypt},
{"aes_ctr_decrypt", 3, aes_ctr_encrypt},
@@ -304,11 +356,12 @@ static ErlNifFunc nif_funcs[] = {
{"rand_bytes", 3, rand_bytes_3},
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
- {"mod_exp_nif", 3, mod_exp_nif},
- {"dss_verify", 4, dss_verify},
+ {"mod_exp_nif", 4, mod_exp_nif},
+ {"dss_verify_nif", 4, dss_verify_nif},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
- {"exor", 2, exor},
+ {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif},
+ {"do_exor", 2, do_exor},
{"rc4_encrypt", 2, rc4_encrypt},
{"rc4_set_key", 1, rc4_set_key},
{"rc4_encrypt_with_state", 2, rc4_encrypt_with_state},
@@ -319,12 +372,22 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_private_crypt", 4, rsa_private_crypt},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 2, dh_generate_key_nif},
+ {"dh_generate_key_nif", 3, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
+ {"srp_value_B_nif", 5, srp_value_B_nif},
+ {"srp_user_secret_nif", 7, srp_user_secret_nif},
+ {"srp_host_secret_nif", 5, srp_host_secret_nif},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
- {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
+ {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
+
+ {"ec_key_generate", 1, ec_key_generate},
+ {"ecdsa_sign_nif", 4, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 5, ecdsa_verify_nif},
+ {"ecdh_compute_key_nif", 3, ecdh_compute_key_nif},
+
+ {"rand_seed_nif", 1, rand_seed_nif}
};
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -359,6 +422,7 @@ static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_md4;
static ERL_NIF_TERM atom_ripemd160;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
@@ -377,24 +441,114 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_ec;
+static ERL_NIF_TERM atom_prime_field;
+static ERL_NIF_TERM atom_characteristic_two_field;
+static ERL_NIF_TERM atom_tpbasis;
+static ERL_NIF_TERM atom_ppbasis;
+static ERL_NIF_TERM atom_onbasis;
+#endif
+
+static ErlNifResourceType* hmac_context_rtype;
+struct hmac_context
+{
+ ErlNifMutex* mtx;
+ int alive;
+ HMAC_CTX ctx;
+};
+static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*);
+
/*
#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
+#define PRINTF_ERR2(FMT, A1, A2) enif_fprintf(stderr, FMT "\n", A1, A2)
*/
#define PRINTF_ERR0(FMT)
#define PRINTF_ERR1(FMT,A1)
+#define PRINTF_ERR2(FMT,A1,A2)
+
+#ifdef __OSE__
+
+/* For crypto on OSE we have to initialize the crypto library on each
+ process that uses it. So since we do not know which scheduler is going
+ to execute the nif we have to check before each nif call that we have
+ initialized crypto in that process. */
+
+#include "ose.h"
+#include "openssl/osessl.h"
+
+static ErlNifTSDKey crypto_init_key;
+static int check_ose_crypto(void);
+static int init_ose_crypto(void);
+
+static int check_ose_crypto() {
+ int key = (int)enif_tsd_get(crypto_init_key);
+ if (!key) {
+ if (!CRYPTO_OSE5_init()) {
+ PRINTF_ERR0("CRYPTO: Call to CRYPTO_OSE5_init failed");
+ return 0;
+ }
+ enif_tsd_set(crypto_init_key,1);
+ }
+ return 1;
+}
+
+static int init_ose_crypto() {
+ /* Crypto nif upgrade does not work on OSE so no need to
+ destroy this key */
+ enif_tsd_key_create("crypto_init_key", &crypto_init_key);
+ return check_ose_crypto();
+}
+
+#define INIT_OSE_CRYPTO() init_ose_crypto()
+#define CHECK_OSE_CRYPTO() check_ose_crypto()
+#else
+#define INIT_OSE_CRYPTO() 1
+#define CHECK_OSE_CRYPTO()
+#endif
+
+
+static int verify_lib_version(void)
+{
+ const unsigned long libv = SSLeay();
+ const unsigned long hdrv = OPENSSL_VERSION_NUMBER;
+
+# define MAJOR_VER(V) ((unsigned long)(V) >> (7*4))
+
+ if (MAJOR_VER(libv) != MAJOR_VER(hdrv)) {
+ PRINTF_ERR2("CRYPTO: INCOMPATIBLE SSL VERSION"
+ " lib=%lx header=%lx\n", libv, hdrv);
+ return 0;
+ }
+ return 1;
+}
+
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
-static int change_basename(char* buf, int bufsz, const char* newfile)
+
+# if defined(DEBUG)
+static char crypto_callback_name[] = "crypto_callback.debug";
+# elif defined(VALGRIND)
+static char crypto_callback_name[] = "crypto_callback.valgrind";
+# else
+static char crypto_callback_name[] = "crypto_callback";
+# endif
+
+static int change_basename(ErlNifBinary* bin, char* buf, int bufsz, const char* newfile)
{
- char* p = strrchr(buf, '/');
- p = (p == NULL) ? buf : p + 1;
+ int i;
- if ((p - buf) + strlen(newfile) >= bufsz) {
+ for (i = bin->size; i > 0; i--) {
+ if (bin->data[i-1] == '/')
+ break;
+ }
+ if (i + strlen(newfile) >= bufsz) {
PRINTF_ERR0("CRYPTO: lib name too long");
return 0;
}
- strcpy(p, newfile);
+ memcpy(buf, bin->data, i);
+ strcpy(buf+i, newfile);
return 1;
}
@@ -413,18 +567,35 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
int tpl_arity;
const ERL_NIF_TERM* tpl_array;
int vernum;
+ ErlNifBinary lib_bin;
char lib_buf[1000];
- /* load_info: {201, "/full/path/of/this/library"} */
+ if (!INIT_OSE_CRYPTO())
+ return 0;
+
+ if (!verify_lib_version())
+ return 0;
+
+ /* load_info: {301, <<"/full/path/of/this/library">>} */
if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)
|| tpl_arity != 2
|| !enif_get_int(env, tpl_array[0], &vernum)
- || vernum != 201
- || enif_get_string(env, tpl_array[1], lib_buf, sizeof(lib_buf), ERL_NIF_LATIN1) <= 0) {
+ || vernum != 301
+ || !enif_inspect_binary(env, tpl_array[1], &lib_bin)) {
PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info);
return 0;
}
+
+ hmac_context_rtype = enif_open_resource_type(env, NULL, "hmac_context",
+ (ErlNifResourceDtor*) hmac_context_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (!hmac_context_rtype) {
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'");
+ return 0;
+ }
+
if (library_refc > 0) {
/* Repeated loading of this library (module upgrade).
* Atoms and callbacks are already set, we are done.
@@ -439,6 +610,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
+ atom_md4 = enif_make_atom(env,"md4");
atom_md5 = enif_make_atom(env,"md5");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
atom_error = enif_make_atom(env,"error");
@@ -457,12 +629,22 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+#if defined(HAVE_EC)
+ atom_ec = enif_make_atom(env,"ec");
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+#endif
+
init_digest_types(env);
+ init_algorithms_types(env);
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
{
void* handle;
- if (!change_basename(lib_buf, sizeof(lib_buf), "crypto_callback")) {
+ if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) {
return 0;
}
if (!(handle = enif_dlopen(lib_buf, &error_handler, NULL))) {
@@ -538,6 +720,63 @@ static void unload(ErlNifEnv* env, void* priv_data)
--library_refc;
}
+static int algo_hash_cnt;
+static ERL_NIF_TERM algo_hash[8]; /* increase when extending the list */
+static int algo_pubkey_cnt;
+static ERL_NIF_TERM algo_pubkey[3]; /* increase when extending the list */
+static int algo_cipher_cnt;
+static ERL_NIF_TERM algo_cipher[2]; /* increase when extending the list */
+
+static void init_algorithms_types(ErlNifEnv* env)
+{
+ algo_hash_cnt = 0;
+ algo_hash[algo_hash_cnt++] = atom_md4;
+ algo_hash[algo_hash_cnt++] = atom_md5;
+ algo_hash[algo_hash_cnt++] = atom_sha;
+ algo_hash[algo_hash_cnt++] = atom_ripemd160;
+#ifdef HAVE_SHA224
+ algo_hash[algo_hash_cnt++] = atom_sha224;
+#endif
+#ifdef HAVE_SHA256
+ algo_hash[algo_hash_cnt++] = atom_sha256;
+#endif
+#ifdef HAVE_SHA384
+ algo_hash[algo_hash_cnt++] = atom_sha384;
+#endif
+#ifdef HAVE_SHA512
+ algo_hash[algo_hash_cnt++] = atom_sha512;
+#endif
+
+ algo_pubkey_cnt = 0;
+#if defined(HAVE_EC)
+#if !defined(OPENSSL_NO_EC2M)
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env,"ec_gf2m");
+#endif
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env,"ecdsa");
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env,"ecdh");
+#endif
+
+ algo_cipher_cnt = 0;
+#ifdef HAVE_DES_ede3_cfb_encrypt
+ algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbf");
+#endif
+#ifdef HAVE_AES_IGE
+ algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ige256");
+#endif
+
+ ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_cipher_cnt <= sizeof(algo_cipher)/sizeof(ERL_NIF_TERM));
+}
+
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_make_tuple3(env,
+ enif_make_list_from_array(env, algo_hash, algo_hash_cnt),
+ enif_make_list_from_array(env, algo_pubkey, algo_pubkey_cnt),
+ enif_make_list_from_array(env, algo_cipher, algo_cipher_cnt));
+}
+
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
/* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
@@ -569,17 +808,19 @@ static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data) */
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
MD5((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,MD5_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* () */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
MD5_Init((MD5_CTX *) enif_make_new_binary(env, MD5_CTX_LEN, &ret));
return ret;
}
@@ -588,6 +829,7 @@ static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
MD5_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin)
|| ctx_bin.size != MD5_CTX_LEN
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
@@ -596,6 +838,7 @@ static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
new_ctx = (MD5_CTX*) enif_make_new_binary(env,MD5_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, MD5_CTX_LEN);
MD5_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
}
static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -603,6 +846,7 @@ static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ErlNifBinary ctx_bin;
MD5_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD5_CTX_LEN) {
return enif_make_badarg(env);
}
@@ -615,17 +859,19 @@ static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
{/* (Data) */
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
- return enif_make_badarg(env);
+ return enif_make_badarg(env);
}
RIPEMD160((unsigned char *) ibin.data, ibin.size,
- enif_make_new_binary(env,RIPEMD160_LEN, &ret));
+ enif_make_new_binary(env,RIPEMD160_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* () */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
RIPEMD160_Init((RIPEMD160_CTX *) enif_make_new_binary(env, RIPEMD160_CTX_LEN, &ret));
return ret;
}
@@ -634,14 +880,16 @@ static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TER
RIPEMD160_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin)
- || ctx_bin.size != RIPEMD160_CTX_LEN
- || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
- return enif_make_badarg(env);
+ || ctx_bin.size != RIPEMD160_CTX_LEN
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
}
new_ctx = (RIPEMD160_CTX*) enif_make_new_binary(env,RIPEMD160_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, RIPEMD160_CTX_LEN);
RIPEMD160_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env, data_bin);
return ret;
}
static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -649,8 +897,9 @@ static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ErlNifBinary ctx_bin;
RIPEMD160_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != RIPEMD160_CTX_LEN) {
- return enif_make_badarg(env);
+ return enif_make_badarg(env);
}
memcpy(&ctx_clone, ctx_bin.data, RIPEMD160_CTX_LEN); /* writable */
RIPEMD160_Final(enif_make_new_binary(env, RIPEMD160_LEN, &ret), &ctx_clone);
@@ -662,17 +911,19 @@ static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data) */
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
SHA1((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* () */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
SHA1_Init((SHA_CTX *) enif_make_new_binary(env, SHA_CTX_LEN, &ret));
return ret;
}
@@ -681,6 +932,7 @@ static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
SHA_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != SHA_CTX_LEN
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
@@ -688,6 +940,7 @@ static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
new_ctx = (SHA_CTX*) enif_make_new_binary(env,SHA_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, SHA_CTX_LEN);
SHA1_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
}
static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -695,6 +948,7 @@ static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ErlNifBinary ctx_bin;
SHA_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != SHA_CTX_LEN) {
return enif_make_badarg(env);
}
@@ -708,12 +962,13 @@ static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
#ifdef HAVE_SHA224
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
SHA224((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA224_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -723,6 +978,7 @@ static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
{/* () */
#ifdef HAVE_SHA224
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
SHA224_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret));
return ret;
#else
@@ -735,6 +991,7 @@ static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
SHA256_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
@@ -742,6 +999,7 @@ static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX));
SHA224_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -753,6 +1011,7 @@ static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
ErlNifBinary ctx_bin;
SHA256_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) {
return enif_make_badarg(env);
}
@@ -769,12 +1028,13 @@ static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
#ifdef HAVE_SHA256
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
SHA256((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA256_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -784,6 +1044,7 @@ static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
{/* () */
#ifdef HAVE_SHA256
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
SHA256_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret));
return ret;
#else
@@ -796,6 +1057,7 @@ static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
SHA256_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
@@ -803,6 +1065,7 @@ static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX));
SHA256_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -814,6 +1077,7 @@ static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
ErlNifBinary ctx_bin;
SHA256_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) {
return enif_make_badarg(env);
}
@@ -830,12 +1094,13 @@ static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
#ifdef HAVE_SHA384
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
SHA384((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA384_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -845,6 +1110,7 @@ static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
{/* () */
#ifdef HAVE_SHA384
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
SHA384_Init((SHA512_CTX *) enif_make_new_binary(env, sizeof(SHA512_CTX), &ret));
return ret;
#else
@@ -857,6 +1123,7 @@ static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
SHA512_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
@@ -864,6 +1131,7 @@ static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX));
SHA384_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -875,6 +1143,7 @@ static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
ErlNifBinary ctx_bin;
SHA512_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) {
return enif_make_badarg(env);
}
@@ -891,12 +1160,13 @@ static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
#ifdef HAVE_SHA512
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
SHA512((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA512_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -918,6 +1188,7 @@ static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
SHA512_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
@@ -925,6 +1196,7 @@ static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX));
SHA512_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -936,6 +1208,7 @@ static ERL_NIF_TERM sha512_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
ErlNifBinary ctx_bin;
SHA512_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) {
return enif_make_badarg(env);
}
@@ -952,17 +1225,19 @@ static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data) */
ErlNifBinary ibin;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
return enif_make_badarg(env);
}
MD4((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,MD4_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* () */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
MD4_Init((MD4_CTX *) enif_make_new_binary(env, MD4_CTX_LEN, &ret));
return ret;
}
@@ -971,6 +1246,7 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
MD4_CTX* new_ctx;
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD4_CTX_LEN
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
@@ -978,6 +1254,7 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
new_ctx = (MD4_CTX*) enif_make_new_binary(env,MD4_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, MD4_CTX_LEN);
MD4_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
}
static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -985,6 +1262,7 @@ static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ErlNifBinary ctx_bin;
MD4_CTX ctx_clone;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD4_CTX_LEN) {
return enif_make_badarg(env);
}
@@ -999,7 +1277,7 @@ static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ErlNifBinary key, data;
unsigned mac_sz;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data)
|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > MD5_LEN) {
@@ -1007,6 +1285,7 @@ static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
}
hmac_md5(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
}
@@ -1016,7 +1295,7 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ErlNifBinary key, data;
unsigned mac_sz;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data)
|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA_LEN) {
@@ -1025,6 +1304,7 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
hmac_sha1(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
}
@@ -1035,7 +1315,7 @@ static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ErlNifBinary key, data;
unsigned mac_sz;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data)
|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA224_DIGEST_LENGTH) {
@@ -1044,6 +1324,7 @@ static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1057,7 +1338,7 @@ static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ErlNifBinary key, data;
unsigned mac_sz;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data)
|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA256_DIGEST_LENGTH) {
@@ -1066,6 +1347,7 @@ static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1079,7 +1361,7 @@ static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ErlNifBinary key, data;
unsigned mac_sz;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data)
|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA384_DIGEST_LENGTH) {
@@ -1088,6 +1370,7 @@ static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1102,7 +1385,7 @@ static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ErlNifBinary key, data;
unsigned mac_sz;
ERL_NIF_TERM ret;
-
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data)
|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA512_DIGEST_LENGTH) {
@@ -1111,19 +1394,31 @@ static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
#endif
}
+static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)
+{
+ if (obj->alive) {
+ HMAC_CTX_cleanup(&obj->ctx);
+ obj->alive = 0;
+ }
+ enif_mutex_destroy(obj->mtx);
+}
+
static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key) */
ErlNifBinary key;
- ERL_NIF_TERM ret;
- unsigned char * ctx_buf;
+ struct hmac_context* obj;
const EVP_MD *md;
+ ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (argv[0] == atom_sha) md = EVP_sha1();
#ifdef HAVE_SHA224
else if (argv[0] == atom_sha224) md = EVP_sha224();
@@ -1146,59 +1441,69 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_badarg(env);
}
- ctx_buf = enif_make_new_binary(env, sizeof(HMAC_CTX), &ret);
- HMAC_CTX_init((HMAC_CTX *) ctx_buf);
- HMAC_Init((HMAC_CTX *) ctx_buf, key.data, key.size, md);
+ obj = enif_alloc_resource(hmac_context_rtype, sizeof(struct hmac_context));
+ obj->mtx = enif_mutex_create("crypto.hmac");
+ obj->alive = 1;
+ HMAC_CTX_init(&obj->ctx);
+ HMAC_Init(&obj->ctx, key.data, key.size, md);
+ ret = enif_make_resource(env, obj);
+ enif_release_resource(obj);
return ret;
}
static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Context, Data) */
- ErlNifBinary context, data;
- ERL_NIF_TERM ret;
- unsigned char * ctx_buf;
+ ErlNifBinary data;
+ struct hmac_context* obj;
- if (!enif_inspect_binary(env, argv[0], &context)
- || !enif_inspect_iolist_as_binary(env, argv[1], &data)
- || context.size != sizeof(HMAC_CTX)) {
+ CHECK_OSE_CRYPTO();
+
+ if (!enif_get_resource(env, argv[0], hmac_context_rtype, (void**)&obj)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data)) {
return enif_make_badarg(env);
}
+ enif_mutex_lock(obj->mtx);
+ if (!obj->alive) {
+ enif_mutex_unlock(obj->mtx);
+ return enif_make_badarg(env);
+ }
+ HMAC_Update(&obj->ctx, data.data, data.size);
+ enif_mutex_unlock(obj->mtx);
- ctx_buf = enif_make_new_binary(env, sizeof(HMAC_CTX), &ret);
- memcpy(ctx_buf, context.data, context.size);
- HMAC_Update((HMAC_CTX *)ctx_buf, data.data, data.size);
-
- return ret;
+ CONSUME_REDS(env,data);
+ return argv[0];
}
static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Context) or (Context, HashLen) */
- ErlNifBinary context;
ERL_NIF_TERM ret;
- HMAC_CTX ctx;
+ struct hmac_context* obj;
unsigned char mac_buf[EVP_MAX_MD_SIZE];
unsigned char * mac_bin;
unsigned int req_len = 0;
unsigned int mac_len;
+
+ CHECK_OSE_CRYPTO();
- if (!enif_inspect_binary(env, argv[0], &context)) {
- return enif_make_badarg(env);
- }
- if (argc == 2 && !enif_get_uint(env, argv[1], &req_len)) {
+ if (!enif_get_resource(env,argv[0],hmac_context_rtype, (void**)&obj)
+ || (argc == 2 && !enif_get_uint(env, argv[1], &req_len))) {
return enif_make_badarg(env);
}
- if (context.size != sizeof(ctx)) {
- return enif_make_badarg(env);
+ enif_mutex_lock(obj->mtx);
+ if (!obj->alive) {
+ enif_mutex_unlock(obj->mtx);
+ return enif_make_badarg(env);
}
- memcpy(&ctx, context.data, context.size);
- HMAC_Final(&ctx, mac_buf, &mac_len);
- HMAC_CTX_cleanup(&ctx);
+ HMAC_Final(&obj->ctx, mac_buf, &mac_len);
+ HMAC_CTX_cleanup(&obj->ctx);
+ obj->alive = 0;
+ enif_mutex_unlock(obj->mtx);
if (argc == 2 && req_len < mac_len) {
- // Only truncate to req_len bytes if asked.
+ /* Only truncate to req_len bytes if asked. */
mac_len = req_len;
}
mac_bin = enif_make_new_binary(env, mac_len, &ret);
@@ -1214,6 +1519,8 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_cblock ivec_clone; /* writable copy */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8
|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 8
|| !enif_inspect_iolist_as_binary(env, argv[2], &text)
@@ -1224,6 +1531,7 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_set_key((const_DES_cblock*)key.data, &schedule);
DES_ncbc_encrypt(text.data, enif_make_new_binary(env, text.size, &ret),
text.size, &schedule, &ivec_clone, (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1234,6 +1542,8 @@ static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_cblock ivec_clone; /* writable copy */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8
|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 8
|| !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
@@ -1243,6 +1553,7 @@ static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_set_key((const_DES_cblock*)key.data, &schedule);
DES_cfb_encrypt(text.data, enif_make_new_binary(env, text.size, &ret),
8, text.size, &schedule, &ivec_clone, (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1251,6 +1562,7 @@ static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
ErlNifBinary key, text;
DES_key_schedule schedule;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8 ||
!enif_inspect_iolist_as_binary(env, argv[1], &text) || text.size != 8) {
return enif_make_badarg(env);
@@ -1259,6 +1571,7 @@ static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_ecb_encrypt((const_DES_cblock*)text.data,
(DES_cblock*)enif_make_new_binary(env, 8, &ret),
&schedule, (argv[2] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1269,6 +1582,8 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T
DES_cblock ivec_clone; /* writable copy */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key1) || key1.size != 8
|| !enif_inspect_iolist_as_binary(env, argv[1], &key2) || key2.size != 8
|| !enif_inspect_iolist_as_binary(env, argv[2], &key3) || key3.size != 8
@@ -1285,6 +1600,7 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T
DES_ede3_cbc_encrypt(text.data, enif_make_new_binary(env,text.size,&ret),
text.size, &schedule1, &schedule2, &schedule3,
&ivec_clone, (argv[5] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1296,6 +1612,8 @@ static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_N
DES_cblock ivec_clone; /* writable copy */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key1) || key1.size != 8
|| !enif_inspect_iolist_as_binary(env, argv[1], &key2) || key2.size != 8
|| !enif_inspect_iolist_as_binary(env, argv[2], &key3) || key3.size != 8
@@ -1311,12 +1629,38 @@ static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_N
DES_ede3_cfb_encrypt(text.data, enif_make_new_binary(env,text.size,&ret),
8, text.size, &schedule1, &schedule2, &schedule3,
&ivec_clone, (argv[5] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
#else
return atom_notsup;
#endif
}
+static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ AES_KEY aes_key;
+ unsigned char ivec_clone[16]; /* writable copy */
+ int new_ivlen = 0;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !(key.size == 16 || key.size == 24 || key.size == 32)
+ || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
+ return enif_make_badarg(env);
+ }
+
+ memcpy(ivec_clone, ivec.data, 16);
+ AES_set_encrypt_key(key.data, key.size * 8, &aes_key);
+ AES_cfb8_encrypt((unsigned char *) text.data,
+ enif_make_new_binary(env, text.size, &ret),
+ text.size, &aes_key, ivec_clone, &new_ivlen,
+ (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
+ return ret;
+}
+
static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec, Data, IsEncrypt) */
ErlNifBinary key, ivec, text;
@@ -1325,18 +1669,22 @@ static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
int new_ivlen = 0;
ERL_NIF_TERM ret;
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 16
+ CHECK_OSE_CRYPTO();
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !(key.size == 16 || key.size == 24 || key.size == 32)
|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
|| !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
return enif_make_badarg(env);
}
memcpy(ivec_clone, ivec.data, 16);
- AES_set_encrypt_key(key.data, 128, &aes_key);
+ AES_set_encrypt_key(key.data, key.size * 8, &aes_key);
AES_cfb128_encrypt((unsigned char *) text.data,
enif_make_new_binary(env, text.size, &ret),
text.size, &aes_key, ivec_clone, &new_ivlen,
(argv[3] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1351,6 +1699,8 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
unsigned int num = 0;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
|| AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0
|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
@@ -1362,6 +1712,7 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
AES_ctr128_encrypt((unsigned char *) text.data,
enif_make_new_binary(env, text.size, &ret),
text.size, &aes_key, ivec_clone, ecount_buf, &num);
+ CONSUME_REDS(env,text);
/* To do an incremental {en|de}cryption, the state to to keep between calls
must include ivec_clone, ecount_buf and num. */
@@ -1381,6 +1732,8 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N
unsigned char * ivec2_buf;
unsigned char * ecount2_buf;
+ CHECK_OSE_CRYPTO();
+
if (!enif_get_tuple(env, argv[0], &state_arity, &state_term)
|| state_arity != 4
|| !enif_inspect_iolist_as_binary(env, state_term[0], &key_bin)
@@ -1405,6 +1758,7 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N
num2_term = enif_make_uint(env, num);
new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term);
ret = enif_make_tuple2(env, new_state_term, cipher_term);
+ CONSUME_REDS(env,text_bin);
return ret;
}
@@ -1413,6 +1767,7 @@ static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
unsigned bytes;
unsigned char* data;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_get_uint(env, argv[0], &bytes)) {
return enif_make_badarg(env);
}
@@ -1426,6 +1781,7 @@ static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NI
unsigned bytes;
unsigned char* data;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_get_uint(env, argv[0], &bytes)) {
return enif_make_badarg(env);
}
@@ -1443,6 +1799,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
unsigned char* data;
unsigned top_mask, bot_mask;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
if (!enif_get_uint(env, argv[0], &bytes)
|| !enif_get_uint(env, argv[1], &top_mask)
|| !enif_get_uint(env, argv[2], &bot_mask)) {
@@ -1465,6 +1822,9 @@ static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NI
unsigned char* data;
unsigned dlen;
ERL_NIF_TERM ret;
+
+ CHECK_OSE_CRYPTO();
+
if (!enif_get_uint(env, argv[0], &bits)
|| !enif_get_int(env, argv[1], &top)
|| !enif_get_int(env, argv[2], &bottom)) {
@@ -1515,12 +1875,26 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ *bnp = BN_bin2bn(bin.data, bin.size, NULL);
+ return 1;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
unsigned char* data;
unsigned dlen;
ERL_NIF_TERM ret;
+
+ CHECK_OSE_CRYPTO();
+
if (!get_bn_from_mpint(env, argv[0], &bn_from)
|| !get_bn_from_mpint(env, argv[1], &bn_rand)) {
if (bn_from) BN_free(bn_from);
@@ -1543,28 +1917,39 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
}
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Base,Exponent,Modulo) */
- BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo, *bn_result;
+{/* (Base,Exponent,Modulo,bin_hdr) */
+ BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo=NULL, *bn_result;
BN_CTX *bn_ctx;
unsigned char* ptr;
unsigned dlen;
+ unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
+ unsigned extra_byte;
ERL_NIF_TERM ret;
- if (!get_bn_from_mpint(env, argv[0], &bn_base)
- || !get_bn_from_mpint(env, argv[1], &bn_exponent)
- || !get_bn_from_mpint(env, argv[2], &bn_modulo)) {
+ CHECK_OSE_CRYPTO();
+
+ if (!get_bn_from_bin(env, argv[0], &bn_base)
+ || !get_bn_from_bin(env, argv[1], &bn_exponent)
+ || !get_bn_from_bin(env, argv[2], &bn_modulo)
+ || !enif_get_uint(env,argv[3],&bin_hdr) || (bin_hdr & ~4)) {
if (bn_base) BN_free(bn_base);
if (bn_exponent) BN_free(bn_exponent);
+ if (bn_modulo) BN_free(bn_modulo);
return enif_make_badarg(env);
}
bn_result = BN_new();
bn_ctx = BN_CTX_new();
BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx);
dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen+4, &ret);
- put_int32(ptr, dlen);
- BN_bn2bin(bn_result, ptr+4);
+ extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen*8-1);
+ ptr = enif_make_new_binary(env, bin_hdr+extra_byte+dlen, &ret);
+ if (bin_hdr) {
+ put_int32(ptr, extra_byte+dlen);
+ ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
+ ptr += bin_hdr + extra_byte;
+ }
+ BN_bn2bin(bn_result, ptr);
BN_free(bn_result);
BN_CTX_free(bn_ctx);
BN_free(bn_modulo);
@@ -1573,13 +1958,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return ret;
}
-static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)
-{
- return enif_inspect_binary(env, term, bin) &&
- bin->size >= 4 && get_int32(bin->data) == bin->size-4;
-}
-
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */
ErlNifBinary data_bin, sign_bin;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
@@ -1591,6 +1970,8 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
DSA *dsa;
int i;
+ CHECK_OSE_CRYPTO();
+
if (argv[0] == atom_sha) {
if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
if (tpl_arity != 2 || tpl_terms[0] != atom_digest
@@ -1602,10 +1983,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env, argv[1], &data_bin)) {
+ if (!enif_inspect_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -1617,15 +1998,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return enif_make_badarg(env);
}
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_p)
+ || !get_bn_from_bin(env, head, &dsa_p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_q)
+ || !get_bn_from_bin(env, head, &dsa_q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_g)
+ || !get_bn_from_bin(env, head, &dsa_g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_y)
+ || !get_bn_from_bin(env, head, &dsa_y)
|| !enif_is_empty_list(env,tail)) {
if (dsa_p) BN_free(dsa_p);
@@ -1642,7 +2023,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
dsa->priv_key = NULL;
dsa->pub_key = dsa_y;
i = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, dsa);
+ sign_bin.data, sign_bin.size, dsa);
DSA_free(dsa);
return(i > 0) ? atom_true : atom_false;
}
@@ -1758,6 +2139,8 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
struct digest_type_t* digp = NULL;
unsigned char* digest = NULL;
+ CHECK_OSE_CRYPTO();
+
digp = get_digest_type(type);
if (!digp) {
return enif_make_badarg(env);
@@ -1768,11 +2151,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
rsa = RSA_new();
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -1788,9 +2171,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
digest = data_bin.data;
}
- else if (inspect_mpint(env, argv[1], &data_bin)) {
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
else {
ret = enif_make_badarg(env);
@@ -1798,7 +2181,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
i = RSA_verify(digp->NID_type, digest, digp->len,
- sign_bin.data+4, sign_bin.size-4, rsa);
+ sign_bin.data, sign_bin.size, rsa);
ret = (i==1 ? atom_true : atom_false);
@@ -1817,6 +2200,8 @@ static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
unsigned char* ret_ptr;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
|| (key_bin.size != 16 && key_bin.size != 32)
|| !enif_inspect_binary(env, argv[1], &ivec_bin)
@@ -1839,16 +2224,60 @@ static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
ret_ptr = enif_make_new_binary(env, data_bin.size, &ret);
memcpy(ivec, ivec_bin.data, 16); /* writable copy */
AES_cbc_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i);
+ CONSUME_REDS(env,data_bin);
+ return ret;
+}
+
+static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+#ifdef HAVE_AES_IGE
+ ErlNifBinary key_bin, ivec_bin, data_bin;
+ AES_KEY aes_key;
+ unsigned char ivec[32];
+ int i;
+ unsigned char* ret_ptr;
+ ERL_NIF_TERM ret;
+
+ CHECK_OSE_CRYPTO();
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || (key_bin.size != 16 && key_bin.size != 32)
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || ivec_bin.size != 32
+ || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)
+ || data_bin.size % 16 != 0) {
+
+ return enif_make_badarg(env);
+ }
+
+ if (argv[3] == atom_true) {
+ i = AES_ENCRYPT;
+ AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key);
+ }
+ else {
+ i = AES_DECRYPT;
+ AES_set_decrypt_key(key_bin.data, key_bin.size*8, &aes_key);
+ }
+
+ ret_ptr = enif_make_new_binary(env, data_bin.size, &ret);
+ memcpy(ivec, ivec_bin.data, 32); /* writable copy */
+ AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i);
+ CONSUME_REDS(env,data_bin);
return ret;
+#else
+ return atom_notsup;
+#endif
}
-static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data1, Data2) */
ErlNifBinary d1, d2;
unsigned char* ret_ptr;
int i;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env,argv[0], &d1)
|| !enif_inspect_iolist_as_binary(env,argv[1], &d2)
|| d1.size != d2.size) {
@@ -1859,6 +2288,7 @@ static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
for (i=0; i<d1.size; i++) {
ret_ptr[i] = d1.data[i] ^ d2.data[i];
}
+ CONSUME_REDS(env,d1);
return ret;
}
@@ -1868,6 +2298,8 @@ static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
RC4_KEY rc4_key;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env,argv[0], &key)
|| !enif_inspect_iolist_as_binary(env,argv[1], &data)) {
return enif_make_badarg(env);
@@ -1875,6 +2307,7 @@ static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
RC4_set_key(&rc4_key, key.size, key.data);
RC4(&rc4_key, data.size, data.data,
enif_make_new_binary(env, data.size, &ret));
+ CONSUME_REDS(env,data);
return ret;
}
@@ -1883,6 +2316,8 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
ErlNifBinary key;
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env,argv[0], &key)) {
return enif_make_badarg(env);
}
@@ -1898,6 +2333,8 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N
RC4_KEY* rc4_key;
ERL_NIF_TERM new_state, new_data;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env,argv[0], &state)
|| state.size != sizeof(RC4_KEY)
|| !enif_inspect_iolist_as_binary(env,argv[1], &data)) {
@@ -1907,7 +2344,7 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N
memcpy(rc4_key, state.data, sizeof(RC4_KEY));
RC4(rc4_key, data.size, data.data,
enif_make_new_binary(env, data.size, &new_data));
-
+ CONSUME_REDS(env,data);
return enif_make_tuple2(env,new_state,new_data);
}
@@ -1917,6 +2354,8 @@ static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
RC2_KEY rc2_key;
ERL_NIF_TERM ret;
unsigned char iv_copy[8];
+
+ CHECK_OSE_CRYPTO();
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
|| (key_bin.size != 5 && key_bin.size != 8 && key_bin.size != 16)
@@ -1934,6 +2373,7 @@ static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
data_bin.size, &rc2_key,
iv_copy,
(argv[3] == atom_true));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -1943,22 +2383,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
ERL_NIF_TERM head, tail;
if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->d)
+ || !get_bn_from_bin(env, head, &rsa->d)
|| (!enif_is_empty_list(env, tail) &&
(!enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->p)
+ || !get_bn_from_bin(env, head, &rsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->q)
+ || !get_bn_from_bin(env, head, &rsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmp1)
+ || !get_bn_from_bin(env, head, &rsa->dmp1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmq1)
+ || !get_bn_from_bin(env, head, &rsa->dmq1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->iqmp)
+ || !get_bn_from_bin(env, head, &rsa->iqmp)
|| !enif_is_empty_list(env, tail)))) {
return 0;
}
@@ -1977,6 +2417,8 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
struct digest_type_t *digp;
unsigned char* digest;
+ CHECK_OSE_CRYPTO();
+
digp = get_digest_type(argv[0]);
if (!digp) {
return enif_make_badarg(env);
@@ -1995,11 +2437,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
rsa = RSA_new();
@@ -2043,6 +2485,8 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
DSA* dsa;
int i;
+ CHECK_OSE_CRYPTO();
+
if (argv[0] == atom_sha) {
if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
if (tpl_arity != 2 || tpl_terms[0] != atom_digest
@@ -2054,10 +2498,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -2075,13 +2519,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
dsa->pub_key = NULL;
if (!enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->p)
+ || !get_bn_from_bin(env, head, &dsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->q)
+ || !get_bn_from_bin(env, head, &dsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->g)
+ || !get_bn_from_bin(env, head, &dsa->g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->priv_key)
+ || !get_bn_from_bin(env, head, &dsa->priv_key)
|| !enif_is_empty_list(env,tail)) {
DSA_free(dsa);
return enif_make_badarg(env);
@@ -2098,6 +2542,7 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return enif_make_binary(env, &ret_bin);
}
else {
+ enif_release_binary(&ret_bin);
return atom_error;
}
}
@@ -2125,13 +2570,17 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER
ErlNifBinary data_bin, ret_bin;
ERL_NIF_TERM head, tail;
int padding, i;
- RSA* rsa = RSA_new();
+ RSA* rsa;
+
+ CHECK_OSE_CRYPTO();
+
+ rsa = RSA_new();
if (!enif_inspect_binary(env, argv[0], &data_bin)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env,tail)
|| !rsa_pad(argv[2], &padding)) {
@@ -2171,7 +2620,11 @@ static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
{/* (Data, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Padding, IsEncrypt) */
ErlNifBinary data_bin, ret_bin;
int padding, i;
- RSA* rsa = RSA_new();
+ RSA* rsa;
+
+ CHECK_OSE_CRYPTO();
+
+ rsa = RSA_new();
if (!enif_inspect_binary(env, argv[0], &data_bin)
|| !get_rsa_private_key(env, argv[1], rsa)
@@ -2217,6 +2670,8 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
unsigned char *p_ptr, *g_ptr;
ERL_NIF_TERM ret_p, ret_g;
+ CHECK_OSE_CRYPTO();
+
if (!enif_get_int(env, argv[0], &prime_len)
|| !enif_get_int(env, argv[1], &generator)) {
@@ -2228,28 +2683,30 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
}
p_len = BN_num_bytes(dh_params->p);
g_len = BN_num_bytes(dh_params->g);
- p_ptr = enif_make_new_binary(env, p_len+4, &ret_p);
- g_ptr = enif_make_new_binary(env, g_len+4, &ret_g);
- put_int32(p_ptr, p_len);
- put_int32(g_ptr, g_len);
- BN_bn2bin(dh_params->p, p_ptr+4);
- BN_bn2bin(dh_params->g, g_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len);
+ p_ptr = enif_make_new_binary(env, p_len, &ret_p);
+ g_ptr = enif_make_new_binary(env, g_len, &ret_g);
+ BN_bn2bin(dh_params->p, p_ptr);
+ BN_bn2bin(dh_params->g, g_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len);
DH_free(dh_params);
return enif_make_list2(env, ret_p, ret_g);
}
static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* ([PrimeLen, Generator]) */
- DH* dh_params = DH_new();
+ DH* dh_params;
int i;
ERL_NIF_TERM ret, head, tail;
+ CHECK_OSE_CRYPTO();
+
+ dh_params = DH_new();
+
if (!enif_get_list_cell(env, argv[0], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env,tail)) {
DH_free(dh_params);
@@ -2271,19 +2728,25 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
}
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey, DHParams=[P,G]) */
- DH* dh_params = DH_new();
+{/* (PrivKey, DHParams=[P,G], Mpint) */
+ DH* dh_params;
int pub_len, prv_len;
unsigned char *pub_ptr, *prv_ptr;
ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+ int mpint; /* 0 or 4 */
+
+ CHECK_OSE_CRYPTO();
- if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key)
+ dh_params = DH_new();
+
+ if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key)
|| argv[0] == atom_undefined)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
- || !enif_is_empty_list(env, tail)) {
+ || !get_bn_from_bin(env, head, &dh_params->g)
+ || !enif_is_empty_list(env, tail)
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) {
DH_free(dh_params);
return enif_make_badarg(env);
}
@@ -2291,14 +2754,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
if (DH_generate_key(dh_params)) {
pub_len = BN_num_bytes(dh_params->pub_key);
prv_len = BN_num_bytes(dh_params->priv_key);
- pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv);
- put_int32(pub_ptr, pub_len);
- put_int32(prv_ptr, prv_len);
- BN_bn2bin(dh_params->pub_key, pub_ptr+4);
- BN_bn2bin(dh_params->priv_key, prv_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len);
+ 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(dh_params->pub_key, pub_ptr);
+ BN_bn2bin(dh_params->priv_key, prv_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
ret = enif_make_tuple2(env, ret_pub, ret_prv);
}
else {
@@ -2310,18 +2775,22 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */
- DH* dh_params = DH_new();
+ DH* dh_params;
BIGNUM* pubkey = NULL;
int i;
ErlNifBinary ret_bin;
ERL_NIF_TERM ret, head, tail;
- if (!get_bn_from_mpint(env, argv[0], &pubkey)
- || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key)
+ CHECK_OSE_CRYPTO();
+
+ dh_params = DH_new();
+
+ if (!get_bn_from_bin(env, argv[0], &pubkey)
+ || !get_bn_from_bin(env, argv[1], &dh_params->priv_key)
|| !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -2336,6 +2805,7 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
ret = enif_make_binary(env, &ret_bin);
}
else {
+ enif_release_binary(&ret_bin);
ret = atom_error;
}
}
@@ -2344,6 +2814,212 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent = NULL, *bn_generator = NULL, *bn_prime = NULL, *bn_multiplier = NULL, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ CHECK_OSE_CRYPTO();
+
+ if (!get_bn_from_bin(env, argv[0], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[1], &bn_verifier)
+ || !get_bn_from_bin(env, argv[2], &bn_generator)
+ || !get_bn_from_bin(env, argv[3], &bn_exponent)
+ || !get_bn_from_bin(env, argv[4], &bn_prime)) {
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_result = BN_new();
+ bn_ctx = BN_CTX_new();
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
+
+ /* g^b % N */
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+
+ /* k*v + g^b % N */
+ BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_multiplier)) {
+ ret = atom_error;
+ } else {
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ }
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_prime);
+ BN_free(bn_generator);
+ BN_free(bn_multiplier);
+ BN_free(bn_exponent);
+ BN_free(bn_verifier);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
+/*
+ <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u = NULL, *bn_multiplier = NULL, *bn_exp2,
+ *bn_base, *bn_prime = NULL, *bn_generator = NULL,
+ *bn_B = NULL, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ CHECK_OSE_CRYPTO();
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a)
+ || !get_bn_from_bin(env, argv[1], &bn_u)
+ || !get_bn_from_bin(env, argv[2], &bn_B)
+ || !get_bn_from_bin(env, argv[3], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[4], &bn_generator)
+ || !get_bn_from_bin(env, argv[5], &bn_exponent)
+ || !get_bn_from_bin(env, argv[6], &bn_prime))
+ {
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_a) BN_free(bn_a);
+ if (bn_u) BN_free(bn_u);
+ if (bn_B) BN_free(bn_B);
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that B % N != 0 */
+ BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ BN_free(bn_u);
+ BN_free(bn_B);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (B - (k * g^x)) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
+ BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
+
+ /* a + (u * x) */
+ bn_exp2 = BN_new();
+ BN_mul(bn_result, bn_u, bn_exponent, bn_ctx);
+ BN_add(bn_exp2, bn_a, bn_result);
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_multiplier);
+ BN_free(bn_exp2);
+ BN_free(bn_u);
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_B);
+ BN_free(bn_base);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime = NULL, *bn_A = NULL, *bn_u = NULL, *bn_base, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ CHECK_OSE_CRYPTO();
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier)
+ || !get_bn_from_bin(env, argv[1], &bn_b)
+ || !get_bn_from_bin(env, argv[2], &bn_u)
+ || !get_bn_from_bin(env, argv[3], &bn_A)
+ || !get_bn_from_bin(env, argv[4], &bn_prime))
+ {
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_b) BN_free(bn_b);
+ if (bn_u) BN_free(bn_u);
+ if (bn_A) BN_free(bn_A);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that A % N != 0 */
+ BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_b);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (A * v^u) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
+ BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
+
+ /* (A * v^u) ^ b % N */
+ BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_u);
+ BN_free(bn_base);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_free(bn_b);
+ return ret;
+}
+
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Ivec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
@@ -2352,6 +3028,8 @@ static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
int bf_n = 0; /* blowfish ivec pos */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
|| !enif_inspect_binary(env, argv[1], &ivec_bin)
|| ivec_bin.size != 8
@@ -2364,6 +3042,7 @@ static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
BF_cfb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
data_bin.size, &bf_key, bf_tkey, &bf_n,
(argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2374,6 +3053,8 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
unsigned char bf_tkey[8]; /* blowfish ivec */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
|| !enif_inspect_binary(env, argv[1], &ivec_bin)
|| ivec_bin.size != 8
@@ -2387,6 +3068,7 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
BF_cbc_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
data_bin.size, &bf_key, bf_tkey,
(argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2396,6 +3078,8 @@ static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
BF_KEY bf_key; /* blowfish key 8 */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)
|| data_bin.size < 8) {
@@ -2404,6 +3088,7 @@ static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
BF_set_key(&bf_key, key_bin.size, key_bin.data);
BF_ecb_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
&bf_key, (argv[2] == atom_true ? BF_ENCRYPT : BF_DECRYPT));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2415,6 +3100,8 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
int bf_n = 0; /* blowfish ivec pos */
ERL_NIF_TERM ret;
+ CHECK_OSE_CRYPTO();
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
|| !enif_inspect_binary(env, argv[1], &ivec_bin)
|| ivec_bin.size != 8
@@ -2426,10 +3113,541 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
memcpy(bf_tkey, ivec_bin.data, 8);
BF_ofb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
data_bin.size, &bf_key, bf_tkey, &bf_n);
+ CONSUME_REDS(env,data_bin);
+ return ret;
+}
+
+#if defined(HAVE_EC)
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
+{
+ EC_KEY *key = NULL;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+
+ /* {Field, Prime, Point, Order, CoFactor} = Curve */
+ if (enif_is_tuple(env, curve_arg)
+ && enif_get_tuple(env,curve_arg,&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_bin(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
+
+ int f_arity = -1;
+ const ERL_NIF_TERM* field;
+ int p_arity = -1;
+ const ERL_NIF_TERM* prime;
+
+ long field_bits;
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
+ || !get_bn_from_bin(env, prime[0], &a)
+ || !get_bn_from_bin(env, prime[1], &b))
+ goto out_err;
+
+ if (!enif_get_tuple(env,curve[0],&f_arity,&field))
+ goto out_err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+
+ if (!get_bn_from_bin(env, field[1], &p))
+ goto out_err;
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ goto out_err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ /* create the EC_GROUP structure */
+ group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+
+#if !defined(OPENSSL_NO_EC2M)
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+ /* {characteristic_two_field, M, Basis} */
+
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+ unsigned int k1, k2, k3;
+
+ if ((p = BN_new()) == NULL)
+ goto out_err;
+
+ if (!enif_get_long(env, field[1], &field_bits)
+ || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
+ if (b_arity == 2
+ && basis[0] == atom_tpbasis
+ && enif_get_uint(env, basis[1], &k1)) {
+ /* {tpbasis, k} = Basis */
+
+ if (!(field_bits > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else if (b_arity == 4
+ && basis[0] == atom_ppbasis
+ && enif_get_uint(env, basis[1], &k1)
+ && enif_get_uint(env, basis[2], &k2)
+ && enif_get_uint(env, basis[3], &k3)) {
+ /* {ppbasis, k1, k2, k3} = Basis */
+
+ if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, (int)k2)
+ || !BN_set_bit(p, (int)k3)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else
+ goto out_err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto out_err;
+
+ } else
+ goto out_err;
+
+ group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+#endif
+ } else
+ goto out_err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ EC_GROUP_set_seed(group, seed.data, seed.size);
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto out_err;
+
+ if (BN_is_negative(bn_order)
+ || BN_is_zero(bn_order)
+ || BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto out_err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto out_err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ key = EC_KEY_new();
+ if (!key)
+ goto out_err;
+ EC_KEY_set_group(key, group);
+ }
+ else {
+ goto out_err;
+ }
+
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (p) BN_free(p);
+ if (a) BN_free(a);
+ if (b) BN_free(b);
+ if (bn_order) BN_free(bn_order);
+ if (cofactor) BN_free(cofactor);
+ if (group) EC_GROUP_free(group);
+ if (point) EC_POINT_free(point);
+
+ return key;
+}
+
+
+static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ unsigned dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (!bn)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn, ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ptr, dlen);
+ return ret;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ unsigned dlen;
+ ErlNifBinary bin;
+
+ dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+ if (dlen == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ return enif_make_badarg(env);
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
+ enif_release_binary(&bin);
+ return enif_make_badarg(env);
+ }
+ ERL_VALGRIND_MAKE_MEM_DEFINED(bin.data, bin.size);
+ return enif_make_binary(env, &bin);
+}
+
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr)
+{
+ int ret = 0;
+ ErlNifBinary bin;
+ EC_POINT *point;
+
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+
+ if ((*pptr = point = EC_POINT_new(group)) == NULL) {
+ return 0;
+ }
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
+ EC_POINT_free(point);
+ *pptr = NULL;
+ } else
+ ret = 1;
+
return ret;
}
+static int get_ec_key(ErlNifEnv* env,
+ ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
+ EC_KEY** res)
+{
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ EC_GROUP *group = NULL;
+
+ if (!(priv == atom_undefined || get_bn_from_bin(env, priv, &priv_key))
+ || !(pub == atom_undefined || enif_is_binary(env, pub))) {
+ goto out_err;
+ }
+
+ key = ec_key_new(env, curve);
+
+ if (!key) {
+ goto out_err;
+ }
+
+ if (!group)
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+
+ if (term2point(env, pub, group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key)) {
+ goto out_err;
+ }
+ }
+ if (priv != atom_undefined
+ && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto out_err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL)
+ {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL
+ || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
+ || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
+ || !EC_KEY_set_public_key(key, pub_key))
+ goto out_err;
+ }
+ }
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key) BN_clear_free(priv_key);
+ if (pub_key) EC_POINT_free(pub_key);
+ if (group) EC_GROUP_free(group);
+ if (!key)
+ return 0;
+ *res = key;
+ return 1;
+}
+#endif /* HAVE_EC */
+
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = ec_key_new(env, argv[0]);
+
+ CHECK_OSE_CRYPTO();
+
+ if (key && EC_KEY_generate_key(key)) {
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ ERL_NIF_TERM priv_key;
+ ERL_NIF_TERM pub_key = atom_undefined;
+ group = EC_KEY_get0_group(key);
+ public_key = EC_KEY_get0_public_key(key);
+
+ if (group && public_key) {
+ pub_key = point2term(env, group, public_key,
+ EC_KEY_get_conv_form(key));
+ }
+ priv_key = bn2term(env, EC_KEY_get0_private_key(key));
+ EC_KEY_free(key);
+ return enif_make_tuple2(env, pub_key, priv_key);
+ }
+ else {
+ if (key)
+ EC_KEY_free(key);
+ return enif_make_badarg(env);
+ }
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Curve, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ EC_KEY* key = NULL;
+ int i;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t *digp;
+ unsigned char* digest;
+
+ CHECK_OSE_CRYPTO();
+
+ digp = get_digest_type(argv[0]);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!get_ec_key(env, argv[2], argv[3], atom_undefined, &key))
+ goto badarg;
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ goto badarg;
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
+ goto badarg;
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+
+ enif_alloc_binary(ECDSA_size(key), &ret_bin);
+
+ i = ECDSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &dsa_s_len, key);
+
+ EC_KEY_free(key);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(&ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ enif_release_binary(&ret_bin);
+ return atom_error;
+ }
+
+badarg:
+ if (key)
+ EC_KEY_free(key);
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Signature, Curve, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA512_LEN];
+ int i;
+ EC_KEY* key = NULL;
+ const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ CHECK_OSE_CRYPTO();
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
+ || !get_ec_key(env, argv[3], atom_undefined, argv[4], &key))
+ goto badarg;
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ goto badarg;
+ }
+ digest = data_bin.data;
+ }
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+ else {
+ goto badarg;
+ }
+
+ i = ECDSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data, sign_bin.size, key);
+
+ EC_KEY_free(key);
+
+ return (i==1 ? atom_true : atom_false);
+
+badarg:
+ if (key)
+ EC_KEY_free(key);
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+/* (OtherPublicKey, Curve, My) */
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ EC_KEY* key = NULL;
+ int field_size = 0;
+ int i;
+ EC_GROUP *group;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint;
+ EC_KEY *other_ecdh = NULL;
+
+ CHECK_OSE_CRYPTO();
+
+ if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))
+ return enif_make_badarg(env);
+
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+ priv_key = EC_KEY_get0_private_key(key);
+
+ if (!term2point(env, argv[0], group, &my_ecpoint)) {
+ goto out_err;
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL
+ || !EC_KEY_set_group(other_ecdh, group)
+ || !EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto out_err;
+
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ goto out_err;
+
+ p = enif_make_new_binary(env, (field_size+7)/8, &ret);
+ i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
+
+ if (i < 0)
+ goto out_err;
+out:
+ if (group) EC_GROUP_free(group);
+ if (my_ecpoint) EC_POINT_free(my_ecpoint);
+ if (other_ecdh) EC_KEY_free(other_ecdh);
+ if (key) EC_KEY_free(key);
+
+ return ret;
+
+out_err:
+ ret = enif_make_badarg(env);
+ goto out;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary seed_bin;
+ CHECK_OSE_CRYPTO();
+ if (!enif_inspect_binary(env, argv[0], &seed_bin))
+ return enif_make_badarg(env);
+ RAND_seed(seed_bin.data,seed_bin.size);
+ return atom_ok;
+}
/* HMAC */
diff --git a/lib/crypto/c_src/crypto_callback.c b/lib/crypto/c_src/crypto_callback.c
index 81106b4cc2..b4c175ae43 100644
--- a/lib/crypto/c_src/crypto_callback.c
+++ b/lib/crypto/c_src/crypto_callback.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012. All Rights Reserved.
+ * Copyright Ericsson AB 2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -17,6 +17,7 @@
* %CopyrightEnd%
*/
+#include <stdio.h>
#include <string.h>
#include <openssl/opensslconf.h>
@@ -51,13 +52,28 @@ DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks);
static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */
+static void nomem(size_t size, const char* op)
+{
+ fprintf(stderr, "Out of memory abort. Crypto failed to %s %zu bytes.\r\n",
+ op, size);
+ abort();
+}
+
static void* crypto_alloc(size_t size)
{
- return enif_alloc(size);
+ void *ret = enif_alloc(size);
+
+ if (!ret && size)
+ nomem(size, "allocate");
+ return ret;
}
static void* crypto_realloc(void* ptr, size_t size)
{
- return enif_realloc(ptr, size);
+ void* ret = enif_realloc(ptr, size);
+
+ if (!ret && size)
+ nomem(size, "reallocate");
+ return ret;
}
static void crypto_free(void* ptr)
{
@@ -91,8 +107,6 @@ static INLINE void locking(int mode, ErlNifRWLock* lock)
static void locking_function(int mode, int n, const char *file, int line)
{
- ASSERT(n>=0 && n<CRYPTO_num_locks());
-
locking(mode, lock_vec[n]);
}