aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2018-09-14 10:49:34 +0200
committerHans Nilsson <[email protected]>2018-09-18 10:12:39 +0200
commite8de0736005e91afd992e49f434e08c940eddfa0 (patch)
tree27fc0ec26e5dcf407e8c4b2d174704b3e877509a
parenta578ee7615e72a8eb0ad0e35ae94437b41db96ee (diff)
downloadotp-e8de0736005e91afd992e49f434e08c940eddfa0.tar.gz
otp-e8de0736005e91afd992e49f434e08c940eddfa0.tar.bz2
otp-e8de0736005e91afd992e49f434e08c940eddfa0.zip
crypto: Use aead functions for CHACHA20_POLY1305
This previously implemented cipher is a block cipher despite using chacha. It also uses the EVP_CIPHER_CTX api which now unifies AES_GCM and AES_CCM into one pair of encrypt and decrypt functions. By integrating the existing chacha20_poly1305 code into aead_encrypt and aead_decrypt we could remove two C-functions and simplify both the C-code and the corresponding Erlang code in the CRYPTO application.
-rw-r--r--lib/crypto/c_src/crypto.c164
-rw-r--r--lib/crypto/src/crypto.erl19
2 files changed, 40 insertions, 143 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 3172059414..b1f0183ac2 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -553,9 +553,6 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#endif
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -648,9 +645,6 @@ static ErlNifFunc nif_funcs[] = {
{"aead_encrypt", 6, aead_encrypt},
{"aead_decrypt", 6, aead_decrypt},
- {"chacha20_poly1305_encrypt", 4, chacha20_poly1305_encrypt},
- {"chacha20_poly1305_decrypt", 5, chacha20_poly1305_decrypt},
-
{"chacha20_stream_init", 2, chacha20_stream_init},
{"chacha20_stream_encrypt", 2, chacha20_stream_crypt},
{"chacha20_stream_decrypt", 2, chacha20_stream_crypt},
@@ -726,6 +720,9 @@ static ERL_NIF_TERM atom_aes_gcm;
#ifdef HAVE_CCM
static ERL_NIF_TERM atom_aes_ccm;
#endif
+#ifdef HAVE_CHACHA20_POLY1305
+static ERL_NIF_TERM atom_chacha20_poly1305;
+#endif
#ifdef HAVE_ECB_IVEC_BUG
static ERL_NIF_TERM atom_aes_ecb;
static ERL_NIF_TERM atom_des_ecb;
@@ -1172,6 +1169,9 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
#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");
@@ -2621,17 +2621,23 @@ static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
} else
#endif
+#if defined(HAVE_CHACHA20_POLY1305)
+ if ((type == atom_chacha20_poly1305)
+ && key.size == 32
+ && (1 <= iv.size && iv.size <= 16)
+ && tag_len == 16
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_AEAD_GET_TAG,
+ cipher = EVP_chacha20_poly1305();
+ } else
+#endif
enif_make_badarg(env);
ctx = EVP_CIPHER_CTX_new();
if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) goto out_err;
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, iv.size, NULL) != 1) goto out_err;
-#if defined(HAVE_GCM)
- if (type == atom_aes_gcm) {
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
- } else
-#endif
#if defined(HAVE_CCM)
if (type == atom_aes_ccm) {
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) goto out_err;
@@ -2639,14 +2645,14 @@ static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in.size) != 1) goto out_err;
} else
#endif
- goto out_err;
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err;
outp = enif_make_new_binary(env, in.size, &out);
if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp, &len) != 1) goto out_err;
+ if (EVP_EncryptFinal_ex(ctx, outp/*+len*/, &len) != 1) goto out_err;
tagp = enif_make_new_binary(env, tag_len, &out_tag);
@@ -2673,7 +2679,7 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
ErlNifBinary key, iv, aad, in, tag;
unsigned char *outp;
ERL_NIF_TERM type, out;
- int len, ctx_ctrl_set_ivlen;
+ int len, ctx_ctrl_set_ivlen, ctx_ctrl_set_tag;
type = argv[0];
#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
@@ -2695,6 +2701,7 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
if ((type == atom_aes_gcm)
&& (iv.size > 0)) {
ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
+ ctx_ctrl_set_tag = EVP_CTRL_GCM_SET_TAG;
if (key.size == 16) cipher = EVP_aes_128_gcm();
else if (key.size == 24) cipher = EVP_aes_192_gcm();
else if (key.size == 32) cipher = EVP_aes_256_gcm();
@@ -2715,6 +2722,17 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
} else
#endif
+#if defined(HAVE_CHACHA20_POLY1305)
+ if ((type == atom_chacha20_poly1305)
+ && key.size == 32
+ && (1 <= iv.size && iv.size <= 16)
+ && tag.size == 16
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
+ ctx_ctrl_set_tag = EVP_CTRL_AEAD_SET_TAG;
+ cipher = EVP_chacha20_poly1305();
+ } else
+#endif
enif_make_badarg(env);
outp = enif_make_new_binary(env, in.size, &out);
@@ -2740,9 +2758,9 @@ static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err;
if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err;
-#if defined(HAVE_GCM)
+#if defined(HAVE_GCM) || defined(HAVE_CHACHA20_POLY1305)
if (type == atom_aes_gcm) {
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size, tag.data) != 1) goto out_err;
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, tag.size, tag.data) != 1) goto out_err;
if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1) goto out_err;
}
#endif
@@ -2807,120 +2825,6 @@ out_err:
#endif /* HAVE_GCM_EVP_DECRYPT_BUG */
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in;
- unsigned char *outp, *tagp;
- ERL_NIF_TERM out, out_tag;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)) {
- return enif_make_badarg(env);
- }
-
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_set_padding(ctx, 0);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- tagp = enif_make_new_binary(env, 16, &out_tag);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagp) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return enif_make_tuple2(env, out, out_tag);
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in, tag;
- unsigned char *outp;
- ERL_NIF_TERM out;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag) || tag.size != 16) {
- return enif_make_badarg(env);
- }
-
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag.size, tag.data) != 1)
- goto out_err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return out;
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-
static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IV) */
#if defined(HAVE_CHACHA20)
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 960fe46c09..2db73c4af0 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -526,8 +526,9 @@ block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= aes_gcm;
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, Key, Ivec, {AAD, PlainText}) ->
- chacha20_poly1305_encrypt(Key, Ivec, AAD, PlainText).
+block_encrypt(chacha20_poly1305=Type, Key, Ivec, {AAD, PlainText}) ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16).
+
-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> binary();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(),
@@ -557,11 +558,9 @@ block_decrypt(des3_cfb, Key0, Ivec, Data) ->
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;
- Type =:= aes_ccm ->
- aead_decrypt(Type, Key, Ivec, AAD, Data, Tag);
-block_decrypt(chacha20_poly1305, Key, Ivec, {AAD, Data, Tag}) ->
- chacha20_poly1305_decrypt(Key, Ivec, AAD, Data, Tag).
-
+ Type =:= aes_ccm;
+ Type =:= chacha20_poly1305 ->
+ aead_decrypt(Type, Key, Ivec, AAD, Data, Tag).
-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary().
@@ -1617,12 +1616,6 @@ aead_encrypt(_Type, _Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
%%
-%% Chacha20/Ppoly1305
-%%
-chacha20_poly1305_encrypt(_Key, _Ivec, _AAD, _In) -> ?nif_stub.
-chacha20_poly1305_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
-
-%%
%% AES - with 256 bit key in infinite garble extension mode (IGE)
%%