From 6bc08d2dd7fd224088f538297ae657113c2a575d Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 13 May 2020 16:35:30 +0200 Subject: crypto/test: Re-write tests --- lib/crypto/test/crypto_SUITE.erl | 319 +++++++++++++++------------------------ 1 file changed, 119 insertions(+), 200 deletions(-) diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 617ca9b760..ed67ecd0b3 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -473,8 +473,7 @@ hmac() -> [{doc, "Test hmac function"}]. hmac(Config) when is_list(Config) -> Tuples = lazy_eval(proplists:get_value(hmac, Config)), - lists:foreach(fun hmac_check/1, Tuples), - lists:foreach(fun hmac_check/1, mac_listify(Tuples)). + do_cipher_tests(fun hmac_check/1, Tuples++mac_listify(Tuples)). %%-------------------------------------------------------------------- no_hmac() -> @@ -502,8 +501,7 @@ cmac() -> [{doc, "Test all different cmac functions"}]. cmac(Config) when is_list(Config) -> Pairs = lazy_eval(proplists:get_value(cmac, Config)), - lists:foreach(fun cmac_check/1, Pairs), - lists:foreach(fun cmac_check/1, mac_listify(Pairs)). + do_cipher_tests(fun cmac_check/1, Pairs ++ mac_listify(Pairs)). %%-------------------------------------------------------------------- poly1305() -> @@ -533,8 +531,7 @@ block() -> [{doc, "Test block ciphers"}]. block(Config) when is_list(Config) -> [_|_] = Blocks = lazy_eval(proplists:get_value(cipher, Config)), - lists:foreach(fun block_cipher/1, Blocks), - lists:foreach(fun block_cipher/1, block_iolistify(Blocks)), + do_cipher_tests(fun block_cipher/1, Blocks++block_iolistify(Blocks)), lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)). %%-------------------------------------------------------------------- @@ -833,8 +830,6 @@ no_stream_ivec(Config) when is_list(Config) -> notsup(fun crypto:stream_init/3, [Type, <<"Key">>, <<"Ivec">>]). %%-------------------------------------------------------------------- -aead() -> - [{doc, "Test AEAD ciphers"}]. aead(Config) when is_list(Config) -> [_|_] = AEADs = lazy_eval(proplists:get_value(cipher, Config)), FilteredAEADs = @@ -849,7 +844,7 @@ aead(Config) when is_list(Config) -> IVLen >= 12 end, AEADs) end, - lists:foreach(fun aead_cipher/1, FilteredAEADs). + do_cipher_tests(fun aead_cipher/1, FilteredAEADs). %%-------------------------------------------------------------------- aead_ng(Config) when is_list(Config) -> @@ -866,7 +861,7 @@ aead_ng(Config) when is_list(Config) -> IVLen >= 12 end, AEADs) end, - lists:foreach(fun aead_cipher_ng/1, FilteredAEADs ++ spec_0_bytes(Config)). + do_cipher_tests(fun aead_cipher_ng/1, FilteredAEADs ++ spec_0_bytes(Config)). %%-------------------------------------------------------------------- aead_bad_tag(Config) -> @@ -883,7 +878,7 @@ aead_bad_tag(Config) -> IVLen >= 12 end, AEADs) end, - lists:foreach(fun aead_cipher_bad_tag/1, FilteredAEADs). + do_cipher_tests(fun aead_cipher_bad_tag/1, FilteredAEADs). %%-------------------------------------------------------------------- sign_verify() -> @@ -1228,76 +1223,49 @@ hmac_increment(State0, [Increment | Rest]) -> hmac_increment(State, Rest). %%%---------------------------------------------------------------- -cmac_check({cmac, Type, Key, Text, CMac}) -> +cmac_check({cmac, Type, Key, Text, CMac}=T) -> ExpCMac = iolist_to_binary(CMac), - case crypto:cmac(Type, Key, Text) of - ExpCMac -> - ok; - Other -> - ct:fail({{crypto, cmac, [Type, Key, Text]}, {expected, ExpCMac}, {got, Other}}) - end; -cmac_check({cmac, Type, Key, Text, Size, CMac}) -> + cipher_test(T, + fun() -> crypto:cmac(Type, Key, Text) end, + ExpCMac); +cmac_check({cmac, Type, Key, Text, Size, CMac}=T) -> ExpCMac = iolist_to_binary(CMac), - case crypto:cmac(Type, Key, Text, Size) of - ExpCMac -> - ok; - Other -> - ct:fail({{crypto, cmac, [Type, Key, Text, Size]}, {expected, ExpCMac}, {got, Other}}) - end. - + cipher_test(T, + fun() -> crypto:cmac(Type, Key, Text, Size) end, + ExpCMac). -mac_check({MacType, SubType, Key, Text, Mac}) -> +mac_check({MacType, SubType, Key, Text, Mac}=T) -> ExpMac = iolist_to_binary(Mac), - case crypto:mac(MacType, SubType, Key, Text) of - ExpMac -> - ok; - Other -> - ct:fail({{crypto, mac, [MacType, SubType, Key, Text]}, {expected, ExpMac}, {got, Other}}) - end; -mac_check({MacType, SubType, Key, Text, Size, Mac}) -> + cipher_test(T, + fun() -> crypto:mac(MacType, SubType, Key, Text) end, + ExpMac); +mac_check({MacType, SubType, Key, Text, Size, Mac}=T) -> ExpMac = iolist_to_binary(Mac), - case crypto:mac(MacType, SubType, Key, Text, Size) of - ExpMac -> - ok; - Other -> - ct:fail({{crypto, mac, [MacType, SubType, Key, Text]}, {expected, ExpMac}, {got, Other}}) - end. + cipher_test(T, + fun() -> crypto:mac(MacType, SubType, Key, Text, Size) end, + ExpMac). - -block_cipher({Type, Key, PlainText}) -> +block_cipher({Type, Key, PlainText}=T) -> Plain = iolist_to_binary(PlainText), CipherText = crypto:block_encrypt(Type, Key, PlainText), - case crypto:block_decrypt(Type, Key, CipherText) of - Plain -> - ok; - Other -> - ct:fail({{crypto, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}}) - end; + cipher_test(T, + fun() -> crypto:block_decrypt(Type, Key, CipherText) end, + Plain); -block_cipher({Type, Key, IV, PlainText}) -> +block_cipher({Type, Key, IV, PlainText}=T) -> Plain = iolist_to_binary(PlainText), CipherText = crypto:block_encrypt(Type, Key, IV, PlainText), - case crypto:block_decrypt(Type, Key, IV, CipherText) of - Plain -> - ok; - Other -> - ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other}}) - end; + cipher_test(T, + fun() -> crypto:block_decrypt(Type, Key, IV, CipherText) end, + Plain); -block_cipher({Type, Key, IV, PlainText, CipherText}) -> +block_cipher({Type, Key, IV, PlainText, CipherText}=T) -> Plain = iolist_to_binary(PlainText), - case crypto:block_encrypt(Type, Key, IV, Plain) of - CipherText -> - ok; - Other0 -> - ct:fail({{crypto, block_encrypt, [Type, Key, IV, Plain]}, {expected, CipherText}, {got, Other0}}) - end, - case crypto:block_decrypt(Type, Key, IV, CipherText) of - Plain -> - ok; - Other1 -> - ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other1}}) - end. + cipher_test(T, + fun() -> crypto:block_encrypt(Type, Key, IV, Plain) end, + CipherText, + fun() -> crypto:block_decrypt(Type, Key, IV, CipherText) end, + Plain). block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc ; Type == des3_cbc ; @@ -1418,124 +1386,99 @@ stream_cipher_incment_loop(State0, OrigState, [PlainText | PlainTexts], Acc, Pla {State, CipherText} = crypto:stream_encrypt(State0, PlainText), stream_cipher_incment_loop(State, OrigState, PlainTexts, [CipherText | Acc], Plain). -aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) -> +aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, _Info}=T) -> Plain = iolist_to_binary(PlainText), - case crypto:block_encrypt(Type, Key, IV, {AAD, Plain}) 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:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) 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({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) -> + cipher_test(T, + fun() -> crypto:block_encrypt(Type, Key, IV, {AAD, Plain}) end, + {CipherText, CipherTag}, + fun() -> crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) end, + Plain); +aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info}=T) -> <> = CipherTag, Plain = iolist_to_binary(PlainText), - try crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) 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:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) 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. + cipher_test(T, + fun() -> crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) end, + {CipherText, TruncatedCipherTag}, + fun() -> crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) end, + Plain). -aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) -> +aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, _Info}=T) -> 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}) -> + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, true) end, + {CipherText, CipherTag}, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, CipherTag, false) end, + Plain); +aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info}=T) -> <> = 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}}) + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true) end, + {CipherText, TruncatedCipherTag}, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, TruncatedCipherTag, false) end, + Plain). + +aead_cipher_bad_tag({Type, Key, _PlainText, IV, AAD, CipherText, CipherTag, _Info}=T) -> + BadTag = mk_bad_tag(CipherTag), + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTag, false) end, + error); +aead_cipher_bad_tag({Type, Key, _PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info}=T) -> + <> = CipherTag, + BadTruncatedTag = mk_bad_tag(TruncatedCipherTag), + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTruncatedTag, false) end, + error). + + +cipher_test(T, Fe, Ee, Fd, Ed) -> + %% Test encrypt + Re = cipher_test(encrypt, T, Fe, Ee), + %% Test decrypt + Rd = cipher_test(decrypt, T, Fd, Ed), + case {Re, Rd} of + {ok,ok} -> ok; + {ok,_} -> Rd; + {_,ok} -> Re; + _ -> {Re,Rd} + end. + +cipher_test(T, F, E) -> + cipher_test(notag, T, F, E). + +cipher_test(Tag, T, F, E) -> + try F() of + E -> ok; + Other -> {other, {Tag,T,Other}} 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}}) + error:Error -> {error, {Tag,T,Error}} + end. + +do_cipher_tests(F, TestVectors) when is_function(F,1) -> + {Passed,Failed} = + lists:partition( + fun(R) -> R == ok end, + lists:map(F, TestVectors) + ), + BothFailed = lists:filter(fun({ok,_}) -> false; + ({_,ok}) -> false; + (ok) -> false; + (_) -> true + end, + Failed), + ct:log("Passed: ~p, BothFailed: ~p OnlyOneFailed: ~p", + [length(Passed), length(BothFailed), length(Failed)-length(BothFailed)]), + case Failed of + [] -> + ct:comment("All ~p passed", [length(Passed)]); + _ -> + ct:log("~p",[hd(Failed)]), + ct:comment("Passed: ~p, BothFailed: ~p OnlyOneFailed: ~p", + [length(Passed), length(BothFailed), length(Failed)-length(BothFailed)]), + ct:fail("Failed", []) end. + mk_bad_tag(CipherTag) -> case <<0:(size(CipherTag))/unit:8>> of CipherTag -> % The correct tag may happen to be a suite of zeroes @@ -1544,30 +1487,6 @@ mk_bad_tag(CipherTag) -> 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), - <> = 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 -> -- cgit v1.2.1