aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2018-08-23 14:26:00 +0200
committerHans Nilsson <[email protected]>2018-08-23 14:26:00 +0200
commita2cb2285d7724759bf820368ade7ba19481ef93e (patch)
treeedbb503025ae646387e075121bc939afcd8e835d /lib
parent4479223613dc6a0e82059c310b13fd072b9e31a3 (diff)
parentc8d09a8237f1d610ab0806fae3e929652811549b (diff)
downloadotp-a2cb2285d7724759bf820368ade7ba19481ef93e.tar.gz
otp-a2cb2285d7724759bf820368ade7ba19481ef93e.tar.bz2
otp-a2cb2285d7724759bf820368ade7ba19481ef93e.zip
Merge branch 'hans/crypto/poly1305_and_chacha20/OTP-15164' into maint
* hans/crypto/poly1305_and_chacha20/OTP-15164: crypto: doc poly1305 crypto: doc chacha20 crypto: Error in test case crypto: chacha20 test case crypto: poly1305 test case crypto: -spec crypto: chacha20 cipher crypto: Mac POLY1305 if >=OpenSSL 1.1.1-pre8
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto/c_src/crypto.c148
-rw-r--r--lib/crypto/doc/src/crypto.xml22
-rw-r--r--lib/crypto/src/crypto.erl38
-rw-r--r--lib/crypto/test/crypto_SUITE.erl168
4 files changed, 360 insertions, 16 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 72aa44e7db..d409ea7dcf 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -178,11 +178,19 @@
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
# ifndef HAS_LIBRESSL
+# define HAVE_CHACHA20
# define HAVE_CHACHA20_POLY1305
# define HAVE_RSA_OAEP_MD
# endif
#endif
+// OPENSSL_VERSION_NUMBER >= 1.1.1-pre8
+#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1)-7)
+# ifndef HAS_LIBRESSL
+# define HAVE_POLY1305
+# endif
+#endif
+
#if OPENSSL_VERSION_NUMBER <= PACKED_OPENSSL_VERSION(0,9,8,'l')
# define HAVE_ECB_IVEC_BUG
#endif
@@ -524,6 +532,11 @@ static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_N
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[]);
+
+static ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
static ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -614,6 +627,12 @@ static ErlNifFunc nif_funcs[] = {
{"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},
+
+ {"poly1305_nif", 2, poly1305_nif},
+
{"engine_by_id_nif", 1, engine_by_id_nif},
{"engine_init_nif", 1, engine_init_nif},
{"engine_finish_nif", 1, engine_finish_nif},
@@ -1246,7 +1265,7 @@ static ERL_NIF_TERM algo_pubkey[11]; /* increase when extending the list */
static int algo_cipher_cnt, algo_cipher_fips_cnt;
static ERL_NIF_TERM algo_cipher[24]; /* increase when extending the list */
static int algo_mac_cnt, algo_mac_fips_cnt;
-static ERL_NIF_TERM algo_mac[2]; /* increase when extending the list */
+static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */
static int algo_curve_cnt, algo_curve_fips_cnt;
static ERL_NIF_TERM algo_curve[87]; /* increase when extending the list */
@@ -1334,13 +1353,19 @@ static void init_algorithms_types(ErlNifEnv* env)
#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");
#ifdef HAVE_CMAC
algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac");
#endif
+#ifdef HAVE_POLY1305
+ algo_mac[algo_mac_cnt++] = enif_make_atom(env,"poly1305");
+#endif
// Non-validated algorithms follow
algo_mac_fips_cnt = algo_mac_cnt;
@@ -2082,6 +2107,62 @@ static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
#endif
}
+/* For OpenSSL >= 1.1.1 the hmac_nif and cmac_nif could be integrated into poly1305 (with 'type' as parameter) */
+static ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Text) */
+#ifdef HAVE_POLY1305
+ ErlNifBinary key_bin, text, ret_bin;
+ ERL_NIF_TERM ret = atom_error;
+ EVP_PKEY *key = NULL;
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY_CTX *pctx = NULL;
+ const EVP_MD *md = NULL;
+ size_t size;
+ int type;
+
+ type = EVP_PKEY_POLY1305;
+
+ if (!enif_inspect_binary(env, argv[0], &key_bin) ||
+ !(key_bin.size == 32) ) {
+ return enif_make_badarg(env);
+ }
+
+ if (!enif_inspect_binary(env, argv[1], &text) ) {
+ return enif_make_badarg(env);
+ }
+
+ key = EVP_PKEY_new_raw_private_key(type, /*engine*/ NULL, key_bin.data, key_bin.size);
+
+ if (!key ||
+ !(mctx = EVP_MD_CTX_new()) ||
+ !EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, key) ||
+ !EVP_DigestSignUpdate(mctx, text.data, text.size)) {
+ goto err;
+ }
+
+ if (!EVP_DigestSignFinal(mctx, NULL, &size) ||
+ !enif_alloc_binary(size, &ret_bin) ||
+ !EVP_DigestSignFinal(mctx, ret_bin.data, &size)) {
+ goto err;
+ }
+
+ if ((size != ret_bin.size) &&
+ !enif_realloc_binary(&ret_bin, size)) {
+ goto err;
+ }
+
+ ret = enif_make_binary(env, &ret_bin);
+
+ err:
+ EVP_MD_CTX_free(mctx);
+ EVP_PKEY_free(key);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
static 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;
@@ -2666,6 +2747,69 @@ out_err:
#endif
}
+
+static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IV) */
+#if defined(HAVE_CHACHA20)
+ ErlNifBinary key_bin, ivec_bin;
+ struct evp_cipher_ctx *ctx;
+ const EVP_CIPHER *cipher;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || key_bin.size != 32
+ || ivec_bin.size != 16) {
+ return enif_make_badarg(env);
+ }
+
+ cipher = EVP_chacha20();
+
+ ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx));
+ ctx->ctx = EVP_CIPHER_CTX_new();
+
+
+ EVP_CipherInit_ex(ctx->ctx, cipher, NULL,
+ key_bin.data, ivec_bin.data, 1);
+ EVP_CIPHER_CTX_set_padding(ctx->ctx, 0);
+ ret = enif_make_resource(env, ctx);
+ enif_release_resource(ctx);
+ return ret;
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+};
+
+static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (State, Data) */
+#if defined(HAVE_CHACHA20)
+ struct evp_cipher_ctx *ctx, *new_ctx;
+ ErlNifBinary data_bin;
+ ERL_NIF_TERM ret, cipher_term;
+ unsigned char *out;
+ int outl = 0;
+
+ if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+ new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx));
+ new_ctx->ctx = EVP_CIPHER_CTX_new();
+ EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx);
+ out = enif_make_new_binary(env, data_bin.size, &cipher_term);
+ EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, data_bin.size);
+ ASSERT(outl == data_bin.size);
+
+ ret = enif_make_tuple2(env, enif_make_resource(env, new_ctx), cipher_term);
+ enif_release_resource(new_ctx);
+ CONSUME_REDS(env,data_bin);
+ return ret;
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+};
+
+
static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Bytes) */
unsigned bytes;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index e6147ddffc..889e5616dd 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -155,7 +155,7 @@
<p>The key's password
</p>
- <code>stream_cipher() = rc4 | aes_ctr </code>
+ <code>stream_cipher() = rc4 | aes_ctr | chacha20 </code>
<code>block_cipher() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ige256 | blowfish_cbc |
blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc </code>
@@ -193,9 +193,9 @@
Note that both md4 and md5 are recommended only for compatibility with existing applications.
</p>
<code> cipher_algorithms() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ctr | aes_gcm |
- aes_ige256 | blowfish_cbc | blowfish_cfb64 | chacha20_poly1305 | des_cbc |
+ aes_ige256 | blowfish_cbc | blowfish_cfb64 | chacha20 | chacha20_poly1305 | des_cbc |
des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc | rc4 </code>
- <code> mac_algorithms() = hmac | cmac</code>
+ <code> mac_algorithms() = hmac | cmac | poly1305</code>
<code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh | ec_gf2m</code>
<p>Note that ec_gf2m is not strictly a public key algorithm, but a restriction on what curves are supported
with ecdsa and ecdh.
@@ -598,6 +598,20 @@
</func>
<func>
+ <name>poly1305(Key, Data) -> Mac</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Key = iodata()</v>
+ <v>Data = iodata()</v>
+ <v>Mac = binary()</v>
+ </type>
+ <desc>
+ <p>Computes a POLY1305 message authentication code (<c>Mac</c>) from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p>
+ </desc>
+ </func>
+
+ <func>
<name>private_decrypt(Type, CipherText, PrivateKey, Padding) -> PlainText</name>
<fsummary>Decrypts CipherText using the private Key.</fsummary>
<type>
@@ -958,7 +972,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<name>stream_init(Type, Key, IVec) -> State</name>
<fsummary></fsummary>
<type>
- <v>Type = aes_ctr </v>
+ <v>Type = aes_ctr | chacha20</v>
<v>State = opaque() </v>
<v>Key = iodata()</v>
<v>IVec = binary()</v>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 81ab4e5ea1..f6a785303b 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -29,6 +29,7 @@
-export([generate_key/2, generate_key/3, compute_key/4]).
-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
-export([cmac/3, cmac/4]).
+-export([poly1305/2]).
-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
-export([rand_seed/0, rand_seed_alg/1]).
-export([rand_seed_s/0, rand_seed_alg_s/1]).
@@ -194,6 +195,11 @@ cmac(Type, Key, Data) ->
cmac(Type, Key, Data, MacSize) ->
erlang:binary_part(cmac(Type, Key, Data), 0, MacSize).
+-spec poly1305(iodata(), iodata()) -> binary().
+
+poly1305(Key, Data) ->
+ poly1305_nif(Key, Data).
+
%% Ecrypt/decrypt %%%
-spec block_encrypt(des_cbc | des_cfb |
@@ -309,7 +315,10 @@ next_iv(Type, Data, _Ivec) ->
next_iv(Type, Data).
stream_init(aes_ctr, Key, Ivec) ->
- {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)};
+stream_init(chacha20, Key, Ivec) ->
+ {chacha20, chacha20_stream_init(Key,Ivec)}.
+
stream_init(rc4, Key) ->
{rc4, notsup_to_error(rc4_set_key(Key))}.
@@ -1060,9 +1069,12 @@ hmac_final_nif(_Context) -> ?nif_stub.
hmac_final_nif(_Context, _MacSize) -> ?nif_stub.
%% CMAC
-
cmac_nif(_Type, _Key, _Data) -> ?nif_stub.
+%% POLY1305
+poly1305_nif(_Key, _Data) -> ?nif_stub.
+
+
%% CIPHERS --------------------------------------------------------------------
block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
@@ -1117,14 +1129,20 @@ do_stream_encrypt({aes_ctr, State0}, Data) ->
{{aes_ctr, State}, Cipher};
do_stream_encrypt({rc4, State0}, Data) ->
{State, Cipher} = rc4_encrypt_with_state(State0, Data),
- {{rc4, State}, Cipher}.
+ {{rc4, State}, Cipher};
+do_stream_encrypt({chacha20, State0}, Data) ->
+ {State, Cipher} = chacha20_stream_encrypt(State0, Data),
+ {{chacha20, State}, Cipher}.
do_stream_decrypt({aes_ctr, State0}, Data) ->
{State, Text} = aes_ctr_stream_decrypt(State0, Data),
{{aes_ctr, State}, Text};
do_stream_decrypt({rc4, State0}, Data) ->
{State, Text} = rc4_encrypt_with_state(State0, Data),
- {{rc4, State}, Text}.
+ {{rc4, State}, Text};
+do_stream_decrypt({chacha20, State0}, Data) ->
+ {State, Cipher} = chacha20_stream_decrypt(State0, Data),
+ {{chacha20, State}, Cipher}.
%%
@@ -1148,6 +1166,18 @@ aes_ctr_stream_decrypt(_State, _Cipher) -> ?nif_stub.
rc4_set_key(_Key) -> ?nif_stub.
rc4_encrypt_with_state(_State, _Data) -> ?nif_stub.
+%%
+%% CHACHA20 - stream cipher
+%%
+-type chacha20_state() :: term().
+-spec chacha20_stream_init(iodata(), binary()) -> chacha20_state().
+-spec chacha20_stream_encrypt(chacha20_state(), binary()) -> {chacha20_state(), binary()}.
+-spec chacha20_stream_decrypt(chacha20_state(), binary()) -> {chacha20_state(), binary()}.
+
+chacha20_stream_init(_Key, _IVec) -> ?nif_stub.
+chacha20_stream_encrypt(_State, _Data) -> ?nif_stub.
+chacha20_stream_decrypt(_State, _Data) -> ?nif_stub.
+
%% Secure remote password -------------------------------------------------------------------
user_srp_gen_key(Private, Generator, Prime) ->
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 13b1fbd047..aff35f4571 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -77,6 +77,8 @@ groups() ->
{group, aes_ctr},
{group, aes_gcm},
{group, chacha20_poly1305},
+ {group, chacha20},
+ {group, poly1305},
{group, aes_cbc}]},
{fips, [], [{group, no_md4},
{group, no_md5},
@@ -112,6 +114,7 @@ groups() ->
{group, aes_ctr},
{group, aes_gcm},
{group, no_chacha20_poly1305},
+ {group, no_chacha20},
{group, aes_cbc}]},
{md4, [], [hash]},
{md5, [], [hash, hmac]},
@@ -157,6 +160,8 @@ groups() ->
{aes_ctr, [], [stream]},
{aes_gcm, [], [aead]},
{chacha20_poly1305, [], [aead]},
+ {chacha20, [], [stream]},
+ {poly1305, [], [poly1305]},
{aes_cbc, [], [block]},
{no_md4, [], [no_support, no_hash]},
{no_md5, [], [no_support, no_hash, no_hmac]},
@@ -170,6 +175,7 @@ groups() ->
{no_blowfish_ofb64, [], [no_support, no_block]},
{no_aes_ige256, [], [no_support, no_block]},
{no_chacha20_poly1305, [], [no_support, no_aead]},
+ {no_chacha20, [], [no_support, no_stream_ivec]},
{no_rc2_cbc, [], [no_support, no_block]},
{no_rc4, [], [no_support, no_stream]},
{api_errors, [], [api_errors_ecdh]}
@@ -356,6 +362,20 @@ cmac(Config) when is_list(Config) ->
lists:foreach(fun cmac_check/1, Pairs),
lists:foreach(fun cmac_check/1, cmac_iolistify(Pairs)).
%%--------------------------------------------------------------------
+poly1305() ->
+ [{doc, "Test poly1305 function"}].
+poly1305(Config) ->
+ lists:foreach(
+ fun({Key, Txt, Expect}) ->
+ case crypto:poly1305(Key,Txt) of
+ Expect ->
+ ok;
+ Other ->
+ ct:fail({{crypto, poly1305, [Key, Txt]}, {expected, Expect}, {got, Other}})
+ end
+ end, proplists:get_value(poly1305, Config)).
+
+%%--------------------------------------------------------------------
block() ->
[{doc, "Test block ciphers"}].
block(Config) when is_list(Config) ->
@@ -420,6 +440,13 @@ no_stream(Config) when is_list(Config) ->
notsup(fun crypto:stream_init/2, [Type, <<"Key">>]).
%%--------------------------------------------------------------------
+no_stream_ivec() ->
+ [{doc, "Test disabled stream ciphers that uses ivec"}].
+no_stream_ivec(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ notsup(fun crypto:stream_init/3, [Type, <<"Key">>, <<"Ivec">>]).
+
+%%--------------------------------------------------------------------
aead() ->
[{doc, "Test AEAD ciphers"}].
aead(Config) when is_list(Config) ->
@@ -757,16 +784,33 @@ stream_cipher({Type, Key, IV, PlainText}) ->
ok;
Other ->
ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ end;
+stream_cipher({Type, Key, IV, PlainText, CipherText}) ->
+ Plain = iolist_to_binary(PlainText),
+ State = crypto:stream_init(Type, Key, IV),
+ case crypto:stream_encrypt(State, PlainText) of
+ {_, CipherText} ->
+ ok;
+ {_, Other0} ->
+ ct:fail({{crypto, stream_encrypt, [State, Type, Key, IV, Plain]}, {expected, CipherText}, {got, Other0}})
+ end,
+ case crypto:stream_decrypt(State, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other1 ->
+ ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other1}})
end.
stream_cipher_incment({Type, Key, PlainTexts}) ->
State = crypto:stream_init(Type, Key),
- stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+ stream_cipher_incment_loop(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
stream_cipher_incment({Type, Key, IV, PlainTexts}) ->
State = crypto:stream_init(Type, Key, IV),
- stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts)).
+ stream_cipher_incment_loop(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+stream_cipher_incment({Type, Key, IV, PlainTexts, _CipherText}) ->
+ stream_cipher_incment({Type, Key, IV, PlainTexts}).
-stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
+stream_cipher_incment_loop(_State, OrigState, [], Acc, Plain) ->
CipherText = iolist_to_binary(lists:reverse(Acc)),
case crypto:stream_decrypt(OrigState, CipherText) of
{_, Plain} ->
@@ -774,9 +818,9 @@ stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
Other ->
ct:fail({{crypto, stream_decrypt, [OrigState, CipherText]}, {expected, Plain}, {got, Other}})
end;
-stream_cipher_incment(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
+stream_cipher_incment_loop(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
{State, CipherText} = crypto:stream_encrypt(State0, PlainText),
- stream_cipher_incment(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
+ stream_cipher_incment_loop(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag}) ->
Plain = iolist_to_binary(PlainText),
@@ -1027,7 +1071,9 @@ do_cmac_iolistify({Type, Key, Text, Size, CMac}) ->
do_stream_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
do_stream_iolistify({Type, Key, IV, PlainText}) ->
- {Type, iolistify(Key), IV, iolistify(PlainText)}.
+ {Type, iolistify(Key), IV, iolistify(PlainText)};
+do_stream_iolistify({Type, Key, IV, PlainText, CipherText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText), CipherText}.
do_block_iolistify({des_cbc = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
@@ -1432,6 +1478,18 @@ group_config(aes_gcm, Config) ->
group_config(chacha20_poly1305, Config) ->
AEAD = chacha20_poly1305(),
[{aead, AEAD} | Config];
+group_config(chacha20, Config) ->
+ Stream = chacha20(),
+ [{stream, Stream} | Config];
+group_config(poly1305, Config) ->
+ V = [%% {Key, Txt, Expect}
+ {%% RFC7539 2.5.2
+ crypto_SUITE:hexstr2bin("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"),
+ <<"Cryptographic Forum Research Group">>,
+ crypto_SUITE:hexstr2bin("a8061dc1305136c6c22b8baf0c0127a9")
+ }
+ ],
+ [{poly1305,V} | Config];
group_config(aes_cbc, Config) ->
Block = aes_cbc(Config),
[{block, Block} | Config];
@@ -2069,6 +2127,7 @@ aes_gcm(Config) ->
"gcmEncryptExtIV192.rsp",
"gcmEncryptExtIV256.rsp"]).
+
%% https://tools.ietf.org/html/rfc7539#appendix-A.5
chacha20_poly1305() ->
[
@@ -2114,6 +2173,103 @@ chacha20_poly1305() ->
hexstr2bin("eead9d67890cbb22392336fea1851f38")} %% CipherTag
].
+
+chacha20() ->
+%%% chacha20 (no mode) test vectors from RFC 7539 A.2
+ [
+ %% Test Vector #1:
+ {chacha20,
+ hexstr2bin("00000000000000000000000000000000"
+ "00000000000000000000000000000000"), %% Key
+ hexstr2bin("00000000" % Initial counter = 0, little-endian
+ "000000000000000000000000"), %% IV
+ hexstr2bin("00000000000000000000000000000000" %% PlainText
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"),
+ hexstr2bin("76b8e0ada0f13d90405d6ae55386bd28" %% CipherText
+ "bdd219b8a08ded1aa836efcc8b770dc7"
+ "da41597c5157488d7724e03fb8d84a37"
+ "6a43b8f41518a11cc387b669b2ee6586")},
+ %% Test Vector #2:
+ {chacha20,
+ hexstr2bin("00000000000000000000000000000000"
+ "00000000000000000000000000000001"), %% Key
+ hexstr2bin("01000000" % Initial counter = 1, little-endian
+ "000000000000000000000002"), %% IV
+ hexstr2bin("416e79207375626d697373696f6e2074" %% PlainText
+ "6f20746865204945544620696e74656e"
+ "6465642062792074686520436f6e7472"
+ "696275746f7220666f72207075626c69"
+ "636174696f6e20617320616c6c206f72"
+ "2070617274206f6620616e2049455446"
+ "20496e7465726e65742d447261667420"
+ "6f722052464320616e6420616e792073"
+ "746174656d656e74206d616465207769"
+ "7468696e2074686520636f6e74657874"
+ "206f6620616e20494554462061637469"
+ "7669747920697320636f6e7369646572"
+ "656420616e20224945544620436f6e74"
+ "7269627574696f6e222e205375636820"
+ "73746174656d656e747320696e636c75"
+ "6465206f72616c2073746174656d656e"
+ "747320696e2049455446207365737369"
+ "6f6e732c2061732077656c6c20617320"
+ "7772697474656e20616e6420656c6563"
+ "74726f6e696320636f6d6d756e696361"
+ "74696f6e73206d61646520617420616e"
+ "792074696d65206f7220706c6163652c"
+ "20776869636820617265206164647265"
+ "7373656420746f"),
+ hexstr2bin("a3fbf07df3fa2fde4f376ca23e827370" %% CipherText
+ "41605d9f4f4f57bd8cff2c1d4b7955ec"
+ "2a97948bd3722915c8f3d337f7d37005"
+ "0e9e96d647b7c39f56e031ca5eb6250d"
+ "4042e02785ececfa4b4bb5e8ead0440e"
+ "20b6e8db09d881a7c6132f420e527950"
+ "42bdfa7773d8a9051447b3291ce1411c"
+ "680465552aa6c405b7764d5e87bea85a"
+ "d00f8449ed8f72d0d662ab052691ca66"
+ "424bc86d2df80ea41f43abf937d3259d"
+ "c4b2d0dfb48a6c9139ddd7f76966e928"
+ "e635553ba76c5c879d7b35d49eb2e62b"
+ "0871cdac638939e25e8a1e0ef9d5280f"
+ "a8ca328b351c3c765989cbcf3daa8b6c"
+ "cc3aaf9f3979c92b3720fc88dc95ed84"
+ "a1be059c6499b9fda236e7e818b04b0b"
+ "c39c1e876b193bfe5569753f88128cc0"
+ "8aaa9b63d1a16f80ef2554d7189c411f"
+ "5869ca52c5b83fa36ff216b9c1d30062"
+ "bebcfd2dc5bce0911934fda79a86f6e6"
+ "98ced759c3ff9b6477338f3da4f9cd85"
+ "14ea9982ccafb341b2384dd902f3d1ab"
+ "7ac61dd29c6f21ba5b862f3730e37cfd"
+ "c4fd806c22f221")},
+ %%Test Vector #3:
+ {chacha20,
+ hexstr2bin("1c9240a5eb55d38af333888604f6b5f0"
+ "473917c1402b80099dca5cbc207075c0"), %% Key
+ hexstr2bin("2a000000" % Initial counter = 42 (decimal), little-endian
+ "000000000000000000000002"), %% IV
+ hexstr2bin("2754776173206272696c6c69672c2061" %% PlainText
+ "6e642074686520736c6974687920746f"
+ "7665730a446964206779726520616e64"
+ "2067696d626c6520696e207468652077"
+ "6162653a0a416c6c206d696d73792077"
+ "6572652074686520626f726f676f7665"
+ "732c0a416e6420746865206d6f6d6520"
+ "7261746873206f757467726162652e"),
+ hexstr2bin("62e6347f95ed87a45ffae7426f27a1df" %% CipherText
+ "5fb69110044c0d73118effa95b01e5cf"
+ "166d3df2d721caf9b21e5fb14c616871"
+ "fd84c54f9d65b283196c7fe4f60553eb"
+ "f39c6402c42234e32a356b3e764312a6"
+ "1a5532055716ead6962568f87d3f3f77"
+ "04c6a8d1bcd1bf4d50d6154b6da731b1"
+ "87b58dfd728afa36757a797ac188d1")}
+ ].
+
+
rsa_plain() ->
<<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
"09812312908312378623487263487623412039812 huagasd">>.