summaryrefslogtreecommitdiff
path: root/lib/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/c_src/aead.c21
-rw-r--r--lib/crypto/c_src/cipher.c12
-rw-r--r--lib/crypto/doc/src/notes.xml58
-rw-r--r--lib/crypto/test/Makefile2
-rw-r--r--lib/crypto/test/crypto_SUITE.erl317
-rw-r--r--lib/crypto/test/crypto_property_test_SUITE.erl50
-rw-r--r--lib/crypto/test/property_test/crypto_ng_api.erl134
-rw-r--r--lib/crypto/test/property_test/crypto_prop_generators.erl93
-rw-r--r--lib/crypto/test/property_test/crypto_prop_generators.hrl36
-rw-r--r--lib/crypto/vsn.mk2
10 files changed, 671 insertions, 54 deletions
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
index ab0e609130..6bb449a986 100644
--- a/lib/crypto/c_src/aead.c
+++ b/lib/crypto/c_src/aead.c
@@ -118,17 +118,19 @@ ERL_NIF_TERM aead_cipher(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{ret = EXCP_BADARG(env, "Can't set text size"); goto done;}
} else
#endif
- {
+ { /* GCM_MODE or CHACHA20_POLY1305 */
+ /* Set key and iv */
if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
{ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
}
+ /* Set the AAD */
if (EVP_CipherUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
{ret = EXCP_BADARG(env, "Can't set AAD"); goto done;}
+ /* Set the plain text and get the crypto text (or vice versa :) ) */
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
{ret = EXCP_ERROR(env, "Can't make 'Out' binary"); goto done;}
-
if (EVP_CipherUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
{
if (encflg)
@@ -141,29 +143,34 @@ ERL_NIF_TERM aead_cipher(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if (encflg)
{
- if (EVP_CipherFinal_ex(ctx, outp/*+len*/, &len) != 1)
+ /* Finalize the encrypted text */
+ if (EVP_CipherFinal_ex(ctx, outp, &len) != 1)
{ret = EXCP_ERROR(env, "Encrypt error"); goto done;}
+ /* Get the tag */
if ((tagp = enif_make_new_binary(env, tag_len, &out_tag)) == NULL)
{ret = EXCP_ERROR(env, "Can't make 'Out' binary"); goto done;}
-
if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_get_tag, (int)tag_len, tagp) != 1)
{ret = EXCP_ERROR(env, "Can't get Tag"); goto done;}
+ /* Make the return value (the tuple with binary crypto text and the tag) */
ret = enif_make_tuple2(env, out, out_tag);
}
- else
+ else /* Decrypting. The plain text is already pointed to by 'out' */
{
-#if defined(HAVE_GCM)
- if (cipherp->flags & GCM_MODE) {
+#if defined(HAVE_GCM) || defined(HAVE_CHACHA20_POLY1305)
+ /* Check the Tag before returning. CCM_MODE does this previously. */
+ if (!(cipherp->flags & CCM_MODE)) { /* That is, CHACHA20_POLY1305 or GCM_MODE */
if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag.data) != 1)
/* Decrypt error */
{ret = atom_error; goto done;}
+ /* CCM dislikes EVP_DecryptFinal_ex on decrypting for pre 1.1.1, so we do it only here */
if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
/* Decrypt error */
{ret = atom_error; goto done;}
}
#endif
+ /* Make the return value, that is, the plain text */
ret = out;
}
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index e144a891a6..5b8835f0a9 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -66,13 +66,13 @@ static struct cipher_type_t cipher_types[] =
{{"aes_192_cbc"}, {&EVP_aes_192_cbc}, 24, 0},
{{"aes_256_cbc"}, {&EVP_aes_256_cbc}, 32, 0},
- {{"aes_128_cfb8"}, {&EVP_aes_128_cfb8}, 16, NO_FIPS_CIPHER | AES_CFBx},
- {{"aes_192_cfb8"}, {&EVP_aes_192_cfb8}, 24, NO_FIPS_CIPHER | AES_CFBx},
- {{"aes_256_cfb8"}, {&EVP_aes_256_cfb8}, 32, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_128_cfb8"}, {&EVP_aes_128_cfb8}, 16, AES_CFBx},
+ {{"aes_192_cfb8"}, {&EVP_aes_192_cfb8}, 24, AES_CFBx},
+ {{"aes_256_cfb8"}, {&EVP_aes_256_cfb8}, 32, AES_CFBx},
- {{"aes_128_cfb128"}, {&EVP_aes_128_cfb128}, 16, NO_FIPS_CIPHER | AES_CFBx},
- {{"aes_192_cfb128"}, {&EVP_aes_192_cfb128}, 24, NO_FIPS_CIPHER | AES_CFBx},
- {{"aes_256_cfb128"}, {&EVP_aes_256_cfb128}, 32, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_128_cfb128"}, {&EVP_aes_128_cfb128}, 16, AES_CFBx},
+ {{"aes_192_cfb128"}, {&EVP_aes_192_cfb128}, 24, AES_CFBx},
+ {{"aes_256_cfb128"}, {&EVP_aes_256_cfb128}, 32, AES_CFBx},
{{"aes_128_ecb"}, {&EVP_aes_128_ecb}, 16, ECB_BUG_0_9_8L},
{{"aes_192_ecb"}, {&EVP_aes_192_ecb}, 24, ECB_BUG_0_9_8L},
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index e0bf845d52..e45a948a0c 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 4.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The AEAD tag was not previously checked on decrypt with
+ chacha20_poly1305</p>
+ <p>
+ Own Id: OTP-16242 Aux Id: ERL-1078 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.6.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -256,6 +272,30 @@
</section>
+<section><title>Crypto 4.4.2.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The chipers aes_cfb8 and aes_cfb128 are now using the EVP
+ interface. The supported key lengths are 128, 192 and 256
+ bits.</p>
+ <p>
+ Own Id: OTP-16133 Aux Id: PR-2407 </p>
+ </item>
+ <item>
+ <p>
+ The chipers aes_cfb8 and aes_cfb128 are now available in
+ FIPS enabled mode.</p>
+ <p>
+ Own Id: OTP-16134 Aux Id: PR-2407 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.4.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -546,6 +586,23 @@
</section>
+<section><title>Crypto 4.2.2.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The chipers aes_cfb8 and aes_cfb128 are now using the EVP
+ interface. The supported key lengths are 128, 192 and 256
+ bits.</p>
+ <p>
+ Own Id: OTP-16133 Aux Id: PR-2407 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.2.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2216,4 +2273,3 @@ Aux Id: seq7864</p>
</p>
</section>
</chapter>
-
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index 988d95a8bc..bc3d25585a 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -8,6 +8,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES = \
crypto_bench_SUITE \
crypto_SUITE \
+ crypto_property_test_SUITE \
engine_SUITE
ERL_FILES= $(MODULES:%=%.erl)
@@ -80,6 +81,7 @@ release_tests_spec: $(TEST_TARGET)
$(INSTALL_DATA) crypto.spec crypto_bench.spec crypto.cover $(RELTEST_FILES) "$(RELSYSDIR)"
@tar cfh - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
chmod -R u+w "$(RELSYSDIR)"
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 0da70d5592..ce515a9ba0 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -64,7 +64,13 @@ all() ->
{group, aes_192_gcm},
{group, aes_256_gcm},
{group, des_ede3_cbc},
- {group, des_ede3_cfb}
+ {group, des_ede3_cfb},
+ {group, aes_128_cfb128},
+ {group, aes_192_cfb128},
+ {group, aes_256_cfb128},
+ {group, aes_128_cfb8},
+ {group, aes_192_cfb8},
+ {group, aes_256_cfb8}
).
-define(RETIRED_TYPE_ALIASES,
@@ -78,7 +84,9 @@ all() ->
{group, des3_cfb},
{group, des3_cbc},
{group, des3_cbf},
- {group, des_ede3}
+ {group, des_ede3},
+ {group, aes_cfb128},
+ {group, aes_cfb8}
).
groups() ->
@@ -123,15 +131,7 @@ groups() ->
{group, rc4},
?NEW_CIPHER_TYPE_SCHEMA,
- {group, aes_128_cfb128},
- {group, aes_192_cfb128},
- {group, aes_256_cfb128},
- {group, aes_128_cfb8},
- {group, aes_192_cfb8},
- {group, aes_256_cfb8},
- ?RETIRED_TYPE_ALIASES,
- {group, aes_cfb128},
- {group, aes_cfb8}
+ ?RETIRED_TYPE_ALIASES
]},
{fips, [], [
{group, no_blake2b},
@@ -163,8 +163,6 @@ groups() ->
{group, no_blowfish_ecb},
{group, no_blowfish_ofb64},
- {group, no_aes_cfb128},
- {group, no_aes_cfb8},
{group, no_aes_ige256},
{group, no_des_cbc},
{group, no_des_cfb},
@@ -234,7 +232,7 @@ groups() ->
{blowfish_ofb64, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
{rc4, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
{aes_ctr, [], [stream]},
- {chacha20_poly1305, [], [aead]},
+ {chacha20_poly1305, [], [aead, aead_ng, aead_bad_tag]},
{chacha20, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
{poly1305, [], [poly1305]},
{no_poly1305, [], [no_poly1305]},
@@ -256,11 +254,19 @@ groups() ->
{no_blowfish_cfb64, [], [no_support, no_block]},
{no_blowfish_ofb64, [], [no_support, no_block]},
{no_aes_ige256, [], [no_support, no_block]},
- {no_chacha20_poly1305, [], [no_support, no_aead]},
+ {no_chacha20_poly1305, [], [no_support, no_aead, no_aead_ng]},
{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]},
+ {api_errors, [], [api_errors_ecdh,
+ bad_cipher_name,
+ bad_generate_key_name,
+ bad_hash_name,
+ bad_hmac_name,
+ bad_mac_name,
+ bad_sign_name,
+ bad_verify_name
+ ]},
%% New cipher nameing schema
{des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
@@ -271,15 +277,15 @@ groups() ->
{aes_128_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_192_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_256_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_128_ccm, [], [aead]},
- {aes_192_ccm, [], [aead]},
- {aes_256_ccm, [], [aead]},
+ {aes_128_ccm, [], [aead, aead_ng, aead_bad_tag]},
+ {aes_192_ccm, [], [aead, aead_ng, aead_bad_tag]},
+ {aes_256_ccm, [], [aead, aead_ng, aead_bad_tag]},
{aes_128_ecb, [], [api_ng, api_ng_one_shot]},
{aes_192_ecb, [], [api_ng, api_ng_one_shot]},
{aes_256_ecb, [], [api_ng, api_ng_one_shot]},
- {aes_128_gcm, [], [aead]},
- {aes_192_gcm, [], [aead]},
- {aes_256_gcm, [], [aead]},
+ {aes_128_gcm, [], [aead, aead_ng, aead_bad_tag]},
+ {aes_192_gcm, [], [aead, aead_ng, aead_bad_tag]},
+ {aes_256_gcm, [], [aead, aead_ng, aead_bad_tag]},
%% Retired aliases
{aes_cbc, [], [block]},
@@ -334,21 +340,7 @@ end_per_suite(_Config) ->
%%-------------------------------------------------------------------
init_per_group(fips, Config) ->
- FIPSConfig = [{fips, true} | Config],
- case crypto:info_fips() of
- enabled ->
- FIPSConfig;
- not_enabled ->
- case crypto:enable_fips_mode(true) of
- true ->
- enabled = crypto:info_fips(),
- FIPSConfig;
- false ->
- {fail, "Failed to enable FIPS mode"}
- end;
- not_supported ->
- {skip, "FIPS mode not supported"}
- end;
+ try_enable_fips_mode(Config);
init_per_group(non_fips, Config) ->
NonFIPSConfig = [{fips, false} | Config],
case crypto:info_fips() of
@@ -543,7 +535,7 @@ api_ng() ->
api_ng(Config) when is_list(Config) ->
[_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
- lists:foreach(fun api_ng_cipher_increment/1, Ciphers).
+ lists:foreach(fun api_ng_cipher_increment/1, Ciphers ++ spec_0_bytes(Config)).
api_ng_cipher_increment({Type, Key, PlainTexts}=_X) ->
ct:log("~p",[_X]),
@@ -593,12 +585,33 @@ api_ng_cipher_increment_loop(Ref, InTexts) ->
end, InTexts).
%%--------------------------------------------------------------------
+%% Check that crypto do not core dump on early 0.9.8 cryptolibs
+spec_0_bytes(Config) ->
+ Type = proplists:get_value(type, Config),
+ #{iv_length := IVS, key_length := KS} = Spec = crypto:cipher_info(Type),
+ Key = <<0:KS/unit:8>>,
+ IV = <<0:IVS/unit:8>>,
+ spec_0_bytes(Type, Key, IV, Spec).
+
+
+spec_0_bytes(chacha20_poly1305, _, _, _) ->
+ [];
+spec_0_bytes(Type, Key, IV, #{mode := M}) when M == ccm_mode ;
+ M == gcm_mode ->
+ AAD = <<>>,
+ Plain = <<>>,
+ {_, Tag} = crypto:crypto_one_time_aead(Type, Key, IV, Plain, AAD, true),
+ [{Type, Key, Plain, IV, AAD, <<>>, Tag, []}];
+spec_0_bytes(Type, Key, IV, _Spec) ->
+ [{Type, Key, IV, <<>>, <<>>}].
+
+%%--------------------------------------------------------------------
api_ng_one_shot() ->
[{doc, "Test new api"}].
api_ng_one_shot(Config) when is_list(Config) ->
[_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
- lists:foreach(fun do_api_ng_one_shot/1, Ciphers).
+ lists:foreach(fun do_api_ng_one_shot/1, Ciphers ++ spec_0_bytes(Config)).
do_api_ng_one_shot({Type, Key, PlainTexts}=_X) ->
ct:log("~p",[_X]),
@@ -700,6 +713,23 @@ no_aead(Config) when is_list(Config) ->
notsup(fun crypto:block_decrypt/4, DecryptArgs).
%%--------------------------------------------------------------------
+no_aead_ng() ->
+ [{doc, "Test disabled aead ciphers"}].
+no_aead_ng(Config) when is_list(Config) ->
+ {EncFun, EncryptArgs} =
+ case lazy_eval(proplists:get_value(cipher, Config)) of
+ [{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info} | _] ->
+ {fun crypto:crypto_one_time_aead/7, [Type, Key, IV, PlainText, AAD, TagLen, true]};
+
+ [{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, _Info} | _] ->
+ {fun crypto:crypto_one_time_aead/6, [Type, Key, IV, PlainText, AAD, true]}
+ end,
+ notsup(EncFun, EncryptArgs),
+
+ DecryptArgs = [Type, Key, IV, CipherText, AAD, CipherTag, false],
+ notsup(fun crypto:crypto_one_time_aead/7, DecryptArgs).
+
+%%--------------------------------------------------------------------
stream() ->
[{doc, "Test stream ciphers"}].
stream(Config) when is_list(Config) ->
@@ -741,6 +771,40 @@ aead(Config) when is_list(Config) ->
end,
lists:foreach(fun aead_cipher/1, FilteredAEADs).
+%%--------------------------------------------------------------------
+aead_ng(Config) when is_list(Config) ->
+ [_|_] = AEADs = lazy_eval(proplists:get_value(cipher, Config)),
+ FilteredAEADs =
+ case proplists:get_bool(fips, Config) of
+ false ->
+ AEADs;
+ true ->
+ %% In FIPS mode, the IV length must be at least 12 bytes.
+ lists:filter(
+ fun(Tuple) ->
+ IVLen = byte_size(element(4, Tuple)),
+ IVLen >= 12
+ end, AEADs)
+ end,
+ lists:foreach(fun aead_cipher_ng/1, FilteredAEADs ++ spec_0_bytes(Config)).
+
+%%--------------------------------------------------------------------
+aead_bad_tag(Config) ->
+ [_|_] = AEADs = lazy_eval(proplists:get_value(cipher, Config)),
+ FilteredAEADs =
+ case proplists:get_bool(fips, Config) of
+ false ->
+ AEADs;
+ true ->
+ %% In FIPS mode, the IV length must be at least 12 bytes.
+ lists:filter(
+ fun(Tuple) ->
+ IVLen = byte_size(element(4, Tuple)),
+ IVLen >= 12
+ end, AEADs)
+ end,
+ lists:foreach(fun aead_cipher_bad_tag/1, FilteredAEADs).
+
%%--------------------------------------------------------------------
sign_verify() ->
[{doc, "Sign/verify digital signatures"}].
@@ -1281,6 +1345,97 @@ aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}
{got, Other1}})
end.
+aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) ->
+ Plain = iolist_to_binary(PlainText),
+ case crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, true) of
+ {CipherText, CipherTag} ->
+ ok;
+ Other0 ->
+ ct:fail({{crypto,
+ block_encrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]},
+ {expected, {CipherText, CipherTag}},
+ {got, Other0}})
+ end,
+ case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, CipherTag, false) of
+ Plain ->
+ ok;
+ Other1 ->
+ ct:fail({{crypto,
+ block_decrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]},
+ {expected, Plain},
+ {got, Other1}})
+ end;
+aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) ->
+ <<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag,
+ Plain = iolist_to_binary(PlainText),
+ try crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true) of
+ {CipherText, TruncatedCipherTag} ->
+ ok;
+ Other0 ->
+ ct:fail({{crypto,
+ block_encrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, {taglen,TagLen}]},
+ {expected, {CipherText, TruncatedCipherTag}},
+ {got, Other0}})
+ catch
+ error:E ->
+ ct:log("~p",[{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}]),
+ try crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true)
+ of
+ RR ->
+ ct:log("Works: ~p",[RR])
+ catch
+ CC:EE ->
+ ct:log("~p:~p", [CC,EE])
+ end,
+ ct:fail("~p",[E])
+ end,
+ case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, TruncatedCipherTag, false) of
+ Plain ->
+ ok;
+ Other1 ->
+ ct:fail({{crypto,
+ block_decrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag},
+ {truncated,TruncatedCipherTag}]},
+ {expected, Plain},
+ {got, Other1}})
+ end.
+
+mk_bad_tag(CipherTag) ->
+ case <<0:(size(CipherTag))/unit:8>> of
+ CipherTag -> % The correct tag may happen to be a suite of zeroes
+ <<1:(size(CipherTag))/unit:8>>;
+ X ->
+ X
+ end.
+
+aead_cipher_bad_tag({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) ->
+ Plain = iolist_to_binary(PlainText),
+ BadTag = mk_bad_tag(CipherTag),
+ case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTag, false) of
+ error ->
+ ok;
+ Plain ->
+ ct:log("~p:~p~n info: ~p~n key: ~p~n pt: ~p~n iv: ~p~n aad: ~p~n ct: ~p~n tag: ~p~n bad tag: ~p~n",
+ [?MODULE,?LINE,Info, Key, PlainText, IV, AAD, CipherText, CipherTag, BadTag]),
+ ct:fail("Didn't fail on bad tag")
+ end;
+aead_cipher_bad_tag({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) ->
+ Plain = iolist_to_binary(PlainText),
+ <<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag,
+ BadTruncatedTag = mk_bad_tag(TruncatedCipherTag),
+ case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTruncatedTag, false) of
+ error ->
+ ok;
+ Plain ->
+ ct:log("~p:~p~n info: ~p~n key: ~p~n pt: ~p~n iv: ~p~n aad: ~p~n ct: ~p~n tag: ~p~n bad tag: ~p~n",
+ [Info, Key, PlainText, IV, AAD, CipherText, TruncatedCipherTag, BadTruncatedTag]),
+ ct:fail("Didn't fail on bad tag")
+ end.
+
do_sign_verify({Type, undefined=Hash, Private, Public, Msg, Signature}) ->
case crypto:sign(eddsa, Hash, Msg, [Private,Type]) of
Signature ->
@@ -1454,6 +1609,8 @@ notsup(Fun, Args) ->
catch
error:notsup ->
ok;
+ error: {notsup, _, _} ->
+ ok;
Class:Error ->
{error, {Class, Error}}
end,
@@ -4157,3 +4314,85 @@ api_errors_ecdh(Config) when is_list(Config) ->
Curves = [gaffel, 0, sect571r1],
[_= (catch Test(O, C)) || O <- Others, C <- Curves],
ok.
+
+
+%%%----- Tests for bad algorithm name as argument
+-define(chk_api_name(Call, Expect),
+ %% Check that we don't segfault on bad names
+ (fun() -> % avoid binding vars
+ try
+ Call
+ catch
+ Expect -> ok;
+
+ Class:Reason:Stack ->
+ ct:log("~p:~p~n~p", [Class,Reason,Stack]),
+ ct:fail("Bad respons for bad name")
+ end
+ end)()
+ ).
+
+bad_cipher_name(_Config) ->
+ ?chk_api_name(crypto:crypto_init(foobar, <<1:128>>, true),
+ error:{badarg,{"api_ng.c",_Line},"Unknown cipher"}).
+
+bad_generate_key_name(_Config) ->
+ ?chk_api_name(crypto:generate_key(foobar, [1024]),
+ error:function_clause).
+
+bad_hash_name(_Config) ->
+ ?chk_api_name(crypto:hash_init(foobar),
+ error:badarg).
+
+bad_hmac_name(_Config) ->
+ ?chk_api_name(crypto:hmac(foobar, <<1:1024>>, "nothing"),
+ error:badarg).
+
+bad_mac_name(_Config) ->
+ ?chk_api_name(crypto:mac(foobar, <<1:1024>>, "nothing"),
+ error:function_clause).
+
+bad_sign_name(_Config) ->
+ ?chk_api_name(crypto:sign(rsa, foobar, "nothing", <<1:1024>>),
+ error:badarg),
+ ?chk_api_name(crypto:sign(foobar, sha, "nothing", <<1:1024>>),
+ error:badarg).
+
+bad_verify_name(_Config) ->
+ ?chk_api_name(crypto:verify(rsa, foobar, "nothing","nothing", <<1:1024>>),
+ error:badarg),
+ ?chk_api_name(crypto:verify(foobar, sha, "nothing", "nothing", <<1:1024>>),
+ error:badarg).
+
+
+%%%----------------------------------------------------------------
+try_enable_fips_mode(Config) ->
+ FIPSConfig = [{fips, true} | Config],
+ case crypto:info_fips() of
+ enabled ->
+ FIPSConfig;
+ not_enabled ->
+ %% Erlang/crypto configured with --enable-fips
+ case crypto:enable_fips_mode(true) of
+ true ->
+ %% and also the cryptolib is fips enabled
+ enabled = crypto:info_fips(),
+ FIPSConfig;
+ false ->
+ try
+ [{_,_,Inf}] = crypto:info_lib(),
+ re:run(Inf, "(F|f)(I|i)(P|p)(S|s)")
+ of
+ nomatch ->
+ {skip, "FIPS mode not supported in cryptolib"};
+ {match,_} ->
+ {fail, "Failed to enable FIPS mode"}
+ catch
+ _:_ ->
+ {fail, "Failed to check cryptolib info"}
+ end,
+ {skip, "FIPS mode not supported in cryptolib"}
+ end;
+ not_supported ->
+ {skip, "FIPS mode not supported"}
+ end.
diff --git a/lib/crypto/test/crypto_property_test_SUITE.erl b/lib/crypto/test/crypto_property_test_SUITE.erl
new file mode 100644
index 0000000000..75a3d4872f
--- /dev/null
+++ b/lib/crypto/test/crypto_property_test_SUITE.erl
@@ -0,0 +1,50 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2017. 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%
+%%
+
+-module(crypto_property_test_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+all() -> [encrypt_decrypt__crypto_one_time,
+ prop__crypto_init_update
+ ].
+
+%%% First prepare Config and compile the property tests for the found tool:
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ Config.
+
+%%%================================================================
+%%% Test suites
+%%%
+encrypt_decrypt__crypto_one_time(Config) ->
+ ct_property_test:quickcheck(
+ crypto_ng_api:prop__crypto_one_time(),
+ Config
+ ).
+prop__crypto_init_update(Config) ->
+ ct_property_test:quickcheck(
+ crypto_ng_api:prop__crypto_init_update(),
+ Config
+ ).
diff --git a/lib/crypto/test/property_test/crypto_ng_api.erl b/lib/crypto/test/property_test/crypto_ng_api.erl
new file mode 100644
index 0000000000..c3a21b0804
--- /dev/null
+++ b/lib/crypto/test/property_test/crypto_ng_api.erl
@@ -0,0 +1,134 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2017. 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%
+%%
+%%
+
+-module(crypto_ng_api).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+%%-define(EQC,true).
+-define(PROPER,true).
+%%-define(TRIQ,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+-include("crypto_prop_generators.hrl").
+
+%%%================================================================
+%%% Properties:
+
+prop__crypto_one_time() ->
+ numtests(10000,
+ ?FORALL({TextPlain, Cipher, Key, IV}, ?LET(Ciph,cipher(),
+ {text_plain(), Ciph, key(Ciph), iv(Ciph)}),
+ equal(TextPlain,
+ full_blocks(TextPlain, Cipher),
+ decrypt_encrypt_one_time(Cipher, Key, IV, TextPlain))
+ )
+ ).
+
+prop__crypto_init_update() ->
+ numtests(10000,
+ ?FORALL({TextPlain, Cipher, Key, IV}, ?LET(Ciph,cipher(),
+ {text_plain(), Ciph, key(Ciph), iv(Ciph)}),
+ equal(TextPlain,
+ full_blocks(TextPlain, Cipher),
+ decrypt_encrypt_init_update(Cipher, Key, IV, TextPlain))
+ )
+ ).
+
+%%%================================================================
+%%% Lib
+
+equal(_, T, T) -> true;
+equal(F, Tp, Td) ->
+ ct:pal("Full: ~p~n"
+ "Block: ~p~n"
+ "Decr: ~p~n",
+ [F, Tp, Td]),
+ false.
+
+
+decrypt_encrypt_one_time(Cipher, Key, IV, TextPlain) ->
+ io:format("~p:~p Cipher: ~p, BlockSize: ~p, Key: ~p, IV: ~p, TextPlain: ~p (~p chunks)",
+ [?MODULE,?LINE, Cipher, block_size(Cipher), size(Key), size(IV), size(iolist_to_binary(TextPlain)),
+ num_chunks(TextPlain)]),
+ TextCrypto = crypto:crypto_one_time(Cipher, Key, IV, TextPlain, true),
+ io:format("~p:~p TextCrypto: ~p", [?MODULE,?LINE, size(TextCrypto)]),
+ TextDecrypt = crypto:crypto_one_time(Cipher, Key, IV, TextCrypto, false),
+ io:format("~p:~p TextDecrypt: ~p", [?MODULE,?LINE, size(TextDecrypt)]),
+ TextDecrypt.
+
+
+decrypt_encrypt_init_update(Cipher, Key, IV, TextPlain) when is_binary(TextPlain) ->
+ decrypt_encrypt_init_update(Cipher, Key, IV, [TextPlain]);
+
+decrypt_encrypt_init_update(Cipher, Key, IV, TextPlain) ->
+ io:format("~p:~p Cipher: ~p, BlockSize: ~p, Key: ~p, IV: ~p, TextPlain: ~p (~p chunks)",
+ [?MODULE,?LINE, Cipher, block_size(Cipher), size(Key), size(IV), size(iolist_to_binary(TextPlain)),
+ num_chunks(TextPlain)]),
+ Cenc = crypto:crypto_init(Cipher, Key, IV, true),
+ TextOut = lists:foldl(fun(TextIn, TextOutAcc) ->
+ [crypto:crypto_update(Cenc,TextIn) | TextOutAcc]
+ end, [], TextPlain),
+ TextCrypto = lists:reverse(TextOut),
+ io:format("~p:~p TextCrypto: ~p",
+ [?MODULE,?LINE, size(iolist_to_binary(TextCrypto))]),
+
+ Cdec = crypto:crypto_init(Cipher, Key, IV, false),
+ TextDec = lists:foldl(fun(TextC, TextDecAcc) ->
+ [crypto:crypto_update(Cdec,TextC) | TextDecAcc]
+ end, [], TextCrypto),
+ iolist_to_binary(lists:reverse(TextDec)).
+
+full_blocks(TextPlain, Cipher) ->
+ TextPlainBin = iolist_to_binary(TextPlain),
+ {Head,_Tail} = split_binary(TextPlainBin, (size(TextPlainBin) - num_rest_bytes(TextPlainBin,Cipher))),
+ Head.
+
+num_chunks(B) when is_binary(B) -> 1;
+num_chunks(L) when is_list(L) -> length(L).
+
+num_rest_bytes(Bin, Cipher) -> size(Bin) rem block_size(Cipher).
+
diff --git a/lib/crypto/test/property_test/crypto_prop_generators.erl b/lib/crypto/test/property_test/crypto_prop_generators.erl
new file mode 100644
index 0000000000..5a53a000f0
--- /dev/null
+++ b/lib/crypto/test/property_test/crypto_prop_generators.erl
@@ -0,0 +1,93 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2017. 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%
+%%
+%%
+
+-module(crypto_prop_generators).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+%%-define(EQC,true).
+-define(PROPER,true).
+%%-define(TRIQ,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+%%%================================================================
+%%% Generators
+
+text_plain() -> iolist().
+
+cipher() -> oneof( non_aead_ciphers() -- [aes_ige256] ).
+
+key(Cipher) ->
+ %% Can't be shrinked
+ crypto:strong_rand_bytes( key_length(Cipher) ).
+
+iv(Cipher) ->
+ %% Can't be shrinked
+ crypto:strong_rand_bytes( iv_length(Cipher) ).
+
+iolist() -> frequency([{5, list( oneof([list(byte()),
+ binary(),
+ list(binary())]))},
+ {1, mybinary(50000)}
+ ]).
+
+mybinary(MaxSize) -> ?LET(Sz, integer(0,MaxSize), binary(Sz)).
+
+
+%%%================================================================
+non_aead_ciphers() ->
+ [C || C <- crypto:supports(ciphers),
+ C =/= chacha20_poly1305,
+ begin
+ #{mode := Mode} = crypto:cipher_info(C),
+ not lists:member(Mode, [ccm_mode, gcm_mode])
+ end].
+
+block_size(Cipher) -> maps:get(block_size, crypto:cipher_info(Cipher)).
+
+key_length(Cipher) -> maps:get(key_length, crypto:cipher_info(Cipher)).
+
+iv_length(Cipher) -> maps:get(iv_length, crypto:cipher_info(Cipher)).
diff --git a/lib/crypto/test/property_test/crypto_prop_generators.hrl b/lib/crypto/test/property_test/crypto_prop_generators.hrl
new file mode 100644
index 0000000000..56a762e651
--- /dev/null
+++ b/lib/crypto/test/property_test/crypto_prop_generators.hrl
@@ -0,0 +1,36 @@
+%%%
+%%% %CopyrightBegin%
+%%%
+%%% Copyright Ericsson AB 2004-2017. 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%
+%%%
+%%%
+
+
+-import(crypto_prop_generators,
+ [
+ text_plain/0,
+ cipher/0,
+ key/1,
+ iv/1,
+ iolist/0,
+ mybinary/1,
+
+ non_aead_ciphers/0,
+ block_size/1,
+ key_length/1,
+ iv_length/1
+ ]).
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index c0ff0c6512..1ecffa37c2 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 4.6.1
+CRYPTO_VSN = 4.6.2