aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2010-04-28 14:08:55 +0000
committerErlang/OTP <[email protected]>2010-04-28 14:08:55 +0000
commit98226b13ccabb8e968b33a649aa175a7c48b0d3b (patch)
treeaf799d50426f0e516e7eba276dbd8ac3cf03050d
parentdf7bf3f81ef645f24110c5e4cdeaf78dca44f810 (diff)
downloadotp-98226b13ccabb8e968b33a649aa175a7c48b0d3b.tar.gz
otp-98226b13ccabb8e968b33a649aa175a7c48b0d3b.tar.bz2
otp-98226b13ccabb8e968b33a649aa175a7c48b0d3b.zip
OTP-8333 Crypto using NIF's
crypto application changed to use NIFs instead of driver.
-rw-r--r--lib/crypto/c_src/Makefile.in20
-rw-r--r--lib/crypto/c_src/crypto.c1531
-rw-r--r--lib/crypto/c_src/crypto_drv.c1817
-rw-r--r--lib/crypto/priv/Makefile28
-rw-r--r--lib/crypto/src/Makefile12
-rw-r--r--lib/crypto/src/crypto.erl497
-rw-r--r--lib/crypto/src/crypto_server.erl88
-rw-r--r--lib/crypto/test/blowfish_SUITE.erl15
-rw-r--r--lib/crypto/test/crypto_SUITE.erl10
-rw-r--r--lib/crypto/vsn.mk2
10 files changed, 1762 insertions, 2258 deletions
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 18040a3b26..e728db18eb 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -68,13 +68,13 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN)
# ----------------------------------------------------
# Misc Macros
# ----------------------------------------------------
-OBJS = $(OBJDIR)/crypto_drv.o
-DRV_MAKEFILE = $(PRIVDIR)/Makefile
+OBJS = $(OBJDIR)/crypto.o
+NIF_MAKEFILE = $(PRIVDIR)/Makefile
ifeq ($(findstring win32,$(TARGET)), win32)
-DYN_DRIVER = $(LIBDIR)/crypto_drv.dll
+NIF_LIB = $(LIBDIR)/crypto.dll
else
-DYN_DRIVER = $(LIBDIR)/crypto_drv.so
+NIF_LIB = $(LIBDIR)/crypto.so
endif
ifeq ($(HOST_OS),)
@@ -94,7 +94,7 @@ endif
# Targets
# ----------------------------------------------------
-debug opt valgrind: $(OBJDIR) $(LIBDIR) $(DYN_DRIVER)
+debug opt valgrind: $(OBJDIR) $(LIBDIR) $(NIF_LIB)
$(OBJDIR):
-@mkdir -p $(OBJDIR)
@@ -106,16 +106,16 @@ $(OBJDIR)/%.o: %.c
$(INSTALL_DIR) $(OBJDIR)
$(CC) -c -o $@ $(ALL_CFLAGS) $<
-$(LIBDIR)/crypto_drv.so: $(OBJS)
+$(LIBDIR)/crypto.so: $(OBJS)
$(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB)
-$(LIBDIR)/crypto_drv.dll: $(OBJS)
+$(LIBDIR)/crypto.dll: $(OBJS)
$(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -llibeay32
clean:
- rm -f $(DYN_DRIVER) $(OBJS)
+ rm -f $(NIF_LIB) $(OBJS)
rm -f core *~
docs:
@@ -128,9 +128,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/priv/obj
$(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_DATA) $(DRV_MAKEFILE) $(RELSYSDIR)/priv/obj
+ $(INSTALL_DATA) $(NIF_MAKEFILE) $(RELSYSDIR)/priv/obj
$(INSTALL_PROGRAM) $(OBJS) $(RELSYSDIR)/priv/obj
- $(INSTALL_PROGRAM) $(DYN_DRIVER) $(RELSYSDIR)/priv/lib
+ $(INSTALL_PROGRAM) $(NIF_LIB) $(RELSYSDIR)/priv/lib
release_docs_spec:
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
new file mode 100644
index 0000000000..a71df1d7fd
--- /dev/null
+++ b/lib/crypto/c_src/crypto.c
@@ -0,0 +1,1531 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. 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
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Purpose: Dynamically loadable NIF library for cryptography.
+ * Based on OpenSSL.
+ */
+
+#ifdef __WIN32__
+ #include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "erl_nif.h"
+
+#define OPENSSL_THREAD_DEFINES
+#include <openssl/opensslconf.h>
+
+#include <openssl/crypto.h>
+#include <openssl/des.h>
+/* #include <openssl/idea.h> This is not supported on the openssl OTP requires */
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/aes.h>
+#include <openssl/md5.h>
+#include <openssl/md4.h>
+#include <openssl/sha.h>
+#include <openssl/bn.h>
+#include <openssl/objects.h>
+#include <openssl/rc4.h>
+#include <openssl/rc2.h>
+#include <openssl/blowfish.h>
+#include <openssl/rand.h>
+
+#ifdef VALGRIND
+ # include <valgrind/memcheck.h>
+
+/* libcrypto mixes supplied buffer contents into its entropy pool,
+ which makes valgrind complain about the use of uninitialized data.
+ We use this valgrind "request" to make sure that no such seemingly
+ undefined data is returned.
+*/
+ # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) \
+ VALGRIND_MAKE_MEM_DEFINED(ptr,size)
+
+ # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size) \
+ ((void) ((VALGRIND_CHECK_MEM_IS_DEFINED(ptr,size) == 0) ? 1 : \
+ (fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%d) failed at %s:%d\r\n",\
+ (ptr),(size), __FILE__, __LINE__), abort(), 0)))
+#else
+ # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size)
+ # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size)
+#endif
+
+#ifdef DEBUG
+ # define ASSERT(e) \
+ ((void) ((e) ? 1 : (fprintf(stderr,"Assert '%s' failed at %s:%d\n",\
+ #e, __FILE__, __LINE__), abort(), 0)))
+#else
+ # define ASSERT(e) ((void) 1)
+#endif
+
+#ifdef __GNUC__
+ # define INLINE __inline__
+#elif defined(__WIN32__)
+ # define INLINE __forceinline
+#else
+ # define INLINE
+#endif
+
+
+#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \
+ (((unsigned char*) (s))[1] << 16) | \
+ (((unsigned char*) (s))[2] << 8) | \
+ (((unsigned char*) (s))[3]))
+
+#define put_int32(s,i) \
+{ (s)[0] = (char)(((i) >> 24) & 0xff);\
+ (s)[1] = (char)(((i) >> 16) & 0xff);\
+ (s)[2] = (char)(((i) >> 8) & 0xff);\
+ (s)[3] = (char)((i) & 0xff);\
+}
+
+/* NIF interface declarations */
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
+static int reload(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);
+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 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[]);
+static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+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 aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rand_bytes_3(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 rsa_verify(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 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[]);
+static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+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 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[]);
+
+
+/* openssl callbacks */
+#ifdef OPENSSL_THREADS
+static void locking_function(int mode, int n, const char *file, int line);
+static unsigned long id_function(void);
+static struct CRYPTO_dynlock_value* dyn_create_function(const char *file,
+ int line);
+static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,
+ const char *file, int line);
+static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr,
+ const char *file, int line);
+#endif /* OPENSSL_THREADS */
+
+/* helpers */
+static void hmac_md5(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf);
+static void hmac_sha1(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf);
+
+static int library_refc = 0; /* number of users of this dynamic library */
+
+static ErlNifFunc nif_funcs[] = {
+ {"info_lib", 0, info_lib},
+ {"md5", 1, md5},
+ {"md5_init", 0, md5_init},
+ {"md5_update", 2, md5_update},
+ {"md5_final", 1, md5_final},
+ {"sha", 1, sha},
+ {"sha_init", 0, sha_init},
+ {"sha_update", 2, sha_update},
+ {"sha_final", 1, sha_final},
+ {"md4", 1, md4},
+ {"md4_init", 0, md4_init},
+ {"md4_update", 2, md4_update},
+ {"md4_final", 1, md4_final},
+ {"md5_mac_n", 3, md5_mac_n},
+ {"sha_mac_n", 3, sha_mac_n},
+ {"des_cbc_crypt", 4, des_cbc_crypt},
+ {"des_ecb_crypt", 3, des_ecb_crypt},
+ {"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt},
+ {"aes_cfb_128_crypt", 4, aes_cfb_128_crypt},
+ {"rand_bytes", 1, rand_bytes_1},
+ {"rand_bytes", 3, rand_bytes_3},
+ {"rand_uniform_nif", 2, rand_uniform_nif},
+ {"mod_exp_nif", 3, mod_exp_nif},
+ {"dss_verify", 3, dss_verify},
+ {"rsa_verify", 4, rsa_verify},
+ {"aes_cbc_crypt", 4, aes_cbc_crypt},
+ {"exor", 2, exor},
+ {"rc4_encrypt", 2, rc4_encrypt},
+ {"rc4_set_key", 1, rc4_set_key},
+ {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state},
+ {"rc2_40_cbc_crypt", 4, rc2_40_cbc_crypt},
+ {"rsa_sign_nif", 3, rsa_sign_nif},
+ {"dss_sign_nif", 2, dss_sign_nif},
+ {"rsa_public_crypt", 4, rsa_public_crypt},
+ {"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_compute_key_nif", 3, dh_compute_key_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}
+};
+
+ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload)
+
+
+#define MD5_CTX_LEN (sizeof(MD5_CTX))
+#define MD5_LEN 16
+#define MD5_LEN_96 12
+#define MD4_CTX_LEN (sizeof(MD4_CTX))
+#define MD4_LEN 16
+#define SHA_CTX_LEN (sizeof(SHA_CTX))
+#define SHA_LEN 20
+#define SHA_LEN_96 12
+#define HMAC_INT_LEN 64
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+
+
+static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */
+static ERL_NIF_TERM atom_true;
+static ERL_NIF_TERM atom_false;
+static ERL_NIF_TERM atom_sha;
+static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_error;
+static ERL_NIF_TERM atom_rsa_pkcs1_padding;
+static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding;
+static ERL_NIF_TERM atom_rsa_no_padding;
+static ERL_NIF_TERM atom_undefined;
+
+static ERL_NIF_TERM atom_ok;
+static ERL_NIF_TERM atom_not_prime;
+static ERL_NIF_TERM atom_not_strong_prime;
+static ERL_NIF_TERM atom_unable_to_check_generator;
+static ERL_NIF_TERM atom_not_suitable_generator;
+static ERL_NIF_TERM atom_check_failed;
+static ERL_NIF_TERM atom_unknown;
+
+
+static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
+{
+ int i;
+ return enif_get_int(env,load_info,&i) && i == 101;
+}
+static void* crypto_alloc(size_t size)
+{
+ return enif_alloc(NULL, size);
+}
+static void* crypto_realloc(void* ptr, size_t size)
+{
+ return enif_realloc(NULL, ptr, size);
+}
+static void crypto_free(void* ptr)
+{
+ enif_free(NULL, ptr);
+}
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ ErlNifSysInfo sys_info;
+ CRYPTO_set_mem_functions(crypto_alloc, crypto_realloc, crypto_free);
+
+ if (!is_ok_load_info(env, load_info)) {
+ return -1;
+ }
+
+#ifdef OPENSSL_THREADS
+ enif_system_info(&sys_info, sizeof(sys_info));
+
+ if (sys_info.scheduler_threads > 1) {
+ int i;
+ lock_vec = enif_alloc(env,CRYPTO_num_locks()*sizeof(*lock_vec));
+ if (lock_vec==NULL) return -1;
+ memset(lock_vec,0,CRYPTO_num_locks()*sizeof(*lock_vec));
+
+ for (i=CRYPTO_num_locks()-1; i>=0; --i) {
+ lock_vec[i] = enif_rwlock_create("crypto_stat");
+ if (lock_vec[i]==NULL) return -1;
+ }
+ CRYPTO_set_locking_callback(locking_function);
+ CRYPTO_set_id_callback(id_function);
+ CRYPTO_set_dynlock_create_callback(dyn_create_function);
+ CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
+ CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
+ }
+ /* else no need for locks */
+#endif /* OPENSSL_THREADS */
+
+ atom_true = enif_make_atom(env,"true");
+ atom_false = enif_make_atom(env,"false");
+ atom_sha = enif_make_atom(env,"sha");
+ atom_md5 = enif_make_atom(env,"md5");
+ atom_error = enif_make_atom(env,"error");
+ atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");
+ atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
+ atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
+ atom_undefined = enif_make_atom(env,"undefined");
+ atom_ok = enif_make_atom(env,"ok");
+ atom_not_prime = enif_make_atom(env,"not_prime");
+ atom_not_strong_prime = enif_make_atom(env,"not_strong_prime");
+ atom_unable_to_check_generator = enif_make_atom(env,"unable_to_check_generator");
+ atom_not_suitable_generator = enif_make_atom(env,"not_suitable_generator");
+ atom_check_failed = enif_make_atom(env,"check_failed");
+ atom_unknown = enif_make_atom(env,"unknown");
+
+ *priv_data = NULL;
+ library_refc++;
+ return 0;
+}
+
+static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ if (*priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (library_refc == 0) {
+ /* No support for real library upgrade. The tricky thing is to know
+ when to (re)set the callbacks for allocation and locking. */
+ return -2;
+ }
+ if (!is_ok_load_info(env, load_info)) {
+ return -1;
+ }
+ return 0;
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info)
+{
+ int i;
+ if (*old_priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ i = reload(env,priv_data,load_info);
+ if (i != 0) {
+ return i;
+ }
+ library_refc++;
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data)
+{
+ if (--library_refc <= 0) {
+ CRYPTO_cleanup_all_ex_data();
+
+ if (lock_vec != NULL) {
+ int i;
+ for (i=CRYPTO_num_locks()-1; i>=0; --i) {
+ if (lock_vec[i] != NULL) {
+ enif_rwlock_destroy(lock_vec[i]);
+ }
+ }
+ enif_free(env,lock_vec);
+ }
+ }
+ /*else NIF library still used by other (new) module code */
+}
+
+static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ /* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
+
+ static const char libname[] = "OpenSSL";
+ unsigned name_sz = strlen(libname);
+ const char* ver = SSLeay_version(SSLEAY_VERSION);
+ unsigned ver_sz = strlen(ver);
+ ERL_NIF_TERM name_term, ver_term;
+
+ memcpy(enif_make_new_binary(env, name_sz, &name_term), libname, name_sz);
+ memcpy(enif_make_new_binary(env, ver_sz, &ver_term), ver, ver_sz);
+
+ return enif_make_list1(env, enif_make_tuple3(env, name_term,
+ enif_make_int(env, SSLeay()),
+ ver_term));
+}
+
+static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data) */
+ ErlNifBinary ibin;
+ ERL_NIF_TERM ret;
+
+ 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));
+ return ret;
+}
+static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+ ERL_NIF_TERM ret;
+ MD5_Init((MD5_CTX *) enif_make_new_binary(env, MD5_CTX_LEN, &ret));
+ return ret;
+}
+static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ MD5_CTX* new_ctx;
+ ErlNifBinary ctx_bin, data_bin;
+ ERL_NIF_TERM ret;
+ 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)) {
+ return enif_make_badarg(env);
+ }
+ 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);
+ return ret;
+}
+static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+ ErlNifBinary ctx_bin;
+ MD5_CTX ctx_clone;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD5_CTX_LEN) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ctx_clone, ctx_bin.data, MD5_CTX_LEN); /* writable */
+ MD5_Final(enif_make_new_binary(env, MD5_LEN, &ret), &ctx_clone);
+ return ret;
+}
+
+static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data) */
+ ErlNifBinary ibin;
+ ERL_NIF_TERM ret;
+
+ 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));
+ return ret;
+}
+static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+ ERL_NIF_TERM ret;
+ SHA1_Init((SHA_CTX *) enif_make_new_binary(env, SHA_CTX_LEN, &ret));
+ return ret;
+}
+static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ SHA_CTX* new_ctx;
+ ErlNifBinary ctx_bin, data_bin;
+ ERL_NIF_TERM ret;
+ 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);
+ }
+ 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);
+ return ret;
+}
+static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+ ErlNifBinary ctx_bin;
+ SHA_CTX ctx_clone;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != SHA_CTX_LEN) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ctx_clone, ctx_bin.data, SHA_CTX_LEN); /* writable */
+ SHA1_Final(enif_make_new_binary(env, SHA_LEN, &ret), &ctx_clone);
+ return ret;
+}
+
+static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data) */
+ ErlNifBinary ibin;
+ ERL_NIF_TERM ret;
+
+ 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));
+ return ret;
+}
+static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+ ERL_NIF_TERM ret;
+ MD4_Init((MD4_CTX *) enif_make_new_binary(env, MD4_CTX_LEN, &ret));
+ return ret;
+}
+static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ MD4_CTX* new_ctx;
+ ErlNifBinary ctx_bin, data_bin;
+ ERL_NIF_TERM ret;
+ 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);
+ }
+ 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);
+ return ret;
+}
+static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+ ErlNifBinary ctx_bin;
+ MD4_CTX ctx_clone;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD4_CTX_LEN) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ctx_clone, ctx_bin.data, MD4_CTX_LEN); /* writable */
+ MD4_Final(enif_make_new_binary(env, MD4_LEN, &ret), &ctx_clone);
+ return ret;
+}
+
+static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, MacSize) */
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ ErlNifBinary key, data;
+ unsigned mac_sz;
+ ERL_NIF_TERM ret;
+
+ 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) {
+ return enif_make_badarg(env);
+ }
+ hmac_md5(key.data, key.size, data.data, data.size, hmacbuf);
+ memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz);
+ return ret;
+}
+
+static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, MacSize) */
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ ErlNifBinary key, data;
+ unsigned mac_sz;
+ ERL_NIF_TERM ret;
+
+ 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) {
+ return enif_make_badarg(env);
+ }
+ hmac_sha1(key.data, key.size, data.data, data.size, hmacbuf);
+ memcpy(enif_make_new_binary(env, mac_sz, &ret),
+ hmacbuf, mac_sz);
+ return ret;
+}
+
+static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Ivec, Text, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ DES_key_schedule schedule;
+ DES_cblock ivec_clone; /* writable copy */
+ ERL_NIF_TERM ret;
+
+ 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)
+ || text.size % 8 != 0) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ivec_clone, ivec.data, 8);
+ 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));
+ return ret;
+}
+
+static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Text/Cipher, IsEncrypt) */
+ ErlNifBinary key, text;
+ DES_key_schedule schedule;
+ ERL_NIF_TERM ret;
+ 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);
+ }
+ DES_set_key((const_DES_cblock*)key.data, &schedule);
+ DES_ecb_encrypt((const_DES_cblock*)text.data,
+ (DES_cblock*)enif_make_new_binary(env, 8, &ret),
+ &schedule, (argv[2] == atom_true));
+ return ret;
+}
+
+static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key1, Key2, Key3, IVec, Text/Cipher, IsEncrypt) */
+ ErlNifBinary key1, key2, key3, ivec, text;
+ DES_key_schedule schedule1, schedule2, schedule3;
+ DES_cblock ivec_clone; /* writable copy */
+ ERL_NIF_TERM ret;
+
+ 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
+ || !enif_inspect_binary(env, argv[3], &ivec) || ivec.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[4], &text)
+ || text.size % 8 != 0) {
+ return enif_make_badarg(env);
+ }
+
+ memcpy(&ivec_clone, ivec.data, 8);
+ DES_set_key((const_DES_cblock*)key1.data, &schedule1);
+ DES_set_key((const_DES_cblock*)key2.data, &schedule2);
+ DES_set_key((const_DES_cblock*)key3.data, &schedule3);
+ 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));
+ 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;
+ 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
+ || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)
+ || text.size % 16 != 0) {
+ return enif_make_badarg(env);
+ }
+
+ memcpy(ivec_clone, ivec.data, 16);
+ AES_set_encrypt_key(key.data, 128, &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));
+ return ret;
+}
+
+static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Bytes) */
+ unsigned bytes;
+ unsigned char* data;
+ ERL_NIF_TERM ret;
+ if (!enif_get_uint(env, argv[0], &bytes)) {
+ return enif_make_badarg(env);
+ }
+ data = enif_make_new_binary(env, bytes, &ret);
+ RAND_pseudo_bytes(data, bytes);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes);
+ return ret;
+}
+static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Bytes, TopMask, BottomMask) */
+ unsigned bytes;
+ unsigned char* data;
+ unsigned top_mask, bot_mask;
+ ERL_NIF_TERM ret;
+ if (!enif_get_uint(env, argv[0], &bytes)
+ || !enif_get_uint(env, argv[1], &top_mask)
+ || !enif_get_uint(env, argv[2], &bot_mask)) {
+ return enif_make_badarg(env);
+ }
+ data = enif_make_new_binary(env, bytes, &ret);
+ RAND_pseudo_bytes(data, bytes);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes);
+ if (bytes > 0) {
+ data[bytes-1] |= top_mask;
+ data[0] |= bot_mask;
+ }
+ return ret;
+}
+
+static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ int sz;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ sz = bin.size - 4;
+ if (sz < 0 || get_int32(bin.data) != sz) {
+ return 0;
+ }
+ *bnp = BN_bin2bn(bin.data+4, sz, NULL);
+ return 1;
+}
+
+static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Lo,Hi) */
+ BIGNUM *bn_from, *bn_to, *bn_rand;
+ unsigned char* data;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+ if (!get_bn_from_mpint(env, argv[0], &bn_from)
+ || !get_bn_from_mpint(env, argv[1], &bn_rand)) {
+ return enif_make_badarg(env);
+ }
+
+ bn_to = BN_new();
+ BN_sub(bn_to, bn_rand, bn_from);
+ BN_pseudo_rand_range(bn_rand, bn_to);
+ BN_add(bn_rand, bn_rand, bn_from);
+ dlen = BN_num_bytes(bn_rand);
+ data = enif_make_new_binary(env, dlen+4, &ret);
+ put_int32(data, dlen);
+ BN_bn2bin(bn_rand, data+4);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen);
+ BN_free(bn_rand);
+ BN_free(bn_from);
+ BN_free(bn_to);
+ return ret;
+}
+
+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;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ 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)) {
+
+ if (bn_base) BN_free(bn_base);
+ if (bn_exponent) BN_free(bn_exponent);
+ 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);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_modulo);
+ BN_free(bn_exponent);
+ BN_free(bn_base);
+ 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[])
+{/* (Data,Signature,Key=[P, Q, G, Y]) */
+ ErlNifBinary data_bin, sign_bin;
+ BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_y;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ ERL_NIF_TERM head, tail;
+ DSA *dsa;
+ int i;
+
+ if (!inspect_mpint(env,argv[0],&data_bin)
+ || !inspect_mpint(env,argv[1],&sign_bin)
+ || !enif_get_list_cell(env, argv[2], &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa_p)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa_q)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa_g)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa_y)
+ || !enif_is_empty_list(env,tail)) {
+
+ return enif_make_badarg(env);
+ }
+ SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+
+ dsa = DSA_new();
+ dsa->p = dsa_p;
+ dsa->q = dsa_q;
+ dsa->g = dsa_g;
+ dsa->priv_key = NULL;
+ dsa->pub_key = dsa_y;
+ i = DSA_verify(0, hmacbuf, SHA_DIGEST_LENGTH,
+ sign_bin.data+4, sign_bin.size-4, dsa);
+ DSA_free(dsa);
+ return(i > 0) ? atom_true : atom_false;
+}
+
+static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data, Signature, Key=[E,N]) */
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ ERL_NIF_TERM head, tail, ret;
+ int i, is_sha;
+ RSA* rsa = RSA_new();
+
+ if (argv[0] == atom_sha) is_sha = 1;
+ else if (argv[0] == atom_md5) is_sha = 0;
+ else goto badarg;
+
+ if (!inspect_mpint(env, argv[1], &data_bin)
+ || !inspect_mpint(env, argv[2], &sign_bin)
+ || !enif_get_list_cell(env, argv[3], &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->e)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->n)
+ || !enif_is_empty_list(env, tail)) {
+ badarg:
+ ret = enif_make_badarg(env);
+ }
+ else {
+ if (is_sha) {
+ SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
+ sign_bin.data+4, sign_bin.size-4, rsa);
+ }
+ else {
+ MD5(data_bin.data+4, data_bin.size-4, hmacbuf);
+ i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH,
+ sign_bin.data+4, sign_bin.size-4, rsa);
+ }
+ ret = (i==1 ? atom_true : atom_false);
+ }
+ RSA_free(rsa);
+ return ret;
+}
+
+static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+ ErlNifBinary key_bin, ivec_bin, data_bin;
+ AES_KEY aes_key;
+ unsigned char ivec[16];
+ int i;
+ unsigned char* ret_ptr;
+ ERL_NIF_TERM ret;
+
+ 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 != 16
+ || !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, 16); /* writable copy */
+ AES_cbc_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i);
+ return ret;
+}
+
+static ERL_NIF_TERM 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;
+
+ if (!enif_inspect_iolist_as_binary(env,argv[0], &d1)
+ || !enif_inspect_iolist_as_binary(env,argv[1], &d2)
+ || d1.size != d2.size) {
+ return enif_make_badarg(env);
+ }
+ ret_ptr = enif_make_new_binary(env, d1.size, &ret);
+
+ for (i=0; i<d1.size; i++) {
+ ret_ptr[i] = d1.data[i] ^ d2.data[i];
+ }
+ return ret;
+}
+
+static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data) */
+ ErlNifBinary key, data;
+ RC4_KEY rc4_key;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env,argv[0], &key)
+ || !enif_inspect_iolist_as_binary(env,argv[1], &data)) {
+ return enif_make_badarg(env);
+ }
+ RC4_set_key(&rc4_key, key.size, key.data);
+ RC4(&rc4_key, data.size, data.data,
+ enif_make_new_binary(env, data.size, &ret));
+ return ret;
+}
+
+static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key) */
+ ErlNifBinary key;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env,argv[0], &key)) {
+ return enif_make_badarg(env);
+ }
+ RC4_set_key((RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &ret),
+ key.size, key.data);
+ return ret;
+}
+
+static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (State, Data) */
+
+ ErlNifBinary state, data;
+ RC4_KEY* rc4_key;
+ ERL_NIF_TERM new_state, new_data;
+
+ if (!enif_inspect_iolist_as_binary(env,argv[0], &state)
+ || state.size != sizeof(RC4_KEY)
+ || !enif_inspect_iolist_as_binary(env,argv[1], &data)) {
+ return enif_make_badarg(env);
+ }
+ rc4_key = (RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &new_state);
+ memcpy(rc4_key, state.data, sizeof(RC4_KEY));
+ RC4(rc4_key, data.size, data.data,
+ enif_make_new_binary(env, data.size, &new_data));
+
+ return enif_make_tuple2(env,argv[0],new_data);
+}
+
+static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key,IVec,Data,IsEncrypt) */
+ ErlNifBinary key_bin, ivec_bin, data_bin;
+ RC2_KEY rc2_key;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || key_bin.size != 5
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || ivec_bin.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) {
+
+ return enif_make_badarg(env);
+ }
+
+ RC2_set_key(&rc2_key, 5, key_bin.data, 40);
+ RC2_cbc_encrypt(data_bin.data,
+ enif_make_new_binary(env, data_bin.size, &ret),
+ data_bin.size, &rc2_key,
+ ivec_bin.data,
+ (argv[3] == atom_true));
+
+ return ret;
+}
+
+static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type,Data,Key=[E,N,D]) */
+ ErlNifBinary data_bin, ret_bin;
+ ERL_NIF_TERM head, tail;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned rsa_s_len;
+ RSA *rsa = RSA_new();
+ int i, is_sha;
+
+ if (argv[0] == atom_sha) is_sha = 1;
+ else if (argv[0] == atom_md5) is_sha = 0;
+ else goto badarg;
+
+ if (!inspect_mpint(env,argv[1],&data_bin)
+ || !enif_get_list_cell(env, argv[2], &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->e)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->n)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->d)
+ || !enif_is_empty_list(env,tail)) {
+ badarg:
+ RSA_free(rsa);
+ return enif_make_badarg(env);
+ }
+ enif_alloc_binary(env, RSA_size(rsa), &ret_bin);
+ if (is_sha) {
+ SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH);
+ i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
+ ret_bin.data, &rsa_s_len, rsa);
+ }
+ else {
+ MD5(data_bin.data+4, data_bin.size-4, hmacbuf);
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH);
+ i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH,
+ ret_bin.data, &rsa_s_len, rsa);
+ }
+ RSA_free(rsa);
+ if (i) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len);
+ if (rsa_s_len != data_bin.size) {
+ enif_realloc_binary(env, &ret_bin, rsa_s_len);
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len);
+ }
+ return enif_make_binary(env,&ret_bin);
+ }
+ else {
+ enif_release_binary(env, &ret_bin);
+ return atom_error;
+ }
+}
+
+static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data,Key=[P,Q,G,PrivKey]) */
+ ErlNifBinary data_bin, ret_bin;
+ ERL_NIF_TERM head, tail;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ DSA* dsa = DSA_new();
+ int i;
+
+ dsa->pub_key = NULL;
+ if (!inspect_mpint(env, argv[0], &data_bin)
+ || !enif_get_list_cell(env, argv[1], &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa->p)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa->q)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa->g)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dsa->priv_key)
+ || !enif_is_empty_list(env,tail)) {
+
+ DSA_free(dsa);
+ return enif_make_badarg(env);
+ }
+
+ SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+
+ enif_alloc_binary(env, DSA_size(dsa), &ret_bin);
+ i = DSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
+ ret_bin.data, &dsa_s_len, dsa);
+ DSA_free(dsa);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(env, &ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ return atom_error;
+ }
+}
+
+static int rsa_pad(ERL_NIF_TERM term, int* padding)
+{
+ if (term == atom_rsa_pkcs1_padding) {
+ *padding = RSA_PKCS1_PADDING;
+ }
+ else if (term == atom_rsa_pkcs1_oaep_padding) {
+ *padding = RSA_PKCS1_OAEP_PADDING;
+ }
+ else if (term == atom_rsa_no_padding) {
+ *padding = RSA_NO_PADDING;
+ }
+ else {
+ return 0;
+ }
+ return 1;
+}
+
+static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data, PublKey=[E,N], Padding, IsEncrypt) */
+ ErlNifBinary data_bin, ret_bin;
+ ERL_NIF_TERM head, tail;
+ int padding, i;
+ RSA* 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)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->n)
+ || !enif_is_empty_list(env,tail)
+ || !rsa_pad(argv[2], &padding)) {
+
+ RSA_free(rsa);
+ return enif_make_badarg(env);
+ }
+
+ enif_alloc_binary(env, RSA_size(rsa), &ret_bin);
+
+ if (argv[3] == atom_true) {
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,data_len);
+ i = RSA_public_encrypt(data_bin.size, data_bin.data,
+ ret_bin.data, rsa, padding);
+ if (i > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, i);
+ }
+ }
+ else {
+ i = RSA_public_decrypt(data_bin.size, data_bin.data,
+ ret_bin.data, rsa, padding);
+ if (i > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, i);
+ enif_realloc_binary(env, &ret_bin, i);
+ }
+ }
+ RSA_free(rsa);
+ if (i > 0) {
+ return enif_make_binary(env,&ret_bin);
+ }
+ else {
+ return atom_error;
+ }
+}
+
+static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data, PublKey=[E,N,D], Padding, IsEncrypt) */
+ ErlNifBinary data_bin, ret_bin;
+ ERL_NIF_TERM head, tail;
+ int padding, i;
+ RSA* 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)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->n)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->d)
+ || !enif_is_empty_list(env,tail)
+ || !rsa_pad(argv[2], &padding)) {
+
+ RSA_free(rsa);
+ return enif_make_badarg(env);
+ }
+
+ enif_alloc_binary(env, RSA_size(rsa), &ret_bin);
+
+ if (argv[3] == atom_true) {
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,data_len);
+ i = RSA_private_encrypt(data_bin.size, data_bin.data,
+ ret_bin.data, rsa, padding);
+ if (i > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, i);
+ }
+ }
+ else {
+ i = RSA_private_decrypt(data_bin.size, data_bin.data,
+ ret_bin.data, rsa, padding);
+ if (i > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, i);
+ enif_realloc_binary(env, &ret_bin, i);
+ }
+ }
+ RSA_free(rsa);
+ if (i > 0) {
+ return enif_make_binary(env,&ret_bin);
+ }
+ else {
+ return atom_error;
+ }
+}
+
+static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (PrimeLen, Generator) */
+ int prime_len, generator;
+ DH* dh_params;
+ int p_len, g_len;
+ unsigned char *p_ptr, *g_ptr;
+ ERL_NIF_TERM ret_p, ret_g;
+
+ if (!enif_get_int(env, argv[0], &prime_len)
+ || !enif_get_int(env, argv[1], &generator)) {
+
+ return enif_make_badarg(env);
+ }
+ dh_params = DH_generate_parameters(prime_len, generator, NULL, NULL);
+ if (dh_params == NULL) {
+ return atom_error;
+ }
+ 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);
+ 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();
+ int i;
+ ERL_NIF_TERM ret, head, tail;
+
+ if (!enif_get_list_cell(env, argv[0], &head, &tail)
+ || !get_bn_from_mpint(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)) {
+
+ DH_free(dh_params);
+ return enif_make_badarg(env);
+ }
+ if (DH_check(dh_params, &i)) {
+ if (i == 0) ret = atom_ok;
+ else if (i & DH_CHECK_P_NOT_PRIME) ret = atom_not_prime;
+ else if (i & DH_CHECK_P_NOT_SAFE_PRIME) ret = atom_not_strong_prime;
+ else if (i & DH_UNABLE_TO_CHECK_GENERATOR) ret = atom_unable_to_check_generator;
+ else if (i & DH_NOT_SUITABLE_GENERATOR) ret = atom_not_suitable_generator;
+ else ret = enif_make_tuple2(env, atom_unknown, enif_make_uint(env, i));
+ }
+ else { /* Check Failed */
+ ret = enif_make_tuple2(env, atom_error, atom_check_failed);
+ }
+ DH_free(dh_params);
+ return ret;
+}
+
+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();
+ int pub_len, prv_len;
+ unsigned char *pub_ptr, *prv_ptr;
+ ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+
+ if (!(get_bn_from_mpint(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)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !enif_is_empty_list(env, tail)) {
+
+ return enif_make_badarg(env);
+ }
+
+ 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);
+ ret = enif_make_tuple2(env, ret_pub, ret_prv);
+ }
+ else {
+ ret = atom_error;
+ }
+ DH_free(dh_params);
+ return ret;
+}
+
+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();
+ BIGNUM* pubkey;
+ 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)
+ || !enif_get_list_cell(env, argv[2], &head, &tail)
+ || !get_bn_from_mpint(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)) {
+
+ ret = enif_make_badarg(env);
+ }
+ else {
+ enif_alloc_binary(env, DH_size(dh_params), &ret_bin);
+ i = DH_compute_key(ret_bin.data, pubkey, dh_params);
+ if (i > 0) {
+ if (i != ret_bin.size) {
+ enif_realloc_binary(env, &ret_bin, i);
+ }
+ ret = enif_make_binary(env, &ret_bin);
+ }
+ else {
+ ret = atom_error;
+ }
+ }
+ DH_free(dh_params);
+ 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;
+ BF_KEY bf_key; /* blowfish key 8 */
+ unsigned char bf_tkey[8]; /* blowfish ivec */
+ int bf_n = 0; /* blowfish ivec pos */
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || ivec_bin.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+
+ BF_set_key(&bf_key, key_bin.size, key_bin.data);
+ memcpy(bf_tkey, ivec_bin.data, 8);
+ 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));
+ return ret;
+}
+
+static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Ivec, Data, IsEncrypt) */
+ ErlNifBinary key_bin, ivec_bin, data_bin;
+ BF_KEY bf_key; /* blowfish key 8 */
+ unsigned char bf_tkey[8]; /* blowfish ivec */
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || ivec_bin.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)
+ || data_bin.size % 8 != 0) {
+ return enif_make_badarg(env);
+ }
+
+ BF_set_key(&bf_key, key_bin.size, key_bin.data);
+ memcpy(bf_tkey, ivec_bin.data, 8);
+ 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));
+ return ret;
+}
+
+static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, IsEncrypt) */
+ ErlNifBinary key_bin, data_bin;
+ BF_KEY bf_key; /* blowfish key 8 */
+ ERL_NIF_TERM ret;
+
+ 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) {
+ return enif_make_badarg(env);
+ }
+ 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));
+ return ret;
+}
+
+static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data) */
+ ErlNifBinary key_bin, ivec_bin, data_bin;
+ BF_KEY bf_key; /* blowfish key 8 */
+ unsigned char bf_tkey[8]; /* blowfish ivec */
+ int bf_n = 0; /* blowfish ivec pos */
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || ivec_bin.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+
+ BF_set_key(&bf_key, key_bin.size, key_bin.data);
+ 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);
+ return ret;
+}
+
+
+
+#ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */
+
+static INLINE void locking(int mode, ErlNifRWLock* lock)
+{
+ switch (mode) {
+ case CRYPTO_LOCK|CRYPTO_READ:
+ enif_rwlock_rlock(lock);
+ break;
+ case CRYPTO_LOCK|CRYPTO_WRITE:
+ enif_rwlock_rwlock(lock);
+ break;
+ case CRYPTO_UNLOCK|CRYPTO_READ:
+ enif_rwlock_runlock(lock);
+ break;
+ case CRYPTO_UNLOCK|CRYPTO_WRITE:
+ enif_rwlock_rwunlock(lock);
+ break;
+ default:
+ ASSERT(!"Invalid lock mode");
+ }
+}
+
+/* Callback from openssl for static locking
+ */
+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]);
+}
+
+/* Callback from openssl for thread id
+ */
+static unsigned long id_function(void)
+{
+ return(unsigned long) enif_thread_self();
+}
+
+/* Callbacks for dynamic locking, not used by current openssl version (0.9.8)
+ */
+static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, int line) {
+ return(struct CRYPTO_dynlock_value*) enif_rwlock_create("crypto_dyn");
+}
+static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,const char *file, int line)
+{
+ locking(mode, (ErlNifRWLock*)ptr);
+}
+static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, const char *file, int line)
+{
+ enif_rwlock_destroy((ErlNifRWLock*)ptr);
+}
+
+#endif /* ^^^^^^^^^^^^^^^^^^^^^^ OPENSSL_THREADS ^^^^^^^^^^^^^^^^^^^^^^ */
+
+/* HMAC */
+
+static void hmac_md5(unsigned char *key, int klen, unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf)
+{
+ MD5_CTX ctx;
+ char ipad[HMAC_INT_LEN];
+ char opad[HMAC_INT_LEN];
+ unsigned char nkey[MD5_LEN];
+ int i;
+
+ /* Change key if longer than 64 bytes */
+ if (klen > HMAC_INT_LEN) {
+ MD5(key, klen, nkey);
+ key = nkey;
+ klen = MD5_LEN;
+ }
+
+ memset(ipad, '\0', sizeof(ipad));
+ memset(opad, '\0', sizeof(opad));
+ memcpy(ipad, key, klen);
+ memcpy(opad, key, klen);
+
+ for (i = 0; i < HMAC_INT_LEN; i++) {
+ ipad[i] ^= HMAC_IPAD;
+ opad[i] ^= HMAC_OPAD;
+ }
+
+ /* inner MD5 */
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, ipad, HMAC_INT_LEN);
+ MD5_Update(&ctx, dbuf, dlen);
+ MD5_Final((unsigned char *) hmacbuf, &ctx);
+ /* outer MD5 */
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, opad, HMAC_INT_LEN);
+ MD5_Update(&ctx, hmacbuf, MD5_LEN);
+ MD5_Final((unsigned char *) hmacbuf, &ctx);
+}
+
+static void hmac_sha1(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf)
+{
+ SHA_CTX ctx;
+ char ipad[HMAC_INT_LEN];
+ char opad[HMAC_INT_LEN];
+ unsigned char nkey[SHA_LEN];
+ int i;
+
+ /* Change key if longer than 64 bytes */
+ if (klen > HMAC_INT_LEN) {
+ SHA1(key, klen, nkey);
+ key = nkey;
+ klen = SHA_LEN;
+ }
+
+ memset(ipad, '\0', sizeof(ipad));
+ memset(opad, '\0', sizeof(opad));
+ memcpy(ipad, key, klen);
+ memcpy(opad, key, klen);
+
+ for (i = 0; i < HMAC_INT_LEN; i++) {
+ ipad[i] ^= HMAC_IPAD;
+ opad[i] ^= HMAC_OPAD;
+ }
+
+ /* inner SHA */
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, ipad, HMAC_INT_LEN);
+ SHA1_Update(&ctx, dbuf, dlen);
+ SHA1_Final((unsigned char *) hmacbuf, &ctx);
+ /* outer SHA */
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, opad, HMAC_INT_LEN);
+ SHA1_Update(&ctx, hmacbuf, SHA_LEN);
+ SHA1_Final((unsigned char *) hmacbuf, &ctx);
+}
+
diff --git a/lib/crypto/c_src/crypto_drv.c b/lib/crypto/c_src/crypto_drv.c
deleted file mode 100644
index 8c1356c4cf..0000000000
--- a/lib/crypto/c_src/crypto_drv.c
+++ /dev/null
@@ -1,1817 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2010. 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
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * Purpose: Dynamically loadable driver for cryptography libraries.
- * Based on OpenSSL.
- */
-
-#ifdef __WIN32__
-#include <windows.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "erl_driver.h"
-
-#define OPENSSL_THREAD_DEFINES
-#include <openssl/opensslconf.h>
-#ifndef OPENSSL_THREADS
-# ifdef __GNUC__
-# warning No thread support by openssl. Driver will use coarse grain locking.
-# endif
-#endif
-
-#include <openssl/crypto.h>
-#include <openssl/des.h>
-/* #include <openssl/idea.h> This is not supported on the openssl OTP requires */
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/aes.h>
-#include <openssl/md5.h>
-#include <openssl/md4.h>
-#include <openssl/sha.h>
-#include <openssl/bn.h>
-#include <openssl/objects.h>
-#include <openssl/rc4.h>
-#include <openssl/rc2.h>
-#include <openssl/blowfish.h>
-#include <openssl/rand.h>
-
-#ifdef VALGRIND
-# include <valgrind/memcheck.h>
-
-/* libcrypto mixes supplied buffer contents into its entropy pool,
- which makes valgrind complain about the use of uninitialized data.
- We use this valgrind "request" to make sure that no such seemingly
- undefined data escapes the driver.
-*/
-# define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) \
- VALGRIND_MAKE_MEM_DEFINED(ptr,size)
-
-# define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size) \
- ((void) ((VALGRIND_CHECK_MEM_IS_DEFINED(ptr,size) == 0) ? 1 : \
- (fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%d) failed at %s:%d\r\n",\
- (ptr),(size), __FILE__, __LINE__), abort(), 0)))
-#else
-# define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size)
-# define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size)
-#endif
-
-#ifdef DEBUG
-# define ASSERT(e) \
- ((void) ((e) ? 1 : (fprintf(stderr,"Assert '%s' failed at %s:%d\n",\
- #e, __FILE__, __LINE__), abort(), 0)))
-#else
-# define ASSERT(e) ((void) 1)
-#endif
-
-#ifdef __GNUC__
-# define INLINE __inline__
-#elif defined(__WIN32__)
-# define INLINE __forceinline
-#else
-# define INLINE
-#endif
-
-
-#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \
- (((unsigned char*) (s))[1] << 16) | \
- (((unsigned char*) (s))[2] << 8) | \
- (((unsigned char*) (s))[3]))
-
-#define put_int32(s,i) \
-{ (s)[0] = (char)(((i) >> 24) & 0xff);\
- (s)[1] = (char)(((i) >> 16) & 0xff);\
- (s)[2] = (char)(((i) >> 8) & 0xff);\
- (s)[3] = (char)((i) & 0xff);\
-}
-
-/* Driver interface declarations */
-static int init(void);
-static void finish(void);
-static ErlDrvData start(ErlDrvPort port, char *command);
-static void stop(ErlDrvData drv_data);
-static int crypto_control(ErlDrvData drv_data, unsigned int command, char *buf,
- int len, char **rbuf, int rlen);
-
-/* openssl callbacks */
-#ifdef OPENSSL_THREADS
-static void locking_function(int mode, int n, const char *file, int line);
-static unsigned long id_function(void);
-static struct CRYPTO_dynlock_value* dyn_create_function(const char *file,
- int line);
-static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,
- const char *file, int line);
-static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr,
- const char *file, int line);
-#endif /* OPENSSL_THREADS */
-
-/* helpers */
-static void hmac_md5(char *key, int klen, char *dbuf, int dlen,
- char *hmacbuf);
-static void hmac_sha1(char *key, int klen, char *dbuf, int dlen,
- char *hmacbuf);
-
-static ErlDrvEntry crypto_driver_entry = {
- init,
- start,
- stop,
- NULL, /* output */
- NULL, /* ready_input */
- NULL, /* ready_output */
- "crypto_drv",
- finish,
- NULL, /* handle */
- crypto_control,
- NULL, /* timeout */
- NULL, /* outputv */
-
- NULL, /* ready_async */
- NULL, /* flush */
- NULL, /* call */
- NULL, /* event */
- ERL_DRV_EXTENDED_MARKER,
- ERL_DRV_EXTENDED_MAJOR_VERSION,
- ERL_DRV_EXTENDED_MINOR_VERSION,
-#ifdef OPENSSL_THREADS
- ERL_DRV_FLAG_USE_PORT_LOCKING,
-#else
- 0,
-#endif
- NULL, /* handle2 */
- NULL /* process_exit */
-};
-
-
-/* Keep the following definitions in alignment with the FUNC_LIST
- * in crypto.erl.
- */
-
-#define DRV_INFO 0
-#define DRV_MD5 1
-#define DRV_MD5_INIT 2
-#define DRV_MD5_UPDATE 3
-#define DRV_MD5_FINAL 4
-#define DRV_SHA 5
-#define DRV_SHA_INIT 6
-#define DRV_SHA_UPDATE 7
-#define DRV_SHA_FINAL 8
-#define DRV_MD5_MAC 9
-#define DRV_MD5_MAC_96 10
-#define DRV_SHA_MAC 11
-#define DRV_SHA_MAC_96 12
-#define DRV_CBC_DES_ENCRYPT 13
-#define DRV_CBC_DES_DECRYPT 14
-#define DRV_EDE3_CBC_DES_ENCRYPT 15
-#define DRV_EDE3_CBC_DES_DECRYPT 16
-#define DRV_AES_CFB_128_ENCRYPT 17
-#define DRV_AES_CFB_128_DECRYPT 18
-#define DRV_RAND_BYTES 19
-#define DRV_RAND_UNIFORM 20
-#define DRV_MOD_EXP 21
-#define DRV_DSS_VERIFY 22
-#define DRV_RSA_VERIFY_SHA 23
-/* #define DRV_RSA_VERIFY_MD5 35 */
-#define DRV_CBC_AES128_ENCRYPT 24
-#define DRV_CBC_AES128_DECRYPT 25
-#define DRV_XOR 26
-#define DRV_RC4_ENCRYPT 27 /* no decrypt needed; symmetric */
-#define DRV_RC4_SETKEY 28
-#define DRV_RC4_ENCRYPT_WITH_STATE 29
-#define DRV_CBC_RC2_40_ENCRYPT 30
-#define DRV_CBC_RC2_40_DECRYPT 31
-#define DRV_CBC_AES256_ENCRYPT 32
-#define DRV_CBC_AES256_DECRYPT 33
-#define DRV_INFO_LIB 34
-/* #define DRV_RSA_VERIFY_SHA 23 */
-#define DRV_RSA_VERIFY_MD5 35
-#define DRV_RSA_SIGN_SHA 36
-#define DRV_RSA_SIGN_MD5 37
-#define DRV_DSS_SIGN 38
-#define DRV_RSA_PUBLIC_ENCRYPT 39
-#define DRV_RSA_PRIVATE_DECRYPT 40
-#define DRV_RSA_PRIVATE_ENCRYPT 41
-#define DRV_RSA_PUBLIC_DECRYPT 42
-#define DRV_DH_GENERATE_PARAMS 43
-#define DRV_DH_CHECK 44
-#define DRV_DH_GENERATE_KEY 45
-#define DRV_DH_COMPUTE_KEY 46
-#define DRV_MD4 47
-#define DRV_MD4_INIT 48
-#define DRV_MD4_UPDATE 49
-#define DRV_MD4_FINAL 50
-
-#define SSL_VERSION_0_9_8 0
-#if SSL_VERSION_0_9_8
-#define DRV_SHA256 51
-#define DRV_SHA256_INIT 52
-#define DRV_SHA256_UPDATE 53
-#define DRV_SHA256_FINAL 54
-#define DRV_SHA512 55
-#define DRV_SHA512_INIT 56
-#define DRV_SHA512_UPDATE 57
-#define DRV_SHA512_FINAL 58
-#endif
-
-#define DRV_BF_CFB64_ENCRYPT 59
-#define DRV_BF_CFB64_DECRYPT 60
-#define DRV_BF_ECB_ENCRYPT 61
-#define DRV_BF_ECB_DECRYPT 62
-#define DRV_BF_OFB64_ENCRYPT 63
-#define DRV_BF_CBC_ENCRYPT 64
-#define DRV_BF_CBC_DECRYPT 65
-
-#define DRV_ECB_DES_ENCRYPT 66
-#define DRV_ECB_DES_DECRYPT 67
-
-/* #define DRV_CBC_IDEA_ENCRYPT 34 */
-/* #define DRV_CBC_IDEA_DECRYPT 35 */
-
-/* Not DRV_DH_GENERATE_PARAMS DRV_DH_CHECK
- * Calc RSA_VERIFY_* and RSA_SIGN once */
-#define NUM_CRYPTO_FUNCS 48
-
-#define MD5_CTX_LEN (sizeof(MD5_CTX))
-#define MD5_LEN 16
-#define MD5_LEN_96 12
-#define MD4_CTX_LEN (sizeof(MD4_CTX))
-#define MD4_LEN 16
-#define SHA_CTX_LEN (sizeof(SHA_CTX))
-#define SHA_LEN 20
-#define SHA_LEN_96 12
-#define HMAC_INT_LEN 64
-
-#define HMAC_IPAD 0x36
-#define HMAC_OPAD 0x5c
-
-#if SSL_VERSION_0_9_8
-#define SHA256_CTX_LEN (sizeof(SHA256_CTX))
-#define SHA256_LEN 32
-
-#define SHA512_CTX_LEN (sizeof(SHA512_CTX))
-#define SHA512_LEN 64
-#endif
-
-/* INITIALIZATION AFTER LOADING */
-
-/*
- * This is the init function called after this driver has been loaded.
- * It must *not* be declared static. Must return the address to
- * the driver entry.
- */
-
-#if !defined(__WIN32__)
-DRIVER_INIT(crypto_drv);
-#endif
-
-DRIVER_INIT(crypto_drv)
-{
- return &crypto_driver_entry;
-}
-
-static ErlDrvRWLock** lock_vec = NULL; /* Static locks used by openssl */
-
-/* DRIVER INTERFACE */
-
-static int init(void)
-{
- ErlDrvSysInfo sys_info;
- int i;
-
- CRYPTO_set_mem_functions(driver_alloc, driver_realloc, driver_free);
-
-#ifdef OPENSSL_THREADS
- driver_system_info(&sys_info, sizeof(sys_info));
-
- if(sys_info.scheduler_threads > 1) {
- lock_vec = driver_alloc(CRYPTO_num_locks()*sizeof(*lock_vec));
- if (lock_vec==NULL) return -1;
- memset(lock_vec,0,CRYPTO_num_locks()*sizeof(*lock_vec));
-
- for(i=CRYPTO_num_locks()-1; i>=0; --i) {
- lock_vec[i] = erl_drv_rwlock_create("crypto_drv_stat");
- if (lock_vec[i]==NULL) return -1;
- }
- CRYPTO_set_locking_callback(locking_function);
- CRYPTO_set_id_callback(id_function);
- CRYPTO_set_dynlock_create_callback(dyn_create_function);
- CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
- CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
- }
- /* else no need for locks */
-#endif /* OPENSSL_THREADS */
-
- return 0;
-}
-
-static void finish(void)
-{
- /* Moved here from crypto_control() as it's not thread safe */
- CRYPTO_cleanup_all_ex_data();
-
- if(lock_vec != NULL) {
- int i;
- for(i=CRYPTO_num_locks()-1; i>=0; --i) {
- if (lock_vec[i] != NULL) {
- erl_drv_rwlock_destroy(lock_vec[i]);
- }
- }
- driver_free(lock_vec);
- }
-}
-
-static ErlDrvData start(ErlDrvPort port, char *command)
-{
- set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
- return 0; /* not used */
-}
-
-static void stop(ErlDrvData drv_data)
-{
- return;
-}
-
-/* Helper functions for 'crypto_control'
-*/
-static INLINE unsigned char* return_binary(char **rbuf, int rlen, int len)
-{
- if (len <= rlen) {
- return (unsigned char *) *rbuf;
- }
- else {
- ErlDrvBinary* bin;
- *rbuf = (char*) (bin = driver_alloc_binary(len));
- return (bin==NULL) ? NULL : (unsigned char *) bin->orig_bytes;
- }
-}
-
-static INLINE unsigned char* return_binary_shrink(char **rbuf, int rlen, unsigned char* data, int len)
-{
- if ((char *) data == *rbuf) { /* default buffer */
- ASSERT(len <= rlen);
- return (unsigned char *) data;
- }
- else {
- ErlDrvBinary* bin = (ErlDrvBinary*) *rbuf;
- *rbuf = (char*) (bin=driver_realloc_binary(bin, len));
- return (bin==NULL) ? NULL : (unsigned char *) bin->orig_bytes;
- }
-}
-
-/* Nowadays (R13) it does matter what value control returns
- * as it may return data in default buffer.
- */
-static int crypto_control(ErlDrvData drv_data, unsigned int command, char *buf,
- int len, char **rbuf, int rlen)
-{
- int klen, dlen, macsize, from_len, to_len, i;
- int base_len, exponent_len, modulo_len;
- int data_len, dsa_p_len, dsa_q_len;
- int dsa_s_len, dsa_g_len, dsa_y_len;
- int rsa_e_len, rsa_n_len, rsa_d_len, padding;
- int or_mask;
- int prime_len, generator;
- int privkey_len, pubkey_len, dh_p_len, dh_g_len;
- unsigned int rsa_s_len, j;
- char *key, *key2, *dbuf;
- unsigned char *p;
- const_DES_cblock *des_key, *des_key2, *des_key3;
- const unsigned char *des_dbuf;
- BIGNUM *bn_from, *bn_to, *bn_rand, *bn_result;
- BIGNUM *bn_base, *bn_exponent, *bn_modulo;
- BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_y;
- BIGNUM *rsa_n, *rsa_e, *rsa_d;
- BIGNUM *dh_p, *dh_g, *privkey, *pubkey;
- DES_cblock *des_ivec;
- unsigned char* bin;
- DES_key_schedule schedule, schedule2, schedule3;
- DH *dh_params;
-/* IDEA_KEY_SCHEDULE idea, idea2; */
- char hmacbuf[SHA_DIGEST_LENGTH];
- unsigned char *rsa_s, *dsa_s;
- /* char hmacbuf[SHA_LEN]; */
-#if SSL_VERSION_0_9_8
- SHA256_CTX sha256_ctx;
- SHA512_CTX sha512_ctx;
-#endif
- MD5_CTX md5_ctx;
- MD4_CTX md4_ctx;
- SHA_CTX sha_ctx;
- int new_ivlen = 0;
- BN_CTX *bn_ctx;
- DSA *dsa;
- RSA *rsa;
- AES_KEY aes_key;
- RC4_KEY rc4_key;
- RC2_KEY rc2_key;
-
- switch(command) {
-
- case DRV_INFO:
- bin = return_binary(rbuf,rlen,NUM_CRYPTO_FUNCS);
- if (bin==NULL) return -1;
-
- for (i = 0; i < NUM_CRYPTO_FUNCS; i++) {
- bin[i] = i + 1;
- }
- return NUM_CRYPTO_FUNCS;
-
- case DRV_MD5:
- bin = return_binary(rbuf,rlen,MD5_LEN);
- if (bin==NULL) return -1;
- MD5((unsigned char *) buf, len, bin);
- return MD5_LEN;
-
- case DRV_MD5_INIT:
- bin = return_binary(rbuf,rlen,MD5_CTX_LEN);
- if (bin==NULL) return -1;
- MD5_Init((MD5_CTX *)bin);
- return MD5_CTX_LEN;
-
- case DRV_MD5_UPDATE:
- if (len < MD5_CTX_LEN)
- return -1;
- bin = return_binary(rbuf,rlen,MD5_CTX_LEN);
- if (bin==NULL) return -1;
- memcpy(bin, buf, MD5_CTX_LEN);
- MD5_Update((MD5_CTX *)bin, buf + MD5_CTX_LEN,
- len - MD5_CTX_LEN);
- return MD5_CTX_LEN;
-
- case DRV_MD5_FINAL:
- if (len != MD5_CTX_LEN)
- return -1;
- memcpy(&md5_ctx, buf, MD5_CTX_LEN); /* XXX Use buf only? */
- bin = return_binary(rbuf,rlen,MD5_LEN);
- if (bin==NULL) return -1;
- MD5_Final(bin, &md5_ctx);
- return MD5_LEN;
-
- case DRV_SHA:
- bin = return_binary(rbuf,rlen,SHA_LEN);
- if (bin==NULL) return -1;
- SHA1((unsigned char *) buf, len, bin);
- return SHA_LEN;
-
- case DRV_SHA_INIT:
- bin = return_binary(rbuf,rlen,SHA_CTX_LEN);
- if (bin==NULL) return -1;
- SHA1_Init((SHA_CTX*)bin);
- return SHA_CTX_LEN;
-
- case DRV_SHA_UPDATE:
- if (len < SHA_CTX_LEN)
- return -1;
- bin = return_binary(rbuf,rlen,SHA_CTX_LEN);
- if (bin==NULL) return -1;
- memcpy(bin, buf, SHA_CTX_LEN);
- SHA1_Update((SHA_CTX*)bin, buf + SHA_CTX_LEN, len - SHA_CTX_LEN);
- return SHA_CTX_LEN;
-
- case DRV_SHA_FINAL:
- if (len != SHA_CTX_LEN)
- return -1;
- memcpy(&sha_ctx, buf, SHA_CTX_LEN); /* XXX Use buf only? */
- bin = return_binary(rbuf,rlen,SHA_LEN);
- if (bin==NULL) return -1;
- SHA1_Final(bin, &sha_ctx);
- return SHA_LEN;
-
- case DRV_MD5_MAC:
- case DRV_MD5_MAC_96:
- /* buf = klen[4] key data */
- klen = get_int32(buf);
- key = buf + 4;
- dlen = len - klen - 4;
- dbuf = key + klen;
- hmac_md5(key, klen, dbuf, dlen, hmacbuf);
- macsize = (command == DRV_MD5_MAC) ? MD5_LEN : MD5_LEN_96;
- bin = return_binary(rbuf,rlen,macsize);
- if (bin==NULL) return -1;
- memcpy(bin, hmacbuf, macsize);
- return macsize;
-
- case DRV_SHA_MAC:
- case DRV_SHA_MAC_96:
- /* buf = klen[4] key data */
- klen = get_int32(buf);
- key = buf + 4;
- dlen = len - klen - 4;
- dbuf = key + klen;
- hmac_sha1(key, klen, dbuf, dlen, hmacbuf);
- macsize = (command == DRV_SHA_MAC) ? SHA_LEN : SHA_LEN_96;
- bin = return_binary(rbuf,rlen,macsize);
- if (bin==NULL) return -1;
- memcpy(bin, (unsigned char *) hmacbuf, macsize);
- return macsize;
-
- case DRV_CBC_DES_ENCRYPT:
- case DRV_CBC_DES_DECRYPT:
- /* buf = key[8] ivec[8] data */
- dlen = len - 16;
- if (dlen < 0)
- return -1;
- if (dlen % 8 != 0)
- return -1;
- des_key = (const_DES_cblock*) buf;
- des_ivec = (DES_cblock*)(buf + 8);
- des_dbuf = (unsigned char *) (buf + 16);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- DES_set_key(des_key, &schedule);
- DES_ncbc_encrypt(des_dbuf, bin, dlen, &schedule, des_ivec,
- (command == DRV_CBC_DES_ENCRYPT));
- return dlen;
-
- case DRV_ECB_DES_ENCRYPT:
- case DRV_ECB_DES_DECRYPT:
- /* buf = key[8] data */
- dlen = len - 8;
- if (dlen != 8)
- return -1;
- des_key = (const_DES_cblock*) buf;
- des_dbuf = (unsigned char *) (buf + 8);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- DES_set_key(des_key, &schedule);
- DES_ecb_encrypt((const_DES_cblock*) des_dbuf, (DES_cblock*) bin, &schedule,
- (command == DRV_ECB_DES_ENCRYPT));
- return dlen;
-
- case DRV_BF_ECB_ENCRYPT:
- case DRV_BF_ECB_DECRYPT:
- {
- /* buf = klen[4] key data */
- int bf_direction;
- const unsigned char *ukey;
- const unsigned char *bf_dbuf; /* blowfish input data */
- BF_KEY bf_key; /* blowfish key 8 */
-
- klen = get_int32(buf);
- ukey = (unsigned char *) buf + 4;
- bf_dbuf = ukey + klen;
- dlen = len - 4 - klen;
- if (dlen < 0) return -1;
- BF_set_key(&bf_key, klen, ukey);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bf_direction = command == DRV_BF_ECB_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT;
- BF_ecb_encrypt(bf_dbuf, bin, &bf_key, bf_direction);
- return dlen;
- }
-
- case DRV_BF_CBC_ENCRYPT:
- case DRV_BF_CBC_DECRYPT:
- {
- /* buf = klen[4] key ivec[8] data */
- unsigned char *ukey;
- unsigned char* ivec;
- unsigned char bf_tkey[8]; /* blowfish ivec */
- int bf_direction;
- const unsigned char *bf_dbuf; /* blowfish input data */
- BF_KEY bf_key; /* blowfish key 8 */
-
- klen = get_int32(buf);
- ukey = (unsigned char *)buf + 4;
- ivec = ukey + klen;
- bf_dbuf = ivec + 8;
- dlen = len - 4 - klen - 8;
- if (dlen < 0) return -1;
- BF_set_key(&bf_key, klen, ukey);
- memcpy(bf_tkey, ivec, 8);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bf_direction = command == DRV_BF_CBC_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT;
- BF_cbc_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, bf_direction);
- return dlen;
- }
-
- case DRV_BF_OFB64_ENCRYPT:
- {
- /* buf = klen[4] key ivec[8] data */
- unsigned char *ukey;
- unsigned char* ivec;
- unsigned char bf_tkey[8]; /* blowfish ivec */
- int bf_n; /* blowfish ivec pos */
- const unsigned char *bf_dbuf; /* blowfish input data */
- BF_KEY bf_key; /* blowfish key 8 */
-
- klen = get_int32(buf);
- ukey = (unsigned char *)buf + 4;
- ivec = ukey + klen;
- bf_dbuf = ivec + 8;
- dlen = len - 4 - klen - 8;
- if (dlen < 0) return -1;
- BF_set_key(&bf_key, klen, ukey);
- memcpy(bf_tkey, ivec, 8);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bf_n = 0;
- BF_ofb64_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, &bf_n);
- return dlen;
- }
-
- case DRV_BF_CFB64_ENCRYPT:
- case DRV_BF_CFB64_DECRYPT:
- {
- /* buf = klen[4] key ivec[8] data */
- unsigned char* ivec;
- unsigned char bf_tkey[8]; /* blowfish ivec */
- int bf_n; /* blowfish ivec pos */
- int bf_direction;
- const unsigned char *bf_dbuf; /* blowfish input data */
- BF_KEY bf_key; /* blowfish key 8 */
-
- klen = get_int32(buf);
- key = buf + 4;
- ivec = (unsigned char *) (key + klen);
- bf_dbuf = ivec + 8;
- dlen = len - 4 - klen - 8;
- if (dlen < 0) return -1;
- BF_set_key(&bf_key, klen, (unsigned char *) key);
- memcpy(bf_tkey, ivec, 8);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bf_direction = command == DRV_BF_CFB64_ENCRYPT ? BF_ENCRYPT : BF_DECRYPT;
- bf_n = 0;
- BF_cfb64_encrypt(bf_dbuf, bin, dlen, &bf_key, bf_tkey, &bf_n, bf_direction);
- return dlen;
- }
-
-/* case DRV_CBC_IDEA_ENCRYPT: */
-/* case DRV_CBC_IDEA_DECRYPT: */
- /* buf = key[16] ivec[8] data */
-/* dlen = len - 24; */
-/* if (dlen < 0) */
-/* return -1; */
-/* if (dlen % 8 != 0) */
-/* return -1; */
-/* bin = return_binary(rbuf,rlen,dlen); */
-/* idea_set_encrypt_key(buf, &idea); */
-/* if (command == DRV_CBC_IDEA_DECRYPT) { */
-/* idea_set_decrypt_key(&idea, &idea2); */
-/* memcpy(&idea, &idea2, sizeof(idea)); */
-/* } */
-/* idea_cbc_encrypt(buf + 24, bin, dlen, &idea, buf + 8, */
-/* (command == DRV_CBC_IDEA_ENCRYPT)); */
-/* return dlen; */
-
- case DRV_CBC_RC2_40_ENCRYPT:
- case DRV_CBC_RC2_40_DECRYPT:
- /* buf = key[5] ivec[8] data */
- dlen = len - 13;
- if (dlen < 0)
- return -1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- RC2_set_key(&rc2_key, 5, (unsigned char *) buf, 40);
- RC2_cbc_encrypt((unsigned char *) (buf + 13), bin, dlen, &rc2_key,
- (unsigned char *) (buf + 5),
- (command == DRV_CBC_RC2_40_ENCRYPT));
- return dlen;
-
- case DRV_EDE3_CBC_DES_ENCRYPT:
- case DRV_EDE3_CBC_DES_DECRYPT:
- dlen = len - 32;
- if (dlen < 0)
- return -1;
- des_key = (const_DES_cblock*) buf;
- des_key2 = (const_DES_cblock*) (buf + 8);
- des_key3 = (const_DES_cblock*) (buf + 16);
- des_ivec = (DES_cblock*) (buf + 24);
- des_dbuf = (unsigned char *) (buf + 32);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- DES_set_key(des_key, &schedule);
- DES_set_key(des_key2, &schedule2);
- DES_set_key(des_key3, &schedule3);
- DES_ede3_cbc_encrypt(des_dbuf, bin, dlen, &schedule,
- &schedule2, &schedule3, des_ivec,
- (command == DRV_EDE3_CBC_DES_ENCRYPT));
- return dlen;
-
- case DRV_AES_CFB_128_ENCRYPT:
- case DRV_AES_CFB_128_DECRYPT:
- /* buf = key[16] ivec[16] data */
- dlen = len - 32;
- if (dlen < 0)
- return -1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- AES_set_encrypt_key((unsigned char *) buf, 128, &aes_key);
- AES_cfb128_encrypt((unsigned char *) (buf+32), bin, dlen, &aes_key,
- (unsigned char *) (buf+16), &new_ivlen,
- (command == DRV_AES_CFB_128_ENCRYPT));
- return dlen;
-
- case DRV_RC4_ENCRYPT:
- /* buf = klen[4] key data */
- klen = get_int32(buf);
- key = buf + 4;
- dlen = len - klen - 4;
- dbuf = key + klen;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- RC4_set_key(&rc4_key, klen, (unsigned char *) key);
- RC4(&rc4_key, dlen, (unsigned char *) dbuf, bin);
- return dlen;
-
- case DRV_RC4_SETKEY:
- /* buf = key */
- dlen = sizeof(rc4_key);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- RC4_set_key(&rc4_key, len, (unsigned char *) buf);
- memcpy(bin, &rc4_key, dlen);
- return dlen;
-
- case DRV_RC4_ENCRYPT_WITH_STATE:
- /* buf = statelength[4] state data, return statelength[4] state data */
- klen = get_int32(buf);
- key = buf + 4;
- dlen = len - klen - 4;
- dbuf = key + klen;
- bin = return_binary(rbuf,rlen,len);
- if (bin==NULL) return -1;
- memcpy(&rc4_key, key, klen);
- RC4(&rc4_key, dlen, (unsigned char *) dbuf, bin + klen + 4);
- memcpy(bin, buf, 4);
- memcpy(bin + 4, &rc4_key, klen);
- return len;
-
- case DRV_RAND_BYTES:
- /* buf = <<rlen:32/integer,topmask:8/integer,bottommask:8/integer>> */
-
- if (len != 6)
- return -1;
- dlen = get_int32(buf);
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- RAND_pseudo_bytes(bin,dlen);
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin, dlen);
- or_mask = ((unsigned char*)buf)[4];
- bin[dlen-1] |= or_mask; /* topmask */
- or_mask = ((unsigned char*)buf)[5];
- bin[0] |= or_mask; /* bottommask */
- return dlen;
-
- case DRV_RAND_UNIFORM:
- /* buf = <<from_len:32/integer,bn_from:from_len/binary, *
- * to_len:32/integer,bn_to:to_len/binary>> */
- if (len < 8)
- return -1;
- from_len = get_int32(buf);
- if (len < (8 + from_len))
- return -1;
- to_len = get_int32(buf + 4 + from_len);
- if (len != (8 + from_len + to_len))
- return -1;
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf, 4 + from_len + 4 + to_len);
- bn_from = BN_new();
- BN_bin2bn((unsigned char *)(buf + 4), from_len, bn_from);
- bn_rand = BN_new();
- BN_bin2bn((unsigned char *)(buf + 8 + from_len), to_len, bn_rand);
- bn_to = BN_new();
- BN_sub(bn_to, bn_rand, bn_from);
- BN_pseudo_rand_range(bn_rand, bn_to);
- BN_add(bn_rand, bn_rand, bn_from);
- dlen = BN_num_bytes(bn_rand);
- bin = return_binary(rbuf,rlen,dlen + 4);
- if (bin==NULL) return -1;
- put_int32(bin, dlen);
- BN_bn2bin(bn_rand,(unsigned char*)(bin + 4));
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+4, dlen);
- BN_free(bn_rand);
- BN_free(bn_from);
- BN_free(bn_to);
- return dlen + 4;
-
- case DRV_MOD_EXP:
- /* buf = <<base_len:32/integer,base/binary, *
- * exponent_len:32/integer,exponent/binary, *
- * modulo_len:32/integer, modulo/binary>> */
- if (len < 12)
- return -1;
- base_len = get_int32(buf);
- if (len < (12 + base_len))
- return -1;
- exponent_len = get_int32(buf + 4 + base_len);
- if (len < (12 + base_len + exponent_len))
- return -1;
- modulo_len = get_int32(buf + 8 + base_len + exponent_len);
- if (len != (12 + base_len + exponent_len + modulo_len))
- return -1;
- bn_base = BN_new();
- BN_bin2bn((unsigned char *)(buf + 4),
- base_len, bn_base);
- bn_exponent = BN_new();
- BN_bin2bn((unsigned char *)(buf + 8 + base_len),
- exponent_len, bn_exponent);
- bn_modulo = BN_new();
- BN_bin2bn((unsigned char *)(buf + 12 + base_len + exponent_len),
- modulo_len, bn_modulo);
- 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);
- bin = return_binary(rbuf,rlen,dlen + 4);
- if (bin==NULL) return -1;
- put_int32(bin, dlen);
- BN_bn2bin(bn_result,(unsigned char*)(bin + 4));
- BN_free(bn_result);
- BN_free(bn_modulo);
- BN_free(bn_exponent);
- BN_free(bn_base);
- BN_CTX_free(bn_ctx);
- return dlen + 4;
-
- case DRV_DSS_VERIFY:
- /* buf = <<data_len:32/integer, data:data_len/binary,
- * dsa_s_len:32/integer, dsa_s:dsa_s_len/binary,
- * dsa_p_len:32/integer, dsa_p:dsa_p_len/binary,
- * dsa_q_len:32/integer, dsa_q:dsa_q_len/binary,
- * dsa_g_len:32/integer, dsa_g:dsa_g_len/binary,
- * dsa_y_len:32/integer, dsa_y:dsa_y_len/binary>> */
- i = 0;
- j = 0;
- if (len < 24)
- return -1;
- data_len = get_int32(buf + i + j);
- j += data_len; i += 4;
- if (len < (24 + j))
- return -1;
- dsa_s_len = get_int32(buf + i + j);
- j += dsa_s_len; i += 4;
- if (len < (24 + j))
- return -1;
- dsa_p_len = get_int32(buf + i + j);
- j += dsa_p_len; i += 4;
- if (len < (24 + j))
- return -1;
- dsa_q_len = get_int32(buf + i + j);
- j += dsa_q_len; i += 4;
- if (len < (24 + j))
- return -1;
- dsa_g_len = get_int32(buf + i + j);
- j += dsa_g_len; i += 4;
- if (len < (24 + j))
- return -1;
- dsa_y_len = get_int32(buf + i + j);
- j += dsa_y_len;
- if (len != (24 + j))
- return -1;
- i = 4;
- SHA1((unsigned char *) (buf + i), data_len, (unsigned char *) hmacbuf);
- i += data_len + 4;
- dsa_s = (unsigned char *)(buf + i);
- i += (dsa_s_len + 4);
- dsa_p = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_p_len, dsa_p);
- i += (dsa_p_len + 4);
- dsa_q = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_q_len, dsa_q);
- i += (dsa_q_len + 4);
- dsa_g = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_g_len, dsa_g);
- i += (dsa_g_len + 4);
- dsa_y = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_y_len, dsa_y);
- dsa = DSA_new();
- dsa->p = dsa_p;
- dsa->q = dsa_q;
- dsa->g = dsa_g;
- dsa->priv_key = NULL;
- dsa->pub_key = dsa_y;
- i = DSA_verify(0, (unsigned char *) hmacbuf, SHA_DIGEST_LENGTH,
- dsa_s, dsa_s_len, dsa);
- bin = return_binary(rbuf,rlen,1);
- if (bin==NULL) return -1;
-
- DSA_free(dsa);
- bin[0] = (i > 0) ? 1 : 0;
- return 1;
-
- case DRV_DSS_SIGN:
- /* buf = <<data_len:32/integer, data:data_len/binary,
- * dsa_p_len:32/integer, dsa_p:dsa_p_len/binary,
- * dsa_q_len:32/integer, dsa_q:dsa_q_len/binary,
- * dsa_g_len:32/integer, dsa_g:dsa_g_len/binary,
- * dsa_y_len:32/integer, dsa_y:dsa_y_len/binary,
- * dsa_x_len:32/integer, dsa_s:dsa_x_len/binary>> */
- i = 0;
- j = 0;
- if (len < 20)
- return -1;
- data_len = get_int32(buf + i + j);
- j += data_len; i += 4;
- if (len < (20 + j))
- return -1;
- dsa_p_len = get_int32(buf + i + j);
- j += dsa_p_len; i += 4;
- if (len < (20 + j))
- return -1;
- dsa_q_len = get_int32(buf + i + j);
- j += dsa_q_len; i += 4;
- if (len < (20 + j))
- return -1;
- dsa_g_len = get_int32(buf + i + j);
- j += dsa_g_len; i += 4;
- if (len < (20 + j))
- return -1;
- dsa_y_len = get_int32(buf + i + j);
- j += dsa_y_len;
- if (len < (20 + j))
- return -1;
- if (len != (20 + j))
- return -1;
-
- i = 4;
- SHA1((unsigned char *) (buf + i), data_len, (unsigned char *) hmacbuf);
- i += data_len + 4;
- dsa_p = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_p_len, dsa_p);
- i += (dsa_p_len + 4);
- dsa_q = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_q_len, dsa_q);
- i += (dsa_q_len + 4);
- dsa_g = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_g_len, dsa_g);
- i += (dsa_g_len + 4);
- dsa_y = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dsa_y_len, dsa_y);
- /* i += (dsa_y_len + 4); */
-
- dsa = DSA_new();
- dsa->p = dsa_p;
- dsa->q = dsa_q;
- dsa->g = dsa_g;
- dsa->priv_key = dsa_y;
- dsa->pub_key = NULL;
- dlen = DSA_size(dsa);
- bin = return_binary(rbuf,rlen, dlen+1);
- if (bin==NULL) return -1;
- i = DSA_sign(NID_sha1,
- (unsigned char *) hmacbuf,SHA_DIGEST_LENGTH,
- (unsigned char *) &bin[1],
- (unsigned int *) &dsa_s_len, dsa);
- DSA_free(dsa);
- if (i) {
- if (dsa_s_len != dlen) {
- bin = return_binary_shrink(rbuf,rlen,bin,dsa_s_len+1);
- }
- bin[0] = 1;
- return dsa_s_len + 1;
- }
- else {
- bin[0] = 0;
- return 1;
- }
-
- case DRV_RSA_VERIFY_MD5:
- case DRV_RSA_VERIFY_SHA:
- /* buf = <<data_len:32/integer, data:data_len/binary,
- * rsa_s_len:32/integer, rsa_s:rsa_s_len/binary,
- * rsa_e_len:32/integer, rsa_e:rsa_e_len/binary,
- * rsa_n_len:32/integer, rsa_n:rsa_n_len/binary>> */
- i = 0;
- j = 0;
- if (len < 16)
- return -1;
- data_len = get_int32(buf + i + j);
- j += data_len; i += 4;
- if (len < (16 + j))
- return -1;
- rsa_s_len = get_int32(buf + i + j);
- j += rsa_s_len; i += 4;
- if (len < (16 + j))
- return -1;
- rsa_e_len = get_int32(buf + i + j);
- j += rsa_e_len; i += 4;
- if (len < (16 + j))
- return -1;
- rsa_n_len = get_int32(buf + i + j);
- j += rsa_n_len; i += 4;
- if (len != (16 + j))
- return -1;
- i = 4;
- i += (data_len + 4);
- rsa_s = (unsigned char *)(buf + i);
- i += (rsa_s_len + 4);
- rsa_e = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), rsa_e_len, rsa_e);
- i += (rsa_e_len + 4);
- rsa_n = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), rsa_n_len, rsa_n);
- rsa = RSA_new();
- rsa->n = rsa_n;
- rsa->e = rsa_e;
- i = 4;
- if(command == DRV_RSA_VERIFY_SHA) {
- SHA1((unsigned char *) (buf + i), data_len,
- (unsigned char *) hmacbuf);
- i = RSA_verify(NID_sha1, (unsigned char *) hmacbuf, SHA_DIGEST_LENGTH,
- rsa_s, rsa_s_len, rsa);
- } else {
- MD5((unsigned char *) (buf + i), data_len, (unsigned char *) hmacbuf);
- i = RSA_verify(NID_md5, (unsigned char *) hmacbuf, MD5_DIGEST_LENGTH,
- rsa_s, rsa_s_len, rsa);
- }
-
- bin = return_binary(rbuf,rlen,1);
- if (bin==NULL) return -1;
- bin[0] = (char)(i & 0xff);
- RSA_free(rsa);
- return 1;
-
- case DRV_RSA_SIGN_MD5:
- case DRV_RSA_SIGN_SHA:
- /* buf = <<data_len:32/integer, data:data_len/binary,
- * rsa_e_len:32/integer, rsa_e:rsa_e_len/binary,
- * rsa_n_len:32/integer, rsa_n:rsa_n_len/binary,
- * rsa_d_len:32/integer, rsa_d:rsa_d_len/binary>> */
-
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf,len);
-
- i = 0;
- j = 0;
-
- if (len < 16)
- return -1;
- data_len = get_int32(buf + i + j);
- j += data_len; i += 4;
- if (len < (16 + j))
- return -1;
- rsa_e_len = get_int32(buf + i + j);
- j += rsa_e_len; i += 4;
- if (len < (16 + j))
- return -1;
- rsa_n_len = get_int32(buf + i + j);
- j += rsa_n_len; i += 4;
- if (len < (16 + j))
- return -1;
- rsa_d_len = get_int32(buf + i + j);
- j += rsa_d_len; i += 4;
- if (len != (16 + j))
- return -1;
-
- i = 4;
- i += (data_len + 4);
- rsa_e = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), rsa_e_len, rsa_e);
- i += (rsa_e_len + 4);
- rsa_n = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), rsa_n_len, rsa_n);
- i += (rsa_n_len + 4);
- rsa_d = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), rsa_d_len, rsa_d);
- i += (rsa_d_len + 4);
-
- rsa = RSA_new();
- rsa->e = rsa_e;
- rsa->n = rsa_n;
- rsa->d = rsa_d;
-
- dlen = RSA_size(rsa);
- bin = return_binary(rbuf,rlen,dlen+1);
- if (bin==NULL) return -1;
- i = 4;
- if (command == DRV_RSA_SIGN_MD5) {
- MD5((unsigned char *) (buf + i), data_len, (unsigned char *) hmacbuf);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH);
- i = RSA_sign(NID_md5,
- (unsigned char *) hmacbuf,MD5_DIGEST_LENGTH,
- (unsigned char *) &bin[1],
- &rsa_s_len, rsa);
- } else {
- SHA1((unsigned char *) (buf + i), data_len,
- (unsigned char *) hmacbuf);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH);
- i = RSA_sign(NID_sha1,
- (unsigned char *) hmacbuf,SHA_DIGEST_LENGTH,
- (unsigned char *) &bin[1],
- &rsa_s_len, rsa);
- }
- RSA_free(rsa);
- if (i) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+1, rsa_s_len);
- if (rsa_s_len != dlen) {
- bin = return_binary_shrink(rbuf,rlen,bin,rsa_s_len+1);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(bin+1, rsa_s_len);
- }
- bin[0] = 1;
- return rsa_s_len + 1;
- }
- else {
- bin[0] = 0;
- return 1;
- }
-
- case DRV_RSA_PRIVATE_DECRYPT:
- case DRV_RSA_PRIVATE_ENCRYPT:
- /* buf = <<data_len:32/integer, data:data_len/binary,
- * rsa_e_len:32/integer, rsa_e:rsa_e_len/binary,
- * rsa_n_len:32/integer, rsa_n:rsa_n_len/binary,
- * rsa_d_len:32/integer, rsa_d:rsa_d_len/binary,
- * pad:8/integer >> */
-
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf,len);
- i = 0;
- j = 0;
-
- if (len < 17)
- return -1;
- data_len = get_int32(buf + i + j);
- j += data_len; i += 4;
- if (len < (17 + j))
- return -1;
- rsa_e_len = get_int32(buf + i + j);
- j += rsa_e_len; i += 4;
- if (len < (17 + j))
- return -1;
- rsa_n_len = get_int32(buf + i + j);
- j += rsa_n_len; i += 4;
- if (len < (17 + j))
- return -1;
- rsa_d_len = get_int32(buf + i + j);
- j += rsa_d_len; i += 4;
- padding = *(unsigned char *) (buf+i+j);
- if (len != (17 + j))
- return -1;
-
- i = 4;
- i += (data_len + 4);
- rsa_e = BN_new();
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,rsa_e_len);
- BN_bin2bn((unsigned char *)(buf + i), rsa_e_len, rsa_e);
- i += (rsa_e_len + 4);
- rsa_n = BN_new();
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,rsa_n_len);
- BN_bin2bn((unsigned char *)(buf + i), rsa_n_len, rsa_n);
- i += (rsa_n_len + 4);
- rsa_d = BN_new();
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,rsa_d_len);
- BN_bin2bn((unsigned char *)(buf + i), rsa_d_len, rsa_d);
- i += (rsa_d_len + 4);
-
- switch(padding) {
- case 0:
- padding = RSA_NO_PADDING;
- break;
- case 1:
- padding = RSA_PKCS1_PADDING;
- break;
- case 2:
- padding = RSA_PKCS1_OAEP_PADDING;
- break;
- case 3:
- padding = RSA_SSLV23_PADDING;
- break;
- default:
- return -1;
- }
-
- rsa = RSA_new();
- rsa->e = rsa_e;
- rsa->n = rsa_n;
- rsa->d = rsa_d;
-
- dlen = RSA_size(rsa) + 1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- i = 4;
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,data_len);
- if(command == DRV_RSA_PRIVATE_DECRYPT) {
- i = RSA_private_decrypt(data_len, (unsigned char *) (buf+i),
- (unsigned char *) &bin[1],
- rsa, padding);
- if(i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(&bin[1],i);
- bin = return_binary_shrink(rbuf,rlen, bin, i+1);
- if (bin==NULL) return -1;
- }
- } else {
- i = RSA_private_encrypt(data_len, (unsigned char *) (buf+i),
- (unsigned char *) &bin[1],
- rsa, padding);
- if(i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(&bin[1],i);
- }
- }
- RSA_free(rsa);
- if(i > 0) {
- bin[0] = 1;
- return i + 1;
- } else {
- bin[0] = 0;
- return 1;
- }
- break;
-
- case DRV_RSA_PUBLIC_ENCRYPT:
- case DRV_RSA_PUBLIC_DECRYPT:
- /* buf = <<data_len:32/integer, data:data_len/binary,
- * rsa_e_len:32/integer, rsa_e:rsa_e_len/binary,
- * rsa_n_len:32/integer, rsa_n:rsa_n_len/binary,
- * pad:8/integer >> */
-
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf,len);
- i = 0;
- j = 0;
-
- if (len < 13)
- return -1;
- data_len = get_int32(buf + i + j);
- j += data_len; i += 4;
- if (len < (13 + j))
- return -1;
- rsa_e_len = get_int32(buf + i + j);
- j += rsa_e_len; i += 4;
- if (len < (13 + j))
- return -1;
- rsa_n_len = get_int32(buf + i + j);
- j += rsa_n_len; i += 4;
- if (len < (13 + j))
- return -1;
- padding = *(unsigned char *) (buf + i + j);
- if (len != (13 + j))
- return -1;
-
- i = 4;
- i += (data_len + 4);
- rsa_e = BN_new();
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,rsa_e_len);
- BN_bin2bn((unsigned char *)(buf + i), rsa_e_len, rsa_e);
- i += (rsa_e_len + 4);
- rsa_n = BN_new();
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,rsa_n_len);
- BN_bin2bn((unsigned char *)(buf + i), rsa_n_len, rsa_n);
- i += (rsa_n_len + 4);
-
- switch(padding) {
- case 0:
- padding = RSA_NO_PADDING;
- break;
- case 1:
- padding = RSA_PKCS1_PADDING;
- break;
- case 2:
- padding = RSA_PKCS1_OAEP_PADDING;
- break;
- case 3:
- padding = RSA_SSLV23_PADDING;
- break;
- default:
- return -1;
- }
-
- rsa = RSA_new();
- rsa->e = rsa_e;
- rsa->n = rsa_n;
-
- dlen = RSA_size(rsa) + 1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- i = 4;
- if(command == DRV_RSA_PUBLIC_ENCRYPT) {
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,data_len);
- i = RSA_public_encrypt(data_len, (unsigned char *) (buf+i),
- (unsigned char *) &bin[1],
- rsa, padding);
- if (i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+1, i);
- }
- } else {
- i = RSA_public_decrypt(data_len, (unsigned char *) (buf+i),
- (unsigned char *) &bin[1],
- rsa, padding);
- if(i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+1, i);
- bin = return_binary_shrink(rbuf,rlen,bin, i+1);
- if (bin==NULL) return -1;
- }
- }
-
- RSA_free(rsa);
- if(i > 0) {
- bin[0] = 1;
- return i + 1;
- } else {
-/* ERR_load_crypto_strings(); */
-/* fprintf(stderr, "%d: %s \r\n", __LINE__, ERR_reason_error_string(ERR_get_error())); */
- bin[0] = 0;
- return 1;
- }
- break;
-
- case DRV_CBC_AES128_ENCRYPT:
- case DRV_CBC_AES256_ENCRYPT:
- case DRV_CBC_AES128_DECRYPT:
- case DRV_CBC_AES256_DECRYPT:
- /* buf = key[klen] ivec[klen] data */
- if (command == DRV_CBC_AES256_ENCRYPT || command == DRV_CBC_AES256_DECRYPT)
- klen = 32;
- else
- klen = 16;
- dlen = len - klen - 16;
- if (dlen < 0)
- return -1;
- if (dlen % 16 != 0)
- return -1;
- if (command == DRV_CBC_AES128_ENCRYPT || command == DRV_CBC_AES256_ENCRYPT) {
- i = AES_ENCRYPT;
- AES_set_encrypt_key((unsigned char *) buf, klen*8, &aes_key);
- } else {
- i = AES_DECRYPT;
- AES_set_decrypt_key((unsigned char *) buf, klen*8, &aes_key);
- }
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- AES_cbc_encrypt((unsigned char *) (buf + klen+16),
- (unsigned char *) bin,
- dlen,
- &aes_key,
- (unsigned char *) (buf + klen),
- i);
- return dlen;
-
-/* case DRV_CBC_AES128_DECRYPT: */
-/* case DRV_CBC_AES256_DECRYPT: */
-/* /\* buf = key[klen] ivec[16] data *\/ */
-/* if (command == DRV_CBC_AES256_DECRYPT) */
-/* klen = 32; */
-/* else */
-/* klen = 16; */
-/* dlen = len - klen - 16; */
-/* if (dlen < 0) */
-/* return -1; */
-/* *rbuf = (char *)(bin = driver_alloc_binary(dlen)); */
-/* AES_set_decrypt_key((unsigned char *) buf, klen*8, &aes_key); */
-/* AES_cbc_encrypt((unsigned char *) (buf + klen+16), */
-/* (unsigned char *) bin->orig_bytes, */
-/* dlen, */
-/* &aes_key, */
-/* (unsigned char *) (buf + klen), */
-/* AES_DECRYPT); */
-/* return dlen; */
-/* break; */
-
- case DRV_XOR:
- /* buf = data1, data2 with same size */
- dlen = len / 2;
- if (len != dlen * 2)
- return -1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- p = bin,
- dbuf = buf + dlen;
- for (key = buf, key2 = dbuf; key != dbuf; ++key, ++key2, ++p)
- *p = *key ^ *key2;
- return dlen;
-
- case DRV_DH_GENERATE_PARAMS:
- /* buf = <<PrimeLen:32 Generator:32>> */
- if (len != 8)
- return -1;
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf,len);
- prime_len = get_int32(buf);
- generator = get_int32(buf+4);
- dh_params = DH_generate_parameters(prime_len, generator, NULL, NULL);
-
- if(dh_params) {
- dh_p_len = BN_num_bytes(dh_params->p);
- dh_g_len = BN_num_bytes(dh_params->g);
- dlen = 1 + 4 + 4 + dh_g_len + dh_p_len;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bin[0] = 1;
- put_int32(bin+1, dh_p_len);
- BN_bn2bin(dh_params->p, bin+5);
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+5,dh_p_len);
- put_int32(bin+5+dh_p_len, dh_g_len);
- BN_bn2bin(dh_params->g, bin+5+dh_p_len+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+5+dh_p_len+4,dh_g_len);
- } else {
- dlen = 1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bin[0] = 0;
- }
- DH_free(dh_params);
- return dlen;
-
- case DRV_DH_CHECK:
- /* buf = <<dh_p_len:32/integer, dh_p:dh_p_len/binary,
- * dh_g_len:32/integer, dh_g:dh_g_len/binary>> */
- i = 0;
- j = 0;
- if(len < 8) return -1;
- dh_p_len = get_int32(buf + i + j);
- j += dh_p_len; i += 4;
- if (len < (8 + j)) return -1;
- dh_g_len = get_int32(buf + i + j);
- j += dh_g_len; i += 4;
- if(len != (8+j)) return -1;
- i=4;
- dh_p = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dh_p_len, dh_p);
- i += (dh_p_len + 4);
- dh_g = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dh_g_len, dh_g);
- /* i += (dsa_g_len + 4); */
-
- dh_params = DH_new();
- dh_params->p = dh_p;
- dh_params->g = dh_g;
-
- i=0;
- bin = return_binary(rbuf,rlen,4);
- if (bin==NULL) return -1;
- if(DH_check(dh_params, &i)) {
- put_int32(bin, i);
- } else {
- /* Check Failed */
- put_int32(bin, -1);
- }
- DH_free(dh_params);
- return 4;
-
- case DRV_DH_GENERATE_KEY:
- /* buf = <<key_len:32, key:key_len/binary, *
- * dh_p_len:32/integer, dh_p:dh_p_len/binary, *
- * dh_g_len:32/integer, dh_g:dh_g_len/binary>> */
- ERL_VALGRIND_ASSERT_MEM_DEFINED(buf,len);
- i = 0;
- j = 0;
- if(len < 12) return -1;
- base_len = get_int32(buf + i + j);
- j += base_len; i += 4;
- if (len < (12 + j)) return -1;
- dh_p_len = get_int32(buf + i + j);
- j += dh_p_len; i += 4;
- if (len < (12 + j)) return -1;
- dh_g_len = get_int32(buf + i + j);
- j += dh_g_len; i += 4;
- if(len != (12 + j)) return -1;
- i=4;
- i += (base_len + 4);
- dh_p = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dh_p_len, dh_p);
- i += (dh_p_len + 4);
- dh_g = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dh_g_len, dh_g);
- /* i += (dsa_g_len + 4); */
-
- dh_params = DH_new();
- dh_params->p = dh_p;
- dh_params->g = dh_g;
- if(base_len > 0) {
- dh_params->priv_key = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), base_len,
- dh_params->priv_key);
- }
- i=0;
- if(DH_generate_key(dh_params)) {
- privkey_len = BN_num_bytes(dh_params->priv_key);
- pubkey_len = BN_num_bytes(dh_params->pub_key);
- dlen = 1 + 4 + 4 + pubkey_len + privkey_len;
- bin = return_binary(rbuf,rlen, dlen);
- if (bin==NULL) return -1;
- bin[0] = 1;
- put_int32(bin+1, pubkey_len);
- BN_bn2bin(dh_params->pub_key, bin+5);
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+5, pubkey_len);
- put_int32(bin+5+pubkey_len, privkey_len);
- BN_bn2bin(dh_params->priv_key, bin+5+pubkey_len+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin+5+pubkey_len+4, privkey_len);
- } else {
- dlen = 1;
- bin = return_binary(rbuf,rlen,dlen);
- if (bin==NULL) return -1;
- bin[0] = 0;
- }
- DH_free(dh_params);
- return dlen;
-
- case DRV_DH_COMPUTE_KEY:
- /* buf = <<pubkey_len:32, pubkey:pubkey_len/binary, *
- * privkey_len:32, privkey:privkey_len/binary, *
- * dh_p_len:32/integer, dh_p:dh_p_len/binary, *
- * dh_g_len:32/integer, dh_g:dh_g_len/binary>> */
- i = 0;
- j = 0;
- if(len < 16) return -1;
- pubkey_len = get_int32(buf + i + j);
- j += pubkey_len; i += 4;
- if (len < (16 + j)) return -1;
- privkey_len = get_int32(buf + i + j);
- j += privkey_len; i += 4;
- if (len < (16 + j)) return -1;
- dh_p_len = get_int32(buf + i + j);
- j += dh_p_len; i += 4;
- if (len < (16 + j)) return -1;
- dh_g_len = get_int32(buf + i + j);
- j += dh_g_len; i += 4;
- if(len != (16 + j)) return -1;
- i=4;
- pubkey = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), pubkey_len, pubkey);
- i += (pubkey_len + 4);
- privkey = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), privkey_len, privkey);
- i += (privkey_len + 4);
- dh_p = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dh_p_len, dh_p);
- i += (dh_p_len + 4);
- dh_g = BN_new();
- BN_bin2bn((unsigned char *)(buf + i), dh_g_len, dh_g);
- /* i += (dsa_g_len + 4); */
-
- dh_params = DH_new();
- dh_params->p = dh_p;
- dh_params->g = dh_g;
- dh_params->priv_key = privkey;
-
- klen = DH_size(dh_params);
- bin = return_binary(rbuf,rlen,1+klen);
- if (bin==NULL) return -1;
- i = DH_compute_key(&bin[1], pubkey, dh_params);
- DH_free(dh_params);
- if (i > 0) {
- if (i != klen) {
- bin = return_binary_shrink(rbuf,rlen,bin,1+i);
- }
- bin[0] = 1;
- return i + 1;
- }
- else {
- bin[0] = 0;
- return 1;
- }
-
- case DRV_MD4:
- bin = return_binary(rbuf,rlen,MD4_LEN);
- MD4((unsigned char *)buf, len, (unsigned char *)bin);
- return MD4_LEN;
-
- case DRV_MD4_INIT:
- bin = return_binary(rbuf,rlen,MD4_CTX_LEN);
- MD4_Init((MD4_CTX *) bin);
- return MD4_CTX_LEN;
-
- case DRV_MD4_UPDATE:
- if (len < MD4_CTX_LEN)
- return -1;
- bin = return_binary(rbuf,rlen,MD4_CTX_LEN);
- memcpy(bin, buf, MD4_CTX_LEN);
- MD4_Update((MD4_CTX *) bin, buf + MD4_CTX_LEN, len - MD4_CTX_LEN);
- return MD4_CTX_LEN;
-
- case DRV_MD4_FINAL:
- if (len != MD4_CTX_LEN)
- return -1;
- memcpy(&md4_ctx, buf, MD4_CTX_LEN); /* XXX Use buf only? */
- bin = return_binary(rbuf,rlen,MD4_LEN);
- MD4_Final((unsigned char *)bin, &md4_ctx);
- return MD4_LEN;
-
-#if SSL_VERSION_0_9_8
- case DRV_SHA256:
- bin = return_binary(rbuf,rlen,SHA256_LEN);
- SHA256(buf, len, bin);
- return SHA256_LEN;
-
- case DRV_SHA256_INIT:
- bin = return_binary(rbuf,rlen,SHA256_CTX_LEN);
- SHA256_Init((SHA256_CTX *)bin);
- return SHA256_CTX_LEN;
-
- case DRV_SHA256_UPDATE:
- if (len < SHA256_CTX_LEN)
- return -1;
- bin = return_binary(rbuf,rlen,SHA256_CTX_LEN);
- memcpy(bin, buf, SHA256_CTX_LEN);
- SHA256_Update((SHA256_CTX *)bin, buf + SHA256_CTX_LEN,
- len - SHA256_CTX_LEN);
- return SHA256_CTX_LEN;
-
- case DRV_SHA256_FINAL:
- if (len != SHA256_CTX_LEN)
- return -1;
- memcpy(&sha256_ctx, buf, SHA256_CTX_LEN); /* XXX Use buf only? */
- bin = return_binary(rbuf,rlen,SHA256_LEN);
- SHA256_Final(bin, &sha256_ctx);
- return SHA256_LEN;
-
- case DRV_SHA512:
- bin = return_binary(rbuf,rlen,SHA512_LEN);
- SHA512(buf, len, bin);
- return SHA512_LEN;
-
- case DRV_SHA512_INIT:
- bin = return_binary(rbuf,rlen,SHA512_CTX_LEN);
- SHA512_Init((SHA512_CTX *)bin);
- return SHA512_CTX_LEN;
-
- case DRV_SHA512_UPDATE:
- if (len < SHA512_CTX_LEN)
- return -1;
- bin = return_binary(rbuf,rlen,SHA512_CTX_LEN);
- memcpy(bin, buf, SHA512_CTX_LEN);
- SHA512_Update((SHA512_CTX *)bin, buf + SHA512_CTX_LEN,
- len - SHA512_CTX_LEN);
- return SHA512_CTX_LEN;
-
- case DRV_SHA512_FINAL:
- if (len != SHA512_CTX_LEN)
- return -1;
- memcpy(&sha512_ctx, buf, SHA512_CTX_LEN); /* XXX Use buf only? */
- bin = return_binary(rbuf,rlen,SHA512_LEN));
- SHA512_Final(bin, &sha512_ctx);
- return SHA512_LEN;
-#endif
-
- case DRV_INFO_LIB:
- {/* <<DrvVer:8, NameSize:8, Name:NameSize/binary, VerNum:32, VerStr/binary>> */
- static const char libname[] = "OpenSSL";
- unsigned name_sz = strlen(libname);
- const char* ver = SSLeay_version(SSLEAY_VERSION);
- unsigned ver_sz = strlen(ver);
- dlen = 1+1+name_sz+4+ver_sz;
- bin = return_binary(rbuf, rlen, dlen);
- if (bin==NULL) return -1;
- p = bin;
- *p++ = 0; /* "driver version" for future use */
- *p++ = name_sz;
- memcpy(p, libname, name_sz);
- p += name_sz;
- put_int32(p,SSLeay()); /* OPENSSL_VERSION_NUMBER */
- p += 4;
- memcpy(p, ver, ver_sz);
- }
- return dlen;
-
- default:
- break;
- }
- return -1;
-}
-
-
-#ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */
-
-static INLINE void locking(int mode, ErlDrvRWLock* lock)
-{
- switch(mode) {
- case CRYPTO_LOCK|CRYPTO_READ:
- erl_drv_rwlock_rlock(lock);
- break;
- case CRYPTO_LOCK|CRYPTO_WRITE:
- erl_drv_rwlock_rwlock(lock);
- break;
- case CRYPTO_UNLOCK|CRYPTO_READ:
- erl_drv_rwlock_runlock(lock);
- break;
- case CRYPTO_UNLOCK|CRYPTO_WRITE:
- erl_drv_rwlock_rwunlock(lock);
- break;
- default:
- ASSERT(!"Invalid lock mode");
- }
-}
-
-/* Callback from openssl for static locking
- */
-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]);
-}
-
-/* Callback from openssl for thread id
- */
-static unsigned long id_function(void)
-{
- return (unsigned long) erl_drv_thread_self();
-}
-
-/* Callbacks for dynamic locking, not used by current openssl version (0.9.8)
- */
-static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, int line)
-{
- return (struct CRYPTO_dynlock_value*) erl_drv_rwlock_create("crypto_drv_dyn");
-}
-static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,const char *file, int line)
-{
- locking(mode, (ErlDrvRWLock*)ptr);
-}
-static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, const char *file, int line)
-{
- erl_drv_rwlock_destroy((ErlDrvRWLock*)ptr);
-}
-
-#endif /* ^^^^^^^^^^^^^^^^^^^^^^ OPENSSL_THREADS ^^^^^^^^^^^^^^^^^^^^^^ */
-
-/* HMAC */
-
-static void hmac_md5(char *key, int klen, char *dbuf, int dlen, char *hmacbuf)
-{
- MD5_CTX ctx;
- char ipad[HMAC_INT_LEN];
- char opad[HMAC_INT_LEN];
- unsigned char nkey[MD5_LEN];
- int i;
-
- /* Change key if longer than 64 bytes */
- if (klen > HMAC_INT_LEN) {
- MD5_CTX kctx;
-
- MD5_Init(&kctx);
- MD5_Update(&kctx, key, klen);
- MD5_Final(nkey, &kctx);
- key = (char *) nkey;
- klen = MD5_LEN;
- }
-
- memset(ipad, '\0', sizeof(ipad));
- memset(opad, '\0', sizeof(opad));
- memcpy(ipad, key, klen);
- memcpy(opad, key, klen);
-
- for (i = 0; i < HMAC_INT_LEN; i++) {
- ipad[i] ^= HMAC_IPAD;
- opad[i] ^= HMAC_OPAD;
- }
-
- /* inner MD5 */
- MD5_Init(&ctx);
- MD5_Update(&ctx, ipad, HMAC_INT_LEN);
- MD5_Update(&ctx, dbuf, dlen);
- MD5_Final((unsigned char *) hmacbuf, &ctx);
- /* outer MD5 */
- MD5_Init(&ctx);
- MD5_Update(&ctx, opad, HMAC_INT_LEN);
- MD5_Update(&ctx, hmacbuf, MD5_LEN);
- MD5_Final((unsigned char *) hmacbuf, &ctx);
-}
-
-static void hmac_sha1(char *key, int klen, char *dbuf, int dlen,
- char *hmacbuf)
-{
- SHA_CTX ctx;
- char ipad[HMAC_INT_LEN];
- char opad[HMAC_INT_LEN];
- unsigned char nkey[SHA_LEN];
- int i;
-
- /* Change key if longer than 64 bytes */
- if (klen > HMAC_INT_LEN) {
- SHA_CTX kctx;
-
- SHA1_Init(&kctx);
- SHA1_Update(&kctx, key, klen);
- SHA1_Final(nkey, &kctx);
- key = (char *) nkey;
- klen = SHA_LEN;
- }
-
- memset(ipad, '\0', sizeof(ipad));
- memset(opad, '\0', sizeof(opad));
- memcpy(ipad, key, klen);
- memcpy(opad, key, klen);
-
- for (i = 0; i < HMAC_INT_LEN; i++) {
- ipad[i] ^= HMAC_IPAD;
- opad[i] ^= HMAC_OPAD;
- }
-
- /* inner SHA */
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, ipad, HMAC_INT_LEN);
- SHA1_Update(&ctx, dbuf, dlen);
- SHA1_Final((unsigned char *) hmacbuf, &ctx);
- /* outer SHA */
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, opad, HMAC_INT_LEN);
- SHA1_Update(&ctx, hmacbuf, SHA_LEN);
- SHA1_Final((unsigned char *) hmacbuf, &ctx);
-}
diff --git a/lib/crypto/priv/Makefile b/lib/crypto/priv/Makefile
index b8acdacc00..0989f14c94 100644
--- a/lib/crypto/priv/Makefile
+++ b/lib/crypto/priv/Makefile
@@ -18,21 +18,21 @@
# ----------------------------------------------------
# THIS MAKEFILE SERVES AS AN EXAMPLE OF
-# HOW TO RELINK THE CRYPTO DRIVER
+# HOW TO RELINK THE CRYPTO NIF LIBRARY
# ----------------------------------------------------
# ----------------------------------------------------
-# Variables for linking a .so driver on unix.
+# Variables for linking a .so library on unix.
# Note: These may differ between systems.
# ----------------------------------------------------
SO_LD = gcc
SO_LDFLAGS = -G
SO_SSL_LIBDIR = /usr/local/lib
-SO_DRIVER = $(LIBDIR)/$(DRIVER_NAME).so
+SO_NIFLIB = $(LIBDIR)/$(LIB_NAME).so
# ----------------------------------------------------
-# Variables for linking a win32 .dll driver.
+# Variables for linking a win32 .dll library.
# Note: These may differ between systems.
# ----------------------------------------------------
@@ -42,9 +42,9 @@ DLL_LIBDIR = "c:\\OpenSSL\\lib\\VC"
DLL_LIBS = libeay32.lib MSVCRT.LIB kernel32.lib \
advapi32.lib gdi32.lib user32.lib \
comctl32.lib comdlg32.lib shell32.lib
-DLL_DRIVER = $(LIBDIR)/$(DRIVER_NAME).dll
-DLL_EXP = $(LIBDIR)/$(DRIVER_NAME).exp
-DLL_LIB = $(LIBDIR)/$(DRIVER_NAME).lib
+DLL_NIFLIB = $(LIBDIR)/$(LIB_NAME).dll
+DLL_EXP = $(LIBDIR)/$(LIB_NAME).exp
+DLL_LIB = $(LIBDIR)/$(LIB_NAME).lib
# ----------------------------------------------------
# Common variables
@@ -52,27 +52,27 @@ DLL_LIB = $(LIBDIR)/$(DRIVER_NAME).lib
OBJDIR = ./
LIBDIR = ../lib
-DRIVER_NAME = crypto_drv
-OBJS = $(OBJDIR)/crypto_drv.o
+LIB_NAME = crypto
+OBJS = $(OBJDIR)/crypto.o
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-$(SO_DRIVER): $(OBJS)
+$(SO_NIFLIB): $(OBJS)
$(SO_LD) $(SO_LDFLAGS) -L$(SO_SSL_LIBDIR) -Wl,-R$(SO_SSL_LIBDIR) \
-o $@ $^ -lcrypto
-$(DLL_DRIVER): $(OBJS)
+$(DLL_NIFLIB): $(OBJS)
$(DLL_LD) $(DLL_LDFLAGS) -out:$@ -libpath:$(DLL_LIBDIR) $(OBJS) \
$(DLL_LIBS)
-so: $(SO_DRIVER)
+so: $(SO_NIFLIB)
-dll: $(DLL_DRIVER)
+dll: $(DLL_NIFLIB)
clean:
- rm -f $(SO_DRIVER) $(DLL_DRIVER)
+ rm -f $(SO_NIFLIB) $(DLL_NIFLIB)
rm -f $(DLL_EXP) $(DLL_LIB)
rm -f core *~
diff --git a/lib/crypto/src/Makefile b/lib/crypto/src/Makefile
index 51092d16a5..0e886ce8bf 100644
--- a/lib/crypto/src/Makefile
+++ b/lib/crypto/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 1999-2010. 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
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
@@ -57,7 +57,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-ERL_COMPILE_FLAGS += +warn_obsolete_guard
+ERL_COMPILE_FLAGS += +warn_obsolete_guard -DCRYPTO_VSN=\"$(VSN)\"
# ----------------------------------------------------
# Targets
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 8cb750759f..5b1ce96caf 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,7 +21,7 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0]).
+-export([start/0, stop/0, info/0, info_lib/0, version/0]).
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
-export([sha/1, sha_init/0, sha_update/2, sha_final/1]).
@@ -54,82 +54,6 @@
-export([dh_generate_parameters/2, dh_check/1]). %% Testing see below
--define(INFO, 0).
--define(MD5, 1).
--define(MD5_INIT, 2).
--define(MD5_UPDATE, 3).
--define(MD5_FINAL, 4).
--define(SHA, 5).
--define(SHA_INIT, 6).
--define(SHA_UPDATE, 7).
--define(SHA_FINAL, 8).
--define(MD5_MAC, 9).
--define(MD5_MAC_96, 10).
--define(SHA_MAC, 11).
--define(SHA_MAC_96, 12).
--define(DES_CBC_ENCRYPT, 13).
--define(DES_CBC_DECRYPT, 14).
--define(DES_EDE3_CBC_ENCRYPT, 15).
--define(DES_EDE3_CBC_DECRYPT, 16).
--define(AES_CFB_128_ENCRYPT, 17).
--define(AES_CFB_128_DECRYPT, 18).
--define(RAND_BYTES, 19).
--define(RAND_UNIFORM, 20).
--define(MOD_EXP, 21).
--define(DSS_VERIFY, 22).
--define(RSA_VERIFY_SHA, 23).
-%-define(RSA_VERIFY_MD5, 35).
--define(AES_CBC_128_ENCRYPT, 24).
--define(AES_CBC_128_DECRYPT, 25).
--define(XOR, 26).
--define(RC4_ENCRYPT, 27).
--define(RC4_SET_KEY, 28).
--define(RC4_ENCRYPT_WITH_STATE, 29).
--define(RC2_40_CBC_ENCRYPT, 30).
--define(RC2_40_CBC_DECRYPT, 31).
--define(AES_CBC_256_ENCRYPT, 32).
--define(AES_CBC_256_DECRYPT, 33).
--define(INFO_LIB,34).
-%-define(RSA_VERIFY_SHA, 23).
--define(RSA_VERIFY_MD5, 35).
--define(RSA_SIGN_SHA, 36).
--define(RSA_SIGN_MD5, 37).
--define(DSS_SIGN, 38).
--define(RSA_PUBLIC_ENCRYPT, 39).
--define(RSA_PRIVATE_DECRYPT, 40).
--define(RSA_PRIVATE_ENCRYPT, 41).
--define(RSA_PUBLIC_DECRYPT, 42).
--define(DH_GENERATE_PARAMS, 43).
--define(DH_CHECK, 44).
--define(DH_GENERATE_KEY, 45).
--define(DH_COMPUTE_KEY, 46).
--define(MD4, 47).
--define(MD4_INIT, 48).
--define(MD4_UPDATE, 49).
--define(MD4_FINAL, 50).
-
-%% -define(SHA256, 51).
-%% -define(SHA256_INIT, 52).
-%% -define(SHA256_UPDATE, 53).
-%% -define(SHA256_FINAL, 54).
-%% -define(SHA512, 55).
-%% -define(SHA512_INIT, 56).
-%% -define(SHA512_UPDATE, 57).
-%% -define(SHA512_FINAL, 58).
-
--define(BF_CFB64_ENCRYPT, 59).
--define(BF_CFB64_DECRYPT, 60).
--define(BF_ECB_ENCRYPT, 61).
--define(BF_ECB_DECRYPT, 62).
--define(BF_OFB64_ENCRYPT, 63).
--define(BF_CBC_ENCRYPT, 64).
--define(BF_CBC_DECRYPT, 65).
-
--define(DES_ECB_ENCRYPT, 66).
--define(DES_ECB_DECRYPT, 67).
-
-%% -define(IDEA_CBC_ENCRYPT, 34).
-%% -define(IDEA_CBC_DECRYPT, 35).
-define(FUNC_LIST, [md4, md4_init, md4_update, md4_final,
md5, md5_init, md5_update, md5_final,
@@ -158,6 +82,44 @@
aes_cbc_256_encrypt, aes_cbc_256_decrypt,
info_lib]).
+-define(nif_stub,nif_stub_error(?LINE)).
+
+-on_load(on_load/0).
+
+-define(CRYPTO_NIF_VSN,101).
+
+on_load() ->
+ LibName = "crypto",
+ PrivDir = code:priv_dir(crypto),
+ Lib1 = filename:join([PrivDir, "lib", LibName]),
+ Status = case erlang:load_nif(Lib1, ?CRYPTO_NIF_VSN) of
+ ok -> ok;
+ {error, {load_failed, _}}=Error1 ->
+ LibDir2 =
+ filename:join([PrivDir, "lib",
+ erlang:system_info(system_architecture)]),
+ Candidate =
+ filelib:wildcard(filename:join([LibDir2,LibName ++ "*" ])),
+ case Candidate of
+ [] -> Error1;
+ _ ->
+ Lib2 = filename:join([LibDir2, LibName]),
+ erlang:load_nif(Lib2, ?CRYPTO_NIF_VSN)
+ end;
+ Error1 -> Error1
+ end,
+ case Status of
+ ok -> ok;
+ {error, {E, Str}} ->
+ error_logger:error_msg("Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n"
+ "OpenSSL might not be installed on this system.~n",[E,Str]),
+ Status
+ end.
+
+
+nif_stub_error(Line) ->
+ erlang:error({nif_not_loaded,module,?MODULE,line,Line}).
+
start() ->
application:start(crypto).
@@ -165,15 +127,15 @@ stop() ->
application:stop(crypto).
info() ->
- lists:map(fun(I) ->
- lists:nth(I, ?FUNC_LIST)
- end, binary_to_list(control(?INFO, []))).
+ ?FUNC_LIST.
-info_lib() ->
- <<_DrvVer:8, NameSize:8, Name:NameSize/binary,
- VerNum:32, VerStr/binary>> = control(?INFO_LIB,[]),
- [{Name,VerNum,VerStr}].
+info_lib() -> ?nif_stub.
+%% Crypto app version history:
+%% (no version): Driver implementation
+%% 2.0 : NIF implementation, requires OTP R14
+version() -> ?CRYPTO_VSN.
+
%% Below Key and Data are binaries or IO-lists. IVec is a binary.
%% Output is always a binary. Context is a binary.
@@ -184,73 +146,27 @@ info_lib() ->
%%
%% MD5
%%
-md5(Data) ->
- control(?MD5, Data).
-
-md5_init() ->
- control(?MD5_INIT, []).
-
-md5_update(Context, Data) ->
- control(?MD5_UPDATE, [Context, Data]).
-
-md5_final(Context) ->
- control(?MD5_FINAL, Context).
+md5(_Data) -> ?nif_stub.
+md5_init() -> ?nif_stub.
+md5_update(_Context, _Data) -> ?nif_stub.
+md5_final(_Context) -> ?nif_stub.
%%
%% MD4
%%
-md4(Data) ->
- control(?MD4, Data).
-
-md4_init() ->
- control(?MD4_INIT, []).
-
-md4_update(Context, Data) ->
- control(?MD4_UPDATE, [Context, Data]).
-
-md4_final(Context) ->
- control(?MD4_FINAL, Context).
+md4(_Data) -> ?nif_stub.
+md4_init() -> ?nif_stub.
+md4_update(_Context, _Data) -> ?nif_stub.
+md4_final(_Context) -> ?nif_stub.
%%
%% SHA
%%
-sha(Data) ->
- control(?SHA, Data).
-
-sha_init() ->
- control(?SHA_INIT, []).
-
-sha_update(Context, Data) ->
- control(?SHA_UPDATE, [Context, Data]).
-
-sha_final(Context) ->
- control(?SHA_FINAL, Context).
+sha(_Data) -> ?nif_stub.
+sha_init() -> ?nif_stub.
+sha_update(_Context, _Data) -> ?nif_stub.
+sha_final(_Context) -> ?nif_stub.
-%% sha256 and sha512 requires openssl-0.9.8 removed for now
-
-%% sha256(Data) ->
-%% control(?SHA256, Data).
-
-%% sha256_init() ->
-%% control(?SHA256_INIT, []).
-
-%% sha256_update(Context, Data) ->
-%% control(?SHA256_UPDATE, [Context, Data]).
-
-%% sha256_final(Context) ->
-%% control(?SHA256_FINAL, Context).
-
-%% sha512(Data) ->
-%% control(?SHA512, Data).
-
-%% sha512_init() ->
-%% control(?SHA512_INIT, []).
-
-%% sha512_update(Context, Data) ->
-%% control(?SHA512_UPDATE, [Context, Data]).
-
-%% sha512_final(Context) ->
-%% control(?SHA512_FINAL, Context).
%%
%% MESSAGE AUTHENTICATION CODES
@@ -260,20 +176,24 @@ sha_final(Context) ->
%% MD5_MAC
%%
md5_mac(Key, Data) ->
- control_bin(?MD5_MAC, Key, Data).
+ md5_mac_n(Key,Data,16).
md5_mac_96(Key, Data) ->
- control_bin(?MD5_MAC_96, Key, Data).
+ md5_mac_n(Key,Data,12).
+md5_mac_n(_Key,_Data,_MacSz) -> ?nif_stub.
+
%%
%% SHA_MAC
%%
sha_mac(Key, Data) ->
- control_bin(?SHA_MAC, Key, Data).
+ sha_mac_n(Key,Data,20).
sha_mac_96(Key, Data) ->
- control_bin(?SHA_MAC_96, Key, Data).
+ sha_mac_n(Key,Data,12).
+sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub.
+
%%
%% CRYPTO FUNCTIONS
%%
@@ -282,10 +202,12 @@ sha_mac_96(Key, Data) ->
%% DES - in cipher block chaining mode (CBC)
%%
des_cbc_encrypt(Key, IVec, Data) ->
- control(?DES_CBC_ENCRYPT, [Key, IVec, Data]).
+ des_cbc_crypt(Key, IVec, Data, true).
des_cbc_decrypt(Key, IVec, Data) ->
- control(?DES_CBC_DECRYPT, [Key, IVec, Data]).
+ des_cbc_crypt(Key, IVec, Data, false).
+
+des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% dec_cbc_ivec(Data) -> binary()
@@ -303,10 +225,10 @@ des_cbc_ivec(Data) when is_list(Data) ->
%% DES - in electronic codebook mode (ECB)
%%
des_ecb_encrypt(Key, Data) ->
- control(?DES_ECB_ENCRYPT, [Key, Data]).
-
+ des_ecb_crypt(Key, Data, true).
des_ecb_decrypt(Key, Data) ->
- control(?DES_ECB_DECRYPT, [Key, Data]).
+ des_ecb_crypt(Key, Data, false).
+des_ecb_crypt(_Key, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% DES3 - in cipher block chaining mode (CBC)
@@ -314,71 +236,64 @@ des_ecb_decrypt(Key, Data) ->
des3_cbc_encrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cbc_encrypt(Key1, Key2, Key3, IVec, Data).
des_ede3_cbc_encrypt(Key1, Key2, Key3, IVec, Data) ->
- %%io:format("des_ede3_cbc_encrypt: size(Data)=~p\n", [size(list_to_binary([Data]))]),
- control(?DES_EDE3_CBC_ENCRYPT, [Key1, Key2, Key3, IVec, Data]).
+ des_ede3_cbc_crypt(Key1, Key2, Key3, IVec, Data, true).
des3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data).
des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
- control(?DES_EDE3_CBC_DECRYPT, [Key1, Key2, Key3, IVec, Data]).
+ des_ede3_cbc_crypt(Key1, Key2, Key3, IVec, Data, false).
+
+des_ede3_cbc_crypt(_Key1, _Key2, _Key3, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% Blowfish
%%
-blowfish_ecb_encrypt(Key, Data) when byte_size(Data) >= 8 ->
- control_bin(?BF_ECB_ENCRYPT, Key, list_to_binary([Data])).
+blowfish_ecb_encrypt(Key, Data) ->
+ bf_ecb_crypt(Key,Data, true).
-blowfish_ecb_decrypt(Key, Data) when byte_size(Data) >= 8 ->
- control_bin(?BF_ECB_DECRYPT, Key, list_to_binary([Data])).
+blowfish_ecb_decrypt(Key, Data) ->
+ bf_ecb_crypt(Key,Data, false).
-blowfish_cbc_encrypt(Key, IVec, Data) when byte_size(Data) rem 8 =:= 0 ->
- control_bin(?BF_CBC_ENCRYPT, Key, list_to_binary([IVec, Data])).
+bf_ecb_crypt(_Key,_Data,_IsEncrypt) -> ?nif_stub.
-blowfish_cbc_decrypt(Key, IVec, Data) when byte_size(Data) rem 8 =:= 0 ->
- control_bin(?BF_CBC_DECRYPT, Key, list_to_binary([IVec, Data])).
+blowfish_cbc_encrypt(Key, IVec, Data) ->
+ bf_cbc_crypt(Key,IVec,Data,true).
-blowfish_cfb64_encrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 ->
- control_bin(?BF_CFB64_ENCRYPT, Key, list_to_binary([IVec, Data])).
+blowfish_cbc_decrypt(Key, IVec, Data) ->
+ bf_cbc_crypt(Key,IVec,Data,false).
-blowfish_cfb64_decrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 ->
- control_bin(?BF_CFB64_DECRYPT, Key, list_to_binary([IVec, Data])).
+bf_cbc_crypt(_Key,_IVec,_Data,_IsEncrypt) -> ?nif_stub.
-blowfish_ofb64_encrypt(Key, IVec, Data) when byte_size(IVec) =:= 8 ->
- control_bin(?BF_OFB64_ENCRYPT, Key, list_to_binary([IVec, Data])).
+blowfish_cfb64_encrypt(Key, IVec, Data) ->
+ bf_cfb64_crypt(Key, IVec, Data, true).
+
+blowfish_cfb64_decrypt(Key, IVec, Data) ->
+ bf_cfb64_crypt(Key, IVec, Data, false).
+
+bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+
+blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub.
%%
%% AES in cipher feedback mode (CFB)
%%
aes_cfb_128_encrypt(Key, IVec, Data) ->
- control(?AES_CFB_128_ENCRYPT, [Key, IVec, Data]).
+ aes_cfb_128_crypt(Key, IVec, Data, true).
aes_cfb_128_decrypt(Key, IVec, Data) ->
- control(?AES_CFB_128_DECRYPT, [Key, IVec, Data]).
-
+ aes_cfb_128_crypt(Key, IVec, Data, false).
-%% %%
-%% %% IDEA - in cipher block chaining mode (CBC)
-%% %%
-%% idea_cbc_encrypt(Key, IVec, Data) ->
-%% control(?IDEA_CBC_ENCRYPT, [Key, IVec, Data]).
-
-%% idea_cbc_decrypt(Key, IVec, Data) ->
-%% control(?IDEA_CBC_DECRYPT, [Key, IVec, Data]).
+aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% RAND - pseudo random numbers using RN_ functions in crypto lib
%%
-
-rand_bytes(Bytes) ->
- rand_bytes(Bytes, 0, 0).
-rand_bytes(Bytes, Topmask, Bottommask) ->
- control(?RAND_BYTES,[<<Bytes:32/integer,
- Topmask:8/integer,
- Bottommask:8/integer>>]).
+rand_bytes(_Bytes) -> ?nif_stub.
+rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub.
rand_uniform(From,To) when is_binary(From), is_binary(To) ->
- case control(?RAND_UNIFORM,[From,To]) of
+ case rand_uniform_nif(From,To) of
<<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
<<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
Whatever ->
@@ -394,6 +309,8 @@ rand_uniform(From,To) when is_integer(From),is_integer(To) ->
Other
end.
+rand_uniform_nif(_From,_To) -> ?nif_stub.
+
%%
%% mod_exp - utility for rsa generation
%%
@@ -402,55 +319,51 @@ mod_exp(Base, Exponent, Modulo)
erlint(mod_exp(mpint(Base), mpint(Exponent), mpint(Modulo)));
mod_exp(Base, Exponent, Modulo) ->
- case control(?MOD_EXP,[Base,Exponent,Modulo]) of
+ case mod_exp_nif(Base,Exponent,Modulo) of
<<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
<<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
Whatever ->
Whatever
end.
+mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub.
+
%%
%% DSS, RSA - verify
%%
%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
-dss_verify(Data,Signature,Key) ->
- control(?DSS_VERIFY, [Data,Signature,Key]) == <<1>>.
+dss_verify(_Data,_Signature,_Key) -> ?nif_stub.
% Key = [E,N] E=PublicExponent N=PublicModulus
rsa_verify(Data,Signature,Key) ->
rsa_verify(sha, Data,Signature,Key).
-rsa_verify(Type,Data,Signature,Key) ->
- control(rsa_verify_digest_type(Type), [Data,Signature,Key]) == <<1>>.
+rsa_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub.
-rsa_verify_digest_type(md5) -> ?RSA_VERIFY_MD5;
-rsa_verify_digest_type(sha) -> ?RSA_VERIFY_SHA;
-rsa_verify_digest_type(Bad) -> erlang:error(badarg, [Bad]).
%%
%% DSS, RSA - sign
%%
%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey
dss_sign(Data, Key) ->
- <<Ret:8, Signature/binary>> = control(?DSS_SIGN, [Data,Key]),
- case Ret of
- 1 -> Signature;
- 0 -> erlang:error(badkey, [Data, Key])
+ case dss_sign_nif(Data,Key) of
+ error -> erlang:error(badkey, [Data, Key]);
+ Sign -> Sign
end.
+dss_sign_nif(_Data,_Key) -> ?nif_stub.
+
%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
rsa_sign(Data,Key) ->
rsa_sign(sha, Data, Key).
rsa_sign(Type, Data, Key) ->
- <<Ret:8, Signature/binary>> = control(rsa_sign_digest_type(Type), [Data,Key]),
- case Ret of
- 1 -> Signature;
- 0 -> erlang:error(badkey, [Type,Data,Key])
+ case rsa_sign_nif(Type,Data,Key) of
+ error -> erlang:error(badkey, [Type,Data,Key]);
+ Sign -> Sign
end.
-rsa_sign_digest_type(md5) -> ?RSA_SIGN_MD5;
-rsa_sign_digest_type(sha) -> ?RSA_SIGN_SHA;
-rsa_sign_digest_type(Bad) -> erlang:error(badarg, [Bad]).
+rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+
%%
%% rsa_public_encrypt
@@ -458,48 +371,39 @@ rsa_sign_digest_type(Bad) -> erlang:error(badarg, [Bad]).
%% Binary, Key = [E,N]
rsa_public_encrypt(BinMesg, Key, Padding) ->
- Size = iolist_size(BinMesg),
- <<Ret:8, Signature/binary>> =
- control(?RSA_PUBLIC_ENCRYPT, [<<Size:32>>,BinMesg,Key,rsa_pad(Padding)]),
- case Ret of
- 1 -> Signature;
- 0 -> erlang:error(encrypt_failed, [BinMesg,Key, Padding])
- end.
+ case rsa_public_crypt(BinMesg, Key, Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_decrypt(BinMesg, Key, Padding) ->
- Size = iolist_size(BinMesg),
- <<Ret:8, Signature/binary>> =
- control(?RSA_PRIVATE_DECRYPT, [<<Size:32>>,BinMesg,Key,rsa_pad(Padding)]),
- case Ret of
- 1 -> Signature;
- 0 -> erlang:error(decrypt_failed, [BinMesg,Key, Padding])
- end.
-
-rsa_pad(rsa_pkcs1_padding) -> 1;
-rsa_pad(rsa_pkcs1_oaep_padding) -> 2;
-%% rsa_pad(rsa_sslv23_padding) -> 3;
-rsa_pad(rsa_no_padding) -> 0;
-rsa_pad(Bad) -> erlang:error(badarg, [Bad]).
+ case rsa_private_crypt(BinMesg, Key, Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
+
%% Binary, Key = [E,N,D]
rsa_private_encrypt(BinMesg, Key, Padding) ->
- Size = iolist_size(BinMesg),
- <<Ret:8, Signature/binary>> =
- control(?RSA_PRIVATE_ENCRYPT, [<<Size:32>>,BinMesg,Key,rsa_pad(Padding)]),
- case Ret of
- 1 -> Signature;
- 0 -> erlang:error(encrypt_failed, [BinMesg,Key, Padding])
- end.
+ case rsa_private_crypt(BinMesg, Key, Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
%% Binary, Key = [E,N]
rsa_public_decrypt(BinMesg, Key, Padding) ->
- Size = iolist_size(BinMesg),
- <<Ret:8, Signature/binary>> =
- control(?RSA_PUBLIC_DECRYPT, [<<Size:32>>,BinMesg,Key,rsa_pad(Padding)]),
- case Ret of
- 1 -> Signature;
- 0 -> erlang:error(decrypt_failed, [BinMesg,Key, Padding])
+ case rsa_public_crypt(BinMesg, Key, Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
end.
%%
@@ -507,16 +411,18 @@ rsa_public_decrypt(BinMesg, Key, Padding) ->
%%
aes_cbc_128_encrypt(Key, IVec, Data) ->
- control(?AES_CBC_128_ENCRYPT, [Key, IVec, Data]).
+ aes_cbc_crypt(Key, IVec, Data, true).
aes_cbc_128_decrypt(Key, IVec, Data) ->
- control(?AES_CBC_128_DECRYPT, [Key, IVec, Data]).
+ aes_cbc_crypt(Key, IVec, Data, false).
aes_cbc_256_encrypt(Key, IVec, Data) ->
- control(?AES_CBC_256_ENCRYPT, [Key, IVec, Data]).
+ aes_cbc_crypt(Key, IVec, Data, true).
aes_cbc_256_decrypt(Key, IVec, Data) ->
- control(?AES_CBC_256_DECRYPT, [Key, IVec, Data]).
+ aes_cbc_crypt(Key, IVec, Data, false).
+
+aes_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% aes_cbc_ivec(Data) -> binary()
@@ -537,31 +443,25 @@ aes_cbc_ivec(Data) when is_list(Data) ->
%% NB doesn't check that they are the same size, just concatenates
%% them and sends them to the driver
%%
-exor(A, B) ->
- control(?XOR, [A, B]).
+exor(_A, _B) -> ?nif_stub.
%%
%% RC4 - symmetric stream cipher
%%
-rc4_encrypt(Key, Data) ->
- control_bin(?RC4_ENCRYPT, Key, Data).
-
-rc4_set_key(Key) ->
- control(?RC4_SET_KEY, Key).
-
-rc4_encrypt_with_state(State, Data) ->
- <<Sz:32/integer-big-unsigned, S:Sz/binary, D/binary>> =
- control_bin(?RC4_ENCRYPT_WITH_STATE, State, Data),
- {S, D}.
+rc4_encrypt(_Key, _Data) -> ?nif_stub.
+rc4_set_key(_Key) -> ?nif_stub.
+rc4_encrypt_with_state(_State, _Data) -> ?nif_stub.
%%
%% RC2 - 40 bits block cipher
%%
rc2_40_cbc_encrypt(Key, IVec, Data) ->
- control(?RC2_40_CBC_ENCRYPT, [Key, IVec, Data]).
+ rc2_40_cbc_crypt(Key,IVec,Data,true).
rc2_40_cbc_decrypt(Key, IVec, Data) ->
- control(?RC2_40_CBC_DECRYPT, [Key, IVec, Data]).
+ rc2_40_cbc_crypt(Key,IVec,Data,false).
+
+rc2_40_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
%% DH Diffie-Hellman functions
@@ -576,87 +476,44 @@ rc2_40_cbc_decrypt(Key, IVec, Data) ->
%%
%% usage: dh_generate_parameters(1024, 2 or 5) ->
%% [Prime=mpint(), SharedGenerator=mpint()]
-dh_generate_parameters(PrimeLen, Generator)
- when is_integer(PrimeLen), is_integer(Generator) ->
- case control(?DH_GENERATE_PARAMS, <<PrimeLen:32, Generator:32>>) of
- <<0:8, _/binary>> ->
- erlang:error(generation_failed, [PrimeLen,Generator]);
- <<1:8, PLen0:32, _:PLen0/binary, GLen0:32,_:GLen0/binary>> = Bin ->
- PLen = PLen0+4,
- GLen = GLen0+4,
- <<_:8, PBin:PLen/binary,GBin:GLen/binary>> = Bin,
- [PBin, GBin]
- end.
+dh_generate_parameters(PrimeLen, Generator) ->
+ case dh_generate_parameters_nif(PrimeLen, Generator) of
+ error -> erlang:error(generation_failed, [PrimeLen,Generator]);
+ Ret -> Ret
+ end.
+
+dh_generate_parameters_nif(_PrimeLen, _Generator) -> ?nif_stub.
%% Checks that the DHParameters are ok.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
-dh_check(DHParameters) ->
- case control(?DH_CHECK, DHParameters) of
- <<0:32>> -> ok;
- <<_:24,_:1,_:1,_:1,1:1>> -> not_prime;
- <<_:24,_:1,_:1,1:1,0:1>> -> not_strong_prime;
- <<_:24,_:1,1:1,0:1,0:1>> -> unable_to_check_generator;
- <<_:24,1:1,0:1,0:1,0:1>> -> not_suitable_generator;
- <<16#FFFF:32>> -> {error, check_failed};
- <<X:32>> -> {unknown, X}
- end.
+dh_check([_Prime,_Gen]) -> ?nif_stub.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
%% PrivKey = mpint()
dh_generate_key(DHParameters) ->
- dh_generate_key(<<0:32>>, DHParameters).
+ dh_generate_key(undefined, DHParameters).
dh_generate_key(PrivateKey, DHParameters) ->
- case control(?DH_GENERATE_KEY, [PrivateKey, DHParameters]) of
- <<0:8, _/binary>> ->
- erlang:error(generation_failed, [PrivateKey,DHParameters]);
- Bin = <<1:8, PubLen0:32, _:PubLen0/binary, PrivLen0:32, _:PrivLen0/binary>> ->
- PubLen = PubLen0+4,
- PrivLen = PrivLen0+4,
- <<_:8, PubBin:PubLen/binary,PrivBin:PrivLen/binary>> = Bin,
- {PubBin, PrivBin}
+ case dh_generate_key_nif(PrivateKey, DHParameters) of
+ error -> erlang:error(generation_failed, [PrivateKey,DHParameters]);
+ Res -> Res
end.
+dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub.
+
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
%% MyPrivKey, OthersPublicKey = mpint()
dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
- case control(?DH_COMPUTE_KEY, [OthersPublicKey, MyPrivateKey, DHParameters]) of
- <<0:8, _/binary>> ->
- erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]);
- <<1:8, Binary/binary>> -> Binary
+ case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of
+ error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]);
+ Ret -> Ret
end.
+dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+
%%
%% LOCAL FUNCTIONS
%%
-control_bin(Cmd, Key, Data) ->
- Sz = iolist_size(Key),
- control(Cmd, [<<Sz:32/integer-unsigned>>, Key, Data]).
-
-control(Cmd, Data) ->
- Port = crypto_server:client_port(),
- erlang:port_control(Port, Cmd, Data).
-
-
-%% sizehdr(N) ->
-%% [(N bsr 24) band 255,
-%% (N bsr 16) band 255,
-%% (N bsr 8) band 255,
-%% N band 255].
-
-%% Flat length of IOlist (or binary)
-%% flen(L) when binary(L) ->
-%% size(L);
-%% flen(L) ->
-%% flen(L, 0).
-
-%% flen([H| T], N) when list(H) ->
-%% flen(H, flen(T, N));
-%% flen([H| T], N) when binary(H) ->
-%% flen(T, N + size(H));
-%% flen([H| T], N) when integer(H), 0 =< H, H =< 255 ->
-%% flen(T, N + 1);
-%% flen([], N) ->
-%% N.
+
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
diff --git a/lib/crypto/src/crypto_server.erl b/lib/crypto/src/crypto_server.erl
index 0b1e5c9b02..89650a9f06 100644
--- a/lib/crypto/src/crypto_server.erl
+++ b/lib/crypto/src/crypto_server.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -23,14 +23,12 @@
-behaviour(gen_server).
--export([start_link/0,client_port/0]).
+-export([start_link/0]).
%% Internal exports, call-back functions.
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,code_change/3,
terminate/2]).
-%% Measurements shows that inlining port_names/0 is worth doing.
--compile({inline,[{port_names,0}]}).
%%% --------------------------------------------------------
%%% Interface Functions.
@@ -40,66 +38,8 @@ start_link() ->
gen_server:start_link({local, crypto_server}, crypto_server, [], []).
init([]) ->
- process_flag(trap_exit, true),
- erl_ddll:start(),
- PrivDir = code:priv_dir(crypto),
- LibDir1 = filename:join([PrivDir, "lib"]),
- {Status, LibDir} =
- case erl_ddll:load_driver(LibDir1, crypto_drv) of
- ok -> {ok,LibDir1};
- {error,Error1} ->
- LibDir2 =
- filename:join(LibDir1,
- erlang:system_info(system_architecture)),
- Candidate =
- filelib:wildcard(filename:join([LibDir2,"crypto_drv*"])),
- case Candidate of
- [] ->
- {{error,Error1},LibDir1};
- _ ->
- case erl_ddll:load_driver(LibDir2, crypto_drv) of
- ok ->
- {ok,LibDir2};
- {error, Error2} ->
- {{error,Error2},LibDir2}
- end
- end
- end,
- case Status of
- ok ->
- Cmd = "crypto_drv elibcrypto " ++
- filename:join([LibDir, "elibcrypto"]),
- open_ports(Cmd,size(port_names()));
- {error, E} ->
- Str = erl_ddll:format_error(E),
- error_logger:error_msg("Unable to load crypto_drv. Failed with error:~n\"~s\"~nOpenSSL might not be installed on this system.~n",[Str]),
- {stop,nodriver}
- end.
-
-open_ports(_,0) ->
- {ok, []};
-open_ports(Cmd,N) ->
- Port = open_port({spawn, Cmd}, []),
- %% check that driver is loaded, linked and working
- %% since crypto_drv links towards libcrypto, this is a good thing
- %% since libcrypto is known to be bad with backwards compatibility
- case catch port_control(Port, 0, []) of
- {'EXIT', _} ->
- {stop, nodriver};
- _ ->
- register(element(N,port_names()), Port),
- open_ports(Cmd,N-1)
- end.
-
-port_names() ->
- { crypto_drv01, crypto_drv02, crypto_drv03, crypto_drv04,
- crypto_drv05, crypto_drv06, crypto_drv07, crypto_drv08,
- crypto_drv09, crypto_drv10, crypto_drv11, crypto_drv12,
- crypto_drv13, crypto_drv14, crypto_drv15, crypto_drv16 }.
-
-client_port() ->
- element(erlang:system_info(scheduler_id) rem size(port_names()) + 1,
- port_names()).
+ {ok,[]}.
+
%%% --------------------------------------------------------
@@ -112,11 +52,6 @@ handle_call(_, _, State) ->
handle_cast(_, State) ->
{noreply, State}.
-handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
- {noreply, State};
-
-handle_info({'EXIT', Port, Reason}, State) when is_port(Port) ->
- {stop, {port_died, Reason}, State};
handle_info(_, State) ->
{noreply, State}.
@@ -124,13 +59,8 @@ code_change(_OldVsn, State, _Extra) ->
{ok, State}.
terminate(_Reason, _State) ->
- close_ports(size(port_names())).
+ [].
-close_ports(0) ->
- ok;
-close_ports(N) ->
- element(N,port_names()) ! {self(), close},
- close_ports(N-1).
diff --git a/lib/crypto/test/blowfish_SUITE.erl b/lib/crypto/test/blowfish_SUITE.erl
index d4cc167ea9..d117e7cc3d 100644
--- a/lib/crypto/test/blowfish_SUITE.erl
+++ b/lib/crypto/test/blowfish_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -116,7 +116,8 @@ all(suite) ->
ecb_test(KeyBytes, ClearBytes, CipherBytes) ->
{Key, Clear, Cipher} =
{to_bin(KeyBytes), to_bin(ClearBytes), to_bin(CipherBytes)},
- crypto:blowfish_ecb_encrypt(Key, Clear) =:= Cipher.
+ ?line m(crypto:blowfish_ecb_encrypt(Key, Clear), Cipher),
+ true.
ecb(doc) ->
"Test that ECB mode is OK";
@@ -208,3 +209,5 @@ to_bin([], Acc) ->
iolist_to_binary(lists:reverse(Acc));
to_bin([C1, C2 | Rest], Acc) ->
to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]).
+
+m(X,X) -> ok.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index ee0e5c0dae..08d7a0ce99 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -119,7 +119,7 @@ link_test(Config) when is_list(Config) ->
link_test_1() ->
?line CryptoPriv = code:priv_dir(crypto),
- ?line Wc = filename:join([CryptoPriv,"lib","crypto_drv.*"]),
+ ?line Wc = filename:join([CryptoPriv,"lib","crypto.*"]),
?line case filelib:wildcard(Wc) of
[] -> {skip,"Didn't find the crypto driver"};
[Drv] -> link_test_2(Drv)
@@ -843,16 +843,16 @@ dsa_sign_test(Config) when is_list(Config) ->
ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
- ?line Sig1 = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PrivKey)]),
+ ?line Sig1 = crypto:dss_sign(sized_binary(Msg), Params ++ [crypto:mpint(PrivKey)]),
?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(Sig1),
- [Params, crypto:mpint(PubKey)]), true),
+ Params ++ [crypto:mpint(PubKey)]), true),
?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1),
- [Params, crypto:mpint(PubKey)]), false),
+ Params ++ [crypto:mpint(PubKey)]), false),
?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)),
- [Params, crypto:mpint(PubKey)]), false),
+ Params ++ [crypto:mpint(PubKey)]), false),
%%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 68eecfe759..d04736fc2b 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 1.6.4
+CRYPTO_VSN = 2.0