From ddc6b01876328be56326596b5be0f2b9d03285ae Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Fri, 24 May 2019 14:34:58 +0200 Subject: crypto: Remove warnings when linking with LibreSSL got warning for unused function. --- lib/crypto/c_src/pkey.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c index a1e2677b34..d53d91c25b 100644 --- a/lib/crypto/c_src/pkey.c +++ b/lib/crypto/c_src/pkey.c @@ -59,8 +59,9 @@ static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_T EVP_PKEY **pkey); static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, PKeyCryptOptions *opt); +#ifdef HAVE_RSA_SSLV23_PADDING static size_t size_of_RSA(EVP_PKEY *pkey); - +#endif static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type, const EVP_MD **md) @@ -1031,6 +1032,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI return PKEY_BADARG; } +#ifdef HAVE_RSA_SSLV23_PADDING static size_t size_of_RSA(EVP_PKEY *pkey) { int ret = 0; RSA *rsa = NULL; @@ -1045,6 +1047,7 @@ static size_t size_of_RSA(EVP_PKEY *pkey) { return (ret < 0) ? 0 : (size_t)ret; } +#endif ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {/* (Algorithm, Data, PublKey=[E,N]|[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Options, IsPrivate, IsEncrypt) */ -- cgit v1.2.3 From 2d4a31cc2e2b7b405baff620f727cc5398833a21 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 22 May 2019 13:22:21 +0200 Subject: crypto: Enable CMAC tests for aes-128-cbc and aes-256-cbc --- lib/crypto/test/crypto_SUITE.erl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 56691223c4..dcbf5ea460 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -265,9 +265,9 @@ groups() -> %% New cipher nameing schema {des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]}, {des_ede3_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]}, - {aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]}, + {aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac]}, {aes_192_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]}, - {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]}, + {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac]}, {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]}, @@ -1836,13 +1836,12 @@ group_config(ecdh, Config) -> group_config(dh, Config) -> GenerateCompute = [dh()], [{generate_compute, GenerateCompute} | Config]; - -group_config(aes_cbc128 = Type, Config) -> - Block = fun() -> aes_cbc128(Config) end, +group_config(aes_128_cbc = Type, Config) -> + Block = fun() -> aes_128_cbc(Config) end, Pairs = fun() -> cmac_nist(Config, Type) end, [{cipher, Block}, {cmac, Pairs} | Config]; -group_config(aes_cbc256 = Type, Config) -> - Block = fun() -> aes_cbc256(Config) end, +group_config(aes_256_cbc = Type, Config) -> + Block = fun() -> aes_256_cbc(Config) end, Pairs = fun() -> cmac_nist(Config, Type) end, [{cipher, Block}, {cmac, Pairs} | Config]; group_config(chacha20_poly1305, Config) -> @@ -3843,11 +3842,11 @@ ecc() -> end, TestCases). -cmac_nist(Config, aes_cbc128 = Type) -> +cmac_nist(Config, aes_128_cbc = Type) -> read_rsp(Config, Type, ["CMACGenAES128.rsp", "CMACVerAES128.rsp"]); -cmac_nist(Config, aes_cbc256 = Type) -> +cmac_nist(Config, aes_256_cbc = Type) -> read_rsp(Config, Type, ["CMACGenAES256.rsp", "CMACVerAES256.rsp"]). -- cgit v1.2.3 From ae4c8e6ee26e3c606054e4a845ac06f95ade1e57 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 22 May 2019 14:56:26 +0200 Subject: crypto: Re-structure cmac and hmac test vector handling as a preparation for a unified cmac and hmac test case. --- lib/crypto/test/crypto_SUITE.erl | 273 +++++++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 110 deletions(-) diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index dcbf5ea460..3b60de9eb7 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -176,19 +176,19 @@ groups() -> ]}, {md4, [], [hash]}, - {md5, [], [hash, hmac]}, + {md5, [], [hash, hmac, hmac_update]}, {ripemd160, [], [hash]}, - {sha, [], [hash, hmac]}, - {sha224, [], [hash, hmac]}, - {sha256, [], [hash, hmac]}, - {sha384, [], [hash, hmac]}, - {sha512, [], [hash, hmac]}, - {sha3_224, [], [hash, hmac]}, - {sha3_256, [], [hash, hmac]}, - {sha3_384, [], [hash, hmac]}, - {sha3_512, [], [hash, hmac]}, - {blake2b, [], [hash, hmac]}, - {blake2s, [], [hash, hmac]}, + {sha, [], [hash, hmac, hmac_update]}, + {sha224, [], [hash, hmac, hmac_update]}, + {sha256, [], [hash, hmac, hmac_update]}, + {sha384, [], [hash, hmac, hmac_update]}, + {sha512, [], [hash, hmac, hmac_update]}, + {sha3_224, [], [hash, hmac, hmac_update]}, + {sha3_256, [], [hash, hmac, hmac_update]}, + {sha3_384, [], [hash, hmac, hmac_update]}, + {sha3_512, [], [hash, hmac, hmac_update]}, + {blake2b, [], [hash, hmac, hmac_update]}, + {blake2s, [], [hash, hmac, hmac_update]}, {no_blake2b, [], [no_hash, no_hmac]}, {no_blake2s, [], [no_hash, no_hmac]}, {rsa, [], [sign_verify, @@ -386,7 +386,7 @@ init_per_testcase(info, Config) -> init_per_testcase(cmac, Config) -> case is_supported(cmac) of true -> - Config; + configure_mac(cmac, proplists:get_value(type,Config), Config); false -> {skip, "CMAC is not supported"} end; @@ -405,6 +405,8 @@ init_per_testcase(generate, Config) -> end; _ -> Config end; +init_per_testcase(hmac, Config) -> + configure_mac(hmac, proplists:get_value(type,Config), Config); init_per_testcase(_Name,Config) -> Config. @@ -452,27 +454,41 @@ no_hash(Config) when is_list(Config) -> notsup(fun crypto:hash_init/1, [Type]). %%-------------------------------------------------------------------- hmac() -> - [{doc, "Test all different hmac functions"}]. + [{doc, "Test hmac function"}]. hmac(Config) when is_list(Config) -> - {Type, Keys, DataLE, Expected} = proplists:get_value(hmac, Config), - Data = lazy_eval(DataLE), - hmac(Type, Keys, Data, Expected), - hmac(Type, lists:map(fun iolistify/1, Keys), lists:map(fun iolistify/1, Data), Expected), - hmac_increment(Type). + Tuples = lazy_eval(proplists:get_value(hmac, Config)), + lists:foreach(fun hmac_check/1, Tuples), + lists:foreach(fun hmac_check/1, mac_listify(Tuples)). + %%-------------------------------------------------------------------- no_hmac() -> [{doc, "Test all disabled hmac functions"}]. no_hmac(Config) when is_list(Config) -> Type = ?config(type, Config), - notsup(fun crypto:hmac/3, [Type, <<"Key">>, <<"Hi There">>]), + notsup(fun crypto:hmac/3, [Type, <<"Key">>, <<"Hi There">>]). + +%%-------------------------------------------------------------------- +hmac_update() -> + [{doc, "Test all incremental hmac functions"}]. +hmac_update(Config) -> + Type = ?config(type, Config), + hmac_increment(Type). + +%%-------------------------------------------------------------------- +no_hmac_update() -> + [{doc, "Test all disabled incremental hmac functions"}]. +no_hmac_update(Config) -> + Type = ?config(type, Config), notsup(fun crypto:hmac_init/2, [Type, <<"Key">>]). + %%-------------------------------------------------------------------- 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, cmac_iolistify(Pairs)). + lists:foreach(fun cmac_check/1, mac_listify(Pairs)). + %%-------------------------------------------------------------------- poly1305() -> [{doc, "Test poly1305 function"}]. @@ -957,33 +973,46 @@ hash_increment(State0, [Increment | Rest]) -> State = crypto:hash_update(State0, Increment), hash_increment(State, Rest). -hmac(_, [],[],[]) -> - ok; -hmac(sha = Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) -> - call_crypto_hmac([Type, Key, Data, 20], Type, Expected), - hmac(Type, Keys, Rest, Expects); -hmac(Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) -> - call_crypto_hmac([Type, Key, Data, 16], Type, Expected), - hmac(Type, Keys, Rest, Expects); -hmac(Type, [Key | Keys], [Data| Rest], [Expected | Expects]) -> - call_crypto_hmac([Type, Key, Data], Type, Expected), - hmac(Type, Keys, Rest, Expects). - -call_crypto_hmac(Args, Type, Expected) -> - try apply(crypto, hmac, Args) + +%%%---------------------------------------------------------------- +hmac_check({hmac, sha=Type, Key, <<"Test With Truncation">>=Data, Expected}) -> + do_hmac_check(Type, Key, Data, 20, Expected); +hmac_check({hmac, Type, Key, <<"Test With Truncation">>=Data, Expected}) -> + do_hmac_check(Type, Key, Data, 16, Expected); +hmac_check({hmac, Type, Key, Data, Expected}) -> + do_hmac_check(Type, Key, Data, Expected). + + +do_hmac_check(Type, Key, Data, Expected) -> + try crypto:hmac(Type, Key, Data) of Expected -> ok; Other -> - ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,Other}}) + ct:fail({{crypto,hmac,[Type,Key,Data]}, {expected,Expected}, {got,Other}}) catch error:notsup -> ct:fail("HMAC ~p not supported", [Type]); Class:Cause -> - ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,{Class,Cause}}}) + ct:fail({{crypto,hmac,[Type,Key,Data]}, {expected,Expected}, {got,{Class,Cause}}}) end. +do_hmac_check(Type, Key, Data, MacLength, Expected) -> + try crypto:hmac(Type, Key, Data, MacLength) + of + Expected -> + ok; + Other -> + ct:fail({{crypto,hmac,[Type,Key,Data,MacLength]}, {expected,Expected}, {got,Other}}) + catch + error:notsup -> + ct:fail("HMAC ~p not supported", [Type]); + Class:Cause -> + ct:fail({{crypto,hmac,[Type,Key,Data,MacLength]}, {expected,Expected}, {got,{Class,Cause}}}) + end. + +%%%---------------------------------------------------------------- hmac_increment(Type) -> Key = hmac_key(Type), Increments = hmac_inc(Type), @@ -1002,7 +1031,8 @@ hmac_increment(State0, [Increment | Rest]) -> State = crypto:hmac_update(State0, Increment), hmac_increment(State, Rest). -cmac_check({Type, Key, Text, CMac}) -> +%%%---------------------------------------------------------------- +cmac_check({cmac, Type, Key, Text, CMac}) -> ExpCMac = iolist_to_binary(CMac), case crypto:cmac(Type, Key, Text) of ExpCMac -> @@ -1010,7 +1040,7 @@ cmac_check({Type, Key, Text, CMac}) -> Other -> ct:fail({{crypto, cmac, [Type, Key, Text]}, {expected, ExpCMac}, {got, Other}}) end; -cmac_check({Type, Key, Text, Size, CMac}) -> +cmac_check({cmac, Type, Key, Text, Size, CMac}) -> ExpCMac = iolist_to_binary(CMac), case crypto:cmac(Type, Key, Text, Size) of ExpCMac -> @@ -1019,7 +1049,6 @@ cmac_check({Type, Key, Text, Size, CMac}) -> ct:fail({{crypto, cmac, [Type, Key, Text, Size]}, {expected, ExpCMac}, {got, Other}}) end. - block_cipher({Type, Key, PlainText}) -> Plain = iolist_to_binary(PlainText), CipherText = crypto:block_encrypt(Type, Key, PlainText), @@ -1450,17 +1479,17 @@ decstr2int(S) -> is_supported(Group) -> lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])). -cmac_iolistify(Blocks) -> - lists:map(fun do_cmac_iolistify/1, Blocks). +mac_listify(Blocks) -> + lists:map(fun do_mac_listify/1, Blocks). block_iolistify(Blocks) -> lists:map(fun do_block_iolistify/1, Blocks). stream_iolistify(Streams) -> lists:map(fun do_stream_iolistify/1, Streams). -do_cmac_iolistify({Type, Key, Text, CMac}) -> - {Type, iolistify(Key), iolistify(Text), CMac}; -do_cmac_iolistify({Type, Key, Text, Size, CMac}) -> - {Type, iolistify(Key), iolistify(Text), Size, CMac}. +do_mac_listify({MType, Type, Key, Text, CMac}) -> + {MType, Type, iolistify(Key), iolistify(Text), CMac}; +do_mac_listify({MType, Type, Key, Text, Size, CMac}) -> + {MType, Type, iolistify(Key), iolistify(Text), Size, CMac}. do_stream_iolistify({Type, Key, PlainText}) -> {Type, iolistify(Key), iolistify(PlainText)}; @@ -1694,10 +1723,7 @@ group_config(md4 = Type, Config) -> group_config(md5 = Type, Config) -> Msgs = rfc_1321_msgs(), Digests = rfc_1321_md5_digests(), - Keys = rfc_2202_md5_keys() ++ [long_hmac_key(md5)], - Data = rfc_2202_msgs() ++ [long_msg()], - Hmac = rfc_2202_hmac_md5() ++ [long_hmac(md5)], - [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(ripemd160 = Type, Config) -> Msgs = ripemd160_msgs(), Digests = ripemd160_digests(), @@ -1705,56 +1731,41 @@ group_config(ripemd160 = Type, Config) -> group_config(sha = Type, Config) -> Msgs = [rfc_4634_test1(), rfc_4634_test2_1(),long_msg()], Digests = rfc_4634_sha_digests() ++ [long_sha_digest()], - Keys = rfc_2202_sha_keys() ++ [long_hmac_key(sha)], - Data = rfc_2202_msgs() ++ [long_msg()], - Hmac = rfc_2202_hmac_sha() ++ [long_hmac(sha)], - [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha224 = Type, Config) -> Msgs = [rfc_4634_test1(), rfc_4634_test2_1()], Digests = rfc_4634_sha224_digests(), - Keys = rfc_4231_keys(), - Data = rfc_4231_msgs(), - Hmac = rfc4231_hmac_sha224(), - [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha256 = Type, Config) -> Msgs = [rfc_4634_test1(), rfc_4634_test2_1(), long_msg()], Digests = rfc_4634_sha256_digests() ++ [long_sha256_digest()], - Keys = rfc_4231_keys() ++ [long_hmac_key(sha256)], - Data = rfc_4231_msgs() ++ [long_msg()], - Hmac = rfc4231_hmac_sha256() ++ [long_hmac(sha256)], - [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha384 = Type, Config) -> Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()], Digests = rfc_4634_sha384_digests() ++ [long_sha384_digest()], - Keys = rfc_4231_keys() ++ [long_hmac_key(sha384)], - Data = rfc_4231_msgs() ++ [long_msg()], - Hmac = rfc4231_hmac_sha384() ++ [long_hmac(sha384)], - [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha512 = Type, Config) -> Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()], Digests = rfc_4634_sha512_digests() ++ [long_sha512_digest()], - Keys = rfc_4231_keys() ++ [long_hmac_key(sha512)], - Data = rfc_4231_msgs() ++ [long_msg()], - Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)], - [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha3_224 = Type, Config) -> {Msgs,Digests} = sha3_test_vectors(Type), - [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha3_256 = Type, Config) -> {Msgs,Digests} = sha3_test_vectors(Type), - [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha3_384 = Type, Config) -> {Msgs,Digests} = sha3_test_vectors(Type), - [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(sha3_512 = Type, Config) -> {Msgs,Digests} = sha3_test_vectors(Type), - [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(blake2b = Type, Config) -> {Msgs, Digests} = blake2_test_vectors(Type), - [{hash, {Type, Msgs, Digests}}, {hmac, blake2_hmac(Type)} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(blake2s = Type, Config) -> {Msgs, Digests} = blake2_test_vectors(Type), - [{hash, {Type, Msgs, Digests}}, {hmac, blake2_hmac(Type)} | Config]; + [{hash, {Type, Msgs, Digests}} | Config]; group_config(rsa, Config) -> Msg = rsa_plain(), Public = rsa_public(), @@ -1828,7 +1839,6 @@ group_config(Type, Config) when Type == ed25519 ; Type == ed448 -> group_config(srp, Config) -> GenerateCompute = [srp3(), srp6(), srp6a(), srp6a_smaller_prime()], [{generate_compute, GenerateCompute} | Config]; - group_config(ecdh, Config) -> Compute = ecdh(), Generate = ecc(), @@ -1836,18 +1846,6 @@ group_config(ecdh, Config) -> group_config(dh, Config) -> GenerateCompute = [dh()], [{generate_compute, GenerateCompute} | Config]; -group_config(aes_128_cbc = Type, Config) -> - Block = fun() -> aes_128_cbc(Config) end, - Pairs = fun() -> cmac_nist(Config, Type) end, - [{cipher, Block}, {cmac, Pairs} | Config]; -group_config(aes_256_cbc = Type, Config) -> - Block = fun() -> aes_256_cbc(Config) end, - Pairs = fun() -> cmac_nist(Config, Type) end, - [{cipher, Block}, {cmac, Pairs} | Config]; -group_config(chacha20_poly1305, Config) -> - AEAD = chacha20_poly1305(Config), - [{cipher, AEAD} | Config]; - group_config(poly1305, Config) -> V = [%% {Key, Txt, Expect} {%% RFC7539 2.5.2 @@ -1863,6 +1861,76 @@ group_config(F, Config) -> [{cipher, TestVectors} | Config]. +configure_mac(MacType, SubType, Config) -> + case do_configure_mac(MacType, SubType, Config) of + undefined -> + {skip, io:format("No ~p test vectors for ~p", [MacType, SubType])}; + Pairs -> + [{MacType, Pairs} | Config] + end. + +do_configure_mac(hmac, Type, _Config) -> + case Type of + md5 -> + Keys = rfc_2202_md5_keys() ++ [long_hmac_key(md5)], + Data = rfc_2202_msgs() ++ [long_msg()], + Hmac = rfc_2202_hmac_md5() ++ [long_hmac(md5)], + zip3_special(hmac, Type, Keys, Data, Hmac); + sha -> + Keys = rfc_2202_sha_keys() ++ [long_hmac_key(sha)], + Data = rfc_2202_msgs() ++ [long_msg()], + Hmac = rfc_2202_hmac_sha() ++ [long_hmac(sha)], + zip3_special(hmac, Type, Keys, Data, Hmac); + sha224 -> + Keys = rfc_4231_keys(), + Data = rfc_4231_msgs(), + Hmac = rfc4231_hmac_sha224(), + zip3_special(hmac, Type, Keys, Data, Hmac); + sha256 -> + Keys = rfc_4231_keys() ++ [long_hmac_key(sha256)], + Data = rfc_4231_msgs() ++ [long_msg()], + Hmac = rfc4231_hmac_sha256() ++ [long_hmac(sha256)], + zip3_special(hmac, Type, Keys, Data, Hmac); + sha384 -> + Keys = rfc_4231_keys() ++ [long_hmac_key(sha384)], + Data = rfc_4231_msgs() ++ [long_msg()], + Hmac = rfc4231_hmac_sha384() ++ [long_hmac(sha384)], + zip3_special(hmac, Type, Keys, Data, Hmac); + sha512 -> + Keys = rfc_4231_keys() ++ [long_hmac_key(sha512)], + Data = rfc_4231_msgs() ++ [long_msg()], + Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)], + zip3_special(hmac, Type, Keys, Data, Hmac); + sha3_224 -> + hmac_sha3(Type); + sha3_256 -> + hmac_sha3(Type); + sha3_384 -> + hmac_sha3(Type); + sha3_512 -> + hmac_sha3(Type); + blake2b -> + blake2_hmac(Type); + blake2s -> + blake2_hmac(Type); + _ -> + undefined + end; +do_configure_mac(cmac, Cipher, Config) -> + case Cipher of + aes_128_cbc -> + fun() -> read_rsp(Config, Cipher, ["CMACGenAES128.rsp", "CMACVerAES128.rsp"]) end; + aes_256_cbc -> + fun() -> read_rsp(Config, Cipher, ["CMACGenAES256.rsp", "CMACVerAES256.rsp"]) end; + _ -> + undefined + end. + + +zip3_special(Type, SubType, As, Bs, Cs) -> + [{Type, SubType, A, B, C} + || {A,B,C} <- lists:zip3(As, Bs, Cs)]. + rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, OptsToTry) -> case ?config(fips, Config) of @@ -1980,10 +2048,8 @@ blake2_test_vectors(blake2s) -> ]}. blake2_hmac(Type) -> - {Ks, Ds, Hs} = lists:unzip3( - [ {hexstr2bin(K), hexstr2bin(D), H} - || {{K, D}, H} <- lists:zip(blake2_hmac_key_data(), blake2_hmac_hmac(Type)) ]), - {Type, Ks, Ds, Hs}. + [{hmac, Type, hexstr2bin(K), hexstr2bin(D), H} + || {{K, D}, H} <- lists:zip(blake2_hmac_key_data(), blake2_hmac_hmac(Type)) ]. blake2_hmac_key_data() -> [ {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 0b0b0b0b", @@ -2082,12 +2148,8 @@ hmac_sha3(Type) -> sha3_384 -> 3; sha3_512 -> 4 end, - {Keys, Datas, Hmacs} = - lists:unzip3( - [{hexstr2bin(Key), hexstr2bin(Data), hexstr2bin(element(N,Hmacs))} - || {Key,Data,Hmacs} <- hmac_sha3_data()]), - {Type, Keys, Datas, Hmacs}. - + [{hmac, Type, hexstr2bin(Key), hexstr2bin(Data), hexstr2bin(element(N,Hmacs))} + || {Key,Data,Hmacs} <- hmac_sha3_data()]. hmac_sha3_data() -> [ @@ -3842,14 +3904,6 @@ ecc() -> end, TestCases). -cmac_nist(Config, aes_128_cbc = Type) -> - read_rsp(Config, Type, - ["CMACGenAES128.rsp", "CMACVerAES128.rsp"]); - -cmac_nist(Config, aes_256_cbc = Type) -> - read_rsp(Config, Type, - ["CMACGenAES256.rsp", "CMACVerAES256.rsp"]). - int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); int_to_bin(X) -> int_to_bin_pos(X, []). @@ -4067,12 +4121,11 @@ parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, State, Acc) -> Mlen = binary_to_integer(Mlen0), <> = hexstr2bin(Msg0), MAC = hexstr2bin(MAC0), - case binary_to_integer(Tlen) of 0 -> - parse_rsp(Type, Next, State, [{Type, Key, Msg, MAC}|Acc]); + parse_rsp(Type, Next, State, [{cmac, Type, Key, Msg, MAC}|Acc]); I -> - parse_rsp(Type, Next, State, [{Type, Key, Msg, I, MAC}|Acc]) + parse_rsp(Type, Next, State, [{cmac, Type, Key, Msg, I, MAC}|Acc]) end. api_errors_ecdh(Config) when is_list(Config) -> -- cgit v1.2.3 From 160cea3f655913b370650f93b0c8f6c1bd163e32 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Tue, 14 May 2019 17:01:17 +0200 Subject: crypto: MAC nif unifying HMAC, CMAC and POLY1305 into one nif using the EVP_DigestSign interface. This enables acceleration if available in lower layers, that is, in cryptolib and lower. However, for older cryptolibs the old HMAC and CMAC low-level interfaces are used, but moved from hmac.c and cmac.c into mac.c. --- lib/crypto/c_src/Makefile.in | 1 + lib/crypto/c_src/algorithms.c | 27 +-- lib/crypto/c_src/atoms.c | 9 + lib/crypto/c_src/atoms.h | 4 + lib/crypto/c_src/crypto.c | 3 + lib/crypto/c_src/mac.c | 389 ++++++++++++++++++++++++++++++++++++++ lib/crypto/c_src/mac.h | 33 ++++ lib/crypto/c_src/openssl_config.h | 7 + lib/crypto/src/crypto.erl | 16 +- 9 files changed, 464 insertions(+), 25 deletions(-) create mode 100644 lib/crypto/c_src/mac.c create mode 100644 lib/crypto/c_src/mac.h diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index b6a65d7488..35ded001d6 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -92,6 +92,7 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \ $(OBJDIR)/hash$(TYPEMARKER).o \ $(OBJDIR)/hmac$(TYPEMARKER).o \ $(OBJDIR)/info$(TYPEMARKER).o \ + $(OBJDIR)/mac$(TYPEMARKER).o \ $(OBJDIR)/math$(TYPEMARKER).o \ $(OBJDIR)/pkey$(TYPEMARKER).o \ $(OBJDIR)/poly1305$(TYPEMARKER).o \ diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c index 75cddeb1e9..53b8b7eaa9 100644 --- a/lib/crypto/c_src/algorithms.c +++ b/lib/crypto/c_src/algorithms.c @@ -20,13 +20,12 @@ #include "algorithms.h" #include "cipher.h" +#include "mac.h" static unsigned int algo_hash_cnt, algo_hash_fips_cnt; static ERL_NIF_TERM algo_hash[14]; /* increase when extending the list */ static unsigned int algo_pubkey_cnt, algo_pubkey_fips_cnt; static ERL_NIF_TERM algo_pubkey[12]; /* increase when extending the list */ -static unsigned int algo_mac_cnt, algo_mac_fips_cnt; -static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */ static unsigned int algo_curve_cnt, algo_curve_fips_cnt; static ERL_NIF_TERM algo_curve[89]; /* increase when extending the list */ static unsigned int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt; @@ -101,19 +100,6 @@ void init_algorithms_types(ErlNifEnv* env) #endif algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp"); - - // 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; - // Validated algorithms first algo_curve_cnt = 0; #if defined(HAVE_EC) @@ -250,7 +236,6 @@ void init_algorithms_types(ErlNifEnv* env) // Check that the max number of algos is updated ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM)); ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM)); - ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM)); ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM)); ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM)); } @@ -284,18 +269,12 @@ ERL_NIF_TERM cipher_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return cipher_types_as_list(env); /* Exclude old api ciphers */ } + ERL_NIF_TERM mac_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - unsigned int cnt = -#ifdef FIPS_SUPPORT - FIPS_mode() ? algo_mac_fips_cnt : -#endif - algo_mac_cnt; - - return enif_make_list_from_array(env, algo_mac, cnt); + return mac_types_as_list(env); } - ERL_NIF_TERM curve_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { unsigned int cnt = diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c index 059c14690f..bbeb329fa2 100644 --- a/lib/crypto/c_src/atoms.c +++ b/lib/crypto/c_src/atoms.c @@ -30,6 +30,10 @@ ERL_NIF_TERM atom_rsa_no_padding; ERL_NIF_TERM atom_signature_md; ERL_NIF_TERM atom_undefined; +ERL_NIF_TERM atom_hmac; +ERL_NIF_TERM atom_cmac; +ERL_NIF_TERM atom_poly1305; + ERL_NIF_TERM atom_ok; ERL_NIF_TERM atom_none; ERL_NIF_TERM atom_notsup; @@ -155,6 +159,11 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding"); atom_signature_md = enif_make_atom(env,"signature_md"); atom_undefined = enif_make_atom(env,"undefined"); + + atom_hmac = enif_make_atom(env,"hmac"); + atom_cmac = enif_make_atom(env,"cmac"); + atom_poly1305 = enif_make_atom(env,"poly1305"); + atom_ok = enif_make_atom(env,"ok"); atom_none = enif_make_atom(env,"none"); atom_notsup = enif_make_atom(env,"notsup"); diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h index f5913de96f..0e2f1a0022 100644 --- a/lib/crypto/c_src/atoms.h +++ b/lib/crypto/c_src/atoms.h @@ -34,6 +34,10 @@ extern ERL_NIF_TERM atom_rsa_no_padding; extern ERL_NIF_TERM atom_signature_md; extern ERL_NIF_TERM atom_undefined; +extern ERL_NIF_TERM atom_hmac; +extern ERL_NIF_TERM atom_cmac; +extern ERL_NIF_TERM atom_poly1305; + extern ERL_NIF_TERM atom_ok; extern ERL_NIF_TERM atom_none; extern ERL_NIF_TERM atom_notsup; diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index d533cba140..7cdc95a841 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -32,6 +32,7 @@ #include "bn.h" #include "cipher.h" #include "cmac.h" +#include "mac.h" #include "dh.h" #include "digest.h" #include "dss.h" @@ -81,6 +82,7 @@ static ErlNifFunc nif_funcs[] = { {"hmac_final_nif", 1, hmac_final_nif, 0}, {"hmac_final_nif", 2, hmac_final_nif, 0}, {"cmac_nif", 3, cmac_nif, 0}, + {"mac_nif", 4, mac_nif, 0}, {"cipher_info_nif", 1, cipher_info_nif, 0}, {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0}, {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0}, @@ -248,6 +250,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) #endif /* OPENSSL_THREADS */ init_digest_types(env); + init_mac_types(env); init_cipher_types(env); init_algorithms_types(env); diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c new file mode 100644 index 0000000000..91dd42314e --- /dev/null +++ b/lib/crypto/c_src/mac.c @@ -0,0 +1,389 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010-2019. 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% + */ + +#include "common.h" +#include "cipher.h" +#include "digest.h" +#include "mac.h" + +#ifdef HAS_EVP_PKEY_CTX +struct mac_type_t { + union { + const char* str; /* before init, NULL for end-of-table */ + ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */ + }type; + union { + const int type; + }alg; +}; + + +static struct mac_type_t mac_types[] = +{ + {{"poly1305"}, +#ifdef HAVE_POLY1305 + {EVP_PKEY_POLY1305} +#else + {EVP_PKEY_NONE} +#endif + }, + + {{"hmac"}, +#ifdef HAVE_PKEY_HMAC + {EVP_PKEY_HMAC} +#else + {EVP_PKEY_NONE} +#endif + }, + + {{"cmac"}, +#ifdef HAVE_CMAC + {EVP_PKEY_CMAC} +#else + {EVP_PKEY_NONE} +#endif + }, + /*==== End of list ==== */ + {{NULL},{0}} +}; + +#endif /* HAS_EVP_PKEY_CTX */ + + +void init_mac_types(ErlNifEnv* env) +{ +#ifdef HAS_EVP_PKEY_CTX + struct mac_type_t* p = mac_types; + + for (p = mac_types; p->type.str; p++) { + p->type.atom = enif_make_atom(env, p->type.str); + } + p->type.atom = atom_false; /* end marker */ +#endif +} + + +ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env) +{ +#ifdef HAS_EVP_PKEY_CTX + struct mac_type_t* p; + ERL_NIF_TERM prev, hd; + + hd = enif_make_list(env, 0); + prev = atom_undefined; + + for (p = mac_types; (p->type.atom & (p->type.atom != atom_false)); p++) { + if (prev == p->type.atom) + continue; + + if (p->alg.type != EVP_PKEY_NONE) + { + hd = enif_make_list_cell(env, p->type.atom, hd); + } + } + + return hd; +#else + return enif_make_list1(env, atom_hmac); +#endif +} + + +#ifdef HAS_EVP_PKEY_CTX +struct mac_type_t* get_mac_type(ERL_NIF_TERM type); + +struct mac_type_t* get_mac_type(ERL_NIF_TERM type) +{ + struct mac_type_t* p = NULL; + for (p = mac_types; p->type.atom != atom_false; p++) { + if (type == p->type.atom) { + return p; + } + } + return NULL; +} +#endif + + + + +ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (MacType, SubType, Key, Text) */ + + ErlNifBinary key_bin, text; + int ret_bin_alloc = 0; + size_t size; + ERL_NIF_TERM return_term; + const EVP_MD *md = NULL; + ErlNifBinary ret_bin; +#ifdef HAS_EVP_PKEY_CTX + EVP_PKEY *pkey = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; +#endif + + if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin)) + { + return_term = EXCP_BADARG(env, "Bad key"); + goto err; + } + + if (!enif_inspect_iolist_as_binary(env, argv[3], &text)) + { + return_term = EXCP_BADARG(env, "Bad text"); + goto err; + } + + if (argv[0] == atom_hmac) + { + struct digest_type_t *digp; + + if ((digp = get_digest_type(argv[1])) == NULL) + { + return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC"); + goto err; + } + if (digp->md.p == NULL) + { + return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm"); + goto err; + } + + md = digp->md.p; + +#ifndef HAS_EVP_PKEY_CTX + /* Old cryptolib: use low level functions */ + { + unsigned int size_int; + + /* Find the needed space */ + if (HMAC(md, + key_bin.data, (int)key_bin.size, + text.data, text.size, + NULL, &size_int) == NULL) + { + return_term = EXCP_ERROR(env, "Get HMAC size failed"); + goto err; + } + + size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */ + if (!enif_alloc_binary(size, &ret_bin)) + { + return_term = EXCP_ERROR(env, "Alloc binary"); + goto err; + } + ret_bin_alloc = 1; + + /* And do the real HMAC calc */ + if (HMAC(md, + key_bin.data, (int)key_bin.size, + text.data, text.size, + ret_bin.data, &size_int) == NULL) + { + return_term = EXCP_ERROR(env, "HMAC sign failed"); + goto err; + } + } +#else +/* HAS_EVP_PKEY_CTX and HMAC is the type. Produce a PKEY for later use */ + +# ifdef HAVE_PKEY_new_raw_private_key + /* Prefered for new applications according to EVP_PKEY_new_mac_key(3) */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size); +# else + /* Available in older versions */ + pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size); +# endif + } + + else if (argv[0] == atom_cmac) + { +#ifdef HAVE_CMAC + const struct cipher_type_t *cipherp; + if (!(cipherp = get_cipher_type(argv[1], key_bin.size))) + { /* Something went wrong. Find out what by retrying in another way. */ + if (!get_cipher_type_no_key(argv[1])) + return_term = EXCP_BADARG(env, "Unknown cipher"); + else + /* Cipher exists, so it must be the key size that is wrong */ + return_term = EXCP_BADARG(env, "Bad key size"); + goto err; + } + + if (FORBIDDEN_IN_FIPS(cipherp)) + { + return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS"); + goto err; + } + + if (cipherp->cipher.p == NULL) + { + return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm"); + goto err; + } + +# ifdef HAVE_EVP_PKEY_new_CMAC_key + pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p); +# else + /* Compatibility with < 1.1.1 that doesn't have EVP_PKEY_new_CMAC_key + It is a complicated flow so just do some goto to get out of it. + */ + { + CMAC_CTX *ctx = NULL; + + if ((ctx = CMAC_CTX_new()) == NULL) + goto local_err; + + if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipherp->cipher.p, NULL)) + goto local_err; + + if (!CMAC_Update(ctx, text.data, text.size)) + goto local_err; + + if ((size = (size_t)EVP_CIPHER_block_size(cipherp->cipher.p)) < 0) + goto local_err; + + if (!enif_alloc_binary(size, &ret_bin)) + goto local_err; + ret_bin_alloc = 1; + + if (!CMAC_Final(ctx, ret_bin.data, &ret_bin.size)) + goto local_err; + + CONSUME_REDS(env, text); + + return_term = enif_make_binary(env, &ret_bin); + ret_bin_alloc = 0; + goto done; + + local_err: + if (ctx) + CMAC_CTX_free(ctx); + + return_term=EXCP_ERROR(env,"Compat cmac"); + goto err; + } +# endif +#else + return_term = EXCP_NOTSUP(env, "Unsupported mac type"); + goto err; +#endif /* HAVE_CMAC */ + } + + else if (argv[0] == atom_poly1305) + { +#ifdef HAVE_POLY1305 + if (key_bin.size != 32) + { + return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes"); + goto err; + } + /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size); +#else + return_term = EXCP_NOTSUP(env, "Unsupported mac type"); + goto err; +#endif /* HAVE_POLY1305 */ +#endif /* HAS_EVP_PKEY_CTX */ + + } + else + { + return_term = EXCP_BADARG(env, "Bad mac type"); + goto err; + } + +#ifdef HAS_EVP_PKEY_CTX + if (!pkey) + { + return_term = EXCP_ERROR(env, "EVP_PKEY_key creation"); + goto err; + } + + + if ((mctx = EVP_MD_CTX_new()) == NULL) + { + return_term = EXCP_ERROR(env, "EVP_MD_CTX_new"); + goto err; + } + + if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, pkey) != 1) + { + return_term = EXCP_ERROR(env, "EVP_DigestSign"); + goto err; + } + +# ifdef HAVE_DigestSign_as_single_op + if (EVP_DigestSign(mctx, NULL, &size, text.data, text.size) != 1) +# else + if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1) + { + return_term = EXCP_ERROR(env, "EVP_DigestSignUpdate"); + goto err; + } + + if (EVP_DigestSignFinal(mctx, NULL, &size) != 1) +# endif + { + return_term = EXCP_ERROR(env, "Can't get sign size"); + goto err; + } + + if (!enif_alloc_binary(size, &ret_bin)) + { + return_term = EXCP_ERROR(env, "Alloc binary"); + goto err; + } + ret_bin_alloc = 1; + +# ifdef HAVE_DigestSign_as_single_op + if (EVP_DigestSign(mctx, ret_bin.data, &size, text.data, text.size) != 1) +# else + if (EVP_DigestSignFinal(mctx, ret_bin.data, &size) != 1) +# endif + { + return_term = EXCP_ERROR(env, "Signing"); + goto err; + } + +#endif /* ifdef HAS_EVP_PKEY_CTX */ + + CONSUME_REDS(env, text); + + return_term = enif_make_binary(env, &ret_bin); + ret_bin_alloc = 0; + goto done; + +err: + if (ret_bin_alloc) + enif_release_binary(&ret_bin); + +done: +#ifdef HAS_EVP_PKEY_CTX + if (pkey) + EVP_PKEY_free(pkey); +#endif + return return_term; +} + + + + + diff --git a/lib/crypto/c_src/mac.h b/lib/crypto/c_src/mac.h new file mode 100644 index 0000000000..00b94a2232 --- /dev/null +++ b/lib/crypto/c_src/mac.h @@ -0,0 +1,33 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010-2018. 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% + */ + +#ifndef E_MAC_H__ +#define E_MAC_H__ 1 + +#include "common.h" + + +void init_mac_types(ErlNifEnv* env); + +ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env); + +ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +#endif /* E_MAC_H__ */ diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h index 339eb5b8f4..aee08ea65f 100644 --- a/lib/crypto/c_src/openssl_config.h +++ b/lib/crypto/c_src/openssl_config.h @@ -110,6 +110,12 @@ # define HAS_EVP_PKEY_CTX # define HAVE_EVP_CIPHER_CTX_COPY # endif + +# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1) +# define HAVE_PKEY_new_raw_private_key +# define HAVE_EVP_PKEY_new_CMAC_key +# define HAVE_DigestSign_as_single_op +# endif #endif @@ -278,6 +284,7 @@ #endif #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) +# define HAVE_PKEY_HMAC # ifdef RSA_PKCS1_PSS_PADDING # define HAVE_RSA_PKCS1_PSS_PADDING # endif diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 169c0f2e91..fd4b9df5e0 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -62,7 +62,8 @@ crypto_one_time_aead/6, crypto_one_time_aead/7, crypto_dyn_iv_init/3, crypto_dyn_iv_update/3, - supports/1 + supports/1, + mac/3, mac/4, mac/5 ]). @@ -602,6 +603,19 @@ hash_final(Context) -> %%% %%%================================================================ +mac(Type, SubType, Key, Data, MacLength) -> + erlang:binary_part(mac(Type, SubType, Key, Data), 0, MacLength). + +mac(poly1305, _, Key, Data) -> mac_nif(poly1305, undefined, Key, Data); +mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data). + +mac(poly1305, Key, Data) -> mac(poly1305, undefined, Key, Data). + + + +mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub. + + %%%---- HMAC -type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash(). -- cgit v1.2.3 From d3e7944c621001c318014b249a456e7d336b7d9e Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 29 May 2019 09:06:26 +0200 Subject: crypto: Use dirty schedulers for the new mac_nif if large data --- lib/crypto/c_src/mac.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 91dd42314e..270c2f0fe1 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -123,8 +123,36 @@ struct mac_type_t* get_mac_type(ERL_NIF_TERM type) +/******************************************************************* + * + * Mac nif + * + ******************************************************************/ +ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (MacType, SubType, Key, Text) */ + ErlNifBinary text; + + if (!enif_inspect_iolist_as_binary(env, argv[3], &text)) + return EXCP_BADARG(env, "Bad text"); + + if (text.size > INT_MAX) + return EXCP_BADARG(env, "Too long text"); + + /* Run long jobs on a dirty scheduler to not block the current emulator thread */ + if (text.size > MAX_BYTES_TO_NIF) { + return enif_schedule_nif(env, "mac_one_time", + ERL_NIF_DIRTY_JOB_CPU_BOUND, + mac_one_time, argc, argv); + } + + return mac_one_time(env, argc, argv); +} + + + +ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (MacType, SubType, Key, Text) */ ErlNifBinary key_bin, text; @@ -385,5 +413,3 @@ done: - - -- cgit v1.2.3 From 5d57c28fdab9f7552da47bc9b7d59926953705c9 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 29 May 2019 14:14:54 +0200 Subject: crypto: Refactor for readability --- lib/crypto/c_src/mac.c | 394 ++++++++++++++++++++++++-------------- lib/crypto/c_src/openssl_config.h | 1 - 2 files changed, 246 insertions(+), 149 deletions(-) diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 270c2f0fe1..0ee431f394 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -23,113 +23,132 @@ #include "digest.h" #include "mac.h" -#ifdef HAS_EVP_PKEY_CTX +/*************************** + MAC type declaration +***************************/ + struct mac_type_t { union { const char* str; /* before init, NULL for end-of-table */ ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */ - }type; + }name; union { - const int type; + const int pkey_type; }alg; + int type; }; +#define NO_mac 0 +#define HMAC_mac 1 +#define CMAC_mac 2 +#define POLY1305_mac 3 static struct mac_type_t mac_types[] = { {{"poly1305"}, #ifdef HAVE_POLY1305 - {EVP_PKEY_POLY1305} + /* If we have POLY then we have EVP_PKEY */ + {EVP_PKEY_POLY1305}, POLY1305_mac #else - {EVP_PKEY_NONE} + {EVP_PKEY_NONE}, NO_mac #endif }, {{"hmac"}, -#ifdef HAVE_PKEY_HMAC - {EVP_PKEY_HMAC} +#ifdef HAS_EVP_PKEY_CTX + {EVP_PKEY_HMAC}, HMAC_mac #else - {EVP_PKEY_NONE} + /* HMAC is always supported, but possibly with low-level routines */ + {EVP_PKEY_NONE}, HMAC_mac #endif }, {{"cmac"}, #ifdef HAVE_CMAC - {EVP_PKEY_CMAC} + /* If we have CMAC then we have EVP_PKEY */ + {EVP_PKEY_CMAC}, CMAC_mac #else - {EVP_PKEY_NONE} + {EVP_PKEY_NONE}, NO_mac #endif }, /*==== End of list ==== */ - {{NULL},{0}} + {{NULL},{0},NO_mac} }; -#endif /* HAS_EVP_PKEY_CTX */ +/*************************** + Mandatory prototypes +***************************/ + +struct mac_type_t* get_mac_type(ERL_NIF_TERM type); + +ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key) +int cmac_low_level(ErlNifEnv* env, + ErlNifBinary key_bin, const struct cipher_type_t *cipherp, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); +#endif + +#if !defined(HAS_EVP_PKEY_CTX) +int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, + ErlNifBinary key_bin, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); +#endif + + +/******************************** + Support functions for type array +*********************************/ void init_mac_types(ErlNifEnv* env) { -#ifdef HAS_EVP_PKEY_CTX struct mac_type_t* p = mac_types; - for (p = mac_types; p->type.str; p++) { - p->type.atom = enif_make_atom(env, p->type.str); + for (p = mac_types; p->name.str; p++) { + p->name.atom = enif_make_atom(env, p->name.str); } - p->type.atom = atom_false; /* end marker */ -#endif + p->name.atom = atom_false; /* end marker */ } ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env) { -#ifdef HAS_EVP_PKEY_CTX struct mac_type_t* p; ERL_NIF_TERM prev, hd; hd = enif_make_list(env, 0); prev = atom_undefined; - for (p = mac_types; (p->type.atom & (p->type.atom != atom_false)); p++) { - if (prev == p->type.atom) + for (p = mac_types; (p->name.atom & (p->name.atom != atom_false)); p++) { + if (prev == p->name.atom) continue; - if (p->alg.type != EVP_PKEY_NONE) + if (p->type != NO_mac) { - hd = enif_make_list_cell(env, p->type.atom, hd); + hd = enif_make_list_cell(env, p->name.atom, hd); } } return hd; -#else - return enif_make_list1(env, atom_hmac); -#endif } - -#ifdef HAS_EVP_PKEY_CTX -struct mac_type_t* get_mac_type(ERL_NIF_TERM type); - struct mac_type_t* get_mac_type(ERL_NIF_TERM type) { struct mac_type_t* p = NULL; - for (p = mac_types; p->type.atom != atom_false; p++) { - if (type == p->type.atom) { + for (p = mac_types; p->name.atom != atom_false; p++) { + if (type == p->name.atom) { return p; } } return NULL; } -#endif - - /******************************************************************* * * Mac nif * ******************************************************************/ -ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (MacType, SubType, Key, Text) */ ErlNifBinary text; @@ -155,18 +174,22 @@ ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (MacType, SubType, Key, Text) */ + struct mac_type_t *macp; ErlNifBinary key_bin, text; int ret_bin_alloc = 0; - size_t size; ERL_NIF_TERM return_term; const EVP_MD *md = NULL; ErlNifBinary ret_bin; #ifdef HAS_EVP_PKEY_CTX + size_t size; EVP_PKEY *pkey = NULL; EVP_MD_CTX *mctx = NULL; EVP_PKEY_CTX *pctx = NULL; #endif + /*--------------------------------- + Get common indata and validate it + */ if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin)) { return_term = EXCP_BADARG(env, "Bad key"); @@ -178,11 +201,29 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return_term = EXCP_BADARG(env, "Bad text"); goto err; } - - if (argv[0] == atom_hmac) + + if (!(macp = get_mac_type(argv[0]))) + { + return_term = EXCP_BADARG(env, "Unknown mac algorithm"); + goto err; + } + + /*-------------------------------------------------- + Algorithm dependent indata checking and computation. + If EVP_PKEY is available, only set the pkey variable + and do the computation after the switch statement. + If not available, do the low-level calls in the + corresponding case part + */ + switch (macp->type) { + + /******** + * HMAC * + ********/ + case HMAC_mac: { struct digest_type_t *digp; - + if ((digp = get_digest_type(argv[1])) == NULL) { return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC"); @@ -196,42 +237,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) md = digp->md.p; -#ifndef HAS_EVP_PKEY_CTX - /* Old cryptolib: use low level functions */ - { - unsigned int size_int; - - /* Find the needed space */ - if (HMAC(md, - key_bin.data, (int)key_bin.size, - text.data, text.size, - NULL, &size_int) == NULL) - { - return_term = EXCP_ERROR(env, "Get HMAC size failed"); - goto err; - } - - size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */ - if (!enif_alloc_binary(size, &ret_bin)) - { - return_term = EXCP_ERROR(env, "Alloc binary"); - goto err; - } - ret_bin_alloc = 1; - - /* And do the real HMAC calc */ - if (HMAC(md, - key_bin.data, (int)key_bin.size, - text.data, text.size, - ret_bin.data, &size_int) == NULL) - { - return_term = EXCP_ERROR(env, "HMAC sign failed"); - goto err; - } - } -#else -/* HAS_EVP_PKEY_CTX and HMAC is the type. Produce a PKEY for later use */ - +#ifdef HAS_EVP_PKEY_CTX # ifdef HAVE_PKEY_new_raw_private_key /* Prefered for new applications according to EVP_PKEY_new_mac_key(3) */ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size); @@ -239,11 +245,23 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) /* Available in older versions */ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size); # endif + +#else + if (!hmac_low_level(env, md, key_bin, text, &ret_bin, &ret_bin_alloc, &return_term)) + goto err; + else + goto success; +#endif } + break; - else if (argv[0] == atom_cmac) - { + + /******** + * CMAC * + ********/ #ifdef HAVE_CMAC + case CMAC_mac: + { const struct cipher_type_t *cipherp; if (!(cipherp = get_cipher_type(argv[1], key_bin.size))) { /* Something went wrong. Find out what by retrying in another way. */ @@ -270,81 +288,52 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) # ifdef HAVE_EVP_PKEY_new_CMAC_key pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p); # else - /* Compatibility with < 1.1.1 that doesn't have EVP_PKEY_new_CMAC_key - It is a complicated flow so just do some goto to get out of it. - */ - { - CMAC_CTX *ctx = NULL; - - if ((ctx = CMAC_CTX_new()) == NULL) - goto local_err; - - if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipherp->cipher.p, NULL)) - goto local_err; - - if (!CMAC_Update(ctx, text.data, text.size)) - goto local_err; - - if ((size = (size_t)EVP_CIPHER_block_size(cipherp->cipher.p)) < 0) - goto local_err; - - if (!enif_alloc_binary(size, &ret_bin)) - goto local_err; - ret_bin_alloc = 1; - - if (!CMAC_Final(ctx, ret_bin.data, &ret_bin.size)) - goto local_err; - - CONSUME_REDS(env, text); - - return_term = enif_make_binary(env, &ret_bin); - ret_bin_alloc = 0; - goto done; - - local_err: - if (ctx) - CMAC_CTX_free(ctx); - - return_term=EXCP_ERROR(env,"Compat cmac"); - goto err; - } + if (!cmac_low_level(env, key_bin, cipherp, text, &ret_bin, &ret_bin_alloc, &return_term)) + goto err; + else + goto success; + /* End of CMAC compatibility functions */ # endif -#else - return_term = EXCP_NOTSUP(env, "Unsupported mac type"); - goto err; -#endif /* HAVE_CMAC */ } + break; +#endif /* HAVE_CMAC */ - else if (argv[0] == atom_poly1305) - { + + /************ + * POLY1305 * + ************/ #ifdef HAVE_POLY1305 - if (key_bin.size != 32) - { - return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes"); - goto err; - } - /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */ - pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size); -#else - return_term = EXCP_NOTSUP(env, "Unsupported mac type"); - goto err; -#endif /* HAVE_POLY1305 */ -#endif /* HAS_EVP_PKEY_CTX */ + case POLY1305_mac: + if (key_bin.size != 32) + { + return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes"); + goto err; + } + /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size); + break; +#endif - } - else - { - return_term = EXCP_BADARG(env, "Bad mac type"); - goto err; - } + /*************** + * Unknown MAC * + ***************/ + case NO_mac: + default: + /* We know that this mac is supported with some version(s) of cryptolib */ + return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm"); + goto err; + } + + /*----------------------------------------- + Common computations when we have EVP_PKEY + */ #ifdef HAS_EVP_PKEY_CTX if (!pkey) { return_term = EXCP_ERROR(env, "EVP_PKEY_key creation"); goto err; } - if ((mctx = EVP_MD_CTX_new()) == NULL) { @@ -360,6 +349,10 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) # ifdef HAVE_DigestSign_as_single_op if (EVP_DigestSign(mctx, NULL, &size, text.data, text.size) != 1) + { + return_term = EXCP_ERROR(env, "Can't get sign size"); + goto err; + } # else if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1) { @@ -368,11 +361,11 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } if (EVP_DigestSignFinal(mctx, NULL, &size) != 1) -# endif { return_term = EXCP_ERROR(env, "Can't get sign size"); goto err; } +# endif if (!enif_alloc_binary(size, &ret_bin)) { @@ -390,26 +383,131 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return_term = EXCP_ERROR(env, "Signing"); goto err; } - + + goto success; /* The label "success:" could be left without any "goto success" + in some combination of flags. This prevents a compiler warning + */ #endif /* ifdef HAS_EVP_PKEY_CTX */ + + /**************************** + Exit when we got a signature + *****************************/ + success: CONSUME_REDS(env, text); return_term = enif_make_binary(env, &ret_bin); ret_bin_alloc = 0; - goto done; -err: - if (ret_bin_alloc) - enif_release_binary(&ret_bin); + out: /* Common for success: and for err: */ -done: #ifdef HAS_EVP_PKEY_CTX if (pkey) EVP_PKEY_free(pkey); + if (mctx) + EVP_MD_CTX_free(mctx); #endif + return return_term; + + + /***************** + Error exit + ******************/ + err: + if (ret_bin_alloc) + enif_release_binary(&ret_bin); + + goto out; } +/***************************************************************** + ***************************************************************** + + Low level compatibility functions for HMAC and CMAC + ***************************************************************** + ****************************************************************/ + +#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key) + +int cmac_low_level(ErlNifEnv* env, + ErlNifBinary key_bin, const struct cipher_type_t *cipherp, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term) +{ + CMAC_CTX *ctx = NULL; + size_t size; + + if ((ctx = CMAC_CTX_new()) == NULL) + goto local_err; + + if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipherp->cipher.p, NULL)) + goto local_err; + + if (!CMAC_Update(ctx, text.data, text.size)) + goto local_err; + + if ((size = (size_t)EVP_CIPHER_block_size(cipherp->cipher.p)) < 0) + goto local_err; + + if (!enif_alloc_binary(size, ret_bin)) + goto local_err; + *ret_bin_alloc = 1; + + if (!CMAC_Final(ctx, ret_bin->data, &ret_bin->size)) + goto local_err; + + CMAC_CTX_free(ctx); + return 1; + + local_err: + if (ctx) + CMAC_CTX_free(ctx); + + *return_term = EXCP_ERROR(env,"Compat cmac"); + return 0; +} + +#endif + + +#if !defined(HAS_EVP_PKEY_CTX) +int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, + ErlNifBinary key_bin, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term) +{ + unsigned int size_int; + size_t size; + + /* Find the needed space */ + if (HMAC(md, + key_bin.data, (int)key_bin.size, + text.data, text.size, + NULL, &size_int) == NULL) + { + *return_term = EXCP_ERROR(env, "Get HMAC size failed"); + return 0; + } + + size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */ + if (!enif_alloc_binary(size, ret_bin)) + { + *return_term = EXCP_ERROR(env, "Alloc binary"); + return 0; + } + *ret_bin_alloc = 1; + + /* And do the real HMAC calc */ + if (HMAC(md, + key_bin.data, (int)key_bin.size, + text.data, text.size, + ret_bin->data, &size_int) == NULL) + { + *return_term = EXCP_ERROR(env, "HMAC sign failed"); + return 0; + } + + return 1; +} +#endif diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h index aee08ea65f..32a0830717 100644 --- a/lib/crypto/c_src/openssl_config.h +++ b/lib/crypto/c_src/openssl_config.h @@ -284,7 +284,6 @@ #endif #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) -# define HAVE_PKEY_HMAC # ifdef RSA_PKCS1_PSS_PADDING # define HAVE_RSA_PKCS1_PSS_PADDING # endif -- cgit v1.2.3 From 45fe2d9fa1f9997bbdf6f50ef721f42204c812f0 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Mon, 3 Jun 2019 12:40:52 +0200 Subject: crypto: Use new mac_nif for hmac, cmac and poly1305 --- lib/crypto/c_src/Makefile.in | 2 - lib/crypto/c_src/cmac.c | 88 ------------------------------------------- lib/crypto/c_src/cmac.h | 28 -------------- lib/crypto/c_src/crypto.c | 7 ---- lib/crypto/c_src/hmac.c | 55 --------------------------- lib/crypto/c_src/hmac.h | 1 - lib/crypto/c_src/poly1305.c | 90 -------------------------------------------- lib/crypto/c_src/poly1305.h | 28 -------------- lib/crypto/src/crypto.erl | 46 +++++++++++----------- 9 files changed, 21 insertions(+), 324 deletions(-) delete mode 100644 lib/crypto/c_src/cmac.c delete mode 100644 lib/crypto/c_src/cmac.h delete mode 100644 lib/crypto/c_src/poly1305.c delete mode 100644 lib/crypto/c_src/poly1305.h diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index 35ded001d6..6e173f8619 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -79,7 +79,6 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \ $(OBJDIR)/atoms$(TYPEMARKER).o \ $(OBJDIR)/bn$(TYPEMARKER).o \ $(OBJDIR)/cipher$(TYPEMARKER).o \ - $(OBJDIR)/cmac$(TYPEMARKER).o \ $(OBJDIR)/dh$(TYPEMARKER).o \ $(OBJDIR)/digest$(TYPEMARKER).o \ $(OBJDIR)/dss$(TYPEMARKER).o \ @@ -95,7 +94,6 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \ $(OBJDIR)/mac$(TYPEMARKER).o \ $(OBJDIR)/math$(TYPEMARKER).o \ $(OBJDIR)/pkey$(TYPEMARKER).o \ - $(OBJDIR)/poly1305$(TYPEMARKER).o \ $(OBJDIR)/rand$(TYPEMARKER).o \ $(OBJDIR)/rsa$(TYPEMARKER).o \ $(OBJDIR)/srp$(TYPEMARKER).o diff --git a/lib/crypto/c_src/cmac.c b/lib/crypto/c_src/cmac.c deleted file mode 100644 index 49e67ccf29..0000000000 --- a/lib/crypto/c_src/cmac.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2010-2018. 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% - */ - -#include "cmac.h" -#include "cipher.h" - -ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Key, Data) */ -#if defined(HAVE_CMAC) - const struct cipher_type_t *cipherp; - const EVP_CIPHER *cipher; - CMAC_CTX *ctx = NULL; - ErlNifBinary key; - ErlNifBinary data; - ERL_NIF_TERM ret; - size_t ret_size; - unsigned char *outp; - int cipher_len; - - ASSERT(argc == 3); - - if (!enif_inspect_iolist_as_binary(env, argv[1], &key)) - goto bad_arg; - if ((cipherp = get_cipher_type(argv[0], key.size)) == NULL) - goto bad_arg; - if (cipherp->flags & (NON_EVP_CIPHER | AEAD_CIPHER)) - goto bad_arg; - if (!enif_inspect_iolist_as_binary(env, argv[2], &data)) - goto bad_arg; - - if (FORBIDDEN_IN_FIPS(cipherp)) - return enif_raise_exception(env, atom_notsup); - if ((cipher = cipherp->cipher.p) == NULL) - return enif_raise_exception(env, atom_notsup); - - if ((ctx = CMAC_CTX_new()) == NULL) - goto err; - if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL)) - goto err; - if (!CMAC_Update(ctx, data.data, data.size)) - goto err; - if ((cipher_len = EVP_CIPHER_block_size(cipher)) < 0) - goto err; - if ((outp = enif_make_new_binary(env, (size_t)cipher_len, &ret)) == NULL) - goto err; - if (!CMAC_Final(ctx, outp, &ret_size)) - goto err; - - ASSERT(ret_size == (unsigned)EVP_CIPHER_block_size(cipher)); - CONSUME_REDS(env, data); - goto done; - - bad_arg: - return enif_make_badarg(env); - - err: - ret = atom_notsup; - - done: - if (ctx) - CMAC_CTX_free(ctx); - return ret; - -#else - /* The CMAC functionality was introduced in OpenSSL 1.0.1 - * Although OTP requires at least version 0.9.8, the versions 0.9.8 and 1.0.0 are - * no longer maintained. */ - return atom_notsup; -#endif -} - diff --git a/lib/crypto/c_src/cmac.h b/lib/crypto/c_src/cmac.h deleted file mode 100644 index 14488def58..0000000000 --- a/lib/crypto/c_src/cmac.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2010-2018. 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% - */ - -#ifndef E_CMAC_H__ -#define E_CMAC_H__ 1 - -#include "common.h" - -ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -#endif /* E_CMAC_H__ */ diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 7cdc95a841..ab6907f828 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -31,7 +31,6 @@ #include "api_ng.h" #include "bn.h" #include "cipher.h" -#include "cmac.h" #include "mac.h" #include "dh.h" #include "digest.h" @@ -47,7 +46,6 @@ #include "info.h" #include "math.h" #include "pkey.h" -#include "poly1305.h" #include "rand.h" #include "rsa.h" #include "srp.h" @@ -75,13 +73,10 @@ static ErlNifFunc nif_funcs[] = { {"hash_init_nif", 1, hash_init_nif, 0}, {"hash_update_nif", 2, hash_update_nif, 0}, {"hash_final_nif", 1, hash_final_nif, 0}, - {"hmac_nif", 3, hmac_nif, 0}, - {"hmac_nif", 4, hmac_nif, 0}, {"hmac_init_nif", 2, hmac_init_nif, 0}, {"hmac_update_nif", 2, hmac_update_nif, 0}, {"hmac_final_nif", 1, hmac_final_nif, 0}, {"hmac_final_nif", 2, hmac_final_nif, 0}, - {"cmac_nif", 3, cmac_nif, 0}, {"mac_nif", 4, mac_nif, 0}, {"cipher_info_nif", 1, cipher_info_nif, 0}, {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0}, @@ -114,8 +109,6 @@ static ErlNifFunc nif_funcs[] = { {"aead_cipher", 7, aead_cipher, 0}, - {"poly1305_nif", 2, poly1305_nif, 0}, - {"engine_by_id_nif", 1, engine_by_id_nif, 0}, {"engine_init_nif", 1, engine_init_nif, 0}, {"engine_finish_nif", 1, engine_finish_nif, 0}, diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c index ff7005d75e..060ad6230f 100644 --- a/lib/crypto/c_src/hmac.c +++ b/lib/crypto/c_src/hmac.c @@ -47,61 +47,6 @@ int init_hmac_ctx(ErlNifEnv *env) { return 0; } -ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Key, Data) or (Type, Key, Data, MacSize) */ - struct digest_type_t *digp = NULL; - ErlNifBinary key, data; - unsigned char buff[EVP_MAX_MD_SIZE]; - unsigned size = 0, req_size = 0; - ERL_NIF_TERM ret; - unsigned char *outp; - - ASSERT(argc == 3 || argc == 4); - - if ((digp = get_digest_type(argv[0])) == NULL) - goto bad_arg; - if (!enif_inspect_iolist_as_binary(env, argv[1], &key)) - goto bad_arg; - if (key.size > INT_MAX) - goto bad_arg; - if (!enif_inspect_iolist_as_binary(env, argv[2], &data)) - goto bad_arg; - if (argc == 4) { - if (!enif_get_uint(env, argv[3], &req_size)) - goto bad_arg; - } - - if (digp->md.p == NULL) - goto err; - if (HMAC(digp->md.p, - key.data, (int)key.size, - data.data, data.size, - buff, &size) == NULL) - goto err; - - ASSERT(0 < size && size <= EVP_MAX_MD_SIZE); - CONSUME_REDS(env, data); - - if (argc == 4) { - if (req_size > size) - goto bad_arg; - - size = req_size; - } - - if ((outp = enif_make_new_binary(env, size, &ret)) == NULL) - goto err; - - memcpy(outp, buff, size); - return ret; - - bad_arg: - return enif_make_badarg(env); - - err: - return atom_notsup; -} - static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj) { if (obj == NULL) diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h index 1f0e0ca632..01c6d3d226 100644 --- a/lib/crypto/c_src/hmac.h +++ b/lib/crypto/c_src/hmac.h @@ -25,7 +25,6 @@ int init_hmac_ctx(ErlNifEnv *env); -ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); diff --git a/lib/crypto/c_src/poly1305.c b/lib/crypto/c_src/poly1305.c deleted file mode 100644 index 76579c0a29..0000000000 --- a/lib/crypto/c_src/poly1305.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2010-2018. 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% - */ - -#include "poly1305.h" - -/* For OpenSSL >= 1.1.1 the hmac_nif and cmac_nif could be integrated into poly1305 (with 'type' as parameter) */ -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; - EVP_PKEY *key = NULL; - EVP_MD_CTX *mctx = NULL; - EVP_PKEY_CTX *pctx = NULL; - const EVP_MD *md = NULL; - size_t size; - int ret_bin_alloc = 0; - - ASSERT(argc == 2); - - if (!enif_inspect_binary(env, argv[0], &key_bin)) - goto bad_arg; - if (key_bin.size != 32) - goto bad_arg; - if (!enif_inspect_binary(env, argv[1], &text)) - goto bad_arg; - - if ((key = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size)) == NULL) - goto err; - - if ((mctx = EVP_MD_CTX_new()) == NULL) - goto err; - if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, key) != 1) - goto err; - if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1) - goto err; - - if (EVP_DigestSignFinal(mctx, NULL, &size) != 1) - goto err; - if (!enif_alloc_binary(size, &ret_bin)) - goto err; - ret_bin_alloc = 1; - if (EVP_DigestSignFinal(mctx, ret_bin.data, &size) != 1) - goto err; - - if (size != ret_bin.size) { - if (!enif_realloc_binary(&ret_bin, size)) - goto err; - } - - ret = enif_make_binary(env, &ret_bin); - ret_bin_alloc = 0; - goto done; - - bad_arg: - return enif_make_badarg(env); - - err: - if (ret_bin_alloc) - enif_release_binary(&ret_bin); - ret = atom_error; - - done: - if (mctx) - EVP_MD_CTX_free(mctx); - if (key) - EVP_PKEY_free(key); - return ret; - -#else - return enif_raise_exception(env, atom_notsup); -#endif -} diff --git a/lib/crypto/c_src/poly1305.h b/lib/crypto/c_src/poly1305.h deleted file mode 100644 index 4bf45e6218..0000000000 --- a/lib/crypto/c_src/poly1305.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2010-2018. 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% - */ - -#ifndef E_POLY1305_H__ -#define E_POLY1305_H__ 1 - -#include "common.h" - -ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -#endif /* E_POLY1305_H__ */ diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index fd4b9df5e0..d2a5786be8 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -457,6 +457,19 @@ -type descriptive_error() :: no_return() . +%%-------------------------------------------------------------------- +%% +%% Make the new descriptive_error() look like the old run_time_error() +%% +-define(COMPAT(CALL), + try begin CALL end + catch + error:{error, {_File,_Line}, _Reason} -> + error(badarg); + error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg -> + error(E) + end). + %%-------------------------------------------------------------------- -compile(no_native). -on_load(on_load/0). @@ -685,7 +698,7 @@ hmac_final_n(Context, HashLen) -> Data :: iodata(), Mac :: binary(). cmac(Type, Key, Data) -> - notsup_to_error(cmac_nif(alias(Type), Key, Data)). + ?COMPAT(mac(cmac, alias(Type), Key, Data)). -spec cmac(Type, Key, Data, MacLength) -> Mac when Type :: ?CMAC_CIPHER_ALGORITHM, @@ -702,7 +715,7 @@ cmac(Type, Key, Data, MacLength) -> -spec poly1305(iodata(), iodata()) -> Mac when Mac :: binary(). poly1305(Key, Data) -> - poly1305_nif(Key, Data). + ?COMPAT( mac(poly1305, Key, Data) ). %%%================================================================ %%% @@ -710,15 +723,6 @@ poly1305(Key, Data) -> %%% %%%================================================================ --define(COMPAT(CALL), - try begin CALL end - catch - error:{error, {_File,_Line}, _Reason} -> - error(badarg); - error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg -> - error(E) - end). - %%%---- Cipher info %%%---------------------------------------------------------------- -spec cipher_info(Type) -> Result | run_time_error() @@ -2259,11 +2263,12 @@ hash_final_nif(_State) -> ?nif_stub. %% HMAC -------------------------------------------------------------------- hmac(Type, Key, Data, MacSize, Size, MaxBytes) when Size =< MaxBytes -> - notsup_to_error( - case MacSize of - undefined -> hmac_nif(Type, Key, Data); - _ -> hmac_nif(Type, Key, Data, MacSize) - end); + ?COMPAT( + case MacSize of + undefined -> mac(hmac, Type, Key, Data); + _ -> mac(hmac, Type, Key, Data, MacSize) + end + ); hmac(Type, Key, Data, MacSize, Size, MaxBytes) -> State0 = hmac_init(Type, Key), State1 = hmac_update(State0, Data, Size, MaxBytes), @@ -2279,20 +2284,11 @@ hmac_update(State0, Data, _, MaxBytes) -> State = notsup_to_error(hmac_update_nif(State0, Increment)), hmac_update(State, Rest, erlang:byte_size(Rest), MaxBytes). -hmac_nif(_Type, _Key, _Data) -> ?nif_stub. -hmac_nif(_Type, _Key, _Data, _MacSize) -> ?nif_stub. hmac_init_nif(_Type, _Key) -> ?nif_stub. hmac_update_nif(_Context, _Data) -> ?nif_stub. 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 -------------------------------------------------------------------- cipher_info_nif(_Type) -> ?nif_stub. -- cgit v1.2.3 From de310ac450cf452b57150ea3abd65b74942d94fd Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Mon, 3 Jun 2019 16:08:02 +0200 Subject: crypto: Implement NIFs for the new mac_init, mac_update and mac_final Use them for old HMAC functions. Also simplify hmac and cmac on the Erlang level --- lib/crypto/c_src/crypto.c | 13 +- lib/crypto/c_src/hmac.c | 11 +- lib/crypto/c_src/hmac.h | 3 + lib/crypto/c_src/mac.c | 294 ++++++++++++++++++++++++++++++++++++++++++++-- lib/crypto/c_src/mac.h | 5 + lib/crypto/src/crypto.erl | 75 +++++------- 6 files changed, 337 insertions(+), 64 deletions(-) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index ab6907f828..802818541b 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -73,11 +73,10 @@ static ErlNifFunc nif_funcs[] = { {"hash_init_nif", 1, hash_init_nif, 0}, {"hash_update_nif", 2, hash_update_nif, 0}, {"hash_final_nif", 1, hash_final_nif, 0}, - {"hmac_init_nif", 2, hmac_init_nif, 0}, - {"hmac_update_nif", 2, hmac_update_nif, 0}, - {"hmac_final_nif", 1, hmac_final_nif, 0}, - {"hmac_final_nif", 2, hmac_final_nif, 0}, {"mac_nif", 4, mac_nif, 0}, + {"mac_init_nif", 3, mac_init_nif, 0}, + {"mac_update_nif", 2, mac_update_nif, 0}, + {"mac_final_nif", 1, mac_final_nif, 0}, {"cipher_info_nif", 1, cipher_info_nif, 0}, {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0}, {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0}, @@ -176,9 +175,15 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) if (!enif_inspect_binary(env, tpl_array[1], &lib_bin)) return __LINE__; +#ifdef HAS_EVP_PKEY_CTX + if (!init_mac_ctx(env)) { + return __LINE__; + } +#else if (!init_hmac_ctx(env)) { return __LINE__; } +#endif if (!init_hash_ctx(env)) { return __LINE__; } diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c index 060ad6230f..1a4f96e1d5 100644 --- a/lib/crypto/c_src/hmac.c +++ b/lib/crypto/c_src/hmac.c @@ -18,6 +18,8 @@ * %CopyrightEnd% */ +#ifndef HAS_EVP_PKEY_CTX + #include "hmac.h" #include "digest.h" @@ -63,17 +65,17 @@ static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj) } ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Key) */ +{/* (hmac, Type, Key) */ struct digest_type_t *digp = NULL; ErlNifBinary key; ERL_NIF_TERM ret; struct hmac_context *obj = NULL; - ASSERT(argc == 2); + ASSERT(argc == 3); - if ((digp = get_digest_type(argv[0])) == NULL) + if ((digp = get_digest_type(argv[1])) == NULL) goto bad_arg; - if (!enif_inspect_iolist_as_binary(env, argv[1], &key)) + if (!enif_inspect_iolist_as_binary(env, argv[2], &key)) goto bad_arg; if (key.size > INT_MAX) goto bad_arg; @@ -213,3 +215,4 @@ ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return ret; } +#endif diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h index 01c6d3d226..5df837a874 100644 --- a/lib/crypto/c_src/hmac.h +++ b/lib/crypto/c_src/hmac.h @@ -21,6 +21,8 @@ #ifndef E_HMAC_H__ #define E_HMAC_H__ 1 +#ifndef HAS_EVP_PKEY_CTX + #include "common.h" int init_hmac_ctx(ErlNifEnv *env); @@ -28,5 +30,6 @@ int init_hmac_ctx(ErlNifEnv *env); ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +#endif #endif /* E_HMAC_H__ */ diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 0ee431f394..0482f97028 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -21,6 +21,7 @@ #include "common.h" #include "cipher.h" #include "digest.h" +#include "hmac.h" #include "mac.h" /*************************** @@ -184,7 +185,6 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) size_t size; EVP_PKEY *pkey = NULL; EVP_MD_CTX *mctx = NULL; - EVP_PKEY_CTX *pctx = NULL; #endif /*--------------------------------- @@ -341,7 +341,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) goto err; } - if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, pkey) != 1) + if (EVP_DigestSignInit(mctx, /*&pctx*/ NULL, md, /*engine*/ NULL, pkey) != 1) { return_term = EXCP_ERROR(env, "EVP_DigestSign"); goto err; @@ -399,7 +399,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return_term = enif_make_binary(env, &ret_bin); ret_bin_alloc = 0; - out: /* Common for success: and for err: */ + err: #ifdef HAS_EVP_PKEY_CTX if (pkey) @@ -408,17 +408,10 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) EVP_MD_CTX_free(mctx); #endif - return return_term; - - - /***************** - Error exit - ******************/ - err: if (ret_bin_alloc) enif_release_binary(&ret_bin); - goto out; + return return_term; } @@ -511,3 +504,282 @@ int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, return 1; } #endif + + +/******************************************************************* + * + * Mac ctx + * + ******************************************************************/ + +int init_mac_ctx(ErlNifEnv *env); + +struct mac_context +{ + EVP_MD_CTX *ctx; +}; + +static ErlNifResourceType* mac_context_rtype; + +static void mac_context_dtor(ErlNifEnv* env, struct mac_context*); + +int init_mac_ctx(ErlNifEnv *env) { + mac_context_rtype = enif_open_resource_type(env, NULL, "mac_context", + (ErlNifResourceDtor*) mac_context_dtor, + ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, + NULL); + if (mac_context_rtype == NULL) + goto err; + + return 1; + + err: + PRINTF_ERR0("CRYPTO: Could not open resource type 'mac_context'"); + return 0; +} + + +static void mac_context_dtor(ErlNifEnv* env, struct mac_context *obj) +{ + if (obj == NULL) + return; + + if (obj->ctx) + EVP_MD_CTX_free(obj->ctx); +} + +/******************************************************************* + * + * Mac nif + * + ******************************************************************/ + +ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (MacType, SubType, Key) */ +#ifdef HAS_EVP_PKEY_CTX + struct mac_context *obj = NULL; + struct mac_type_t *macp; + ErlNifBinary key_bin; + ERL_NIF_TERM return_term; + const EVP_MD *md = NULL; + EVP_PKEY *pkey = NULL; + + /*--------------------------------- + Get common indata and validate it + */ + if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin)) + { + return_term = EXCP_BADARG(env, "Bad key"); + goto err; + } + + if (!(macp = get_mac_type(argv[0]))) + { + return_term = EXCP_BADARG(env, "Unknown mac algorithm"); + goto err; + } + + /*-------------------------------------------------- + Algorithm dependent indata checking and computation. + If EVP_PKEY is available, only set the pkey variable + and do the computation after the switch statement. + If not available, do the low-level calls in the + corresponding case part + */ + switch (macp->type) { + + /******** + * HMAC * + ********/ + case HMAC_mac: + { + struct digest_type_t *digp; + + if ((digp = get_digest_type(argv[1])) == NULL) + { + return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC"); + goto err; + } + if (digp->md.p == NULL) + { + return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm"); + goto err; + } + + md = digp->md.p; + +# ifdef HAVE_PKEY_new_raw_private_key + /* Prefered for new applications according to EVP_PKEY_new_mac_key(3) */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size); +# else + /* Available in older versions */ + pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, /*engine*/ NULL, key_bin.data, key_bin.size); +# endif + } + break; + + + /******** + * CMAC * + ********/ +#if defined(HAVE_CMAC) && defined(HAVE_EVP_PKEY_new_CMAC_key) + case CMAC_mac: + { + const struct cipher_type_t *cipherp; + if (!(cipherp = get_cipher_type(argv[1], key_bin.size))) + { /* Something went wrong. Find out what by retrying in another way. */ + if (!get_cipher_type_no_key(argv[1])) + return_term = EXCP_BADARG(env, "Unknown cipher"); + else + /* Cipher exists, so it must be the key size that is wrong */ + return_term = EXCP_BADARG(env, "Bad key size"); + goto err; + } + + if (FORBIDDEN_IN_FIPS(cipherp)) + { + return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS"); + goto err; + } + + if (cipherp->cipher.p == NULL) + { + return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm"); + goto err; + } + + pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p); + } + break; +#endif /* HAVE_CMAC && HAVE_EVP_PKEY_new_CMAC_key */ + + + /************ + * POLY1305 * + ************/ +#ifdef HAVE_POLY1305 + case POLY1305_mac: + if (key_bin.size != 32) + { + return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes"); + goto err; + } + /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */ + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size); + break; +#endif + + + /*************** + * Unknown MAC * + ***************/ + case NO_mac: + default: + /* We know that this mac is supported with some version(s) of cryptolib */ + return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm"); + goto err; + } + + /*----------------------------------------- + Common computations + */ + if (!pkey) + { + return_term = EXCP_ERROR(env, "EVP_PKEY_key creation"); + goto err; + } + + if ((obj = enif_alloc_resource(mac_context_rtype, sizeof(struct mac_context))) == NULL) + { + return_term = EXCP_ERROR(env, "Can't allocate mac_context_rtype"); + goto err; + } + + if ((obj->ctx = EVP_MD_CTX_new()) == NULL) + { + return_term = EXCP_ERROR(env, "EVP_MD_CTX_new"); + goto err; + } + + if (EVP_DigestSignInit(obj->ctx, /*&pctx*/ NULL, md, /*engine*/ NULL, pkey) != 1) + { + return_term = EXCP_ERROR(env, "EVP_DigestSign"); + goto err; + } + + return_term = enif_make_resource(env, obj); + + err: + + if (obj) + enif_release_resource(obj); + + if (pkey) + EVP_PKEY_free(pkey); + + return return_term; + +#else + if (argv[0] != atom_hmac) + return EXCP_NOTSUP(env, "Unsupported mac algorithm"); + + return hmac_init_nif(env, argc, argv); +#endif +} + + + +ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Ref, Text) */ +#ifdef HAS_EVP_PKEY_CTX + struct mac_context *obj = NULL; + ErlNifBinary text; + + if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj)) + return EXCP_BADARG(env, "Bad ref"); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &text)) + return EXCP_BADARG(env, "Bad text"); + + if (EVP_DigestSignUpdate(obj->ctx, text.data, text.size) != 1) + return EXCP_ERROR(env, "EVP_DigestSignUpdate"); + + CONSUME_REDS(env, text); + return argv[0]; + +#else + return hmac_update_nif(env, argc, argv); +#endif +} + + + +ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Ref) */ +#ifdef HAS_EVP_PKEY_CTX + struct mac_context *obj; + size_t size; + ErlNifBinary ret_bin; + + if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj)) + return EXCP_BADARG(env, "Bad ref"); + + if (EVP_DigestSignFinal(obj->ctx, NULL, &size) != 1) + return EXCP_ERROR(env, "Can't get sign size"); + + if (!enif_alloc_binary(size, &ret_bin)) + return EXCP_ERROR(env, "Alloc binary"); + + if (EVP_DigestSignFinal(obj->ctx, ret_bin.data, &size) != 1) + { + enif_release_binary(&ret_bin); + return EXCP_ERROR(env, "Signing"); + } + + return enif_make_binary(env, &ret_bin); + +#else + return hmac_final_nif(env, argc, argv); +#endif +} + diff --git a/lib/crypto/c_src/mac.h b/lib/crypto/c_src/mac.h index 00b94a2232..053a331324 100644 --- a/lib/crypto/c_src/mac.h +++ b/lib/crypto/c_src/mac.h @@ -23,6 +23,7 @@ #include "common.h" +int init_mac_ctx(ErlNifEnv *env); void init_mac_types(ErlNifEnv* env); @@ -30,4 +31,8 @@ ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env); ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + #endif /* E_MAC_H__ */ diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index d2a5786be8..371a2ee451 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -63,7 +63,8 @@ crypto_dyn_iv_init/3, crypto_dyn_iv_update/3, supports/1, - mac/3, mac/4, mac/5 + mac/3, mac/4, mac/5, + mac_init/3, mac_update/2, mac_final/1 ]). @@ -617,17 +618,33 @@ hash_final(Context) -> %%%================================================================ mac(Type, SubType, Key, Data, MacLength) -> - erlang:binary_part(mac(Type, SubType, Key, Data), 0, MacLength). + erlang:binary_part(mac(Type,SubType,Key,Data), 0, MacLength). -mac(poly1305, _, Key, Data) -> mac_nif(poly1305, undefined, Key, Data); +mac(poly1305, _, Key, Data) -> mac(poly1305, undefined, Key, Data); mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data). mac(poly1305, Key, Data) -> mac(poly1305, undefined, Key, Data). - + +mac_init(Type, SubType, Key) -> + mac_init_nif(Type, SubType, Key). + +mac_update(Ref, Data) -> + mac_update_nif(Ref, Data). + +mac_final(Ref) -> + mac_final_nif(Ref). + +mac_final(Ref, MacLength) -> + erlang:binary_part(mac_final(Ref), 0, MacLength). + mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub. +mac_init_nif(_Type, _SubType, _Key) -> ?nif_stub. +mac_update_nif(_Ref, _Data) -> ?nif_stub. +mac_final_nif(_Ref) -> ?nif_stub. + %%%---- HMAC @@ -641,8 +658,7 @@ mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub. Data :: iodata(), Mac :: binary() . hmac(Type, Key, Data) -> - Data1 = iolist_to_binary(Data), - hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()). + ?COMPAT(mac(hmac, Type, Key, Data)). -spec hmac(Type, Key, Data, MacLength) -> Mac when Type :: hmac_hash_algorithm(), @@ -652,8 +668,7 @@ hmac(Type, Key, Data) -> Mac :: binary() . hmac(Type, Key, Data, MacLength) -> - Data1 = iolist_to_binary(Data), - hmac(Type, Key, Data1, MacLength, erlang:byte_size(Data1), max_bytes()). + ?COMPAT(mac(hmac, Type, Key, Data, MacLength)). %%%---- hmac_init, hamc_update, hmac_final @@ -664,29 +679,28 @@ hmac(Type, Key, Data, MacLength) -> Key :: iodata(), State :: hmac_state() . hmac_init(Type, Key) -> - notsup_to_error(hmac_init_nif(Type, Key)). + ?COMPAT(mac_init(hmac, Type, Key)). %%%---- hmac_update -spec hmac_update(State, Data) -> NewState when Data :: iodata(), State :: hmac_state(), NewState :: hmac_state(). -hmac_update(State, Data0) -> - Data = iolist_to_binary(Data0), - hmac_update(State, Data, erlang:byte_size(Data), max_bytes()). +hmac_update(State, Data) -> + ?COMPAT(mac_update(State, Data)). %%%---- hmac_final -spec hmac_final(State) -> Mac when State :: hmac_state(), Mac :: binary(). hmac_final(Context) -> - notsup_to_error(hmac_final_nif(Context)). + ?COMPAT(mac_final(Context)). -spec hmac_final_n(State, HashLen) -> Mac when State :: hmac_state(), HashLen :: integer(), Mac :: binary(). hmac_final_n(Context, HashLen) -> - notsup_to_error(hmac_final_nif(Context, HashLen)). + ?COMPAT(mac_final(Context, HashLen)). %%%---- CMAC @@ -708,14 +722,14 @@ cmac(Type, Key, Data) -> Mac :: binary(). cmac(Type, Key, Data, MacLength) -> - erlang:binary_part(cmac(alias(Type), Key, Data), 0, MacLength). + ?COMPAT(mac(cmac, alias(Type), Key, Data, MacLength)). %%%---- POLY1305 -spec poly1305(iodata(), iodata()) -> Mac when Mac :: binary(). poly1305(Key, Data) -> - ?COMPAT( mac(poly1305, Key, Data) ). + ?COMPAT(mac(poly1305, Key, Data)). %%%================================================================ %%% @@ -2260,35 +2274,6 @@ hash_init_nif(_Hash) -> ?nif_stub. hash_update_nif(_State, _Data) -> ?nif_stub. hash_final_nif(_State) -> ?nif_stub. -%% HMAC -------------------------------------------------------------------- - -hmac(Type, Key, Data, MacSize, Size, MaxBytes) when Size =< MaxBytes -> - ?COMPAT( - case MacSize of - undefined -> mac(hmac, Type, Key, Data); - _ -> mac(hmac, Type, Key, Data, MacSize) - end - ); -hmac(Type, Key, Data, MacSize, Size, MaxBytes) -> - State0 = hmac_init(Type, Key), - State1 = hmac_update(State0, Data, Size, MaxBytes), - case MacSize of - undefined -> hmac_final(State1); - _ -> hmac_final_n(State1, MacSize) - end. - -hmac_update(State, Data, Size, MaxBytes) when Size =< MaxBytes -> - notsup_to_error(hmac_update_nif(State, Data)); -hmac_update(State0, Data, _, MaxBytes) -> - <> = Data, - State = notsup_to_error(hmac_update_nif(State0, Increment)), - hmac_update(State, Rest, erlang:byte_size(Rest), MaxBytes). - -hmac_init_nif(_Type, _Key) -> ?nif_stub. -hmac_update_nif(_Context, _Data) -> ?nif_stub. -hmac_final_nif(_Context) -> ?nif_stub. -hmac_final_nif(_Context, _MacSize) -> ?nif_stub. - %% CIPHERS -------------------------------------------------------------------- cipher_info_nif(_Type) -> ?nif_stub. -- cgit v1.2.3 From f8c479ce0b1baa91c8e9f7fa11cb1ed0d273ca25 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Tue, 4 Jun 2019 12:27:06 +0200 Subject: crypto: Use dirty schedulers for mac_update --- lib/crypto/c_src/mac.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 0482f97028..0e7f9a5651 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -97,6 +97,8 @@ int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); #endif +ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + /******************************** Support functions for type array @@ -550,7 +552,7 @@ static void mac_context_dtor(ErlNifEnv* env, struct mac_context *obj) /******************************************************************* * - * Mac nif + * mac_init, mac_update, mac_final nifs * ******************************************************************/ @@ -730,6 +732,27 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Ref, Text) */ + ErlNifBinary text; + + if (!enif_inspect_iolist_as_binary(env, argv[1], &text)) + return EXCP_BADARG(env, "Bad text"); + + if (text.size > INT_MAX) + return EXCP_BADARG(env, "Too long text"); + + /* Run long jobs on a dirty scheduler to not block the current emulator thread */ + if (text.size > MAX_BYTES_TO_NIF) { + return enif_schedule_nif(env, "mac_update", + ERL_NIF_DIRTY_JOB_CPU_BOUND, + mac_update, argc, argv); + } + + return mac_update(env, argc, argv); +} + + +ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Ref, Text) */ #ifdef HAS_EVP_PKEY_CTX struct mac_context *obj = NULL; -- cgit v1.2.3 From 8b7bdb61da4fd055955b7947934067856a5cd983 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Tue, 4 Jun 2019 11:52:24 +0200 Subject: crypto: White space removed at line ends --- lib/crypto/src/crypto.erl | 56 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 371a2ee451..1754828229 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -113,7 +113,7 @@ hash_state/0, crypto_state/0 ]). - + %% Private. For tests. -export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2, get_test_engine/0]). @@ -138,7 +138,7 @@ -type rsa_private() :: [key_integer()] . % [E, N, D] | [E, N, D, P1, P2, E1, E2, C] -type rsa_params() :: {ModulusSizeInBits::integer(), PublicExponent::key_integer()} . --type dss_public() :: [key_integer()] . % [P, Q, G, Y] +-type dss_public() :: [key_integer()] . % [P, Q, G, Y] -type dss_private() :: [key_integer()] . % [P, Q, G, X] -type ecdsa_public() :: key_integer() . @@ -284,7 +284,7 @@ %%% New cipher schema %%% -type cipher() :: cipher_no_iv() - | cipher_iv() + | cipher_iv() | cipher_aead() . -type cipher_no_iv() :: aes_128_ecb @@ -328,7 +328,7 @@ -type cipher_aead() :: aes_128_ccm | aes_192_ccm | aes_256_ccm - + | aes_128_gcm | aes_192_gcm | aes_256_gcm @@ -348,7 +348,7 @@ %% | des_ede3 % des_ede3_cbc %% | des_ede3_cbf % des_ede3_cfb %% | des3_cbf % des_ede3_cfb -%% | des3_cfb . % des_ede3_cfb +%% | des3_cfb . % des_ede3_cfb %% -type retired_cipher_aead_aliases() :: aes_ccm %% | aes_gcm . @@ -367,7 +367,7 @@ -type stream_cipher() :: ctr_cipher() | chacha20 | rc4 . - + %%%---- -type cbc_cipher() :: aes_128_cbc @@ -376,7 +376,7 @@ | blowfish_cbc | des_cbc | des_ede3_cbc - | rc2_cbc + | rc2_cbc | retired_cbc_cipher_aliases() . -type retired_cbc_cipher_aliases() :: aes_cbc % aes_*_cbc @@ -384,7 +384,7 @@ | aes_cbc256 % aes_256_cbc | des3_cbc % des_ede3_cbc | des_ede3 . % des_ede3_cbc - + %%%---- -type cfb_cipher() :: aes_128_cfb128 | aes_192_cfb128 @@ -400,7 +400,7 @@ -type retired_cfb_cipher_aliases() :: aes_cfb8 % aes_*_cfb8 | aes_cfb128 % aes_*_cfb128 | des3_cbf % des_ede3_cfb, cfb misspelled - | des3_cfb % des_ede3_cfb + | des3_cfb % des_ede3_cfb | des_ede3_cbf .% cfb misspelled @@ -595,7 +595,7 @@ hash(Type, Data) -> -spec hash_init(Type) -> State when Type :: hash_algorithm(), State :: hash_state(). -hash_init(Type) -> +hash_init(Type) -> notsup_to_error(hash_init_nif(Type)). -spec hash_update(State, Data) -> NewState when State :: hash_state(), @@ -614,7 +614,7 @@ hash_final(Context) -> %%%================================================================ %%% %%% MACs (Message Authentication Codes) -%%% +%%% %%%================================================================ mac(Type, SubType, Key, Data, MacLength) -> @@ -650,9 +650,9 @@ mac_final_nif(_Ref) -> ?nif_stub. -type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash(). -%%%---- hmac/3,4 +%%%---- hmac/3,4 --spec hmac(Type, Key, Data) -> +-spec hmac(Type, Key, Data) -> Mac when Type :: hmac_hash_algorithm(), Key :: iodata(), Data :: iodata(), @@ -660,7 +660,7 @@ mac_final_nif(_Ref) -> ?nif_stub. hmac(Type, Key, Data) -> ?COMPAT(mac(hmac, Type, Key, Data)). --spec hmac(Type, Key, Data, MacLength) -> +-spec hmac(Type, Key, Data, MacLength) -> Mac when Type :: hmac_hash_algorithm(), Key :: iodata(), Data :: iodata(), @@ -718,7 +718,7 @@ cmac(Type, Key, Data) -> Mac when Type :: ?CMAC_CIPHER_ALGORITHM, Key :: iodata(), Data :: iodata(), - MacLength :: integer(), + MacLength :: integer(), Mac :: binary(). cmac(Type, Key, Data, MacLength) -> @@ -877,7 +877,7 @@ block_decrypt(Type, Key0, CryptoText) -> Key :: iodata(), IVec ::binary(), State :: stream_state() . -stream_init(Type, Key0, IVec) when is_binary(IVec) -> +stream_init(Type, Key0, IVec) when is_binary(IVec) -> Key = iolist_to_binary(Key0), Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key), Key, iolist_to_binary(IVec), @@ -965,7 +965,7 @@ next_iv(Type, Data, _Ivec) -> %%%---------------------------------------------------------------- %%% %%% Create and initialize a new state for encryption or decryption -%%% +%%% -spec crypto_init(Cipher, Key, EncryptFlag) -> State | descriptive_error() when Cipher :: cipher_no_iv(), @@ -1003,7 +1003,7 @@ crypto_dyn_iv_init(Cipher, Key, EncryptFlag) -> %%% Encrypt/decrypt a sequence of bytes. The sum of the sizes %%% of all blocks must be an integer multiple of the crypto's %%% blocksize. -%%% +%%% -spec crypto_update(State, Data) -> Result | descriptive_error() when State :: crypto_state(), @@ -1037,7 +1037,7 @@ crypto_dyn_iv_update(State, Data0, IV) -> %%% %%% Encrypt/decrypt one set bytes. %%% The size must be an integer multiple of the crypto's blocksize. -%%% +%%% -spec crypto_one_time(Cipher, Key, Data, EncryptFlag) -> Result | descriptive_error() @@ -1160,7 +1160,7 @@ ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub. false -> Ciphers end). - + prepend_old_aliases(L0) -> L1 = ?if_also(des_ede3_cbc, L0, @@ -1504,7 +1504,7 @@ rand_seed_nif(_Seed) -> ?nif_stub. %%% Sign -spec sign(Algorithm, DigestType, Msg, Key) - -> Signature + -> Signature when Algorithm :: pk_sign_verify_algs(), DigestType :: rsa_digest_type() | dss_digest_type() @@ -1522,7 +1522,7 @@ sign(Algorithm, Type, Data, Key) -> -spec sign(Algorithm, DigestType, Msg, Key, Options) - -> Signature + -> Signature when Algorithm :: pk_sign_verify_algs(), DigestType :: rsa_digest_type() | dss_digest_type() @@ -1619,7 +1619,7 @@ sign_verify_compatibility(Algorithm0, Type0, _Digest) -> | rsa_x931_padding | rsa_no_padding. --type rsa_opt() :: {rsa_padding, rsa_padding()} +-type rsa_opt() :: {rsa_padding, rsa_padding()} | {signature_md, atom()} | {rsa_mgf1_md, sha} | {rsa_oaep_label, binary()} @@ -1692,7 +1692,7 @@ pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_ %%%================================================================ -spec generate_key(Type, Params) - -> {PublicKey, PrivKeyOut} + -> {PublicKey, PrivKeyOut} when Type :: dh | ecdh | rsa | srp, PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(), PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()}, @@ -1702,7 +1702,7 @@ generate_key(Type, Params) -> generate_key(Type, Params, undefined). -spec generate_key(Type, Params, PrivKeyIn) - -> {PublicKey, PrivKeyOut} + -> {PublicKey, PrivKeyOut} when Type :: dh | ecdh | rsa | srp, PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(), PrivKeyIn :: undefined | dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()}, @@ -1853,7 +1853,7 @@ mod_pow(Base, Exponent, Prime) -> %%%====================================================================== %%% %%% Engine functions -%%% +%%% %%%====================================================================== %%%---- Refering to keys stored in an engine: @@ -2160,7 +2160,7 @@ ensure_engine_unloaded(Engine) -> %%---------------------------------------------------------------------- %% Function: ensure_engine_unloaded/2 %%---------------------------------------------------------------------- --spec ensure_engine_unloaded(Engine, EngineMethods) -> +-spec ensure_engine_unloaded(Engine, EngineMethods) -> Result when Engine :: engine_ref(), EngineMethods :: [engine_method_type()], Result :: ok | {error, Reason::term()}. @@ -2242,7 +2242,7 @@ path2bin(Path) when is_list(Path) -> %%%================================================================ %%% %%% Internal functions -%%% +%%% %%%================================================================ max_bytes() -> -- cgit v1.2.3 From 88772e99964342bac0442b01da93ba51e4b2f3f9 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Tue, 4 Jun 2019 13:15:48 +0200 Subject: crypto: Move functions around for better readability --- lib/crypto/src/crypto.erl | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 1754828229..6aa3b30e79 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -28,9 +28,6 @@ -export([hash/2, hash_init/1, hash_update/2, hash_final/1]). -export([sign/4, sign/5, verify/5, verify/6]). -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, rand_seed_alg/2]). -export([rand_seed_s/0, rand_seed_alg_s/1, rand_seed_alg_s/2]). @@ -48,6 +45,9 @@ -export([rand_seed/1]). %% Old interface. Now implemented with the New interface +-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([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2, @@ -617,14 +617,20 @@ hash_final(Context) -> %%% %%%================================================================ -mac(Type, SubType, Key, Data, MacLength) -> - erlang:binary_part(mac(Type,SubType,Key,Data), 0, MacLength). +%%%---------------------------------------------------------------- +%%% Calculate MAC for the whole text at once + +mac(Type, Key, Data) -> mac(Type, undefined, Key, Data). -mac(poly1305, _, Key, Data) -> mac(poly1305, undefined, Key, Data); +mac(Type, Key, Data, MacLength) when is_integer(MacLength) ->mac(Type,undefined,Key,Data); mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data). -mac(poly1305, Key, Data) -> mac(poly1305, undefined, Key, Data). +mac(Type, SubType, Key, Data, MacLength) -> + erlang:binary_part(mac(Type,SubType,Key,Data), 0, MacLength). + +%%%---------------------------------------------------------------- +%%% Calculate the MAC by uppdating by pieces of the text mac_init(Type, SubType, Key) -> mac_init_nif(Type, SubType, Key). @@ -639,12 +645,25 @@ mac_final(Ref, MacLength) -> erlang:binary_part(mac_final(Ref), 0, MacLength). +%%%---------------------------------------------------------------- +%%% NIFs for the functions above + mac_nif(_Type, _SubType, _Key, _Data) -> ?nif_stub. mac_init_nif(_Type, _SubType, _Key) -> ?nif_stub. mac_update_nif(_Ref, _Data) -> ?nif_stub. mac_final_nif(_Ref) -> ?nif_stub. +%%%================================================================ +%%% +%%% The "Old API", kept for compatibility +%%% +%%%================================================================ + +%%%---------------------------------------------------------------- +%%%---------------------------------------------------------------- +%%% Message Authentication Codes, MAC +%%% %%%---- HMAC @@ -731,14 +750,12 @@ cmac(Type, Key, Data, MacLength) -> poly1305(Key, Data) -> ?COMPAT(mac(poly1305, Key, Data)). -%%%================================================================ -%%% -%%% Encrypt/decrypt, The "Old API" -%%% -%%%================================================================ +%%%---------------------------------------------------------------- +%%%---------------------------------------------------------------- +%%% Ciphers + %%%---- Cipher info -%%%---------------------------------------------------------------- -spec cipher_info(Type) -> Result | run_time_error() when Type :: cipher(), Result :: #{key_length := integer(), -- cgit v1.2.3 From c8be59d5ec262084b335eceec2ab1db0a6dd133d Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 5 Jun 2019 10:09:37 +0200 Subject: crypto: Move mac compatibility functions to hmac.c and cmac.c The ultimate goal is to get rid of compatibility with old cryptolib versions so we could remove those compatibility files permanently. --- lib/crypto/c_src/Makefile.in | 1 + lib/crypto/c_src/cmac.c | 73 +++++++++++++++++++++++++++++ lib/crypto/c_src/cmac.h | 34 ++++++++++++++ lib/crypto/c_src/hmac.c | 50 ++++++++++++++++++++ lib/crypto/c_src/hmac.h | 4 ++ lib/crypto/c_src/mac.c | 107 +------------------------------------------ 6 files changed, 164 insertions(+), 105 deletions(-) create mode 100644 lib/crypto/c_src/cmac.c create mode 100644 lib/crypto/c_src/cmac.h diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index 6e173f8619..2512013ed6 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -79,6 +79,7 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \ $(OBJDIR)/atoms$(TYPEMARKER).o \ $(OBJDIR)/bn$(TYPEMARKER).o \ $(OBJDIR)/cipher$(TYPEMARKER).o \ + $(OBJDIR)/cmac$(TYPEMARKER).o \ $(OBJDIR)/dh$(TYPEMARKER).o \ $(OBJDIR)/digest$(TYPEMARKER).o \ $(OBJDIR)/dss$(TYPEMARKER).o \ diff --git a/lib/crypto/c_src/cmac.c b/lib/crypto/c_src/cmac.c new file mode 100644 index 0000000000..a1564f6661 --- /dev/null +++ b/lib/crypto/c_src/cmac.c @@ -0,0 +1,73 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010-2018. 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% + */ + +#include "common.h" + +/***************************************************************** + * + * This file has functions for compatibility with cryptolibs + * lacking the EVP_Digest API. + * + * See mac.c for the implementation using the EVP interface. + * + ****************************************************************/ + +#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key) + +#include "cmac.h" + +int cmac_low_level(ErlNifEnv* env, + ErlNifBinary key_bin, const EVP_CIPHER* cipher, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term) +{ + CMAC_CTX *ctx = NULL; + size_t size; + + if ((ctx = CMAC_CTX_new()) == NULL) + goto local_err; + + if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipher, NULL)) + goto local_err; + + if (!CMAC_Update(ctx, text.data, text.size)) + goto local_err; + + if ((size = (size_t)EVP_CIPHER_block_size(cipher)) < 0) + goto local_err; + + if (!enif_alloc_binary(size, ret_bin)) + goto local_err; + *ret_bin_alloc = 1; + + if (!CMAC_Final(ctx, ret_bin->data, &ret_bin->size)) + goto local_err; + + CMAC_CTX_free(ctx); + return 1; + + local_err: + if (ctx) + CMAC_CTX_free(ctx); + + *return_term = EXCP_ERROR(env,"Compat cmac"); + return 0; +} + +#endif diff --git a/lib/crypto/c_src/cmac.h b/lib/crypto/c_src/cmac.h new file mode 100644 index 0000000000..04c742b2dc --- /dev/null +++ b/lib/crypto/c_src/cmac.h @@ -0,0 +1,34 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010-2018. 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% + */ + +#ifndef E_CMAC_H__ +#define E_CMAC_H__ 1 + +#include "common.h" + +#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key) + +int cmac_low_level(ErlNifEnv* env, + ErlNifBinary key_bin, const EVP_CIPHER* cipher, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); + +#endif + +#endif /* E_CMAC_H__ */ diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c index 1a4f96e1d5..5e2c68bfee 100644 --- a/lib/crypto/c_src/hmac.c +++ b/lib/crypto/c_src/hmac.c @@ -18,6 +18,16 @@ * %CopyrightEnd% */ + +/***************************************************************** + * + * This file has functions for compatibility with cryptolibs + * lacking the EVP_Digest API. + * + * See mac.c for the implementation using the EVP interface. + * + ****************************************************************/ + #ifndef HAS_EVP_PKEY_CTX #include "hmac.h" @@ -215,4 +225,44 @@ ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return ret; } + + +int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, + ErlNifBinary key_bin, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term) +{ + unsigned int size_int; + size_t size; + + /* Find the needed space */ + if (HMAC(md, + key_bin.data, (int)key_bin.size, + text.data, text.size, + NULL, &size_int) == NULL) + { + *return_term = EXCP_ERROR(env, "Get HMAC size failed"); + return 0; + } + + size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */ + if (!enif_alloc_binary(size, ret_bin)) + { + *return_term = EXCP_ERROR(env, "Alloc binary"); + return 0; + } + *ret_bin_alloc = 1; + + /* And do the real HMAC calc */ + if (HMAC(md, + key_bin.data, (int)key_bin.size, + text.data, text.size, + ret_bin->data, &size_int) == NULL) + { + *return_term = EXCP_ERROR(env, "HMAC sign failed"); + return 0; + } + + return 1; +} + #endif diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h index 5df837a874..f5805e13e5 100644 --- a/lib/crypto/c_src/hmac.h +++ b/lib/crypto/c_src/hmac.h @@ -30,6 +30,10 @@ int init_hmac_ctx(ErlNifEnv *env); ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, + ErlNifBinary key_bin, ErlNifBinary text, + ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); #endif #endif /* E_HMAC_H__ */ diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 0e7f9a5651..1995d67c2c 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -21,6 +21,7 @@ #include "common.h" #include "cipher.h" #include "digest.h" +#include "cmac.h" #include "hmac.h" #include "mac.h" @@ -85,18 +86,6 @@ struct mac_type_t* get_mac_type(ERL_NIF_TERM type); ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key) -int cmac_low_level(ErlNifEnv* env, - ErlNifBinary key_bin, const struct cipher_type_t *cipherp, ErlNifBinary text, - ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); -#endif - -#if !defined(HAS_EVP_PKEY_CTX) -int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, - ErlNifBinary key_bin, ErlNifBinary text, - ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term); -#endif - ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -290,11 +279,10 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) # ifdef HAVE_EVP_PKEY_new_CMAC_key pkey = EVP_PKEY_new_CMAC_key(/*engine*/ NULL, key_bin.data, key_bin.size, cipherp->cipher.p); # else - if (!cmac_low_level(env, key_bin, cipherp, text, &ret_bin, &ret_bin_alloc, &return_term)) + if (!cmac_low_level(env, key_bin, cipherp->cipher.p, text, &ret_bin, &ret_bin_alloc, &return_term)) goto err; else goto success; - /* End of CMAC compatibility functions */ # endif } break; @@ -417,97 +405,6 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } -/***************************************************************** - ***************************************************************** - - Low level compatibility functions for HMAC and CMAC - - ***************************************************************** - ****************************************************************/ - -#if defined(HAVE_CMAC) && !defined(HAVE_EVP_PKEY_new_CMAC_key) - -int cmac_low_level(ErlNifEnv* env, - ErlNifBinary key_bin, const struct cipher_type_t *cipherp, ErlNifBinary text, - ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term) -{ - CMAC_CTX *ctx = NULL; - size_t size; - - if ((ctx = CMAC_CTX_new()) == NULL) - goto local_err; - - if (!CMAC_Init(ctx, key_bin.data, key_bin.size, cipherp->cipher.p, NULL)) - goto local_err; - - if (!CMAC_Update(ctx, text.data, text.size)) - goto local_err; - - if ((size = (size_t)EVP_CIPHER_block_size(cipherp->cipher.p)) < 0) - goto local_err; - - if (!enif_alloc_binary(size, ret_bin)) - goto local_err; - *ret_bin_alloc = 1; - - if (!CMAC_Final(ctx, ret_bin->data, &ret_bin->size)) - goto local_err; - - CMAC_CTX_free(ctx); - return 1; - - local_err: - if (ctx) - CMAC_CTX_free(ctx); - - *return_term = EXCP_ERROR(env,"Compat cmac"); - return 0; -} - -#endif - - -#if !defined(HAS_EVP_PKEY_CTX) -int hmac_low_level(ErlNifEnv* env, const EVP_MD *md, - ErlNifBinary key_bin, ErlNifBinary text, - ErlNifBinary *ret_bin, int *ret_bin_alloc, ERL_NIF_TERM *return_term) -{ - unsigned int size_int; - size_t size; - - /* Find the needed space */ - if (HMAC(md, - key_bin.data, (int)key_bin.size, - text.data, text.size, - NULL, &size_int) == NULL) - { - *return_term = EXCP_ERROR(env, "Get HMAC size failed"); - return 0; - } - - size = (size_t)size_int; /* Otherwise "size" is unused in 0.9.8.... */ - if (!enif_alloc_binary(size, ret_bin)) - { - *return_term = EXCP_ERROR(env, "Alloc binary"); - return 0; - } - *ret_bin_alloc = 1; - - /* And do the real HMAC calc */ - if (HMAC(md, - key_bin.data, (int)key_bin.size, - text.data, text.size, - ret_bin->data, &size_int) == NULL) - { - *return_term = EXCP_ERROR(env, "HMAC sign failed"); - return 0; - } - - return 1; -} -#endif - - /******************************************************************* * * Mac ctx -- cgit v1.2.3 From e4afb9b62bfcfc2e89ffb893163c2bd374ec7865 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 22 May 2019 15:17:48 +0200 Subject: crypto: Begin test of the new mac interface directly. --- lib/crypto/test/crypto_SUITE.erl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 3b60de9eb7..0da70d5592 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1049,6 +1049,25 @@ cmac_check({cmac, Type, Key, Text, Size, CMac}) -> ct:fail({{crypto, cmac, [Type, Key, Text, Size]}, {expected, ExpCMac}, {got, Other}}) end. + +mac_check({MacType, SubType, Key, Text, Mac}) -> + 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}) -> + 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. + + block_cipher({Type, Key, PlainText}) -> Plain = iolist_to_binary(PlainText), CipherText = crypto:block_encrypt(Type, Key, PlainText), -- cgit v1.2.3 From 86f648027e56896cd1cc6bbe116aa61ed0f39378 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 5 Jun 2019 15:27:14 +0200 Subject: crypto: Renaming, typing and some polishing --- lib/crypto/src/crypto.erl | 119 +++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 34 deletions(-) diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 6aa3b30e79..965697578d 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -63,8 +63,8 @@ crypto_dyn_iv_init/3, crypto_dyn_iv_update/3, supports/1, - mac/3, mac/4, mac/5, - mac_init/3, mac_update/2, mac_final/1 + mac/3, mac/4, macN/4, macN/5, + mac_init/2, mac_init/3, mac_update/2, mac_final/1, mac_finalN/2 ]). @@ -111,7 +111,8 @@ stream_state/0, hmac_state/0, hash_state/0, - crypto_state/0 + crypto_state/0, + mac_state/0 ]). %% Private. For tests. @@ -336,23 +337,6 @@ | chacha20_poly1305 . -%% -type retired_cipher_no_iv_aliases() :: aes_ecb . - -%% -type retired_cipher_iv_aliases() :: aes_cbc -%% | aes_cbc128 % aes_128_cbc -%% | aes_cbc256 % aes_256_cbc -%% | aes_cfb128 -%% | aes_cfb8 -%% | aes_ctr -%% | des3_cbc % des_ede3_cbc -%% | des_ede3 % des_ede3_cbc -%% | des_ede3_cbf % des_ede3_cfb -%% | des3_cbf % des_ede3_cfb -%% | des3_cfb . % des_ede3_cfb - -%% -type retired_cipher_aead_aliases() :: aes_ccm -%% | aes_gcm . - %%%---------------------------------------------------------------- %%% Old cipher scheme %%% @@ -617,31 +601,100 @@ hash_final(Context) -> %%% %%%================================================================ +-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash(). + +-type cmac_cipher_algorithm() :: aes_128_cbc | aes_192_cbc | aes_256_cbc | blowfish_cbc + | des_cbc | des_ede3_cbc | rc2_cbc + | aes_128_cfb128 | aes_192_cfb128 | aes_256_cfb128 + | aes_128_cfb8 | aes_192_cfb8 | aes_256_cfb8 + . + %%%---------------------------------------------------------------- %%% Calculate MAC for the whole text at once -mac(Type, Key, Data) -> mac(Type, undefined, Key, Data). +-spec mac(Type :: poly1305, Key, Data) -> Mac | descriptive_error() + when Key :: iodata(), + Data :: iodata(), + Mac :: binary(). + +mac(poly1305, Key, Data) -> mac(poly1305, undefined, Key, Data). + + +-spec mac(Type, SubType, Key, Data) -> Mac | descriptive_error() + when Type :: hmac | cmac | poly1305, + SubType :: hmac_hash_algorithm() | cmac_cipher_algorithm() | undefined, + Key :: iodata(), + Data :: iodata(), + Mac :: binary(). -mac(Type, Key, Data, MacLength) when is_integer(MacLength) ->mac(Type,undefined,Key,Data); mac(Type, SubType, Key, Data) -> mac_nif(Type, SubType, Key, Data). -mac(Type, SubType, Key, Data, MacLength) -> + + +-spec macN(Type :: poly1305, Key, Data, MacLength) -> Mac | descriptive_error() + when Key :: iodata(), + Data :: iodata(), + Mac :: binary(), + MacLength :: pos_integer(). + +macN(Type, Key, Data, MacLength) -> + macN(Type, undefined, Key, Data, MacLength). + + +-spec macN(Type, SubType, Key, Data, MacLength) -> Mac | descriptive_error() + when Type :: hmac | cmac | poly1305, + SubType :: hmac_hash_algorithm() | cmac_cipher_algorithm() | undefined, + Key :: iodata(), + Data :: iodata(), + Mac :: binary(), + MacLength :: pos_integer(). + +macN(Type, SubType, Key, Data, MacLength) -> erlang:binary_part(mac(Type,SubType,Key,Data), 0, MacLength). %%%---------------------------------------------------------------- %%% Calculate the MAC by uppdating by pieces of the text +-opaque mac_state() :: reference() . + +-spec mac_init(Type :: poly1305, Key) -> State | descriptive_error() + when Key :: iodata(), + State :: mac_state() . +mac_init(poly1305, Key) -> + mac_init_nif(poly1305, undefined, Key). + + +-spec mac_init(Type, SubType, Key) -> State | descriptive_error() + when Type :: hmac | cmac | poly1305, + SubType :: hmac_hash_algorithm() | cmac_cipher_algorithm() | undefined, + Key :: iodata(), + State :: mac_state() . mac_init(Type, SubType, Key) -> mac_init_nif(Type, SubType, Key). + +-spec mac_update(State0, Data) -> State | descriptive_error() + when Data :: iodata(), + State0 :: mac_state(), + State :: mac_state(). mac_update(Ref, Data) -> mac_update_nif(Ref, Data). + + +-spec mac_final(State) -> Mac | descriptive_error() + when State :: mac_state(), + Mac :: binary(). mac_final(Ref) -> mac_final_nif(Ref). -mac_final(Ref, MacLength) -> + +-spec mac_finalN(State, MacLength) -> Mac | descriptive_error() + when State :: mac_state(), + MacLength :: pos_integer(), + Mac :: binary(). +mac_finalN(Ref, MacLength) -> erlang:binary_part(mac_final(Ref), 0, MacLength). @@ -667,8 +720,6 @@ mac_final_nif(_Ref) -> ?nif_stub. %%%---- HMAC --type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash(). - %%%---- hmac/3,4 -spec hmac(Type, Key, Data) -> @@ -687,11 +738,11 @@ hmac(Type, Key, Data) -> Mac :: binary() . hmac(Type, Key, Data, MacLength) -> - ?COMPAT(mac(hmac, Type, Key, Data, MacLength)). + ?COMPAT(macN(hmac, Type, Key, Data, MacLength)). %%%---- hmac_init, hamc_update, hmac_final --opaque hmac_state() :: binary(). +-opaque hmac_state() :: mac_state(). % Was: binary(). -spec hmac_init(Type, Key) -> State when Type :: hmac_hash_algorithm(), @@ -719,11 +770,11 @@ hmac_final(Context) -> HashLen :: integer(), Mac :: binary(). hmac_final_n(Context, HashLen) -> - ?COMPAT(mac_final(Context, HashLen)). + ?COMPAT(mac_finalN(Context, HashLen)). %%%---- CMAC --define(CMAC_CIPHER_ALGORITHM, cbc_cipher() | cfb_cipher() | blowfish_cbc | des_ede3 | rc2_cbc ). +-define(CMAC_CIPHER_ALGORITHM, cbc_cipher() | cfb_cipher() | blowfish_cbc | des_ede3 | rc2_cbc ). -spec cmac(Type, Key, Data) -> Mac when Type :: ?CMAC_CIPHER_ALGORITHM, @@ -741,7 +792,7 @@ cmac(Type, Key, Data) -> Mac :: binary(). cmac(Type, Key, Data, MacLength) -> - ?COMPAT(mac(cmac, alias(Type), Key, Data, MacLength)). + ?COMPAT(macN(cmac, alias(Type), Key, Data, MacLength)). %%%---- POLY1305 @@ -1023,9 +1074,9 @@ crypto_dyn_iv_init(Cipher, Key, EncryptFlag) -> %%% -spec crypto_update(State, Data) -> Result | descriptive_error() - when State :: crypto_state(), - Data :: iodata(), - Result :: binary() . + when State :: crypto_state(), + Data :: iodata(), + Result :: binary() . crypto_update(State, Data0) -> case iolist_to_binary(Data0) of <<>> -> -- cgit v1.2.3 From 8c4dfdafddec0aab02615fc3ebb95b7bc245f4db Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 13 Jun 2019 11:42:01 +0200 Subject: crypto: Enable MAC key length checking in mac-table --- lib/crypto/c_src/mac.c | 59 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 1995d67c2c..8b2710b91a 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -38,6 +38,7 @@ struct mac_type_t { const int pkey_type; }alg; int type; + size_t key_len; /* != 0 to also match on key_len */ }; #define NO_mac 0 @@ -50,31 +51,34 @@ static struct mac_type_t mac_types[] = {{"poly1305"}, #ifdef HAVE_POLY1305 /* If we have POLY then we have EVP_PKEY */ - {EVP_PKEY_POLY1305}, POLY1305_mac + {EVP_PKEY_POLY1305}, POLY1305_mac, 32 #else - {EVP_PKEY_NONE}, NO_mac + {EVP_PKEY_NONE}, NO_mac, 0 #endif }, {{"hmac"}, #ifdef HAS_EVP_PKEY_CTX - {EVP_PKEY_HMAC}, HMAC_mac + {EVP_PKEY_HMAC}, HMAC_mac, 0 #else /* HMAC is always supported, but possibly with low-level routines */ - {EVP_PKEY_NONE}, HMAC_mac + {EVP_PKEY_NONE}, HMAC_mac, 0 #endif }, {{"cmac"}, #ifdef HAVE_CMAC /* If we have CMAC then we have EVP_PKEY */ - {EVP_PKEY_CMAC}, CMAC_mac + {EVP_PKEY_CMAC}, CMAC_mac, 0 #else - {EVP_PKEY_NONE}, NO_mac + {EVP_PKEY_NONE}, NO_mac, 0 #endif }, + /*==== End of list ==== */ - {{NULL},{0},NO_mac} + {{NULL}, + {0}, NO_mac, 0 + } }; @@ -82,7 +86,8 @@ static struct mac_type_t mac_types[] = Mandatory prototypes ***************************/ -struct mac_type_t* get_mac_type(ERL_NIF_TERM type); +struct mac_type_t* get_mac_type(ERL_NIF_TERM type, size_t key_len); +struct mac_type_t* get_mac_type_no_key(ERL_NIF_TERM type); ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -125,7 +130,19 @@ ERL_NIF_TERM mac_types_as_list(ErlNifEnv* env) return hd; } -struct mac_type_t* get_mac_type(ERL_NIF_TERM type) +struct mac_type_t* get_mac_type(ERL_NIF_TERM type, size_t key_len) +{ + struct mac_type_t* p = NULL; + for (p = mac_types; p->name.atom != atom_false; p++) { + if (type == p->name.atom) { + if ((p->key_len == 0) || (p->key_len == key_len)) + return p; + } + } + return NULL; +} + +struct mac_type_t* get_mac_type_no_key(ERL_NIF_TERM type) { struct mac_type_t* p = NULL; for (p = mac_types; p->name.atom != atom_false; p++) { @@ -193,9 +210,12 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) goto err; } - if (!(macp = get_mac_type(argv[0]))) + if (!(macp = get_mac_type(argv[0], key_bin.size))) { - return_term = EXCP_BADARG(env, "Unknown mac algorithm"); + if (!get_mac_type_no_key(argv[0])) + return_term = EXCP_BADARG(env, "Unknown mac algorithm"); + else + return_term = EXCP_BADARG(env, "Bad key length"); goto err; } @@ -294,11 +314,6 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ************/ #ifdef HAVE_POLY1305 case POLY1305_mac: - if (key_bin.size != 32) - { - return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes"); - goto err; - } /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size); break; @@ -472,9 +487,12 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) goto err; } - if (!(macp = get_mac_type(argv[0]))) + if (!(macp = get_mac_type(argv[0], key_bin.size))) { - return_term = EXCP_BADARG(env, "Unknown mac algorithm"); + if (!get_mac_type_no_key(argv[0])) + return_term = EXCP_BADARG(env, "Unknown mac algorithm"); + else + return_term = EXCP_BADARG(env, "Bad key length"); goto err; } @@ -558,11 +576,6 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ************/ #ifdef HAVE_POLY1305 case POLY1305_mac: - if (key_bin.size != 32) - { - return_term = EXCP_BADARG(env, "Bad key size, != 32 bytes"); - goto err; - } /* poly1305 implies that EVP_PKEY_new_raw_private_key exists */ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size); break; -- cgit v1.2.3 From 511480bd35d03a52062ac340f49b5149d3dce507 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 5 Jun 2019 15:27:36 +0200 Subject: crypto: Documentation --- lib/crypto/doc/src/algorithm_details.xml | 63 ++---- lib/crypto/doc/src/crypto.xml | 360 ++++++++++++++++++++++++------- lib/crypto/doc/src/new_api.xml | 181 +++++++++++----- 3 files changed, 427 insertions(+), 177 deletions(-) diff --git a/lib/crypto/doc/src/algorithm_details.xml b/lib/crypto/doc/src/algorithm_details.xml index 854bfbb4b1..85ae766c35 100644 --- a/lib/crypto/doc/src/algorithm_details.xml +++ b/lib/crypto/doc/src/algorithm_details.xml @@ -48,8 +48,7 @@

Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.

