aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2019-02-22 19:06:34 +0100
committerHans Nilsson <[email protected]>2019-03-19 12:45:54 +0100
commit26754483d39dab9ab09f69fcecb89ab1fb5135bd (patch)
treeb6cd8e0c8b68366958739f1b42407d89dac690b7
parentfcc89ded7f5cb5f81533883c30e7daa89195970d (diff)
downloadotp-26754483d39dab9ab09f69fcecb89ab1fb5135bd.tar.gz
otp-26754483d39dab9ab09f69fcecb89ab1fb5135bd.tar.bz2
otp-26754483d39dab9ab09f69fcecb89ab1fb5135bd.zip
crypto: Implement crypto one-shot
Also: Compatibility functions for aes_ctr in historic crypto libs
-rw-r--r--lib/crypto/c_src/api_ng.c432
-rw-r--r--lib/crypto/c_src/api_ng.h1
-rw-r--r--lib/crypto/c_src/cipher.c9
-rw-r--r--lib/crypto/c_src/cipher.h4
-rw-r--r--lib/crypto/c_src/crypto.c2
-rw-r--r--lib/crypto/src/crypto.erl106
6 files changed, 342 insertions, 212 deletions
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index f24aded748..c3f5ee0bea 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -29,6 +29,7 @@
*
*/
ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_one_shot(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -36,186 +37,367 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
#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)
+
+#ifdef HAVE_ECB_IVEC_BUG
+ /* <= 0.9.8l returns faulty ivec length */
+# define GET_IV_LEN(Ciph) ((Ciph)->flags & ECB_BUG_0_9_8L) ? 0 : EVP_CIPHER_iv_length((Ciph)->cipher.p)
+#else
+# define GET_IV_LEN(Ciph) EVP_CIPHER_iv_length((Ciph)->cipher.p)
+#endif
+
+/*************************************************************************/
+/* Get the arguments for the initialization of the EVP_CIPHER_CTX. Check */
+/* them and initialize that context. */
+/*************************************************************************/
+static int get_init_args(ErlNifEnv* env,
+ struct evp_cipher_ctx *ctx_res,
+ const ERL_NIF_TERM cipher_arg,
+ const ERL_NIF_TERM key_arg,
+ const ERL_NIF_TERM ivec_arg,
+ const ERL_NIF_TERM encflg_arg,
+ const struct cipher_type_t **cipherp,
+ ERL_NIF_TERM *return_term)
+{
+ int ivec_len;
+ ErlNifBinary key_bin;
+ ErlNifBinary ivec_bin;
+ int encflg;
+
+ ctx_res->ctx = NULL; /* For testing if *ctx should be freed after errors */
+
+ /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
+ if (encflg_arg == atom_true)
+ encflg = 1;
+ else if (encflg_arg == atom_false)
+ encflg = 0;
+ else if (encflg_arg == atom_undefined)
/* For compat funcs in crypto.erl */
- enc = -1;
+ encflg = -1;
else
- return ERROR_Str(env, "Bad enc flag");
-
- if (!enif_inspect_binary(env, argv[1], &key_bin))
- return ERROR_Str(env, "Bad key");
+ {
+ *return_term = ERROR_Str(env, "Bad enc flag");
+ goto err;
+ }
- if (!(cipherp = get_cipher_type(argv[0], key_bin.size)))
- return ERROR_Str(env, "Unknown cipher or bad key size");
+ /* Fetch the key */
+ if (!enif_inspect_iolist_as_binary(env, key_arg, &key_bin))
+ {
+ *return_term = ERROR_Str(env, "Bad key");
+ goto err;
+ }
- if (FORBIDDEN_IN_FIPS(cipherp))
- return enif_raise_exception(env, atom_notsup);
+ /* Fetch cipher type */
+ if (!enif_is_atom(env, cipher_arg))
+ {
+ *return_term = ERROR_Str(env, "Cipher id is not an atom");
+ goto err;
+ }
- if (enc == -1)
- return atom_undefined;
+ if (!(*cipherp = get_cipher_type(cipher_arg, key_bin.size)))
+ {
+ *return_term = ERROR_Str(env, "Unknown cipher or bad key size for the cipher");
+ goto err;
+ }
- if (!(cipher = cipherp->cipher.p)) {
+ if (FORBIDDEN_IN_FIPS(*cipherp))
+ {
+ *return_term = enif_raise_exception(env, atom_notsup);
+ goto err;
+ }
+
+ /* Fetch IV */
#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);
- }
+ /* This is code for OpenSSL 0.9.8. Therefore we could accept some ineficient code */
+ ctx_res->env = NULL;
+ ctx_res->state = atom_undefined;
-#ifdef HAVE_ECB_IVEC_BUG
- if (cipherp->flags & ECB_BUG_0_9_8L)
- iv_len = 0; /* <= 0.9.8l returns faulty ivec length */
+ if (!((*cipherp)->cipher.p) && (*cipherp)->flags & AES_CTR_COMPAT)
+ ivec_len = 16;
else
#endif
- iv_len = EVP_CIPHER_iv_length(cipher);
+ ivec_len = GET_IV_LEN(*cipherp);
+
+ if (ivec_len) {
+ if (!enif_inspect_iolist_as_binary(env, ivec_arg, &ivec_bin))
+ {
+ *return_term = ERROR_Str(env, "Bad iv type");
+ goto err;
+ }
+
+ if (ivec_len != ivec_bin.size)
+ {
+ *return_term = ERROR_Str(env, "Bad iv size");
+ goto err;
+ }
+ }
- if (iv_len) {
- if (!enif_inspect_binary(env, argv[2], &ivec_bin))
- return ERROR_Str(env, "Bad iv type");
+ if (!((*cipherp)->cipher.p))
+ {
+#if !defined(HAVE_EVP_AES_CTR)
+ if ((*cipherp)->flags & AES_CTR_COMPAT)
+ {
+ ERL_NIF_TERM ecount_bin;
+ unsigned char *outp;
+ if ((outp = enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin)) == NULL) {
+ *return_term = ERROR_Str(env, "Can't allocate ecount_bin");
+ goto err;
+ }
+ memset(outp, 0, AES_BLOCK_SIZE);
+
+ ctx_res->env = enif_alloc_env();
+ if (!ctx_res->env) {
+ *return_term = ERROR_Str(env, "Can't allocate env");
+ goto err;
+ }
+ ctx_res->state =
+ enif_make_copy(ctx_res->env,
+ enif_make_tuple4(env, key_arg, ivec_arg, ecount_bin, enif_make_int(env, 0)));
+ goto success;
+ }
+#endif
+ *return_term = enif_raise_exception(env, atom_notsup);
+ goto err;
+ }
- if (iv_len != ivec_bin.size)
- return ERROR_Str(env, "Bad iv size");
+ if (encflg == -1)
+ {
+ *return_term = atom_undefined;
+ goto err; // Yes...
+ }
- iv = ivec_bin.data;
- }
+ /* Initialize the EVP_CIPHER_CTX */
- if ((ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL)
- return ERROR_Str(env, "Can't allocate resource");
+ ctx_res->ctx = EVP_CIPHER_CTX_new();
+ if (! ctx_res->ctx)
+ {
+ *return_term = ERROR_Str(env, "Can't allocate context");
+ goto err;
+ }
- ctx->ctx = EVP_CIPHER_CTX_new();
- if (! ctx->ctx)
- return ERROR_Str(env, "Can't allocate context");
+ if (!EVP_CipherInit_ex(ctx_res->ctx, (*cipherp)->cipher.p, NULL, NULL, NULL, encflg))
+ {
+ *return_term = ERROR_Str(env, "Can't initialize context, step 1");
+ goto err;
+ }
- 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_res->ctx, (int)key_bin.size))
+ {
+ *return_term = ERROR_Str(env, "Can't initialize context, key_length");
+ goto err;
+ }
- 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 (EVP_CIPHER_type((*cipherp)->cipher.p) == NID_rc2_cbc) {
if (key_bin.size > INT_MAX / 8) {
- enif_release_resource(ctx);
- return ERROR_Str(env, "To large rc2_cbc key");
+ *return_term = ERROR_Str(env, "To large rc2_cbc key");
+ goto err;
}
- 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_CIPHER_CTX_ctrl(ctx_res->ctx, EVP_CTRL_SET_RC2_KEY_BITS, (int)key_bin.size * 8, NULL)) {
+ *return_term = ERROR_Str(env, "ctrl rc2_cbc key");
+ goto err;
}
}
- 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");
+ if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, ivec_bin.data, encflg)) {
+ *return_term = ERROR_Str(env, "Can't initialize key and/or iv");
+ goto err;
}
- EVP_CIPHER_CTX_set_padding(ctx->ctx, 0);
-
- ret = enif_make_resource(env, ctx);
- enif_release_resource(ctx);
- return ret;
-}
+ EVP_CIPHER_CTX_set_padding(ctx_res->ctx, 0);
-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;
+ *return_term = atom_ok;
#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]);
- }
+ success:
#endif
+ return 1;
- 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");
+ err:
+ if (ctx_res->ctx) EVP_CIPHER_CTX_free(ctx_res->ctx);
+ return 0;
+}
+
+/*************************************************************************/
+/* Get the arguments for the EVP_CipherUpdate function, and call it. */
+/*************************************************************************/
+
+static int get_update_args(ErlNifEnv* env,
+ struct evp_cipher_ctx *ctx_res,
+ const ERL_NIF_TERM indata_arg,
+ ERL_NIF_TERM *return_term)
+{
+ ErlNifBinary in_data_bin, out_data_bin;
+ int out_len, block_size;
+
+ if (!enif_inspect_binary(env, indata_arg, &in_data_bin) )
+ {
+ *return_term = ERROR_Str(env, "Bad 2:nd arg");
+ goto err;
+ }
- /* arg[1] was checked by the caller */
ASSERT(in_data_bin.size =< INT_MAX);
- block_size = EVP_CIPHER_CTX_block_size(ctx->ctx);
-
- 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 !defined(HAVE_EVP_AES_CTR)
+ // enif_fprintf(stdout, "%s:%u state = %T\r\n", __FILE__, __LINE__, ctx_res->state);
+ if (ctx_res->state != atom_undefined) {
+ ERL_NIF_TERM state0, newstate_and_outdata;
+ const ERL_NIF_TERM *tuple_argv;
+ int tuple_argc;
+
+ state0 = enif_make_copy(env, ctx_res->state);
+
+ if (enif_get_tuple(env, state0, &tuple_argc, &tuple_argv) && (tuple_argc == 4)) {
+ /* A compatibility state term */
+ /* encrypt and decrypt is performed by calling the same function */
+ newstate_and_outdata = aes_ctr_stream_encrypt_compat(env, state0, indata_arg);
+
+ if (enif_get_tuple(env, newstate_and_outdata, &tuple_argc, &tuple_argv) && (tuple_argc == 2)) {
+ /* newstate_and_outdata = {NewState, OutData} */
+ ctx_res->state = enif_make_copy(ctx_res->env, tuple_argv[0]);
+ *return_term = tuple_argv[1];
+ }
+ }
+ } else
+#endif
+ {
+ block_size = EVP_CIPHER_CTX_block_size(ctx_res->ctx);
+
+ if (!enif_alloc_binary((size_t)in_data_bin.size+block_size, &out_data_bin))
+ {
+ *return_term = ERROR_Str(env, "Can't allocate outdata");
+ goto err;
+ }
+
+ if (!EVP_CipherUpdate(ctx_res->ctx, out_data_bin.data, &out_len, in_data_bin.data, in_data_bin.size))
+ {
+ *return_term = ERROR_Str(env, "Can't update");
+ goto err;
+ }
+
+ if (!enif_realloc_binary(&out_data_bin, (size_t)out_len))
+ {
+ *return_term = ERROR_Str(env, "Can't reallocate");
+ goto err;
+ }
+
+ CONSUME_REDS(env, in_data_bin);
+ *return_term = enif_make_binary(env, &out_data_bin);
}
- if (!enif_alloc_binary((size_t)in_data_bin.size+block_size, &out_data_bin))
- return ERROR_Str(env, "Can't allocate outdata");
+ /* success: */
+ return 1;
+
+ err:
+ return 0;
+}
+
+/*************************************************************************/
+/* Initialize the state for (de/en)cryption */
+/*************************************************************************/
+
+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 = <<>>
+ */
+ struct evp_cipher_ctx *ctx_res = NULL;
+ const struct cipher_type_t *cipherp;
+ ERL_NIF_TERM ret;
+
+ if ((ctx_res = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL)
+ return ERROR_Str(env, "Can't allocate resource");
+
+ if (!get_init_args(env, ctx_res, argv[0], argv[1], argv[2], argv[argc-1],
+ &cipherp, &ret))
+ /* Error msg in &ret */
+ goto ret;
+
+ ret = enif_make_resource(env, ctx_res);
+ if(ctx_res) enif_release_resource(ctx_res);
+ ret:
+ return ret;
+}
+
- 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");
+/*************************************************************************/
+/* Encrypt/decrypt */
+/*************************************************************************/
- 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(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ struct evp_cipher_ctx *ctx_res;
+ ERL_NIF_TERM ret;
+
+ if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx_res))
+ return ERROR_Str(env, "Bad 1:st arg");
+
+ get_update_args(env, ctx_res, argv[1], &ret);
+
+ return ret; /* Both success and error */
}
ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Context, Data)
- (Context, Data, IV) */
- int i;
+{/* (Context, Data) */
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 (!enif_inspect_binary(env, argv[1], &data_bin))
+ return ERROR_Str(env, "expected binary 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);
+ ng_crypto_update, argc, argv);
}
- return ng_crypto_update(env, argc, new_argv);
+ return ng_crypto_update(env, argc, argv);
}
+/*************************************************************************/
+/* One shot */
+/*************************************************************************/
+
+ERL_NIF_TERM ng_crypto_one_shot(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Cipher, Key, IVec, Data, Encrypt) */
+ struct evp_cipher_ctx ctx_res;
+ const struct cipher_type_t *cipherp;
+ ERL_NIF_TERM ret;
+
+ if (!get_init_args(env, &ctx_res, argv[0], argv[1], argv[2], argv[4], &cipherp, &ret))
+ goto ret;
+
+ get_update_args(env, &ctx_res, argv[3], &ret);
+
+ ret:
+ if (ctx_res.ctx)
+ EVP_CIPHER_CTX_free(ctx_res.ctx);
+ return ret;
+}
+
+ERL_NIF_TERM ng_crypto_one_shot_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Cipher, Key, IVec, Data, Encrypt) % if no IV for the Cipher, set IVec = <<>>
+ */
+ ErlNifBinary data_bin;
+
+ ASSERT(argc == 5);
+
+ if (!enif_inspect_binary(env, argv[3], &data_bin))
+ return ERROR_Str(env, "expected binary as data");
+
+ if (data_bin.size > INT_MAX)
+ return ERROR_Str(env, "to long data");
+
+ /* 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_one_shot",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ ng_crypto_one_shot, argc, argv);
+ }
+
+ return ng_crypto_one_shot(env, argc, argv);
+}
diff --git a/lib/crypto/c_src/api_ng.h b/lib/crypto/c_src/api_ng.h
index a3b40fe7fc..5c7d9af3c5 100644
--- a/lib/crypto/c_src/api_ng.h
+++ b/lib/crypto/c_src/api_ng.h
@@ -25,5 +25,6 @@
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[]);
+ERL_NIF_TERM ng_crypto_one_shot_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#endif /* E_AES_H__ */
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index c055a62654..5c57898c50 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -98,7 +98,9 @@ static struct cipher_type_t cipher_types[] =
{{"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},
+ {{"aes_ctr"}, {NULL}, 16, AES_CTR_COMPAT},
+ {{"aes_ctr"}, {NULL}, 24, AES_CTR_COMPAT},
+ {{"aes_ctr"}, {NULL}, 32, AES_CTR_COMPAT},
#endif
#if defined(HAVE_CHACHA20)
@@ -162,6 +164,11 @@ static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
if (ctx->ctx)
EVP_CIPHER_CTX_free(ctx->ctx);
+
+#if !defined(HAVE_EVP_AES_CTR)
+ if (ctx->env)
+ enif_free_env(ctx->env);
+#endif
}
int init_cipher_ctx(ErlNifEnv *env) {
diff --git a/lib/crypto/c_src/cipher.h b/lib/crypto/c_src/cipher.h
index b0d9d324e1..f7b1a09f21 100644
--- a/lib/crypto/c_src/cipher.h
+++ b/lib/crypto/c_src/cipher.h
@@ -59,6 +59,10 @@ struct cipher_type_t {
extern ErlNifResourceType* evp_cipher_ctx_rtype;
struct evp_cipher_ctx {
EVP_CIPHER_CTX* ctx;
+#if !defined(HAVE_EVP_AES_CTR)
+ ErlNifEnv* env;
+ ERL_NIF_TERM state;
+#endif
};
ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 261590d9a5..c6a5dde67f 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -88,7 +88,7 @@ static ErlNifFunc nif_funcs[] = {
{"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},
+ {"ng_crypto_one_shot_nif", 5, ng_crypto_one_shot_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},
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 8d6d24210a..96213fa6e6 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -51,13 +51,13 @@
%% Experiment
-export([crypto_init/4,
- crypto_update/2, crypto_update/3,
+ crypto_update/2,
+ crypto_one_shot/5,
+
%% 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
+ crypto_stream_decrypt/2
]).
@@ -556,11 +556,6 @@ cipher_info(Type) ->
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(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));
@@ -577,14 +572,13 @@ do_block_encrypt(Type, Key, Ivec, Data) when Type =:= aes_gcm;
end;
do_block_encrypt(Type, Key, Ivec, PlainText) ->
- block_crypt_nif(Type, Key, Ivec, PlainText, true).
-
+ crypto_one_shot(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).
+ crypto_one_shot(Type, Key, <<>>, PlainText, true).
%%%----------------------------------------------------------------
%%%----------------------------------------------------------------
@@ -595,11 +589,6 @@ block_encrypt(Type, Key, PlainText) ->
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(Type, Key, Ivec, Data, false);
-
do_block_decrypt(aes_ige256, Key, Ivec, Data) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
@@ -609,14 +598,13 @@ do_block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm;
aead_decrypt(Type, Key, Ivec, AAD, Data, Tag);
do_block_decrypt(Type, Key, Ivec, Data) ->
- block_crypt_nif(Type, Key, Ivec, Data, false).
-
+ crypto_one_shot(Type, Key, Ivec, Data, false).
-spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) -> binary().
block_decrypt(Type, Key, Data) ->
- block_crypt_nif(alias(Type), Key, Data, false).
+ crypto_one_shot(Type, Key, <<>>, Data, false).
%%%----------------------------------------------------------------
-spec next_iv(Type:: cbc_cipher(), Data) -> NextIVec when % Type :: cbc_cipher(), %des_cbc | des3_cbc | aes_cbc | aes_ige,
@@ -1785,19 +1773,6 @@ poly1305_nif(_Key, _Data) -> ?nif_stub.
cipher_info_nif(_Type) -> ?nif_stub.
-block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
-block_crypt_nif(_Type, _Key, _Text, _IsEncrypt) -> ?nif_stub.
-
-check_des3_key(Key) ->
- case lists:map(fun erlang:iolist_to_binary/1, Key) of
- ValidKey = [B1, B2, B3] when byte_size(B1) =:= 8,
- byte_size(B2) =:= 8,
- byte_size(B3) =:= 8 ->
- ValidKey;
- _ ->
- error(badarg)
- end.
-
%%
%% AES - in Galois/Counter Mode (GCM)
%%
@@ -2289,67 +2264,29 @@ crypto_update(State, Data0) ->
<<>> ->
<<>>; % Known to fail on OpenSSL 0.9.8h
Data ->
- mk_ret(ng_crypto_update_nif(State, Data))
+ ng_crypto_update_nif(State, Data)
end.
%%%----------------------------------------------------------------
-%%%
-%%% 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.
+
+%% _Data MUST be binary()
ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
-ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
+
+%% _Data MUST be binary()
+ng_crypto_one_shot_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?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)
+crypto_one_shot(Cipher, Key, IV, Data0, EncryptFlag) ->
+ case iolist_to_binary(Data0) of
+ <<>> ->
+ <<>>; % Known to fail on OpenSSL 0.9.8h
+ Data ->
+ ng_crypto_one_shot_nif(Cipher, iolist_to_binary(Key), iolist_to_binary(IV), Data, EncryptFlag)
end.
%%%--------------------------------
@@ -2391,7 +2328,6 @@ crypto_stream_emulate({Cipher,State}, Data, _) ->
{error,_} -> error(badarg)
end.
-
%%%================================================================
prepend_cipher_aliases(L) ->