aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2019-01-31 10:27:23 +0100
committerHans Nilsson <[email protected]>2019-02-25 10:01:24 +0100
commitc7cab680b80ef9220832151ed2c8c23a5d590b8b (patch)
treec197e1682ecdea385f93b5bbeee540e444b84e06 /lib
parentb3dbf45fdbe8c584c89b5e061f6e9a28a5d3ea86 (diff)
downloadotp-c7cab680b80ef9220832151ed2c8c23a5d590b8b.tar.gz
otp-c7cab680b80ef9220832151ed2c8c23a5d590b8b.tar.bz2
otp-c7cab680b80ef9220832151ed2c8c23a5d590b8b.zip
crypto: New experimental api
The new files api_ng.h and api_ng.c implements an api using EVP. The api is not by any mean new, except for the crypto application in Erlang/OTP. The aims at using the block api in a stream manor, that is 1) call crypto_init/4 2..N) call crypto_update/{2,3} The purpose is to simplify and hopefully optimize the SSL and SSH applications. By keeping the crypto state in C in an enif_resource the costful state copying in SSL and SSH is reduced with 1-2 per message sent or received. Changes in other files are for adaptation like FIPS etc since many functions uses the central get_cipher_type() function.
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto/c_src/Makefile.in1
-rw-r--r--lib/crypto/c_src/aead.c188
-rw-r--r--lib/crypto/c_src/aes.c36
-rw-r--r--lib/crypto/c_src/aes.h5
-rw-r--r--lib/crypto/c_src/algorithms.c59
-rw-r--r--lib/crypto/c_src/api_ng.c223
-rw-r--r--lib/crypto/c_src/api_ng.h29
-rw-r--r--lib/crypto/c_src/atoms.c70
-rw-r--r--lib/crypto/c_src/atoms.h37
-rw-r--r--lib/crypto/c_src/block.c40
-rw-r--r--lib/crypto/c_src/cipher.c194
-rw-r--r--lib/crypto/c_src/cipher.h31
-rw-r--r--lib/crypto/c_src/cmac.c6
-rw-r--r--lib/crypto/c_src/crypto.c5
-rw-r--r--lib/crypto/c_src/engine.c17
-rw-r--r--lib/crypto/c_src/pkey.c6
-rw-r--r--lib/crypto/doc/src/crypto.xml18
-rw-r--r--lib/crypto/src/crypto.erl366
18 files changed, 849 insertions, 482 deletions
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 508e1c40ee..e1e7f71538 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -75,6 +75,7 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
$(OBJDIR)/aead$(TYPEMARKER).o \
$(OBJDIR)/aes$(TYPEMARKER).o \
$(OBJDIR)/algorithms$(TYPEMARKER).o \
+ $(OBJDIR)/api_ng$(TYPEMARKER).o \
$(OBJDIR)/atoms$(TYPEMARKER).o \
$(OBJDIR)/block$(TYPEMARKER).o \
$(OBJDIR)/bn$(TYPEMARKER).o \
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
index c6f4cf52b1..3ee04f1be9 100644
--- a/lib/crypto/c_src/aead.c
+++ b/lib/crypto/c_src/aead.c
@@ -20,17 +20,19 @@
#include "aead.h"
#include "aes.h"
+#include "cipher.h"
ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type,Key,Iv,AAD,In) */
#if defined(HAVE_AEAD)
+ const struct cipher_type_t *cipherp;
EVP_CIPHER_CTX *ctx = NULL;
const EVP_CIPHER *cipher = NULL;
ErlNifBinary key, iv, aad, in;
unsigned int tag_len;
unsigned char *outp, *tagp;
ERL_NIF_TERM type, out, out_tag, ret;
- int len, ctx_ctrl_set_ivlen, ctx_ctrl_get_tag;
+ int len, ctx_ctrl_set_ivlen, ctx_ctrl_get_tag, ctx_ctrl_set_tag;
type = argv[0];
@@ -55,77 +57,19 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
|| aad.size > INT_MAX)
goto bad_arg;
- /* Use cipher_type some day. Must check block_encrypt|decrypt first */
-#if defined(HAVE_GCM)
- if (type == atom_aes_gcm) {
- if (iv.size == 0)
- goto bad_arg;
- if (tag_len < 1 || tag_len > 16)
- goto bad_arg;
-
- ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
- ctx_ctrl_get_tag = EVP_CTRL_GCM_GET_TAG;
-
- switch (key.size) {
- case 16:
- cipher = EVP_aes_128_gcm();
- break;
- case 24:
- cipher = EVP_aes_192_gcm();
- break;
- case 32:
- cipher = EVP_aes_256_gcm();
- break;
- default:
- goto bad_arg;
- }
- } else
-#endif
-#if defined(HAVE_CCM)
- if (type == atom_aes_ccm) {
- if (iv.size < 7 || iv.size > 13)
- goto bad_arg;
- if (tag_len < 4 || tag_len > 16)
- goto bad_arg;
- if ((tag_len & 1) != 0)
- goto bad_arg;
-
- ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
- ctx_ctrl_get_tag = EVP_CTRL_CCM_GET_TAG;
-
- switch (key.size) {
- case 16:
- cipher = EVP_aes_128_ccm();
- break;
- case 24:
- cipher = EVP_aes_192_ccm();
- break;
- case 32:
- cipher = EVP_aes_256_ccm();
- break;
- default:
- goto bad_arg;
- }
- } else
-#endif
-#if defined(HAVE_CHACHA20_POLY1305)
- if (type == atom_chacha20_poly1305) {
- if (key.size != 32)
- goto bad_arg;
- if (iv.size < 1 || iv.size > 16)
- goto bad_arg;
- if (tag_len != 16)
- goto bad_arg;
-
- ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
- ctx_ctrl_get_tag = EVP_CTRL_AEAD_GET_TAG;
-
- cipher = EVP_chacha20_poly1305();
-
- } else
-#endif
+ if ((cipherp = get_cipher_type(type, key.size)) == NULL)
+ goto bad_arg;
+ if (cipherp->flags & NON_EVP_CIPHER)
+ goto bad_arg;
+ if (! (cipherp->flags & AEAD_CIPHER) )
+ goto bad_arg;
+ if ((cipher = cipherp->cipher.p) == NULL)
return enif_raise_exception(env, atom_notsup);
-
+
+ ctx_ctrl_set_ivlen = cipherp->extra.aead.ctx_ctrl_set_ivlen;
+ ctx_ctrl_get_tag = cipherp->extra.aead.ctx_ctrl_get_tag;
+ ctx_ctrl_set_tag = cipherp->extra.aead.ctx_ctrl_set_tag;
+
if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
goto err;
@@ -136,7 +80,7 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
#if defined(HAVE_CCM)
if (type == atom_aes_ccm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, (int)tag_len, NULL) != 1)
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag_len, NULL) != 1)
goto err;
if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
goto err;
@@ -144,10 +88,10 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto err;
} else
#endif
- {
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto err;
- }
+ {
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
+ goto err;
+ }
if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
goto err;
@@ -190,6 +134,7 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type,Key,Iv,AAD,In,Tag) */
#if defined(HAVE_AEAD)
+ const struct cipher_type_t *cipherp;
EVP_CIPHER_CTX *ctx = NULL;
const EVP_CIPHER *cipher = NULL;
ErlNifBinary key, iv, aad, in, tag;
@@ -225,70 +170,18 @@ ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
|| aad.size > INT_MAX)
goto bad_arg;
- /* Use cipher_type some day. Must check block_encrypt|decrypt first */
-#if defined(HAVE_GCM)
- if (type == atom_aes_gcm) {
- if (iv.size == 0)
- goto bad_arg;
-
- ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
- ctx_ctrl_set_tag = EVP_CTRL_GCM_SET_TAG;
-
- switch (key.size) {
- case 16:
- cipher = EVP_aes_128_gcm();
- break;
- case 24:
- cipher = EVP_aes_192_gcm();
- break;
- case 32:
- cipher = EVP_aes_256_gcm();
- break;
- default:
- goto bad_arg;
- }
- } else
-#endif
-#if defined(HAVE_CCM)
- if (type == atom_aes_ccm) {
- if (iv.size == 0)
- goto bad_arg;
-
- ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
- ctx_ctrl_set_tag = EVP_CTRL_CCM_SET_TAG;
-
- switch (key.size) {
- case 16:
- cipher = EVP_aes_128_ccm();
- break;
- case 24:
- cipher = EVP_aes_192_ccm();
- break;
- case 32:
- cipher = EVP_aes_256_ccm();
- break;
- default:
- goto bad_arg;
- }
- } else
-#endif
-#if defined(HAVE_CHACHA20_POLY1305)
- if (type == atom_chacha20_poly1305) {
- if (key.size != 32)
- goto bad_arg;
- if (iv.size < 1 || iv.size > 16)
- goto bad_arg;
- if (tag.size != 16)
- goto bad_arg;
-
- ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
- ctx_ctrl_set_tag = EVP_CTRL_AEAD_SET_TAG;
-
- cipher = EVP_chacha20_poly1305();
- } else
-#endif
+ if ((cipherp = get_cipher_type(type, key.size)) == NULL)
+ goto bad_arg;
+ if (cipherp->flags & NON_EVP_CIPHER)
+ goto bad_arg;
+ if ( !(cipherp->flags & AEAD_CIPHER) )
+ goto bad_arg;
+ if ((cipher = cipherp->cipher.p) == NULL)
return enif_raise_exception(env, atom_notsup);
+ ctx_ctrl_set_ivlen = cipherp->extra.aead.ctx_ctrl_set_ivlen;
+ ctx_ctrl_set_tag = cipherp->extra.aead.ctx_ctrl_set_tag;
+
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
goto err;
@@ -301,27 +194,26 @@ ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
#if defined(HAVE_CCM)
if (type == atom_aes_ccm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, (int)tag.size, tag.data) != 1)
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag.size, tag.data) != 1)
+ goto err;
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
goto err;
- }
-#endif
-
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto err;
-
-#if defined(HAVE_CCM)
- if (type == atom_aes_ccm) {
if (EVP_DecryptUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
goto err;
}
+ else
#endif
+ {
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
+ goto err;
+ }
if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
goto err;
if (EVP_DecryptUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
goto err;
-#if defined(HAVE_GCM) || defined(HAVE_CHACHA20_POLY1305)
+#if defined(HAVE_GCM)
if (type == atom_aes_gcm) {
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag.size, tag.data) != 1)
goto err;
diff --git a/lib/crypto/c_src/aes.c b/lib/crypto/c_src/aes.c
index 2f30ec8a58..ee2bb70fb7 100644
--- a/lib/crypto/c_src/aes.c
+++ b/lib/crypto/c_src/aes.c
@@ -166,8 +166,6 @@ ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
}
-/* Initializes state for ctr streaming (de)encryption
-*/
#ifdef HAVE_EVP_AES_CTR
ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec) */
@@ -279,27 +277,31 @@ ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec) */
+ ASSERT(argc == 2);
+
+ return aes_ctr_stream_init_compat(env, argv[0], argv[1]);
+}
+
+
+ERL_NIF_TERM aes_ctr_stream_init_compat(ErlNifEnv* env, const ERL_NIF_TERM key_term, const ERL_NIF_TERM iv_term)
+{
ErlNifBinary key_bin, ivec_bin;
ERL_NIF_TERM ecount_bin;
unsigned char *outp;
-
- ASSERT(argc == 2);
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin))
+
+ if (!enif_inspect_iolist_as_binary(env, key_term, &key_bin))
goto bad_arg;
if (key_bin.size != 16 && key_bin.size != 24 && key_bin.size != 32)
goto bad_arg;
- if (!enif_inspect_binary(env, argv[1], &ivec_bin))
+ if (!enif_inspect_binary(env, iv_term, &ivec_bin))
goto bad_arg;
if (ivec_bin.size != 16)
goto bad_arg;
-
if ((outp = enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin)) == NULL)
goto err;
-
memset(outp, 0, AES_BLOCK_SIZE);
- return enif_make_tuple4(env, argv[0], argv[1], ecount_bin, enif_make_int(env, 0));
+ return enif_make_tuple4(env, key_term, iv_term, ecount_bin, enif_make_int(env, 0));
bad_arg:
err:
@@ -307,6 +309,14 @@ ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
}
ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ASSERT(argc == 2);
+
+ return aes_ctr_stream_encrypt_compat(env, argv[0], argv[1]);
+}
+
+
+ERL_NIF_TERM aes_ctr_stream_encrypt_compat(ErlNifEnv* env, const ERL_NIF_TERM state_arg, const ERL_NIF_TERM data_arg)
{/* ({Key, IVec, ECount, Num}, Data) */
ErlNifBinary key_bin, ivec_bin, text_bin, ecount_bin;
AES_KEY aes_key;
@@ -318,9 +328,7 @@ ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
unsigned char * ecount2_buf;
unsigned char *outp;
- ASSERT(argc == 2);
-
- if (!enif_get_tuple(env, argv[0], &state_arity, &state_term))
+ if (!enif_get_tuple(env, state_arg, &state_arity, &state_term))
goto bad_arg;
if (state_arity != 4)
goto bad_arg;
@@ -338,7 +346,7 @@ ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
goto bad_arg;
if (!enif_get_uint(env, state_term[3], &num))
goto bad_arg;
- if (!enif_inspect_iolist_as_binary(env, argv[1], &text_bin))
+ if (!enif_inspect_iolist_as_binary(env, data_arg, &text_bin))
goto bad_arg;
/* NOTE: This function returns 0 on success unlike most OpenSSL functions */
diff --git a/lib/crypto/c_src/aes.h b/lib/crypto/c_src/aes.h
index 09c984f84a..527d041410 100644
--- a/lib/crypto/c_src/aes.h
+++ b/lib/crypto/c_src/aes.h
@@ -26,8 +26,13 @@
ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+#if !defined(HAVE_EVP_AES_CTR)
+ERL_NIF_TERM aes_ctr_stream_init_compat(ErlNifEnv* env, const ERL_NIF_TERM key_term, const ERL_NIF_TERM iv_term);
+ERL_NIF_TERM aes_ctr_stream_encrypt_compat(ErlNifEnv* env, const ERL_NIF_TERM state_arg, const ERL_NIF_TERM data_arg);
+#endif
#ifdef HAVE_GCM_EVP_DECRYPT_BUG
ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
index a5bf248ea0..06cd109fc1 100644
--- a/lib/crypto/c_src/algorithms.c
+++ b/lib/crypto/c_src/algorithms.c
@@ -19,13 +19,12 @@
*/
#include "algorithms.h"
+#include "cipher.h"
static unsigned int algo_hash_cnt, algo_hash_fips_cnt;
static ERL_NIF_TERM algo_hash[14]; /* increase when extending the list */
static unsigned int algo_pubkey_cnt, algo_pubkey_fips_cnt;
static ERL_NIF_TERM algo_pubkey[12]; /* increase when extending the list */
-static unsigned int algo_cipher_cnt, algo_cipher_fips_cnt;
-static ERL_NIF_TERM algo_cipher[25]; /* increase when extending the list */
static unsigned int algo_mac_cnt, algo_mac_fips_cnt;
static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */
static unsigned int algo_curve_cnt, algo_curve_fips_cnt;
@@ -92,56 +91,7 @@ void init_algorithms_types(ErlNifEnv* env)
#endif
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
- // Validated algorithms first
- algo_cipher_cnt = 0;
-#ifndef OPENSSL_NO_DES
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des_ede3");
-#ifdef HAVE_DES_ede3_cfb_encrypt
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbf");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cfb");
-#endif
-#endif
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc128");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb8");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb128");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc256");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ctr");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ecb");
-#if defined(HAVE_GCM)
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_gcm");
-#endif
-#if defined(HAVE_CCM)
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ccm");
-#endif
- // Non-validated algorithms follow
- algo_cipher_fips_cnt = algo_cipher_cnt;
-#ifdef HAVE_AES_IGE
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ige256");
-#endif
-#ifndef OPENSSL_NO_DES
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cfb");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_ecb");
-#endif
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cfb64");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ofb64");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ecb");
-#ifndef OPENSSL_NO_RC2
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc2_cbc");
-#endif
-#ifndef OPENSSL_NO_RC4
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc4");
-#endif
-#if defined(HAVE_CHACHA20_POLY1305)
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20_poly1305");
-#endif
-#if defined(HAVE_CHACHA20)
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20");
-#endif
-
+
// Validated algorithms first
algo_mac_cnt = 0;
algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac");
@@ -290,7 +240,6 @@ void init_algorithms_types(ErlNifEnv* env)
// Check that the max number of algos is updated
ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
- ASSERT(algo_cipher_cnt <= sizeof(algo_cipher)/sizeof(ERL_NIF_TERM));
ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM));
ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM));
@@ -303,14 +252,12 @@ ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
unsigned int hash_cnt = fips_mode ? algo_hash_fips_cnt : algo_hash_cnt;
unsigned int pubkey_cnt = fips_mode ? algo_pubkey_fips_cnt : algo_pubkey_cnt;
- unsigned int cipher_cnt = fips_mode ? algo_cipher_fips_cnt : algo_cipher_cnt;
unsigned int mac_cnt = fips_mode ? algo_mac_fips_cnt : algo_mac_cnt;
unsigned int curve_cnt = fips_mode ? algo_curve_fips_cnt : algo_curve_cnt;
unsigned int rsa_opts_cnt = fips_mode ? algo_rsa_opts_fips_cnt : algo_rsa_opts_cnt;
#else
unsigned int hash_cnt = algo_hash_cnt;
unsigned int pubkey_cnt = algo_pubkey_cnt;
- unsigned int cipher_cnt = algo_cipher_cnt;
unsigned int mac_cnt = algo_mac_cnt;
unsigned int curve_cnt = algo_curve_cnt;
unsigned int rsa_opts_cnt = algo_rsa_opts_cnt;
@@ -318,7 +265,7 @@ ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_tuple6(env,
enif_make_list_from_array(env, algo_hash, hash_cnt),
enif_make_list_from_array(env, algo_pubkey, pubkey_cnt),
- enif_make_list_from_array(env, algo_cipher, cipher_cnt),
+ cipher_types_as_list(env),
enif_make_list_from_array(env, algo_mac, mac_cnt),
enif_make_list_from_array(env, algo_curve, curve_cnt),
enif_make_list_from_array(env, algo_rsa_opts, rsa_opts_cnt)
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
new file mode 100644
index 0000000000..c4114d1626
--- /dev/null
+++ b/lib/crypto/c_src/api_ng.c
@@ -0,0 +1,223 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "api_ng.h"
+#include "aes.h"
+#include "cipher.h"
+
+/*
+ * A unified set of functions for encryption/decryption.
+ *
+ * EXPERIMENTAL!!
+ *
+ */
+ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+
+
+/* Try better error messages in new functions */
+#define ERROR_Term(Env, ReasonTerm) enif_make_tuple2((Env), atom_error, (ReasonTerm))
+#define ERROR_Str(Env, ReasonString) ERROR_Term((Env), enif_make_string((Env),(ReasonString),(ERL_NIF_LATIN1)))
+
+/* Initializes state for (de)encryption
+ */
+ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Cipher, Key, IVec, Encrypt) % if no IV for the Cipher, set IVec = <<>>
+ */
+ ErlNifBinary key_bin, ivec_bin;
+ unsigned char *iv = NULL;
+ struct evp_cipher_ctx *ctx;
+ const struct cipher_type_t *cipherp;
+ const EVP_CIPHER *cipher;
+ ERL_NIF_TERM enc_flg_arg, ret;
+ int enc;
+ unsigned iv_len;
+
+ enc_flg_arg = argv[argc-1];
+ if (enc_flg_arg == atom_true)
+ enc = 1;
+ else if (enc_flg_arg == atom_false)
+ enc = 0;
+ else if (enc_flg_arg == atom_undefined)
+ /* For compat funcs in crypto.erl */
+ enc = -1;
+ else
+ return ERROR_Str(env, "Bad enc flag");
+
+ if (!enif_inspect_binary(env, argv[1], &key_bin))
+ return ERROR_Str(env, "Bad key");
+
+ if (!(cipherp = get_cipher_type(argv[0], key_bin.size)))
+ return ERROR_Str(env, "Unknown cipher or bad key size");
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
+
+ if (enc == -1)
+ return atom_undefined;
+
+ if (!(cipher = cipherp->cipher.p)) {
+#if !defined(HAVE_EVP_AES_CTR)
+ if (cipherp->flags & AES_CTR_COMPAT)
+ return aes_ctr_stream_init_compat(env, argv[1], argv[2]);
+ else
+#endif
+ return enif_raise_exception(env, atom_notsup);
+ }
+
+#ifdef HAVE_ECB_IVEC_BUG
+ if (cipherp->flags & ECB_BUG_0_9_8L)
+ iv_len = 0; /* <= 0.9.8l returns faulty ivec length */
+ else
+#endif
+ iv_len = EVP_CIPHER_iv_length(cipher);
+
+ if (iv_len) {
+ if (!enif_inspect_binary(env, argv[2], &ivec_bin))
+ return ERROR_Str(env, "Bad iv type");
+
+ if (iv_len != ivec_bin.size)
+ return ERROR_Str(env, "Bad iv size");
+
+ iv = ivec_bin.data;
+ }
+
+ if ((ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL)
+ return ERROR_Str(env, "Can't allocate resource");
+
+ ctx->ctx = EVP_CIPHER_CTX_new();
+ if (! ctx->ctx)
+ return ERROR_Str(env, "Can't allocate context");
+
+ if (!EVP_CipherInit_ex(ctx->ctx, cipher, NULL, NULL, NULL, enc)) {
+ enif_release_resource(ctx);
+ return ERROR_Str(env, "Can't initialize context, step 1");
+ }
+
+ if (!EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)key_bin.size)) {
+ enif_release_resource(ctx);
+ return ERROR_Str(env, "Can't initialize context, key_length");
+ }
+
+ if (EVP_CIPHER_type(cipher) == NID_rc2_cbc) {
+ if (key_bin.size > INT_MAX / 8) {
+ enif_release_resource(ctx);
+ return ERROR_Str(env, "To large rc2_cbc key");
+ }
+ if (!EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_SET_RC2_KEY_BITS, (int)key_bin.size * 8, NULL)) {
+ enif_release_resource(ctx);
+ return ERROR_Str(env, "ctrl rc2_cbc key");
+ }
+ }
+
+ if (!EVP_CipherInit_ex(ctx->ctx, NULL, NULL, key_bin.data, iv, enc)) {
+ enif_release_resource(ctx);
+ return ERROR_Str(env, "Can't initialize key and/or iv");
+ }
+
+ EVP_CIPHER_CTX_set_padding(ctx->ctx, 0);
+
+ ret = enif_make_resource(env, ctx);
+ enif_release_resource(ctx);
+ return ret;
+}
+
+ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data)
+ (Context, Data, IV) */
+ struct evp_cipher_ctx *ctx;
+ ErlNifBinary in_data_bin, ivec_bin, out_data_bin;
+ int out_len, block_size;
+
+#if !defined(HAVE_EVP_AES_CTR)
+ const ERL_NIF_TERM *state_term;
+ int state_arity;
+
+ if (enif_get_tuple(env, argv[0], &state_arity, &state_term) && (state_arity == 4)) {
+ return aes_ctr_stream_encrypt_compat(env, argv[0], argv[1]);
+ }
+#endif
+
+ if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx))
+ return ERROR_Str(env, "Bad 1:st arg");
+
+ if (!enif_inspect_binary(env, argv[1], &in_data_bin) )
+ return ERROR_Str(env, "Bad 2:nd arg");
+
+ /* arg[1] was checked by the caller */
+ ASSERT(in_data_bin.size =< INT_MAX);
+
+ block_size = EVP_CIPHER_CTX_block_size(ctx->ctx);
+ if (in_data_bin.size % (size_t)block_size != 0)
+ return ERROR_Str(env, "Data not a multiple of block size");
+
+ if (argc==3) {
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &ivec_bin))
+ return ERROR_Str(env, "Not binary IV");
+
+ if (ivec_bin.size > INT_MAX)
+ return ERROR_Str(env, "Too big IV");
+
+ if (!EVP_CipherInit_ex(ctx->ctx, NULL, NULL, NULL, ivec_bin.data, -1))
+ return ERROR_Str(env, "Can't set IV");
+ }
+
+ if (!enif_alloc_binary((size_t)in_data_bin.size+block_size, &out_data_bin))
+ return ERROR_Str(env, "Can't allocate outdata");
+
+ if (!EVP_CipherUpdate(ctx->ctx, out_data_bin.data, &out_len, in_data_bin.data, in_data_bin.size))
+ return ERROR_Str(env, "Can't update");
+
+ if (!enif_realloc_binary(&out_data_bin, (size_t)out_len))
+ return ERROR_Str(env, "Can't reallocate");
+
+ CONSUME_REDS(env, in_data_bin);
+ return enif_make_binary(env, &out_data_bin);
+}
+
+
+ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data)
+ (Context, Data, IV) */
+ int i;
+ ErlNifBinary data_bin;
+ ERL_NIF_TERM new_argv[3];
+
+ ASSERT(argc =< 3);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data_bin))
+ return ERROR_Str(env, "iodata expected as data");
+
+ if (data_bin.size > INT_MAX)
+ return ERROR_Str(env, "to long data");
+
+ for (i=0; i<argc; i++) new_argv[i] = argv[i];
+ new_argv[1] = enif_make_binary(env, &data_bin);
+
+ /* Run long jobs on a dirty scheduler to not block the current emulator thread */
+ if (data_bin.size > MAX_BYTES_TO_NIF) {
+ return enif_schedule_nif(env, "ng_crypto_update",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ ng_crypto_update, argc, new_argv);
+ }
+
+ return ng_crypto_update(env, argc, new_argv);
+}
+
diff --git a/lib/crypto/c_src/api_ng.h b/lib/crypto/c_src/api_ng.h
new file mode 100644
index 0000000000..a3b40fe7fc
--- /dev/null
+++ b/lib/crypto/c_src/api_ng.h
@@ -0,0 +1,29 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_API_NG_H__
+#define E_API_NG_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_AES_H__ */
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 5f19327197..2e417da7f4 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -31,12 +31,6 @@ ERL_NIF_TERM atom_signature_md;
ERL_NIF_TERM atom_undefined;
ERL_NIF_TERM atom_ok;
-ERL_NIF_TERM atom_not_prime;
-ERL_NIF_TERM atom_not_strong_prime;
-ERL_NIF_TERM atom_unable_to_check_generator;
-ERL_NIF_TERM atom_not_suitable_generator;
-ERL_NIF_TERM atom_check_failed;
-ERL_NIF_TERM atom_unknown;
ERL_NIF_TERM atom_none;
ERL_NIF_TERM atom_notsup;
ERL_NIF_TERM atom_digest;
@@ -48,7 +42,6 @@ ERL_NIF_TERM atom_not_supported;
#endif
#if defined(HAVE_EC)
-ERL_NIF_TERM atom_ec;
ERL_NIF_TERM atom_prime_field;
ERL_NIF_TERM atom_characteristic_two_field;
ERL_NIF_TERM atom_tpbasis;
@@ -64,14 +57,6 @@ ERL_NIF_TERM atom_aes_gcm;
#ifdef HAVE_CCM
ERL_NIF_TERM atom_aes_ccm;
#endif
-#ifdef HAVE_CHACHA20_POLY1305
-ERL_NIF_TERM atom_chacha20_poly1305;
-#endif
-#ifdef HAVE_ECB_IVEC_BUG
-ERL_NIF_TERM atom_aes_ecb;
-ERL_NIF_TERM atom_des_ecb;
-ERL_NIF_TERM atom_blowfish_ecb;
-#endif
ERL_NIF_TERM atom_rsa;
ERL_NIF_TERM atom_dss;
@@ -99,16 +84,6 @@ ERL_NIF_TERM atom_rsa_sslv23_padding;
#endif
ERL_NIF_TERM atom_rsa_x931_padding;
ERL_NIF_TERM atom_rsa_pss_saltlen;
-ERL_NIF_TERM atom_sha224;
-ERL_NIF_TERM atom_sha256;
-ERL_NIF_TERM atom_sha384;
-ERL_NIF_TERM atom_sha512;
-ERL_NIF_TERM atom_sha3_224;
-ERL_NIF_TERM atom_sha3_256;
-ERL_NIF_TERM atom_sha3_384;
-ERL_NIF_TERM atom_sha3_512;
-ERL_NIF_TERM atom_md5;
-ERL_NIF_TERM atom_ripemd160;
#ifdef HAVE_BLAKE2
ERL_NIF_TERM atom_blake2b;
@@ -116,14 +91,6 @@ ERL_NIF_TERM atom_blake2s;
#endif
#ifdef HAS_ENGINE_SUPPORT
-ERL_NIF_TERM atom_bad_engine_method;
-ERL_NIF_TERM atom_bad_engine_id;
-ERL_NIF_TERM atom_ctrl_cmd_failed;
-ERL_NIF_TERM atom_engine_init_failed;
-ERL_NIF_TERM atom_register_engine_failed;
-ERL_NIF_TERM atom_add_engine_failed;
-ERL_NIF_TERM atom_remove_engine_failed;
-ERL_NIF_TERM atom_engine_method_not_supported;
ERL_NIF_TERM atom_engine_method_rsa;
ERL_NIF_TERM atom_engine_method_dsa;
@@ -169,18 +136,11 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_signature_md = enif_make_atom(env,"signature_md");
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");
atom_none = enif_make_atom(env,"none");
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
#if defined(HAVE_EC)
- atom_ec = enif_make_atom(env,"ec");
atom_prime_field = enif_make_atom(env,"prime_field");
atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
atom_tpbasis = enif_make_atom(env,"tpbasis");
@@ -196,14 +156,6 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
#ifdef HAVE_CCM
atom_aes_ccm = enif_make_atom(env, "aes_ccm");
#endif
-#ifdef HAVE_CHACHA20_POLY1305
- atom_chacha20_poly1305 = enif_make_atom(env,"chacha20_poly1305");
-#endif
-#ifdef HAVE_ECB_IVEC_BUG
- atom_aes_ecb = enif_make_atom(env, "aes_ecb");
- atom_des_ecb = enif_make_atom(env, "des_ecb");
- atom_blowfish_ecb = enif_make_atom(env, "blowfish_ecb");
-#endif
#ifdef FIPS_SUPPORT
atom_enabled = enif_make_atom(env,"enabled");
@@ -214,6 +166,7 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_rsa = enif_make_atom(env,"rsa");
atom_dss = enif_make_atom(env,"dss");
atom_ecdsa = enif_make_atom(env,"ecdsa");
+
#ifdef HAVE_ED_CURVE_DH
atom_x25519 = enif_make_atom(env,"x25519");
atom_x448 = enif_make_atom(env,"x448");
@@ -234,29 +187,8 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
#endif
atom_rsa_x931_padding = enif_make_atom(env,"rsa_x931_padding");
atom_rsa_pss_saltlen = enif_make_atom(env,"rsa_pss_saltlen");
- atom_sha224 = enif_make_atom(env,"sha224");
- atom_sha256 = enif_make_atom(env,"sha256");
- atom_sha384 = enif_make_atom(env,"sha384");
- atom_sha512 = enif_make_atom(env,"sha512");
- atom_sha3_224 = enif_make_atom(env,"sha3_224");
- atom_sha3_256 = enif_make_atom(env,"sha3_256");
- atom_sha3_384 = enif_make_atom(env,"sha3_384");
- atom_sha3_512 = enif_make_atom(env,"sha3_512");
- atom_md5 = enif_make_atom(env,"md5");
- atom_ripemd160 = enif_make_atom(env,"ripemd160");
-#ifdef HAVE_BLAKE2
- atom_blake2b = enif_make_atom(env,"blake2b");
- atom_blake2s = enif_make_atom(env,"blake2s");
-#endif
#ifdef HAS_ENGINE_SUPPORT
- atom_bad_engine_method = enif_make_atom(env,"bad_engine_method");
- atom_bad_engine_id = enif_make_atom(env,"bad_engine_id");
- atom_ctrl_cmd_failed = enif_make_atom(env,"ctrl_cmd_failed");
- atom_engine_init_failed = enif_make_atom(env,"engine_init_failed");
- atom_engine_method_not_supported = enif_make_atom(env,"engine_method_not_supported");
- atom_add_engine_failed = enif_make_atom(env,"add_engine_failed");
- atom_remove_engine_failed = enif_make_atom(env,"remove_engine_failed");
atom_engine_method_rsa = enif_make_atom(env,"engine_method_rsa");
atom_engine_method_dsa = enif_make_atom(env,"engine_method_dsa");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index 32f5ec856c..f15523d865 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -35,12 +35,6 @@ extern ERL_NIF_TERM atom_signature_md;
extern ERL_NIF_TERM atom_undefined;
extern ERL_NIF_TERM atom_ok;
-extern ERL_NIF_TERM atom_not_prime;
-extern ERL_NIF_TERM atom_not_strong_prime;
-extern ERL_NIF_TERM atom_unable_to_check_generator;
-extern ERL_NIF_TERM atom_not_suitable_generator;
-extern ERL_NIF_TERM atom_check_failed;
-extern ERL_NIF_TERM atom_unknown;
extern ERL_NIF_TERM atom_none;
extern ERL_NIF_TERM atom_notsup;
extern ERL_NIF_TERM atom_digest;
@@ -52,7 +46,6 @@ extern ERL_NIF_TERM atom_not_supported;
#endif
#if defined(HAVE_EC)
-extern ERL_NIF_TERM atom_ec;
extern ERL_NIF_TERM atom_prime_field;
extern ERL_NIF_TERM atom_characteristic_two_field;
extern ERL_NIF_TERM atom_tpbasis;
@@ -68,14 +61,6 @@ extern ERL_NIF_TERM atom_aes_gcm;
#ifdef HAVE_CCM
extern ERL_NIF_TERM atom_aes_ccm;
#endif
-#ifdef HAVE_CHACHA20_POLY1305
-extern ERL_NIF_TERM atom_chacha20_poly1305;
-#endif
-#ifdef HAVE_ECB_IVEC_BUG
-extern ERL_NIF_TERM atom_aes_ecb;
-extern ERL_NIF_TERM atom_des_ecb;
-extern ERL_NIF_TERM atom_blowfish_ecb;
-#endif
extern ERL_NIF_TERM atom_rsa;
extern ERL_NIF_TERM atom_dss;
@@ -103,30 +88,8 @@ extern ERL_NIF_TERM atom_rsa_sslv23_padding;
#endif
extern ERL_NIF_TERM atom_rsa_x931_padding;
extern ERL_NIF_TERM atom_rsa_pss_saltlen;
-extern ERL_NIF_TERM atom_sha224;
-extern ERL_NIF_TERM atom_sha256;
-extern ERL_NIF_TERM atom_sha384;
-extern ERL_NIF_TERM atom_sha512;
-extern ERL_NIF_TERM atom_sha3_224;
-extern ERL_NIF_TERM atom_sha3_256;
-extern ERL_NIF_TERM atom_sha3_384;
-extern ERL_NIF_TERM atom_sha3_512;
-extern ERL_NIF_TERM atom_md5;
-extern ERL_NIF_TERM atom_ripemd160;
-#ifdef HAVE_BLAKE2
-extern ERL_NIF_TERM atom_blake2b;
-extern ERL_NIF_TERM atom_blake2s;
-#endif
#ifdef HAS_ENGINE_SUPPORT
-extern ERL_NIF_TERM atom_bad_engine_method;
-extern ERL_NIF_TERM atom_bad_engine_id;
-extern ERL_NIF_TERM atom_ctrl_cmd_failed;
-extern ERL_NIF_TERM atom_engine_init_failed;
-extern ERL_NIF_TERM atom_register_engine_failed;
-extern ERL_NIF_TERM atom_add_engine_failed;
-extern ERL_NIF_TERM atom_remove_engine_failed;
-extern ERL_NIF_TERM atom_engine_method_not_supported;
extern ERL_NIF_TERM atom_engine_method_rsa;
extern ERL_NIF_TERM atom_engine_method_dsa;
diff --git a/lib/crypto/c_src/block.c b/lib/crypto/c_src/block.c
index d88ee8dba7..0a4fd72623 100644
--- a/lib/crypto/c_src/block.c
+++ b/lib/crypto/c_src/block.c
@@ -24,7 +24,7 @@
ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Ivec, Text, IsEncrypt) or (Type, Key, Text, IsEncrypt) */
- struct cipher_type_t *cipherp = NULL;
+ const struct cipher_type_t *cipherp;
const EVP_CIPHER *cipher;
ErlNifBinary key, ivec, text;
EVP_CIPHER_CTX *ctx = NULL;
@@ -41,36 +41,42 @@ ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
goto bad_arg;
if ((cipherp = get_cipher_type(argv[0], key.size)) == NULL)
goto bad_arg;
+ if (cipherp->flags & (NON_EVP_CIPHER | AEAD_CIPHER))
+ goto bad_arg;
if (!enif_inspect_iolist_as_binary(env, argv[argc - 2], &text))
goto bad_arg;
if (text.size > INT_MAX)
goto bad_arg;
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
if ((cipher = cipherp->cipher.p) == NULL)
return enif_raise_exception(env, atom_notsup);
- if (argv[0] == atom_aes_cfb8
- && (key.size == 24 || key.size == 32)) {
- /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
- * Fall back on low level API
- */
- return aes_cfb_8_crypt(env, argc-1, argv+1);
+ if (cipherp->flags & AES_CFBx) {
+ if (argv[0] == atom_aes_cfb8
+ && (key.size == 24 || key.size == 32)) {
+ /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
+ * Fall back on low level API
+ */
+ return aes_cfb_8_crypt(env, argc-1, argv+1);
+ }
+ else if (argv[0] == atom_aes_cfb128
+ && (key.size == 24 || key.size == 32)) {
+ /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
+ * Fall back on low level API
+ */
+ return aes_cfb_128_crypt_nif(env, argc-1, argv+1);
+ }
}
- else if (argv[0] == atom_aes_cfb128
- && (key.size == 24 || key.size == 32)) {
- /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
- * Fall back on low level API
- */
- return aes_cfb_128_crypt_nif(env, argc-1, argv+1);
- }
ivec_size = EVP_CIPHER_iv_length(cipher);
#ifdef HAVE_ECB_IVEC_BUG
- if (argv[0] == atom_aes_ecb || argv[0] == atom_blowfish_ecb ||
- argv[0] == atom_des_ecb)
- ivec_size = 0; /* 0.9.8l returns faulty ivec_size */
+ if (cipherp->flags & ECB_BUG_0_9_8L)
+ ivec_size = 0; /* 0.9.8l returns faulty ivec_size */
#endif
+
if (ivec_size < 0)
goto bad_arg;
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 449e636037..f8e44b228a 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -28,51 +28,122 @@
static struct cipher_type_t cipher_types[] =
{
- {{"rc2_cbc"},
#ifndef OPENSSL_NO_RC2
- {&EVP_rc2_cbc}
+ {{"rc2_cbc"}, {&EVP_rc2_cbc}, 0, NO_FIPS_CIPHER},
#else
- {NULL}
+ {{"rc2_cbc"}, {NULL}, 0, NO_FIPS_CIPHER},
#endif
- ,0},
- {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}, 0},
- {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}, 0},
- {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}, 0},
- {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}, 0},
- {{"des_ede3_cbf"}, /* Misspelled, retained */
-#ifdef HAVE_DES_ede3_cfb_encrypt
- {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
+#ifndef OPENSSL_NO_RC4
+ {{"rc4"}, {&EVP_rc4}, 0, NO_FIPS_CIPHER},
#else
- {NULL}
+ {{"rc4"}, {NULL}, 0, NO_FIPS_CIPHER},
#endif
- ,0},
- {{"des_ede3_cfb"},
+ {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}, 0, NO_FIPS_CIPHER},
+ {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}, 0, NO_FIPS_CIPHER},
+ {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}, 0, NO_FIPS_CIPHER | ECB_BUG_0_9_8L},
+
+ {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}, 0, 0},
+
#ifdef HAVE_DES_ede3_cfb_encrypt
- {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
+ {{"des_ede3_cfb"}, {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}, 0, 0},
+#else
+ {{"des_ede3_cfb"}, {NULL}, 0, 0},
+#endif
+
+ {{"blowfish_cbc"}, {&EVP_bf_cbc}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_cfb64"}, {&EVP_bf_cfb64}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_ofb64"}, {&EVP_bf_ofb}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_ecb"}, {&EVP_bf_ecb}, 0, NO_FIPS_CIPHER | ECB_BUG_0_9_8L},
+
+ {{"aes_cbc"}, {&EVP_aes_128_cbc}, 16, 0},
+ {{"aes_cbc"}, {&EVP_aes_192_cbc}, 24, 0},
+ {{"aes_cbc"}, {&EVP_aes_256_cbc}, 32, 0},
+
+ {{"aes_128_cbc"}, {&EVP_aes_128_cbc}, 16, 0},
+ {{"aes_192_cbc"}, {&EVP_aes_192_cbc}, 24, 0},
+ {{"aes_256_cbc"}, {&EVP_aes_256_cbc}, 32, 0},
+
+ {{"aes_cfb8"}, {&EVP_aes_128_cfb8}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb8"}, {&EVP_aes_192_cfb8}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb8"}, {&EVP_aes_256_cfb8}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
+ {{"aes_cfb128"}, {&EVP_aes_128_cfb128}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb128"}, {&EVP_aes_192_cfb128}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb128"}, {&EVP_aes_256_cfb128}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
+ {{"aes_ecb"}, {&EVP_aes_128_ecb}, 16, ECB_BUG_0_9_8L},
+ {{"aes_ecb"}, {&EVP_aes_192_ecb}, 24, ECB_BUG_0_9_8L},
+ {{"aes_ecb"}, {&EVP_aes_256_ecb}, 32, ECB_BUG_0_9_8L},
+
+#if defined(HAVE_EVP_AES_CTR)
+ {{"aes_128_ctr"}, {&EVP_aes_128_ctr}, 16, 0},
+ {{"aes_192_ctr"}, {&EVP_aes_192_ctr}, 24, 0},
+ {{"aes_256_ctr"}, {&EVP_aes_256_ctr}, 32, 0},
+ {{"aes_ctr"}, {&EVP_aes_128_ctr}, 16, 0},
+ {{"aes_ctr"}, {&EVP_aes_192_ctr}, 24, 0},
+ {{"aes_ctr"}, {&EVP_aes_256_ctr}, 32, 0},
+#else
+ {{"aes_128_ctr"}, {NULL}, 16, AES_CTR_COMPAT},
+ {{"aes_192_ctr"}, {NULL}, 24, AES_CTR_COMPAT},
+ {{"aes_256_ctr"}, {NULL}, 32, AES_CTR_COMPAT},
+ {{"aes_ctr"}, {NULL}, 0, AES_CTR_COMPAT},
+#endif
+
+#if defined(HAVE_CHACHA20)
+ {{"chacha20"}, {&EVP_chacha20}, 32, NO_FIPS_CIPHER},
+#else
+ {{"chacha20"}, {NULL}, 0, NO_FIPS_CIPHER},
+#endif
+
+ /*==== AEAD ciphers ====*/
+#if defined(HAVE_CHACHA20_POLY1305)
+ {{"chacha20_poly1305"}, {&EVP_chacha20_poly1305}, 0, NO_FIPS_CIPHER | AEAD_CIPHER, {{EVP_CTRL_AEAD_SET_IVLEN,EVP_CTRL_AEAD_GET_TAG,EVP_CTRL_AEAD_SET_TAG}}},
+#else
+ {{"chacha20_poly1305"}, {NULL}, 0, NO_FIPS_CIPHER | AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+#if defined(HAVE_GCM)
+ {{"aes_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_128_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_192_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_256_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+#else
+ {{"aes_gcm"}, {NULL}, 0, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_128_gcm"}, {NULL}, 16, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_192_gcm"}, {NULL}, 24, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_256_gcm"}, {NULL}, 32, AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+#if defined(HAVE_CCM)
+ {{"aes_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_128_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_192_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_256_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
#else
- {NULL}
+ {{"aes_ccm"}, {NULL}, 0, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_128_ccm"}, {NULL}, 16, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_192_ccm"}, {NULL}, 24, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_256_ccm"}, {NULL}, 32, AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+ /*==== Specialy handled ciphers, only for inclusion in algorithm's list ====*/
+#ifdef HAVE_AES_IGE
+ {{"aes_ige256"}, {NULL}, 0, NO_FIPS_CIPHER | NON_EVP_CIPHER},
#endif
- ,0},
- {{"blowfish_cbc"}, {&EVP_bf_cbc}, 0},
- {{"blowfish_cfb64"}, {&EVP_bf_cfb64}, 0},
- {{"blowfish_ofb64"}, {&EVP_bf_ofb}, 0},
- {{"blowfish_ecb"}, {&EVP_bf_ecb}, 0},
- {{"aes_cbc"}, {&EVP_aes_128_cbc}, 16},
- {{"aes_cbc"}, {&EVP_aes_192_cbc}, 24},
- {{"aes_cbc"}, {&EVP_aes_256_cbc}, 32},
- {{"aes_cbc128"}, {&EVP_aes_128_cbc}, 0},
- {{"aes_cbc256"}, {&EVP_aes_256_cbc}, 0},
- {{"aes_cfb8"}, {&EVP_aes_128_cfb8}, 0},
- {{"aes_cfb128"}, {&EVP_aes_128_cfb128}, 0},
- {{"aes_ecb"}, {&EVP_aes_128_ecb}, 16},
- {{"aes_ecb"}, {&EVP_aes_192_ecb}, 24},
- {{"aes_ecb"}, {&EVP_aes_256_ecb}, 32},
- {{NULL},{NULL},0}
+
+ /*==== End of list ==== */
+
+ {{NULL},{NULL},0,0}
};
-#ifdef HAVE_EVP_AES_CTR
ErlNifResourceType* evp_cipher_ctx_rtype;
+static size_t num_cipher_types = 0;
+
static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
if (ctx == NULL)
return;
@@ -80,46 +151,79 @@ static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
if (ctx->ctx)
EVP_CIPHER_CTX_free(ctx->ctx);
}
-#endif
int init_cipher_ctx(ErlNifEnv *env) {
-#ifdef HAVE_EVP_AES_CTR
evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_CIPHER_CTX",
(ErlNifResourceDtor*) evp_cipher_ctx_dtor,
ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
NULL);
if (evp_cipher_ctx_rtype == NULL)
goto err;
-#endif
return 1;
-#ifdef HAVE_EVP_AES_CTR
err:
PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'");
return 0;
-#endif
}
void init_cipher_types(ErlNifEnv* env)
{
struct cipher_type_t* p = cipher_types;
+ num_cipher_types = 0;
for (p = cipher_types; p->type.str; p++) {
+ num_cipher_types++;
p->type.atom = enif_make_atom(env, p->type.str);
if (p->cipher.funcp)
p->cipher.p = p->cipher.funcp();
}
p->type.atom = atom_false; /* end marker */
+
+ qsort(cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types);
}
-struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len)
+const struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len)
{
- struct cipher_type_t* p = NULL;
- for (p = cipher_types; p->type.atom != atom_false; p++) {
- if (type == p->type.atom && (!p->key_len || key_len == p->key_len)) {
- return p;
- }
+ struct cipher_type_t key;
+
+ key.type.atom = type;
+ key.key_len = key_len;
+
+ return bsearch(&key, cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types);
+}
+
+
+int cmp_cipher_types(const void *keyp, const void *elemp) {
+ const struct cipher_type_t *key = keyp;
+ const struct cipher_type_t *elem = elemp;
+
+ if (key->type.atom < elem->type.atom) return -1;
+ else if (key->type.atom > elem->type.atom) return 1;
+ else /* key->type.atom == elem->type.atom */
+ if (!elem->key_len || key->key_len == elem->key_len) return 0;
+ else if (key->key_len < elem->key_len) return -1;
+ else return 1;
+}
+
+
+ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env)
+{
+ struct cipher_type_t* p;
+ ERL_NIF_TERM prev, hd;
+
+ hd = enif_make_list(env, 0);
+ prev = atom_undefined;
+
+ for (p = cipher_types; (p->type.atom & (p->type.atom != atom_false)); p++) {
+ if ((prev != p->type.atom) &&
+ ((p->cipher.p != NULL) ||
+ (p->flags & (NON_EVP_CIPHER|AES_CTR_COMPAT)) ) && /* Special handling. Bad indeed... */
+ ! FORBIDDEN_IN_FIPS(p)
+ )
+ hd = enif_make_list_cell(env, p->type.atom, hd);
+ prev = p->type.atom;
}
- return NULL;
+
+ return hd;
}
diff --git a/lib/crypto/c_src/cipher.h b/lib/crypto/c_src/cipher.h
index 3fb27f0ba3..6b43afea99 100644
--- a/lib/crypto/c_src/cipher.h
+++ b/lib/crypto/c_src/cipher.h
@@ -32,19 +32,42 @@ struct cipher_type_t {
const EVP_CIPHER* (*funcp)(void); /* before init, NULL if notsup */
const EVP_CIPHER* p; /* after init, NULL if notsup */
}cipher;
- const size_t key_len; /* != 0 to also match on key_len */
+ size_t key_len; /* != 0 to also match on key_len */
+ unsigned flags;
+ union {
+ struct aead_ctrl {int ctx_ctrl_set_ivlen, ctx_ctrl_get_tag, ctx_ctrl_set_tag;} aead;
+ } extra;
};
-#ifdef HAVE_EVP_AES_CTR
+/* masks in the flags field if cipher_type_t */
+#define NO_FIPS_CIPHER 1
+#define AES_CFBx 2
+#define ECB_BUG_0_9_8L 4
+#define AEAD_CIPHER 8
+#define NON_EVP_CIPHER 16
+#define AES_CTR_COMPAT 32
+
+
+#ifdef FIPS_SUPPORT
+/* May have FIPS support, must check dynamically if it is enabled */
+# define FORBIDDEN_IN_FIPS(P) (((P)->flags & NO_FIPS_CIPHER) && FIPS_mode())
+#else
+/* No FIPS support since the symbol FIPS_SUPPORT is undefined */
+# define FORBIDDEN_IN_FIPS(P) 0
+#endif
+
extern ErlNifResourceType* evp_cipher_ctx_rtype;
struct evp_cipher_ctx {
EVP_CIPHER_CTX* ctx;
};
-#endif
int init_cipher_ctx(ErlNifEnv *env);
void init_cipher_types(ErlNifEnv* env);
-struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len);
+const struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len);
+
+int cmp_cipher_types(const void *keyp, const void *elemp);
+
+ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env);
#endif /* E_CIPHER_H__ */
diff --git a/lib/crypto/c_src/cmac.c b/lib/crypto/c_src/cmac.c
index 196b7476e3..49e67ccf29 100644
--- a/lib/crypto/c_src/cmac.c
+++ b/lib/crypto/c_src/cmac.c
@@ -24,7 +24,7 @@
ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Data) */
#if defined(HAVE_CMAC)
- struct cipher_type_t *cipherp = NULL;
+ const struct cipher_type_t *cipherp;
const EVP_CIPHER *cipher;
CMAC_CTX *ctx = NULL;
ErlNifBinary key;
@@ -40,9 +40,13 @@ ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto bad_arg;
if ((cipherp = get_cipher_type(argv[0], key.size)) == NULL)
goto bad_arg;
+ if (cipherp->flags & (NON_EVP_CIPHER | AEAD_CIPHER))
+ goto bad_arg;
if (!enif_inspect_iolist_as_binary(env, argv[2], &data))
goto bad_arg;
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
if ((cipher = cipherp->cipher.p) == NULL)
return enif_raise_exception(env, atom_notsup);
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 03f11c9059..06439c34b2 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -28,6 +28,7 @@
#include "aead.h"
#include "aes.h"
#include "algorithms.h"
+#include "api_ng.h"
#include "block.h"
#include "bn.h"
#include "chacha20.h"
@@ -83,6 +84,9 @@ static ErlNifFunc nif_funcs[] = {
{"aes_ctr_stream_init", 2, aes_ctr_stream_init, 0},
{"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt, 0},
{"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt, 0},
+ {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
+ {"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0},
+ {"ng_crypto_update_nif", 3, ng_crypto_update_nif, 0},
{"strong_rand_bytes_nif", 1, strong_rand_bytes_nif, 0},
{"strong_rand_range_nif", 1, strong_rand_range_nif, 0},
{"rand_uniform_nif", 2, rand_uniform_nif, 0},
@@ -132,7 +136,6 @@ static ErlNifFunc nif_funcs[] = {
{"engine_get_id_nif", 1, engine_get_id_nif, 0},
{"engine_get_name_nif", 1, engine_get_name_nif, 0},
{"engine_get_all_methods_nif", 0, engine_get_all_methods_nif, 0}
-
};
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
diff --git a/lib/crypto/c_src/engine.c b/lib/crypto/c_src/engine.c
index 6692ccd734..7ffbb9e70d 100644
--- a/lib/crypto/c_src/engine.c
+++ b/lib/crypto/c_src/engine.c
@@ -26,6 +26,9 @@ struct engine_ctx {
char *id;
};
+#define ERROR_Term(Env, ReasonTerm) enif_make_tuple2((Env), atom_error, (ReasonTerm))
+#define ERROR_Atom(Env, ReasonString) ERROR_Term((Env), enif_make_atom((Env),(ReasonString)))
+
static ErlNifResourceType* engine_ctx_rtype;
static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i);
@@ -136,7 +139,7 @@ ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
if ((engine = ENGINE_by_id(engine_id)) == NULL) {
PRINTF_ERR0("engine_by_id_nif Leaved: {error, bad_engine_id}");
- ret = enif_make_tuple2(env, atom_error, atom_bad_engine_id);
+ ret = ERROR_Atom(env, "bad_engine_id");
goto done;
}
@@ -179,7 +182,7 @@ ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
goto bad_arg;
if (!ENGINE_init(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_engine_init_failed);
+ return ERROR_Atom(env, "engine_init_failed");
return atom_ok;
@@ -306,7 +309,7 @@ ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF
goto done;
cmd_failed:
- ret = enif_make_tuple2(env, atom_error, atom_ctrl_cmd_failed);
+ ret = ERROR_Atom(env, "ctrl_cmd_failed");
done:
if (cmds_loaded) {
@@ -344,7 +347,7 @@ ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
failed:
- return enif_make_tuple2(env, atom_error, atom_add_engine_failed);
+ return ERROR_Atom(env, "add_engine_failed");
#else
return atom_notsup;
@@ -371,7 +374,7 @@ ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return enif_make_badarg(env);
failed:
- return enif_make_tuple2(env, atom_error, atom_remove_engine_failed);
+ return ERROR_Atom(env, "remove_engine_failed");
#else
return atom_notsup;
#endif
@@ -466,7 +469,7 @@ ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
break;
#endif
default:
- return enif_make_tuple2(env, atom_error, atom_engine_method_not_supported);
+ return ERROR_Atom(env, "engine_method_not_supported");
}
return atom_ok;
@@ -475,7 +478,7 @@ ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return enif_make_badarg(env);
failed:
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
+ return ERROR_Atom(env, "register_engine_failed");
#else
return atom_notsup;
diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c
index 4e76f817bc..567e8df08a 100644
--- a/lib/crypto/c_src/pkey.c
+++ b/lib/crypto/c_src/pkey.c
@@ -110,7 +110,7 @@ static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm,
goto bad_arg;
if (tpl_terms[0] != atom_digest)
goto bad_arg;
- if (!enif_inspect_binary(env, tpl_terms[1], &tbs_bin))
+ if (!enif_inspect_iolist_as_binary(env, tpl_terms[1], &tbs_bin))
goto bad_arg;
if (tbs_bin.size > INT_MAX)
goto bad_arg;
@@ -123,14 +123,14 @@ static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm,
tbs = tbs_bin.data;
tbslen = tbs_bin.size;
} else if (md == NULL) {
- if (!enif_inspect_binary(env, data, &tbs_bin))
+ if (!enif_inspect_iolist_as_binary(env, data, &tbs_bin))
goto bad_arg;
/* md == NULL, that is no hashing because DigestType argument was atom_none */
tbs = tbs_bin.data;
tbslen = tbs_bin.size;
} else {
- if (!enif_inspect_binary(env, data, &tbs_bin))
+ if (!enif_inspect_iolist_as_binary(env, data, &tbs_bin))
goto bad_arg;
/* We have the cleartext in tbs_bin and the hash algo info in md */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index e0794a080e..83e10c4c78 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -193,10 +193,12 @@
<datatype_title>Ciphers</datatype_title>
<datatype>
<name name="stream_cipher"/>
+ <name name="stream_cipher_iv"/>
+ <name name="stream_cipher_no_iv"/>
<desc>
<p>Stream ciphers for
- <seealso marker="#stream_encrypt-2">stream_encrypt/2</seealso> and
- <seealso marker="#stream_decrypt-2">stream_decrypt/2</seealso> .
+ <seealso marker="#stream_init-3">stream_init/3</seealso> and
+ <seealso marker="#stream_init-2">stream_init/2</seealso> .
</p>
</desc>
</datatype>
@@ -214,6 +216,18 @@
</datatype>
<datatype>
+ <name name="alias_cfb"/>
+ <name name="alias_cbc"/>
+ <desc>
+ <p>Names that are replaced by more common names. They may deprecated in futer releases.</p>
+ <p><c>des3_cbc</c> and <c>des_ede3</c> should be replaced by <c>des_ede3_cbc</c></p>
+ <p><c>des_ede3_cbf</c>, <c>des3_cbf</c> and <c>des3_cfb</c> should be replaced by <c>des_ede3_cfb</c>.</p>
+ <p><c>aes_cbc128</c> should be replaced by <c>aes_128_cbc</c>.</p>
+ <p><c>aes_cbc256</c> should be replaced by <c>aes_256_cbc</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
<name name="block_cipher_without_iv"/>
<name name="ecb_cipher"/>
<desc>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index de8cfac9a2..fe8390c5b8 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -47,6 +47,19 @@
-export([privkey_to_pubkey/2]).
-export([ec_curve/1, ec_curves/0]).
-export([rand_seed/1]).
+
+%% Experiment
+-export([crypto_init/4,
+ crypto_update/2, crypto_update/3,
+ %% Emulates old api:
+ crypto_stream_init/2, crypto_stream_init/3,
+ crypto_stream_encrypt/2,
+ crypto_stream_decrypt/2,
+ crypto_block_encrypt/3, crypto_block_encrypt/4,
+ crypto_block_decrypt/3, crypto_block_decrypt/4
+ ]).
+
+
%% Engine
-export([
engine_get_all_methods/0,
@@ -89,7 +102,8 @@
-export_type([
stream_state/0,
hmac_state/0,
- hash_state/0
+ hash_state/0,
+ crypto_state/0
]).
%% Private. For tests.
@@ -261,17 +275,36 @@
%%%
-type block_cipher_with_iv() :: cbc_cipher()
| cfb_cipher()
- | aes_cbc128
- | aes_cbc256
| aes_ige256
| blowfish_ofb64
- | des3_cbf % cfb misspelled
- | des_ede3
| rc2_cbc .
--type cbc_cipher() :: des_cbc | des3_cbc | aes_cbc | blowfish_cbc .
--type aead_cipher() :: aes_gcm | aes_ccm | chacha20_poly1305 .
--type cfb_cipher() :: aes_cfb128 | aes_cfb8 | blowfish_cfb64 | des3_cfb | des_cfb .
+-type cbc_cipher() :: des_cbc | des_ede3_cbc
+ | blowfish_cbc
+ | aes_cbc | aes_128_cbc | aes_192_cbc | aes_256_cbc
+ | alias_cbc() .
+-type alias_cbc() :: des3_cbc | des_ede3
+ | aes_cbc128 | aes_cbc256 .
+
+-type aead_cipher() :: aes_gcm
+ | aes_128_gcm
+ | aes_192_gcm
+ | aes_256_gcm
+ | aes_ccm
+ | aes_128_ccm
+ | aes_192_ccm
+ | aes_256_ccm
+ | chacha20_poly1305 .
+
+-type cfb_cipher() :: aes_cfb8
+ | aes_cfb128
+ | blowfish_cfb64
+ | des_cfb
+ | des_ede3_cfb
+ | alias_cfb() .
+-type alias_cfb() :: des_ede3_cbf | des3_cbf
+ | des3_cfb .
+
-type block_cipher_without_iv() :: ecb_cipher() .
-type ecb_cipher() :: des_ecb | blowfish_ecb | aes_ecb .
@@ -342,7 +375,7 @@ stop() ->
supports()->
{Hashs, PubKeys, Ciphers, Macs, Curves, RsaOpts} = algorithms(),
[{hashs, Hashs},
- {ciphers, Ciphers},
+ {ciphers, prepend_cipher_aliases(Ciphers)},
{public_keys, PubKeys},
{macs, Macs},
{curves, Curves},
@@ -473,7 +506,7 @@ hmac_final_n(Context, HashLen) ->
Data :: iodata(),
Mac :: binary().
cmac(Type, Key, Data) ->
- notsup_to_error(cmac_nif(Type, Key, Data)).
+ notsup_to_error(cmac_nif(alias(Type), Key, Data)).
-spec cmac(Type, Key, Data, MacLength) ->
Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
@@ -481,8 +514,9 @@ cmac(Type, Key, Data) ->
Data :: iodata(),
MacLength :: integer(),
Mac :: binary().
+
cmac(Type, Key, Data, MacLength) ->
- erlang:binary_part(cmac(Type, Key, Data), 0, MacLength).
+ erlang:binary_part(cmac(alias(Type), Key, Data), 0, MacLength).
%%%---- POLY1305
@@ -499,91 +533,80 @@ poly1305(Key, Data) ->
%%%---- Block ciphers
+%%%----------------------------------------------------------------
-spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) -> binary();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata()}) ->
{binary(), binary()};
(aes_gcm | aes_ccm, Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata(), TagLength::1..16}) ->
{binary(), binary()}.
-block_encrypt(Type, Key, Ivec, PlainText) when Type =:= des_cbc;
- Type =:= des_cfb;
- Type =:= blowfish_cbc;
- Type =:= blowfish_cfb64;
- Type =:= blowfish_ofb64;
- Type =:= aes_cbc128;
- Type =:= aes_cfb8;
- Type =:= aes_cfb128;
- Type =:= aes_cbc256;
- Type =:= aes_cbc;
- Type =:= rc2_cbc ->
- block_crypt_nif(Type, Key, Ivec, PlainText, true);
-block_encrypt(Type, Key0, Ivec, PlainText) when Type =:= des3_cbc;
- Type =:= des_ede3 ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbc, Key, Ivec, PlainText, true);
-block_encrypt(des3_cbf, Key0, Ivec, PlainText) -> % cfb misspelled
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbf, Key, Ivec, PlainText, true);
-block_encrypt(des3_cfb, Key0, Ivec, PlainText) ->
+
+block_encrypt(Type, Key, Ivec, Data) ->
+ do_block_encrypt(alias(Type), Key, Ivec, Data).
+
+do_block_encrypt(Type, Key0, Ivec, Data) when Type =:= des_ede3_cbc;
+ Type =:= des_ede3_cfb ->
Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cfb, Key, Ivec, PlainText, true);
-block_encrypt(aes_ige256, Key, Ivec, PlainText) ->
+ block_crypt_nif(Type, Key, Ivec, Data, true);
+
+do_block_encrypt(Type, Key, Ivec, PlainText) when Type =:= aes_ige256 ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, PlainText, true));
-block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= aes_gcm;
- Type =:= aes_ccm ->
- aead_encrypt(Type, Key, Ivec, AAD, PlainText);
-block_encrypt(Type, Key, Ivec, {AAD, PlainText, TagLength}) when Type =:= aes_gcm;
- Type =:= aes_ccm ->
- aead_encrypt(Type, Key, Ivec, AAD, PlainText, TagLength);
-block_encrypt(chacha20_poly1305=Type, Key, Ivec, {AAD, PlainText}) ->
- aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16).
+do_block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= chacha20_poly1305 ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16);
+do_block_encrypt(Type, Key, Ivec, Data) when Type =:= aes_gcm;
+ Type =:= aes_ccm ->
+ case Data of
+ {AAD, PlainText} ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText);
+ {AAD, PlainText, TagLength} ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText, TagLength)
+ end;
+
+do_block_encrypt(Type, Key, Ivec, PlainText) ->
+ block_crypt_nif(Type, Key, Ivec, PlainText, true).
+
+
+
+-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary().
+
+block_encrypt(Type, Key, PlainText) ->
+ block_crypt_nif(alias(Type), Key, PlainText, true).
+
+%%%----------------------------------------------------------------
+%%%----------------------------------------------------------------
-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> binary();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(),
{AAD::binary(), Data::iodata(), Tag::binary()}) -> binary() | error.
-block_decrypt(Type, Key, Ivec, Data) when Type =:= des_cbc;
- Type =:= des_cfb;
- Type =:= blowfish_cbc;
- Type =:= blowfish_cfb64;
- Type =:= blowfish_ofb64;
- Type =:= aes_cbc;
- Type =:= aes_cbc128;
- Type =:= aes_cfb8;
- Type =:= aes_cfb128;
- Type =:= aes_cbc256;
- Type =:= rc2_cbc ->
- block_crypt_nif(Type, Key, Ivec, Data, false);
-block_decrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
- Type =:= des_ede3 ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbc, Key, Ivec, Data, false);
-block_decrypt(des3_cbf, Key0, Ivec, Data) -> % cfb misspelled
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, false);
-block_decrypt(des3_cfb, Key0, Ivec, Data) ->
+
+block_decrypt(Type, Key, Ivec, Data) ->
+ do_block_decrypt(alias(Type), Key, Ivec, Data).
+
+do_block_decrypt(Type, Key0, Ivec, Data) when Type =:= des_ede3_cbc;
+ Type =:= des_ede3_cfb ->
Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, false);
-block_decrypt(aes_ige256, Key, Ivec, Data) ->
+ block_crypt_nif(Type, Key, Ivec, Data, false);
+
+do_block_decrypt(aes_ige256, Key, Ivec, Data) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
-block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm;
+
+do_block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm;
Type =:= aes_ccm;
Type =:= chacha20_poly1305 ->
- aead_decrypt(Type, Key, Ivec, AAD, Data, Tag).
-
+ aead_decrypt(Type, Key, Ivec, AAD, Data, Tag);
--spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary().
+do_block_decrypt(Type, Key, Ivec, Data) ->
+ block_crypt_nif(Type, Key, Ivec, Data, false).
-block_encrypt(Type, Key, PlainText) ->
- block_crypt_nif(Type, Key, PlainText, true).
-spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) -> binary().
block_decrypt(Type, Key, Data) ->
- block_crypt_nif(Type, Key, Data, false).
-
+ block_crypt_nif(alias(Type), Key, Data, false).
+%%%----------------------------------------------------------------
-spec next_iv(Type:: cbc_cipher(), Data) -> NextIVec when % Type :: cbc_cipher(), %des_cbc | des3_cbc | aes_cbc | aes_ige,
Data :: iodata(),
NextIVec :: binary().
@@ -614,18 +637,30 @@ next_iv(Type, Data, _Ivec) ->
-opaque stream_state() :: {stream_cipher(), reference()}.
--type stream_cipher() :: rc4 | aes_ctr | chacha20 .
+-type stream_cipher() :: stream_cipher_iv() | stream_cipher_no_iv() .
+-type stream_cipher_no_iv() :: rc4 .
+-type stream_cipher_iv() :: aes_ctr
+ | aes_128_ctr
+ | aes_192_ctr
+ | aes_256_ctr
+ | chacha20 .
--spec stream_init(Type, Key, IVec) -> State when Type :: aes_ctr | chacha20,
+-spec stream_init(Type, Key, IVec) -> State when Type :: stream_cipher_iv(),
Key :: iodata(),
IVec :: binary(),
State :: stream_state() .
stream_init(aes_ctr, Key, Ivec) ->
{aes_ctr, aes_ctr_stream_init(Key, Ivec)};
+stream_init(aes_128_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)};
+stream_init(aes_192_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)};
+stream_init(aes_256_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)};
stream_init(chacha20, Key, Ivec) ->
{chacha20, chacha20_stream_init(Key,Ivec)}.
--spec stream_init(Type, Key) -> State when Type :: rc4,
+-spec stream_init(Type, Key) -> State when Type :: stream_cipher_no_iv(),
Key :: iodata(),
State :: stream_state() .
stream_init(rc4, Key) ->
@@ -932,7 +967,7 @@ rand_seed_nif(_Seed) -> ?nif_stub.
DigestType :: rsa_digest_type()
| dss_digest_type()
| ecdsa_digest_type(),
- Msg :: binary() | {digest,binary()},
+ Msg :: iodata() | {digest,iodata()},
Key :: rsa_private()
| dss_private()
| [ecdsa_private() | ecdsa_params()]
@@ -951,7 +986,7 @@ sign(Algorithm, Type, Data, Key) ->
| dss_digest_type()
| ecdsa_digest_type()
| none,
- Msg :: binary() | {digest,binary()},
+ Msg :: iodata() | {digest,iodata()},
Key :: rsa_private()
| dss_private()
| [ecdsa_private() | ecdsa_params()]
@@ -980,7 +1015,7 @@ pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
| dss_digest_type()
| ecdsa_digest_type()
| none,
- Msg :: binary() | {digest,binary()},
+ Msg :: iodata() | {digest,iodata()},
Signature :: binary(),
Key :: rsa_public()
| dss_public()
@@ -998,7 +1033,7 @@ verify(Algorithm, Type, Data, Signature, Key) ->
DigestType :: rsa_digest_type()
| dss_digest_type()
| ecdsa_digest_type(),
- Msg :: binary() | {digest,binary()},
+ Msg :: iodata() | {digest,iodata()},
Signature :: binary(),
Key :: rsa_public()
| dss_public()
@@ -2180,3 +2215,178 @@ check_otp_test_engine(LibDir) ->
{error, notexist}
end
end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%
+%%% Experimental NG
+%%%
+
+%%% -> {ok,State::ref()} | {error,Reason}
+
+-opaque crypto_state() :: reference() | {any(),any(),any(),any()}.
+
+
+%%%----------------------------------------------------------------
+%%%
+%%% Create and initialize a new state for encryption or decryption
+%%%
+
+-spec crypto_init(Cipher, Key, IV, EncryptFlag) -> {ok,State} | {error,term()} | undefined
+ when Cipher :: stream_cipher()
+ | block_cipher_with_iv()
+ | block_cipher_without_iv() ,
+ Key :: iodata(),
+ IV :: binary(),
+ EncryptFlag :: boolean() | undefined,
+ State :: crypto_state() .
+
+crypto_init(Cipher, Key, IV, EncryptFlag) when is_atom(Cipher),
+ is_binary(Key),
+ is_binary(IV),
+ is_atom(EncryptFlag) ->
+ case ng_crypto_init_nif(alias(Cipher), Key, IV, EncryptFlag) of
+ {error,Error} ->
+ {error,Error};
+ undefined -> % For compatibility function crypto_stream_init/3
+ undefined;
+ Ref when is_reference(Ref) ->
+ {ok,Ref};
+ State when is_tuple(State),
+ size(State)==4 ->
+ {ok,State} % compatibility with old cryptolibs < 1.0.1
+ end.
+
+
+%%%----------------------------------------------------------------
+%%%
+%%% Encrypt/decrypt a sequence of bytes. The sum of the sizes
+%%% of all blocks must be an integer multiple of the crypto's
+%%% blocksize.
+%%%
+
+-spec crypto_update(State, Data) -> {ok,Result} | {error,term()}
+ when State :: crypto_state(),
+ Data :: iodata(),
+ Result :: binary() | {crypto_state(),binary()}.
+crypto_update(State, Data) ->
+ mk_ret(ng_crypto_update_nif(State, Data)).
+
+%%%----------------------------------------------------------------
+%%%
+%%% Encrypt/decrypt a sequence of bytes but change the IV first.
+%%% Not applicable for all modes.
+%%%
+
+-spec crypto_update(State, Data, IV) -> {ok,Result} | {error,term()}
+ when State :: crypto_state(),
+ Data :: iodata(),
+ IV :: binary(),
+ Result :: binary() | {crypto_state(),binary()}.
+crypto_update(State, Data, IV) ->
+ mk_ret(ng_crypto_update_nif(State, Data, IV)).
+
+%%%----------------------------------------------------------------
+%%% Helpers
+mk_ret(R) -> mk_ret(R, []).
+
+mk_ret({error,Error}, _) ->
+ {error,Error};
+mk_ret(Bin, Acc) when is_binary(Bin) ->
+ {ok, iolist_to_binary(lists:reverse([Bin|Acc]))};
+mk_ret({State1,Bin}, Acc) when is_tuple(State1),
+ size(State1) == 4,
+ is_binary(Bin) ->
+ %% compatibility with old cryptolibs < 1.0.1
+ {ok, {State1, iolist_to_binary(lists:reverse([Bin|Acc]))}}.
+
+%%%----------------------------------------------------------------
+%%% NIFs
+ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlg) -> ?nif_stub.
+ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
+ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
+
+%%%================================================================
+%%% Compatibility functions to be called by "old" api functions.
+
+%%%--------------------------------
+%%%---- block encrypt/decrypt
+crypto_block_encrypt(Cipher, Key, Data) -> crypto_block_encrypt(Cipher, Key, <<>>, Data).
+crypto_block_decrypt(Cipher, Key, Data) -> crypto_block_decrypt(Cipher, Key, <<>>, Data).
+
+crypto_block_encrypt(Cipher, Key, Ivec, Data) -> crypto_block(Cipher, Key, Ivec, Data, true).
+crypto_block_decrypt(Cipher, Key, Ivec, Data) -> crypto_block(Cipher, Key, Ivec, Data, false).
+
+%% AEAD: use old funcs
+
+%%%---- helper
+crypto_block(Cipher, Key, IV, Data, EncryptFlag) ->
+ case crypto_init(Cipher, iolist_to_binary(Key), iolist_to_binary(IV), EncryptFlag) of
+ {ok, Ref} ->
+ case crypto_update(Ref, Data) of
+ {ok, {_,Bin}} when is_binary(Bin) -> Bin;
+ {ok, Bin} when is_binary(Bin) -> Bin;
+ {error,_} -> error(badarg)
+ end;
+
+ {error,_} -> error(badarg)
+ end.
+
+%%%--------------------------------
+%%%---- stream init, encrypt/decrypt
+
+crypto_stream_init(Cipher, Key) ->
+ crypto_stream_init(Cipher, Key, <<>>).
+
+crypto_stream_init(Cipher, Key0, IV0) ->
+ Key = iolist_to_binary(Key0),
+ IV = iolist_to_binary(IV0),
+ %% First check the argumensts:
+ case crypto_init(Cipher, Key, IV, undefined) of
+ undefined ->
+ {Cipher, {Key, IV}};
+ {error,_} ->
+ {error,badarg}
+ end.
+
+crypto_stream_encrypt(State, PlainText) ->
+ crypto_stream_emulate(State, PlainText, true).
+
+crypto_stream_decrypt(State, CryptoText) ->
+ crypto_stream_emulate(State, CryptoText, false).
+
+
+%%%---- helper
+crypto_stream_emulate({Cipher,{Key,IV}}, Data, EncryptFlag) ->
+ case crypto_init(Cipher, Key, IV, EncryptFlag) of
+ {ok,State} ->
+ crypto_stream_emulate({Cipher,State}, Data, EncryptFlag);
+ {error,_} ->
+ error(badarg)
+ end;
+crypto_stream_emulate({Cipher,State}, Data, _) ->
+ case crypto_update(State, Data) of
+ {ok, {State1,Bin}} when is_binary(Bin) -> {{Cipher,State1},Bin};
+ {ok,Bin} when is_binary(Bin) -> {{Cipher,State},Bin};
+ {error,_} -> error(badarg)
+ end.
+
+
+%%%================================================================
+
+prepend_cipher_aliases(L) ->
+ [des3_cbc, des_ede3, des_ede3_cbf, des3_cbf, des3_cfb, aes_cbc128, aes_cbc256 | L].
+
+
+%%%---- des_ede3_cbc
+alias(des3_cbc) -> des_ede3_cbc;
+alias(des_ede3) -> des_ede3_cbc;
+%%%---- des_ede3_cfb
+alias(des_ede3_cbf) -> des_ede3_cfb;
+alias(des3_cbf) -> des_ede3_cfb;
+alias(des3_cfb) -> des_ede3_cfb;
+%%%---- aes_*_cbc
+alias(aes_cbc128) -> aes_128_cbc;
+alias(aes_cbc256) -> aes_256_cbc;
+
+alias(Alg) -> Alg.