To dynamically check availability, check that the name in the Cipher and Mode column is present in the - list with the cipher tag in the return value of - crypto:supports(). + list returned by crypto:supports(ciphers).

Cipher and ModeKey length
[bytes]
IV length
[bytes]
Block size
[bytes]
@@ -85,8 +84,7 @@ block_decrypt/4.

To dynamically check availability, check that the name in the Cipher and Mode column is present in the - list with the cipher tag in the return value of - crypto:supports(). + list returned by crypto:supports(ciphers).

Cipher and ModeKey length
[bytes]
IV length
[bytes]
AAD length
[bytes]
Tag length
[bytes]
Block size
[bytes]
Supported with
OpenSSL versions
@@ -103,8 +101,7 @@ stream_init/3.

To dynamically check availability, check that the name in the Cipher and Mode column is present in the - list with the cipher tag in the return value of - crypto:supports(). + list returned by crypto:supports(ciphers).

Cipher and ModeKey length
[bytes]
IV length
[bytes]
Supported with
OpenSSL versions
@@ -117,20 +114,19 @@
Message Authentication Codes (MACs) +

To be used in mac/4 and + related functions. +

CMAC -

To be used in cmac/3 and - cmac/4. -

CMAC with the following ciphers are available with OpenSSL 1.0.1 or later if not disabled by configuration.

To dynamically check availability, check that the name cmac is present in the - list with the macs tag in the return value of - crypto:supports(). + list returned by crypto:supports(macs). Also check that the name in the Cipher and Mode column is present in the - list with the cipher tag in the return value. + list returned by crypto:supports(ciphers).

Cipher and ModeKey length
[bytes]
Max Mac Length
[bytes]
@@ -162,8 +158,7 @@

Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.

To dynamically check availability, check that the name hmac is present in the - list with the macs tag in the return value of - crypto:supports(). + list returned by crypto:supports(macs).

@@ -172,8 +167,7 @@

POLY1305 is available with OpenSSL 1.1.1 or later if not disabled by configuration.

To dynamically check availability, check that the name poly1305 is present in the - list with the macs tag in the return value of - crypto:supports(). + list returned by crypto:supports(macs).

@@ -183,11 +177,9 @@ Hash

To dynamically check availability, check that the wanted name in the Names column is present in the - list with the hashs tag in the return value of - crypto:supports(). + list returned by crypto:supports(hashs).

-
Type Names @@ -210,8 +202,7 @@ RSA

RSA is available with all OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration. To dynamically check availability, check that the atom rsa is present in the - list with the public_keys tag in the return value of - crypto:supports(). + list returned by crypto:supports(public_keys).

@@ -283,8 +274,7 @@ DSS

DSS is available with OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration. To dynamically check availability, check that the atom dss is present in the - list with the public_keys tag in the return value of - crypto:supports(). + list returned by crypto:supports(public_keys).

@@ -292,13 +282,11 @@ ECDSA

ECDSA is available with OpenSSL 0.9.8o or later if not disabled by configuration. To dynamically check availability, check that the atom ecdsa is present in the - list with the public_keys tag in the return value of - crypto:supports(). - If the atom ec_gf2m characteristic two field curves are available. + list returned by crypto:supports(public_keys). + If the atom ec_gf2m also is present, the characteristic two field curves are available.

-

The actual supported named curves could be checked by examining the list with the - curves tag in the return value of - crypto:supports(). +

The actual supported named curves could be checked by examining the + list returned by crypto:supports(curves).

@@ -306,13 +294,11 @@ EdDSA

EdDSA is available with OpenSSL 1.1.1 or later if not disabled by configuration. To dynamically check availability, check that the atom eddsa is present in the - list with the public_keys tag in the return value of - crypto:supports(). + list returned by crypto:supports(public_keys).

Support for the curves ed25519 and ed448 is implemented. The actual supported named curves could be checked by examining the list with the - curves tag in the return value of - crypto:supports(). + list returned by crypto:supports(curves).

@@ -321,8 +307,7 @@

Diffie-Hellman computations are available with OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration. To dynamically check availability, check that the atom dh is present in the - list with the public_keys tag in the return value of - crypto:supports(). + list returned by crypto:supports(public_keys).

@@ -330,17 +315,15 @@ Elliptic Curve Diffie-Hellman

Elliptic Curve Diffie-Hellman is available with OpenSSL 0.9.8o or later if not disabled by configuration. To dynamically check availability, check that the atom ecdh is present in the - list with the public_keys tag in the return value of - crypto:supports(). + list returned by crypto:supports(public_keys).

The Edward curves x25519 and x448 are supported with OpenSSL 1.1.1 or later if not disabled by configuration.

-

The actual supported named curves could be checked by examining the list with the - curves tag in the return value of - crypto:supports(). +

The actual supported named curves could be checked by examining the + list returned by crypto:supports(curves).

diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index d1d1252f29..26fbfc166e 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -301,6 +301,12 @@ + + + + + + @@ -324,6 +330,11 @@ + + + + +

The compatibility_only_hash() algorithms are recommended only for compatibility with existing applications.

@@ -575,10 +586,11 @@ Internal data types - - - + + + +

Contexts with an internal state that should not be manipulated but passed between function calls.

@@ -783,6 +795,161 @@
+ + + + +

Short for mac(Type, undefined, Key, Data). +

+
+
+ + + + + +

Computes a MAC (Message Authentication Code) of type Type from Data. +

+ +

SubType depends on the MAC Type: +

+ + For hmac it is a hash algorithm + For cmac it is a cipher suitable for cmac + For poly1305 it should be set to undefined or the + mac/3 function could be used instead. + + +

Key is the authentication key with a length according to the + Type and SubType. + The key length could be found with the + hash_info/1 (hmac) for and + cipher_info/1 (cmac) + functions. For poly1305 the key length is 32 bytes. Note that + the cryptographic quality of the key is not checked. +

+ +

The Mac result will have a default length depending on the Type and SubType. + To set a shorter length, use macN/4 or + macN/5 instead. +

+
+
+ + + + + +

Short for macN(Type, undefined, Key, Data, MacLength). +

+
+
+ + + + + +

Computes a MAC (Message Authentication Code) + as mac/3 and mac/4 but + MacLength will limit the size of the resultant Mac to + at most MacLength bytes. + Note that if MacLength is greater than the actual number of + bytes returned from the underlying hash, the returned hash will have + that shorter length instead. +

+
+
+ + + + + +

Short for mac_init(Type, undefined, Key). +

+
+
+ + + + + +

Initializes the context for streaming MAC operations. +

+

Type determines which mac algorithm to use in the MAC operation. +

+ +

SubType depends on the MAC Type: +

+ + For hmac it is a hash algorithm + For cmac it is a cipher suitable for cmac + For poly1305 it should be set to undefined or the + mac/2 function could be used instead. + + +

Key is the authentication key with a length according to the + Type and SubType. + The key length could be found with the + hash_info/1 (hmac) for and + cipher_info/1 (cmac) + functions. For poly1305 the key length is 32 bytes. Note that + the cryptographic quality of the key is not checked. +

+ +

The returned State should be used in one or more subsequent calls to + mac_update/2. + The MAC value is finally returned by calling + mac_final/1 or + mac_finalN/2. +

+ +

See + examples in the User's Guide. +

+
+
+ + + + + +

Updates the MAC represented by State0 using the given Data which + could be of any length. +

+

The State0 is the State value originally from a MAC init function, that is + mac_init/2, + mac_init/3 or + a previous call of mac_update/2. + The value State0 is returned unchanged by the function as State. +

+
+
+ + + + + +

Finalizes the MAC operation referenced by State. The Mac result will have + a default length depending on the Type and SubType in the + mac_init/2,3 call. + To set a shorter length, use mac_finalN/2 instead. +

+
+
+ + + + + +

Finalizes the MAC operation referenced by State. +

+

Mac will be a binary with at most MacLength bytes. + Note that if MacLength is greater than the actual number of + bytes returned from the underlying hash, the returned hash will have + that shorter length instead. +

+
+
@@ -885,75 +1052,6 @@ - - - - - -

Computes a HMAC of type Type from Data using - Key as the authentication key.

MacLength - will limit the size of the resultant Mac.

-
-
- - - - - -

Initializes the context for streaming HMAC operations. Type determines - which hash function to use in the HMAC operation. Key is the authentication - key. The key can be any length.

-
-
- - - - - -

Updates the HMAC represented by Context using the given Data. Context - must have been generated using an HMAC init function (such as - hmac_init). Data can be any length. NewContext - must be passed into the next call to hmac_update - or to one of the functions hmac_final and - hmac_final_n -

-

Do not use a Context as argument in more than one - call to hmac_update or hmac_final. The semantics of reusing old contexts - in any way is undefined and could even crash the VM in earlier releases. - The reason for this limitation is a lack of support in the underlying - libcrypto API.

-
-
- - - - - -

Finalizes the HMAC operation referenced by Context. The size of the resultant MAC is - determined by the type of hash function used to generate it.

-
-
- - - - - -

Finalizes the HMAC operation referenced by Context. HashLen must be greater than - zero. Mac will be a binary with at most HashLen bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than HashLen bytes.

-
-
- - - - - Calculates the Cipher-based Message Authentication Code. - -

Computes a CMAC of type Type from Data using - Key as the authentication key.

MacLength - will limit the size of the resultant Mac.

-
-
- Provides information about the FIPS operating status. @@ -1067,15 +1165,6 @@ - - - - -

Computes a POLY1305 message authentication code (Mac) from Data using - Key as the authentication key.

-
-
- Decrypts CipherText using the private Key. @@ -1961,6 +2050,115 @@ FloatValue = rand:uniform(). % again + + + + + +

Don't use this function for new programs! Use + mac/4 or + macN/5 in + the new api.

+
+

Computes a HMAC of type Type from Data using + Key as the authentication key.

MacLength + will limit the size of the resultant Mac.

+
+
+ + + + + +

Don't use this function for new programs! Use + mac_init/3 in + the new api.

+
+

Initializes the context for streaming HMAC operations. Type determines + which hash function to use in the HMAC operation. Key is the authentication + key. The key can be any length.

+
+
+ + + + + +

Don't use this function for new programs! Use + mac_update/2 in + the new api.

+
+

Updates the HMAC represented by Context using the given Data. Context + must have been generated using an HMAC init function (such as + hmac_init). Data can be any length. NewContext + must be passed into the next call to hmac_update + or to one of the functions hmac_final and + hmac_final_n +

+

Do not use a Context as argument in more than one + call to hmac_update or hmac_final. The semantics of reusing old contexts + in any way is undefined and could even crash the VM in earlier releases. + The reason for this limitation is a lack of support in the underlying + libcrypto API.

+
+
+ + + + + +

Don't use this function for new programs! Use + mac_final/1 in + the new api.

+
+

Finalizes the HMAC operation referenced by Context. The size of the resultant MAC is + determined by the type of hash function used to generate it.

+
+
+ + + + + +

Don't use this function for new programs! Use + mac_finalN/2 in + the new api.

+
+

Finalizes the HMAC operation referenced by Context. HashLen must be greater than + zero. Mac will be a binary with at most HashLen bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than HashLen bytes.

+
+
+ + + + + Calculates the Cipher-based Message Authentication Code. + +

Don't use this function for new programs! Use + mac/4 or + macN/5 in + the new api.

+
+

Computes a CMAC of type Type from Data using + Key as the authentication key.

MacLength + will limit the size of the resultant Mac.

+
+
+ + + + + +

Don't use this function for new programs! Use + mac/3 or + macN/4 in + the new api.

+
+

Computes a POLY1305 message authentication code (Mac) from Data using + Key as the authentication key.

+
+
+ diff --git a/lib/crypto/doc/src/new_api.xml b/lib/crypto/doc/src/new_api.xml index bd2334ac9f..aacf5e4f76 100644 --- a/lib/crypto/doc/src/new_api.xml +++ b/lib/crypto/doc/src/new_api.xml @@ -40,7 +40,7 @@ to maintain.

It turned out that using the old api in the new way (more about that later), and still keep it - backwards compatible, was not possible. Specially as more precision in the error messages was wanted + backwards compatible, was not possible. Specially as more precision in the error messages is desired it could not be combined with the old standard.

Therefore the old api (see next section) is kept for now but internally implemented with new primitives. @@ -49,7 +49,7 @@

The old API -

The old functions - not recommended for new programs - are:

+

The old functions - not recommended for new programs - are for chipers:

block_encrypt/3 block_encrypt/4 @@ -59,60 +59,100 @@ stream_init/3 stream_encrypt/2 stream_decrypt/2 + +

for lists of supported algorithms:

+ supports/0 +

and for MACs (Message Authentication Codes):

+ + cmac/3 + cmac/4 + hmac/3 + hmac/4 + hmac_init/2 + hmac_update/2 + hmac_final/1 + hmac_final_n/2 + poly1305/2 +

They are not deprecated for now, but may be in a future release.

The new API -

The new functions for encrypting or decrypting one single binary are: -

- - crypto_one_time/4 - crypto_one_time/5 - crypto_one_time_aead/6 - crypto_one_time_aead/7 - -

In those functions the internal crypto state is first created and initialized - with the cipher type, the key and possibly other data. Then the single binary is encrypted - or decrypted, - the crypto state is de-allocated and the result of the crypto operation is returned. -

-

The crypto_one_time_aead functions are for the ciphers of mode ccm or - gcm, and for the cipher chacha20-poly1305. -

-

For repeated encryption or decryption of a text divided in parts, where the internal - crypto state is initialized once, and then many binaries are encrypted or decrypted with - the same state, the functions are: -

- - crypto_init/4 - crypto_init/3 - crypto_update/2 - -

The crypto_init initialies an internal cipher state, and one or more calls of - crypto_update does the acual encryption or decryption. Note that AEAD ciphers - can't be handled this way due to their nature. -

-

For repeated encryption or decryption of a text divided in parts where the - same cipher and same key is used, but a new initialization vector (nounce) should be applied - for each part, the functions are: -

- - crypto_dyn_iv_init/3 - crypto_dyn_iv_update/3 - -

An example of where those functions are needed, is when handling the TLS protocol.

-

For information about available algorithms, use: -

- - supports/1 - hash_info/1 - cipher_info/1 - +
+ Encryption and decryption +

The new functions for encrypting or decrypting one single binary are: +

+ + crypto_one_time/4 + crypto_one_time/5 + crypto_one_time_aead/6 + crypto_one_time_aead/7 + +

In those functions the internal crypto state is first created and initialized + with the cipher type, the key and possibly other data. Then the single binary is encrypted + or decrypted, + the crypto state is de-allocated and the result of the crypto operation is returned. +

+

The crypto_one_time_aead functions are for the ciphers of mode ccm or + gcm, and for the cipher chacha20-poly1305. +

+

For repeated encryption or decryption of a text divided in parts, where the internal + crypto state is initialized once, and then many binaries are encrypted or decrypted with + the same state, the functions are: +

+ + crypto_init/4 + crypto_init/3 + crypto_update/2 + +

The crypto_init initialies an internal cipher state, and one or more calls of + crypto_update does the acual encryption or decryption. Note that AEAD ciphers + can't be handled this way due to their nature. +

+

For repeated encryption or decryption of a text divided in parts where the + same cipher and same key is used, but a new initialization vector (nounce) should be applied + for each part, the functions are: +

+ + crypto_dyn_iv_init/3 + crypto_dyn_iv_update/3 + +

An example of where those functions are needed, is when handling the TLS protocol.

+

For information about available algorithms, use: +

+ + supports/1 + hash_info/1 + cipher_info/1 + +
+
+ MACs (Message Authentication Codes) +

The new functions for calculating a MAC of a single piece of text are:

+ + mac/3 + mac/4 + macN/4 + macN/5 + +

For calculating a MAC of a text divided in parts use:

+ + mac_init/2 + mac_init/3 + mac_update/2 + mac_final/1 + mac_finalN/2 + +
+
+ +
+ Examples of the new api
Examples of crypto_init/4 and crypto_update/2

The functions crypto_init/4 @@ -143,7 +183,7 @@ 8> crypto:crypto_update(StateDec, <<67,44,216,166,25,130,203>>). <<"First b">> 9> crypto:crypto_update(StateDec, <<5,66,6,162,16,79,94,115,234,197, - 94,253,16,144,151>>). + 94,253,16,144,151>>). <<"ytesSecond byte">> 10> crypto:crypto_update(StateDec, <<41>>). <<"s">> @@ -159,16 +199,16 @@

encode(Crypto, Key, IV) -> - crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)). + crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)). crypto_loop(State) -> - receive - {Text, Requester} -> - Requester ! crypto:crypto_update(State, Text), - loop(State) - end. + receive + {Text, Requester} -> + Requester ! crypto:crypto_update(State, Text), + loop(State) + end. -
+
Example of crypto_one_time/5 @@ -219,6 +259,35 @@

+
+ Example of mac_init mac_update and mac_final + + 1> Key = <<1:128>>. + <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>> + 2> StateMac = crypto:mac_init(cmac, aes_128_cbc, Key). + #Ref<0.2424664121.2781478916.232610> + 3> crypto:mac_update(StateMac, <<"First bytes">>). + #Ref<0.2424664121.2781478916.232610> + 4> crypto:mac_update(StateMac, " "). + #Ref<0.2424664121.2781478916.232610> + 5> crypto:mac_update(StateMac, <<"last bytes">>). + #Ref<0.2424664121.2781478916.232610> + 6> crypto:mac_final(StateMac). + <<68,191,219,128,84,77,11,193,197,238,107,6,214,141,160, + 249>> + 7> + +

and compare the result with a single calculation just for this example:

+ + 7> crypto:mac(cmac, aes_128_cbc, Key, "First bytes last bytes"). + <<68,191,219,128,84,77,11,193,197,238,107,6,214,141,160, + 249>> + 8> v(7) == v(6). + true + 9> + +
+
@@ -233,7 +302,7 @@ on the mode. An example is the ccm mode which has a variant called ccm8 where the so called tag has a length of eight bits.

-

The old names had by time lost any common naming which the new names now introduces. The new names include +

The old names had by time lost any common naming convention which the new names now introduces. The new names include the key length which improves the error checking in the lower levels of the crypto application.

-- cgit v1.2.3