From 2702f65e834a65d05d82cebf77bc7385becbf3a7 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 31 May 2012 13:08:03 +0200 Subject: crypto: Add rsa and dss hash signing support --- lib/crypto/c_src/crypto.c | 139 +++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 30 +++++++-- lib/crypto/test/crypto_SUITE.erl | 63 +++++++++++++++++- 3 files changed, 227 insertions(+), 5 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 4be593e208..62e745db6c 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -168,6 +168,7 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -175,7 +176,9 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -256,6 +259,7 @@ static ErlNifFunc nif_funcs[] = { {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, {"rsa_verify_nif", 4, rsa_verify_nif}, + {"rsa_verify_hash_nif", 4, rsa_verify_hash_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, {"exor", 2, exor}, {"rc4_encrypt", 2, rc4_encrypt}, @@ -263,7 +267,9 @@ static ErlNifFunc nif_funcs[] = { {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, {"rc2_cbc_crypt", 4, rc2_cbc_crypt}, {"rsa_sign_nif", 3, rsa_sign_nif}, + {"rsa_sign_hash_nif", 3, rsa_sign_hash_nif}, {"dss_sign_nif", 3, dss_sign_nif}, + {"dss_sign_hash_nif", 3, dss_sign_hash_nif}, {"rsa_public_crypt", 4, rsa_public_crypt}, {"rsa_private_crypt", 4, rsa_private_crypt}, {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif}, @@ -1327,6 +1333,46 @@ done: return ret; } +static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data, Signature, Key=[E,N]) */ + ErlNifBinary data_bin, sign_bin; + ERL_NIF_TERM head, tail, ret; + int i, type; + RSA* rsa = RSA_new(); + + if (!enif_inspect_binary(env,argv[1],&data_bin)) { + ret = enif_make_badarg(env); + goto done; + } + + if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; + else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; + else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; + else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; + else { + ret = enif_make_badarg(env); + goto done; + } + + if (!inspect_mpint(env, argv[2], &sign_bin) + || !enif_get_list_cell(env, argv[3], &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->e) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->n) + || !enif_is_empty_list(env, tail)) { + + ret = enif_make_badarg(env); + } + else { + i = RSA_verify(type, data_bin.data, data_bin.size, + sign_bin.data+4, sign_bin.size-4, rsa); + ret = (i==1 ? atom_true : atom_false); + } +done: + RSA_free(rsa); + return ret; +} + static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, IVec, Data, IsEncrypt) */ ErlNifBinary key_bin, ivec_bin, data_bin; @@ -1530,6 +1576,52 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } } +static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type,Data,Key=[E,N,D]) */ + ErlNifBinary data_bin, ret_bin; + ERL_NIF_TERM head, tail; + unsigned rsa_s_len; + RSA *rsa = RSA_new(); + int i, type; + + if (!enif_inspect_binary(env,argv[1],&data_bin)) + goto badarg; + + if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; + else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; + else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; + else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; + else goto badarg; + + if (!enif_get_list_cell(env, argv[2], &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->e) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->n) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &rsa->d) + || !enif_is_empty_list(env,tail)) { + badarg: + RSA_free(rsa); + return enif_make_badarg(env); + } + enif_alloc_binary(RSA_size(rsa), &ret_bin); + i = RSA_sign(type, data_bin.data, data_bin.size, + ret_bin.data, &rsa_s_len, rsa); + RSA_free(rsa); + if (i) { + ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); + if (rsa_s_len != data_bin.size) { + enif_realloc_binary(&ret_bin, rsa_s_len); + ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len); + } + return enif_make_binary(env,&ret_bin); + } + else { + enif_release_binary(&ret_bin); + return atom_error; + } +} + static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ ErlNifBinary data_bin, ret_bin; @@ -1579,6 +1671,53 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } } +static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ + ErlNifBinary data_bin, ret_bin; + ERL_NIF_TERM head, tail; + unsigned int dsa_s_len; + DSA* dsa = DSA_new(); + int i, type; + + if (!enif_inspect_binary(env,argv[1],&data_bin)) + goto badarg; + + if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; + else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; + else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; + else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; + else goto badarg; + + dsa->pub_key = NULL; + if (!enif_get_list_cell(env, argv[2], &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->p) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->q) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->g) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_mpint(env, head, &dsa->priv_key) + || !enif_is_empty_list(env,tail)) { + badarg: + DSA_free(dsa); + return enif_make_badarg(env); + } + + enif_alloc_binary(DSA_size(dsa), &ret_bin); + i = DSA_sign(type, data_bin.data, data_bin.size, + ret_bin.data, &dsa_s_len, dsa); + DSA_free(dsa); + if (i) { + if (dsa_s_len != ret_bin.size) { + enif_realloc_binary(&ret_bin, dsa_s_len); + } + return enif_make_binary(env, &ret_bin); + } + else { + return atom_error; + } +} + static int rsa_pad(ERL_NIF_TERM term, int* padding) { if (term == atom_rsa_pkcs1_padding) { diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index d7aac27825..f4f4e20b4d 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -43,8 +43,8 @@ -export([exor/2]). -export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). -export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). --export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). +-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4, rsa_verify_hash/4]). +-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3, dss_sign_hash/3, rsa_sign_hash/3]). -export([rsa_public_encrypt/3, rsa_private_decrypt/3]). -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). @@ -80,8 +80,8 @@ strong_rand_mpint, rand_uniform, mod_exp, - dss_verify,dss_sign, - rsa_verify,rsa_sign, + dss_verify,dss_sign,dss_sign_hash, + rsa_verify,rsa_verify_hash,rsa_sign,rsa_sign_hash, rsa_public_encrypt,rsa_private_decrypt, rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, @@ -581,6 +581,8 @@ mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub. -spec rsa_verify(binary(), binary(), [binary()]) -> boolean(). -spec rsa_verify(rsa_digest_type(), binary(), binary(), [binary()]) -> boolean(). +-spec rsa_verify_hash(rsa_digest_type(), binary(), binary(), [binary()]) -> + boolean(). %% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey dss_verify(Data,Signature,Key) -> @@ -595,8 +597,14 @@ rsa_verify(Type, Data, Signature, Key) -> notsup -> erlang:error(notsup); Bool -> Bool end. +rsa_verify_hash(Type, Hash, Signature, Key) -> + case rsa_verify_hash_nif(Type, Hash, Signature, Key) of + notsup -> erlang:error(notsup); + Bool -> Bool + end. rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +rsa_verify_hash_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. %% @@ -605,8 +613,10 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. %% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey -spec dss_sign(binary(), [binary()]) -> binary(). -spec dss_sign(dss_digest_type(), binary(), [binary()]) -> binary(). +-spec dss_sign_hash(dss_digest_type(), binary(), [binary()]) -> binary(). -spec rsa_sign(binary(), [binary()]) -> binary(). -spec rsa_sign(rsa_digest_type(), binary(), [binary()]) -> binary(). +-spec rsa_sign_hash(rsa_digest_type(), binary(), [binary()]) -> binary(). dss_sign(Data,Key) -> dss_sign(sha,Data,Key). @@ -615,8 +625,14 @@ dss_sign(Type, Data, Key) -> error -> erlang:error(badkey, [Data, Key]); Sign -> Sign end. +dss_sign_hash(Type, Hash, Key) -> + case dss_sign_hash_nif(Type,Hash,Key) of + error -> erlang:error(badkey, [Hash, Key]); + Sign -> Sign + end. dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +dss_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent rsa_sign(Data,Key) -> @@ -626,8 +642,14 @@ rsa_sign(Type, Data, Key) -> error -> erlang:error(badkey, [Type,Data,Key]); Sign -> Sign end. +rsa_sign_hash(Type, Hash, Key) -> + case rsa_sign_hash_nif(Type,Hash,Key) of + error -> erlang:error(badkey, [Type,Hash,Key]); + Sign -> Sign + end. rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +rsa_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 627c966dfb..a399511de0 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -61,7 +61,9 @@ rsa_verify_test/1, dsa_verify_test/1, rsa_sign_test/1, + rsa_sign_hash_test/1, dsa_sign_test/1, + dsa_sign_hash_test/1, rsa_encrypt_decrypt/1, dh/1, exor_test/1, @@ -88,7 +90,8 @@ groups() -> aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, - dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, + rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test, + rsa_encrypt_decrypt, dh, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, smp]}]. @@ -1207,6 +1210,33 @@ rsa_sign_test(Config) when is_list(Config) -> ok. +rsa_sign_hash_test(doc) -> + "rsa_sign_hash testing"; +rsa_sign_hash_test(suite) -> + []; +rsa_sign_hash_test(Config) when is_list(Config) -> + PubEx = 65537, + PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945, + Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123, + Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" + "09812312908312378623487263487623412039812 huagasd">>, + + PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], + PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], + MD5 = crypto:md5(sized_binary(Msg)), + SHA = crypto:sha(sized_binary(Msg)), + ?line Sig1 = crypto:rsa_sign_hash(sha, SHA, PrivKey), + ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig1),PubKey), true), + + ?line Sig2 = crypto:rsa_sign_hash(md5, MD5, PrivKey), + ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig2),PubKey), true), + + ?line m(Sig1 =:= Sig2, false), + ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig1),PubKey), false), + ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig2),PubKey), false), + + ok. + dsa_sign_test(doc) -> "dsa_sign testing"; dsa_sign_test(suite) -> @@ -1237,6 +1267,37 @@ dsa_sign_test(Config) when is_list(Config) -> ok. +dsa_sign_hash_test(doc) -> + "dsa_sign_hash testing"; +dsa_sign_hash_test(suite) -> + []; +dsa_sign_hash_test(Config) when is_list(Config) -> + Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" + "09812312908312378623487263487623412039812 huagasd">>, + SHA = crypto:sha(sized_binary(Msg)), + + PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978, + PrivKey = _X = 441502407453038284293378221372000880210588566361, + ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797, + ParamQ = 1349199015905534965792122312016505075413456283393, + ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669, + + Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)], + ?line Sig1 = crypto:dss_sign_hash(sha, SHA, Params ++ [crypto:mpint(PrivKey)]), + + ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1), + Params ++ [crypto:mpint(PubKey)]), true), + + ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1), + Params ++ [crypto:mpint(PubKey)]), false), + + ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)), + Params ++ [crypto:mpint(PubKey)]), false), + + %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]), + + ok. + rsa_encrypt_decrypt(doc) -> ["Test rsa_public_encrypt and rsa_private_decrypt functions."]; -- cgit v1.2.3 From 90167202a4ce3dc6d4822fad04c51cc35913d796 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 15:35:26 +0200 Subject: crypto: Redo interface for rsa and dss hash signing Replace _hash functions with {digest,_} argument to existing sign/verify functions. --- lib/crypto/c_src/crypto.c | 435 ++++++++++++++++++++------------------- lib/crypto/doc/src/crypto.xml | 66 +++--- lib/crypto/src/crypto.erl | 73 +++---- lib/crypto/test/crypto_SUITE.erl | 14 +- 4 files changed, 292 insertions(+), 296 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 62e745db6c..25616410be 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -168,7 +168,6 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -176,9 +175,7 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -204,6 +201,7 @@ static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, #endif /* OPENSSL_THREADS */ /* helpers */ +static void init_digest_types(ErlNifEnv* env); static void hmac_md5(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); @@ -259,7 +257,6 @@ static ErlNifFunc nif_funcs[] = { {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, {"rsa_verify_nif", 4, rsa_verify_nif}, - {"rsa_verify_hash_nif", 4, rsa_verify_hash_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, {"exor", 2, exor}, {"rc4_encrypt", 2, rc4_encrypt}, @@ -267,9 +264,7 @@ static ErlNifFunc nif_funcs[] = { {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, {"rc2_cbc_crypt", 4, rc2_cbc_crypt}, {"rsa_sign_nif", 3, rsa_sign_nif}, - {"rsa_sign_hash_nif", 3, rsa_sign_hash_nif}, {"dss_sign_nif", 3, dss_sign_nif}, - {"dss_sign_hash_nif", 3, dss_sign_hash_nif}, {"rsa_public_crypt", 4, rsa_public_crypt}, {"rsa_private_crypt", 4, rsa_private_crypt}, {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif}, @@ -326,6 +321,7 @@ static ERL_NIF_TERM atom_check_failed; static ERL_NIF_TERM atom_unknown; static ERL_NIF_TERM atom_none; static ERL_NIF_TERM atom_notsup; +static ERL_NIF_TERM atom_digest; static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) @@ -399,6 +395,9 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_unknown = enif_make_atom(env,"unknown"); atom_none = enif_make_atom(env,"none"); atom_notsup = enif_make_atom(env,"notsup"); + atom_digest = enif_make_atom(env,"digest"); + + init_digest_types(env); *priv_data = NULL; library_refc++; @@ -1214,14 +1213,43 @@ static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin) } static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigestType,Data,Signature,Key=[P, Q, G, Y]) */ +{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */ ErlNifBinary data_bin, sign_bin; BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; + unsigned char* digest; ERL_NIF_TERM head, tail; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; DSA *dsa; int i; + if (argv[0] == atom_sha) { + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != SHA_DIGEST_LENGTH) { + + return enif_make_badarg(env); + } + digest = data_bin.data; + } + else { + if (!inspect_mpint(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + digest = hmacbuf; + } + } + else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin) + && data_bin.size == SHA_DIGEST_LENGTH) { + digest = data_bin.data; + } + else { + return enif_make_badarg(env); + } + if (!inspect_mpint(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) || !get_bn_from_mpint(env, head, &dsa_p) @@ -1232,23 +1260,13 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_mpint(env, head, &dsa_y) || !enif_is_empty_list(env,tail)) { - badarg: + if (dsa_p) BN_free(dsa_p); if (dsa_q) BN_free(dsa_q); if (dsa_g) BN_free(dsa_g); if (dsa_y) BN_free(dsa_y); return enif_make_badarg(env); } - if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - } - else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin) - && data_bin.size == SHA_DIGEST_LENGTH) { - memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH); - } - else { - goto badarg; - } dsa = DSA_new(); dsa->p = dsa_p; @@ -1256,23 +1274,121 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv dsa->g = dsa_g; dsa->priv_key = NULL; dsa->pub_key = dsa_y; - i = DSA_verify(0, hmacbuf, SHA_DIGEST_LENGTH, + i = DSA_verify(0, digest, SHA_DIGEST_LENGTH, sign_bin.data+4, sign_bin.size-4, dsa); DSA_free(dsa); return(i > 0) ? atom_true : atom_false; } + +static void md5_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + MD5(in, in_len, out); +} +static void sha1_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA1(in, in_len, out); +} +#ifdef HAVE_SHA256 +static void sha256_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA256(in, in_len, out); +} +#endif +#ifdef HAVE_SHA384 +static void sha384_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA384(in, in_len, out); +} +#endif +#ifdef HAVE_SHA512 +static void sha512_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA512(in, in_len, out); +} +#endif + +struct digest_type_t { + const char* type_str; + unsigned len; /* 0 if notsup */ + int NID_type; + void (*funcp)(unsigned char* in, unsigned int in_len, unsigned char* out); + ERL_NIF_TERM type_atom; +}; + +struct digest_type_t digest_types[] = +{ + {"md5", MD5_DIGEST_LENGTH, NID_md5, md5_digest}, + {"sha", SHA_DIGEST_LENGTH, NID_sha1, sha1_digest}, + {"sha256", +#ifdef HAVE_SHA256 + SHA256_LEN, NID_sha256, sha256_digest +#else + 0 +#endif + }, + {"sha384", +#ifdef HAVE_SHA384 + SHA384_LEN, NID_sha384, sha384_digest +#else + 0 +#endif + }, + {"sha512", +#ifdef HAVE_SHA512 + SHA512_LEN, NID_sha512, sha512_digest +#else + 0 +#endif + }, + {NULL} +}; + +static void init_digest_types(ErlNifEnv* env) +{ + struct digest_type_t* p = digest_types; + + for (p = digest_types; p->type_str; p++) { + p->type_atom = enif_make_atom(env, p->type_str); + } + +} + +static struct digest_type_t* get_digest_type(ERL_NIF_TERM type) +{ + struct digest_type_t* p = NULL; + for (p = digest_types; p->type_str; p++) { + if (type == p->type_atom) { + return p; + } + } + return NULL; +} + static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data, Signature, Key=[E,N]) */ +{/* (Type, Data|{digest,Digest}, Signature, Key=[E,N]) */ ErlNifBinary data_bin, sign_bin; unsigned char hmacbuf[SHA512_LEN]; ERL_NIF_TERM head, tail, ret; int i; - RSA* rsa = RSA_new(); + RSA* rsa; const ERL_NIF_TERM type = argv[0]; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t* digp = NULL; + unsigned char* digest = NULL; + + digp = get_digest_type(type); + if (!digp) { + return enif_make_badarg(env); + } + if (!digp->len) { + return atom_notsup; + } + + rsa = RSA_new(); - if (!inspect_mpint(env, argv[1], &data_bin) - || !inspect_mpint(env, argv[2], &sign_bin) + if (!inspect_mpint(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) || !get_bn_from_mpint(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) @@ -1280,99 +1396,38 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM || !enif_is_empty_list(env, tail)) { ret = enif_make_badarg(env); + goto done; } - else { - if (type == atom_sha) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, rsa); - } - else if (type == atom_sha256) { - #ifdef HAVE_SHA256 - SHA256(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha256, hmacbuf, SHA256_LEN, - sign_bin.data+4, sign_bin.size-4, rsa); - #else - ret = atom_notsup; - goto done; - #endif - } - else if (type == atom_sha384) { - #ifdef HAVE_SHA384 - SHA384(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha384, hmacbuf, SHA384_LEN, - sign_bin.data+4, sign_bin.size-4, rsa); - #else - ret = atom_notsup; - goto done; - #endif - } - else if (type == atom_sha512) { - #ifdef HAVE_SHA512 - SHA512(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_sha512, hmacbuf, SHA512_LEN, - sign_bin.data+4, sign_bin.size-4, rsa); - #else - ret = atom_notsup; - goto done; - #endif - } - else if (type == atom_md5) { - MD5(data_bin.data+4, data_bin.size-4, hmacbuf); - i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, rsa); - } - else { + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != digp->len) { + ret = enif_make_badarg(env); goto done; } - ret = (i==1 ? atom_true : atom_false); - } -done: - RSA_free(rsa); - return ret; -} - -static ERL_NIF_TERM rsa_verify_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data, Signature, Key=[E,N]) */ - ErlNifBinary data_bin, sign_bin; - ERL_NIF_TERM head, tail, ret; - int i, type; - RSA* rsa = RSA_new(); - - if (!enif_inspect_binary(env,argv[1],&data_bin)) { - ret = enif_make_badarg(env); - goto done; + digest = data_bin.data; + } + else if (inspect_mpint(env, argv[1], &data_bin)) { + digest = hmacbuf; + digp->funcp(data_bin.data+4, data_bin.size-4, digest); } - - if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; - else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; - else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; - else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; else { ret = enif_make_badarg(env); goto done; } - if (!inspect_mpint(env, argv[2], &sign_bin) - || !enif_get_list_cell(env, argv[3], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) - || !enif_is_empty_list(env, tail)) { + i = RSA_verify(digp->NID_type, digest, digp->len, + sign_bin.data+4, sign_bin.size-4, rsa); + + ret = (i==1 ? atom_true : atom_false); - ret = enif_make_badarg(env); - } - else { - i = RSA_verify(type, data_bin.data, data_bin.size, - sign_bin.data+4, sign_bin.size-4, rsa); - ret = (i==1 ? atom_true : atom_false); - } done: RSA_free(rsa); return ret; } + static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, IVec, Data, IsEncrypt) */ ErlNifBinary key_bin, ivec_bin, data_bin; @@ -1531,86 +1586,59 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) } static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Data,Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ +{/* (Type, Data|{digest,Digest}, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ ErlNifBinary data_bin, ret_bin; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned rsa_s_len; - RSA *rsa = RSA_new(); - int i, is_sha; - - if (argv[0] == atom_sha) is_sha = 1; - else if (argv[0] == atom_md5) is_sha = 0; - else goto badarg; + RSA* rsa; + int i; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t *digp; + unsigned char* digest; - if (!inspect_mpint(env,argv[1],&data_bin) - || !get_rsa_private_key(env, argv[2], rsa)) { - badarg: - RSA_free(rsa); + digp = get_digest_type(argv[0]); + if (!digp) { return enif_make_badarg(env); } - enif_alloc_binary(RSA_size(rsa), &ret_bin); - if (is_sha) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH); - i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - ret_bin.data, &rsa_s_len, rsa); - } - else { - MD5(data_bin.data+4, data_bin.size-4, hmacbuf); - ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH); - i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH, - ret_bin.data, &rsa_s_len, rsa); + if (!digp->len) { + return atom_notsup; } - RSA_free(rsa); - if (i) { - ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); - if (rsa_s_len != data_bin.size) { - enif_realloc_binary(&ret_bin, rsa_s_len); - ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len); + + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != digp->len) { + + return enif_make_badarg(env); } - return enif_make_binary(env,&ret_bin); + digest = data_bin.data; } else { - enif_release_binary(&ret_bin); - return atom_error; + if (!inspect_mpint(env,argv[1],&data_bin)) { + return enif_make_badarg(env); + } + digest = hmacbuf; + digp->funcp(data_bin.data+4, data_bin.size-4, digest); } -} -static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Data,Key=[E,N,D]) */ - ErlNifBinary data_bin, ret_bin; - ERL_NIF_TERM head, tail; - unsigned rsa_s_len; - RSA *rsa = RSA_new(); - int i, type; - - if (!enif_inspect_binary(env,argv[1],&data_bin)) - goto badarg; - - if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; - else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; - else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; - else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; - else goto badarg; - - if (!enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->d) - || !enif_is_empty_list(env,tail)) { - badarg: + rsa = RSA_new(); + if (!get_rsa_private_key(env, argv[2], rsa)) { RSA_free(rsa); return enif_make_badarg(env); } + + enif_alloc_binary(RSA_size(rsa), &ret_bin); - i = RSA_sign(type, data_bin.data, data_bin.size, + + ERL_VALGRIND_ASSERT_MEM_DEFINED(digest, digp->len); + i = RSA_sign(digp->NID_type, digest, digp->len, ret_bin.data, &rsa_s_len, rsa); + RSA_free(rsa); if (i) { ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len); - if (rsa_s_len != data_bin.size) { + if (rsa_s_len != ret_bin.size) { enif_realloc_binary(&ret_bin, rsa_s_len); ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len); } @@ -1622,71 +1650,48 @@ static ERL_NIF_TERM rsa_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE } } + static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ +{/* (DigesType|none, Data|{digest,Digest}, Key=[P,Q,G,PrivKey]) */ ErlNifBinary data_bin, ret_bin; ERL_NIF_TERM head, tail; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; unsigned int dsa_s_len; - DSA* dsa = DSA_new(); + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + unsigned char* digest = NULL; + DSA* dsa; int i; - dsa->pub_key = NULL; - if (!enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->q) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->g) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->priv_key) - || !enif_is_empty_list(env,tail)) { - goto badarg; - } - if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) { - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + if (argv[0] == atom_sha) { + if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { + if (tpl_arity != 2 || tpl_terms[0] != atom_digest + || !enif_inspect_binary(env, tpl_terms[1], &data_bin) + || data_bin.size != SHA_DIGEST_LENGTH) { + + return enif_make_badarg(env); + } + digest = data_bin.data; + } + else { + if (!inspect_mpint(env,argv[1],&data_bin)) { + return enif_make_badarg(env); + } + SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + digest = hmacbuf; + } } - else if (argv[0] == atom_none && enif_inspect_binary(env,argv[1],&data_bin) + else if (argv[0] == atom_none + && enif_inspect_binary(env,argv[1],&data_bin) && data_bin.size == SHA_DIGEST_LENGTH) { - memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH); - } - else { - badarg: - DSA_free(dsa); - return enif_make_badarg(env); - } - enif_alloc_binary(DSA_size(dsa), &ret_bin); - i = DSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH, - ret_bin.data, &dsa_s_len, dsa); - DSA_free(dsa); - if (i) { - if (dsa_s_len != ret_bin.size) { - enif_realloc_binary(&ret_bin, dsa_s_len); - } - return enif_make_binary(env, &ret_bin); + digest = data_bin.data; } else { - return atom_error; + return enif_make_badarg(env); } -} -static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */ - ErlNifBinary data_bin, ret_bin; - ERL_NIF_TERM head, tail; - unsigned int dsa_s_len; - DSA* dsa = DSA_new(); - int i, type; - - if (!enif_inspect_binary(env,argv[1],&data_bin)) - goto badarg; - - if (argv[0] == atom_sha && data_bin.size == SHA_DIGEST_LENGTH) type = NID_sha1; - else if (argv[0] == atom_sha256 && data_bin.size == SHA256_DIGEST_LENGTH) type = NID_sha256; - else if (argv[0] == atom_sha512 && data_bin.size == SHA512_DIGEST_LENGTH) type = NID_sha512; - else if (argv[0] == atom_md5 && data_bin.size == MD5_DIGEST_LENGTH) type = NID_md5; - else goto badarg; + dsa = DSA_new(); dsa->pub_key = NULL; if (!enif_get_list_cell(env, argv[2], &head, &tail) @@ -1698,13 +1703,12 @@ static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_mpint(env, head, &dsa->priv_key) || !enif_is_empty_list(env,tail)) { - badarg: - DSA_free(dsa); - return enif_make_badarg(env); + DSA_free(dsa); + return enif_make_badarg(env); } enif_alloc_binary(DSA_size(dsa), &ret_bin); - i = DSA_sign(type, data_bin.data, data_bin.size, + i = DSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, ret_bin.data, &dsa_s_len, dsa); DSA_free(dsa); if (i) { @@ -1718,6 +1722,7 @@ static ERL_NIF_TERM dss_sign_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE } } + static int rsa_pad(ERL_NIF_TERM term, int* padding) { if (term == atom_rsa_pkcs1_padding) { diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 19db6c9dd4..36f8bc6deb 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -865,11 +865,13 @@ Mpint() = >]]> - rsa_sign(Data, Key) -> Signature - rsa_sign(DigestType, Data, Key) -> Signature + rsa_sign(DataOrDigest, Key) -> Signature + rsa_sign(DigestType, DataOrDigest, Key) -> Signature Sign the data using rsa with the given key. + DataOrDigest = Data | {digest,Digest} Data = Mpint + Digest = binary() Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] E, N, D = Mpint Where E is the public exponent, N is public modulus and @@ -879,37 +881,40 @@ Mpint() = >]]> the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C is the CRT coefficient. Terminology is taken from RFC 3447. - DigestType = md5 | sha + DigestType = md5 | sha | sha256 | sha384 | sha512 The default DigestType is sha. Mpint = binary() Signature = binary() -

Calculates a DigestType digest of the Data - and creates a RSA signature with the private key Key - of the digest.

+

Creates a RSA signature with the private key Key + of a digest. The digest is either calculated as a + DigestType digest of Data or a precalculated + binary Digest.

- rsa_verify(Data, Signature, Key) -> Verified - rsa_verify(DigestType, Data, Signature, Key) -> Verified + rsa_verify(DataOrDigest, Signature, Key) -> Verified + rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified Verify the digest and signature using rsa with given public key. Verified = boolean() + DataOrDigest = Data | {digest|Digest} Data, Signature = Mpint + Digest = binary() Key = [E, N] E, N = Mpint Where E is the public exponent and N is public modulus. DigestType = md5 | sha | sha256 | sha384 | sha512 - The default DigestType is sha. + The default DigestType is sha. Mpint = binary() -

Calculates a DigestType digest of the Data - and verifies that the digest matches the RSA signature using the +

Verifies that a digest matches the RSA signature using the signer's public key Key. -

+ The digest is either calculated as a DigestType + digest of Data or a precalculated binary Digest.

May throw exception notsup in case the chosen DigestType is not supported by the underlying OpenSSL implementation.

@@ -1022,45 +1027,52 @@ Mpint() = >]]>
- dss_sign(Data, Key) -> Signature - dss_sign(DigestType, Data, Key) -> Signature + dss_sign(DataOrDigest, Key) -> Signature + dss_sign(DigestType, DataOrDigest, Key) -> Signature Sign the data using dsa with given private key. - DigestType = sha | none (default is sha) - Data = Mpint | ShaDigest + DigestType = sha + DataOrDigest = Mpint | {digest,Digest} Key = [P, Q, G, X] P, Q, G, X = Mpint Where P, Q and G are the dss parameters and X is the private key. - ShaDigest = binary() with length 20 bytes + Digest = binary() with length 20 bytes Signature = binary() -

Creates a DSS signature with the private key Key of a digest. - If DigestType is 'sha', the digest is calculated as SHA1 of Data. - If DigestType is 'none', Data is the precalculated SHA1 digest.

+

Creates a DSS signature with the private key Key of + a digest. The digest is either calculated as a SHA1 + digest of Data or a precalculated binary Digest.

+

A deprecated feature is having DigestType = 'none' + in which case DataOrDigest is a precalculated SHA1 + digest.

- dss_verify(Data, Signature, Key) -> Verified - dss_verify(DigestType, Data, Signature, Key) -> Verified + dss_verify(DataOrDigest, Signature, Key) -> Verified + dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified Verify the data and signature using dsa with given public key. Verified = boolean() - DigestType = sha | none + DigestType = sha + DataOrDigest = Mpint | {digest,Digest} Data = Mpint | ShaDigest Signature = Mpint Key = [P, Q, G, Y] P, Q, G, Y = Mpint Where P, Q and G are the dss parameters and Y is the public key. - ShaDigest = binary() with length 20 bytes + Digest = binary() with length 20 bytes -

Verifies that a digest matches the DSS signature using the public key Key. - If DigestType is 'sha', the digest is calculated as SHA1 of Data. - If DigestType is 'none', Data is the precalculated SHA1 digest.

+

Verifies that a digest matches the DSS signature using the + public key Key. The digest is either calculated as a SHA1 + digest of Data or is a precalculated binary Digest.

+

A deprecated feature is having DigestType = 'none' + in which case DataOrDigest is a precalculated SHA1 + digest binary.

diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index f4f4e20b4d..69ab51d11e 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -43,8 +43,8 @@ -export([exor/2]). -export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). -export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4, rsa_verify_hash/4]). --export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3, dss_sign_hash/3, rsa_sign_hash/3]). +-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). +-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). -export([rsa_public_encrypt/3, rsa_private_decrypt/3]). -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). @@ -80,8 +80,8 @@ strong_rand_mpint, rand_uniform, mod_exp, - dss_verify,dss_sign,dss_sign_hash, - rsa_verify,rsa_verify_hash,rsa_sign,rsa_sign_hash, + dss_verify,dss_sign, + rsa_verify,rsa_sign, rsa_public_encrypt,rsa_private_decrypt, rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, @@ -97,6 +97,7 @@ -type rsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. +-type data_or_digest() :: binary() | {digest, binary()}. -type crypto_integer() :: binary() | integer(). -define(nif_stub,nif_stub_error(?LINE)). @@ -576,12 +577,10 @@ mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub. %% %% DSS, RSA - verify %% --spec dss_verify(binary(), binary(), [binary()]) -> boolean(). --spec dss_verify(dss_digest_type(), binary(), binary(), [binary()]) -> boolean(). --spec rsa_verify(binary(), binary(), [binary()]) -> boolean(). --spec rsa_verify(rsa_digest_type(), binary(), binary(), [binary()]) -> - boolean(). --spec rsa_verify_hash(rsa_digest_type(), binary(), binary(), [binary()]) -> +-spec dss_verify(data_or_digest(), binary(), [binary()]) -> boolean(). +-spec dss_verify(dss_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean(). +-spec rsa_verify(data_or_digest(), binary(), [binary()]) -> boolean(). +-spec rsa_verify(rsa_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean(). %% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey @@ -592,64 +591,44 @@ dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub. % Key = [E,N] E=PublicExponent N=PublicModulus rsa_verify(Data,Signature,Key) -> rsa_verify_nif(sha, Data,Signature,Key). -rsa_verify(Type, Data, Signature, Key) -> - case rsa_verify_nif(Type, Data, Signature, Key) of +rsa_verify(Type, DataOrDigest, Signature, Key) -> + case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of notsup -> erlang:error(notsup); Bool -> Bool end. -rsa_verify_hash(Type, Hash, Signature, Key) -> - case rsa_verify_hash_nif(Type, Hash, Signature, Key) of - notsup -> erlang:error(notsup); - Bool -> Bool - end. rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. -rsa_verify_hash_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. %% %% DSS, RSA - sign %% %% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey --spec dss_sign(binary(), [binary()]) -> binary(). --spec dss_sign(dss_digest_type(), binary(), [binary()]) -> binary(). --spec dss_sign_hash(dss_digest_type(), binary(), [binary()]) -> binary(). --spec rsa_sign(binary(), [binary()]) -> binary(). --spec rsa_sign(rsa_digest_type(), binary(), [binary()]) -> binary(). --spec rsa_sign_hash(rsa_digest_type(), binary(), [binary()]) -> binary(). - -dss_sign(Data,Key) -> - dss_sign(sha,Data,Key). -dss_sign(Type, Data, Key) -> - case dss_sign_nif(Type,Data,Key) of - error -> erlang:error(badkey, [Data, Key]); - Sign -> Sign - end. -dss_sign_hash(Type, Hash, Key) -> - case dss_sign_hash_nif(Type,Hash,Key) of - error -> erlang:error(badkey, [Hash, Key]); +-spec dss_sign(data_or_digest(), [binary()]) -> binary(). +-spec dss_sign(dss_digest_type(), data_or_digest(), [binary()]) -> binary(). +-spec rsa_sign(data_or_digest(), [binary()]) -> binary(). +-spec rsa_sign(rsa_digest_type(), data_or_digest(), [binary()]) -> binary(). + +dss_sign(DataOrDigest,Key) -> + dss_sign(sha,DataOrDigest,Key). +dss_sign(Type, DataOrDigest, Key) -> + case dss_sign_nif(Type,DataOrDigest,Key) of + error -> erlang:error(badkey, [DataOrDigest, Key]); Sign -> Sign end. dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -dss_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent -rsa_sign(Data,Key) -> - rsa_sign(sha, Data, Key). -rsa_sign(Type, Data, Key) -> - case rsa_sign_nif(Type,Data,Key) of - error -> erlang:error(badkey, [Type,Data,Key]); - Sign -> Sign - end. -rsa_sign_hash(Type, Hash, Key) -> - case rsa_sign_hash_nif(Type,Hash,Key) of - error -> erlang:error(badkey, [Type,Hash,Key]); +rsa_sign(DataOrDigest,Key) -> + rsa_sign(sha, DataOrDigest, Key). +rsa_sign(Type, DataOrDigest, Key) -> + case rsa_sign_nif(Type,DataOrDigest,Key) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); Sign -> Sign end. rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -rsa_sign_hash_nif(_Type,_Data,_Key) -> ?nif_stub. %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index a399511de0..6cc00d85ad 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1225,15 +1225,15 @@ rsa_sign_hash_test(Config) when is_list(Config) -> PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], MD5 = crypto:md5(sized_binary(Msg)), SHA = crypto:sha(sized_binary(Msg)), - ?line Sig1 = crypto:rsa_sign_hash(sha, SHA, PrivKey), - ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig1),PubKey), true), + ?line Sig1 = crypto:rsa_sign(sha, {digest,SHA}, PrivKey), + ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig1),PubKey), true), - ?line Sig2 = crypto:rsa_sign_hash(md5, MD5, PrivKey), - ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig2),PubKey), true), + ?line Sig2 = crypto:rsa_sign(md5, {digest,MD5}, PrivKey), + ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig2),PubKey), true), ?line m(Sig1 =:= Sig2, false), - ?line m(crypto:rsa_verify_hash(md5, MD5, sized_binary(Sig1),PubKey), false), - ?line m(crypto:rsa_verify_hash(sha, SHA, sized_binary(Sig2),PubKey), false), + ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig1),PubKey), false), + ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig2),PubKey), false), ok. @@ -1283,7 +1283,7 @@ dsa_sign_hash_test(Config) when is_list(Config) -> ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669, Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)], - ?line Sig1 = crypto:dss_sign_hash(sha, SHA, Params ++ [crypto:mpint(PrivKey)]), + ?line Sig1 = crypto:dss_sign(sha, {digest,SHA}, Params ++ [crypto:mpint(PrivKey)]), ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1), Params ++ [crypto:mpint(PubKey)]), true), -- cgit v1.2.3 From 208f9ad3828313f6c659a501d53f5534ec1bdf2e Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 15 Jun 2012 17:34:28 +0200 Subject: crypto: Add SHA256 and SHA512 based MACs --- lib/crypto/c_src/crypto.c | 144 ++++++++++++++++++++++++++++++++++++++- lib/crypto/src/crypto.erl | 63 ++++++++++++++++- lib/crypto/test/crypto_SUITE.erl | 49 +++++++++++-- 3 files changed, 249 insertions(+), 7 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 25616410be..a1f2614f69 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2011. All Rights Reserved. + * Copyright Ericsson AB 2010-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -149,6 +149,8 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -208,6 +210,16 @@ static void hmac_md5(unsigned char *key, int klen, static void hmac_sha1(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); +#ifdef HAVE_SHA256 +static void hmac_sha256(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif +#ifdef HAVE_SHA512 +static void hmac_sha512(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif static int library_refc = 0; /* number of users of this dynamic library */ @@ -235,6 +247,8 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, + {"sha256_mac_n_nif", 3, sha256_mac_n_nif}, + {"sha512_mac_n_nif", 3, sha512_mac_n_nif}, {"hmac_init", 2, hmac_init}, {"hmac_update", 2, hmac_update}, {"hmac_final", 1, hmac_final}, @@ -292,6 +306,7 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) #define SHA384_LEN (384/8) #define SHA512_LEN (512/8) #define HMAC_INT_LEN 64 +#define HMAC_INT2_LEN 128 #define HMAC_IPAD 0x36 #define HMAC_OPAD 0x5c @@ -765,6 +780,50 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA256 + unsigned char hmacbuf[SHA256_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA256_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + +static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA512 + unsigned char hmacbuf[SHA512_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA512_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type, Key) */ ErlNifBinary key; @@ -773,6 +832,8 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ const EVP_MD *md; if (argv[0] == atom_sha) md = EVP_sha1(); + else if (argv[0] == atom_sha256) md = EVP_sha256(); + else if (argv[0] == atom_sha512) md = EVP_sha512(); else if (argv[0] == atom_md5) md = EVP_md5(); else if (argv[0] == atom_ripemd160) md = EVP_ripemd160(); else goto badarg; @@ -2184,3 +2245,84 @@ static void hmac_sha1(unsigned char *key, int klen, SHA1_Final((unsigned char *) hmacbuf, &ctx); } +#ifdef HAVE_SHA256 +static void hmac_sha256(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA256_CTX ctx; + char ipad[HMAC_INT_LEN]; + char opad[HMAC_INT_LEN]; + unsigned char nkey[SHA256_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT_LEN) { + SHA256(key, klen, nkey); + key = nkey; + klen = SHA256_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA256_Init(&ctx); + SHA256_Update(&ctx, ipad, HMAC_INT_LEN); + SHA256_Update(&ctx, dbuf, dlen); + SHA256_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA256_Init(&ctx); + SHA256_Update(&ctx, opad, HMAC_INT_LEN); + SHA256_Update(&ctx, hmacbuf, SHA256_DIGEST_LENGTH); + SHA256_Final((unsigned char *) hmacbuf, &ctx); +} +#endif + +#ifdef HAVE_SHA512 +static void hmac_sha512(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA512_CTX ctx; + char ipad[HMAC_INT2_LEN]; + char opad[HMAC_INT2_LEN]; + unsigned char nkey[SHA512_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT2_LEN) { + SHA512(key, klen, nkey); + key = nkey; + klen = SHA512_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT2_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA512_Init(&ctx); + SHA512_Update(&ctx, ipad, HMAC_INT2_LEN); + SHA512_Update(&ctx, dbuf, dlen); + SHA512_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA512_Init(&ctx); + SHA512_Update(&ctx, opad, HMAC_INT2_LEN); + SHA512_Update(&ctx, hmacbuf, SHA512_DIGEST_LENGTH); + SHA512_Final((unsigned char *) hmacbuf, &ctx); +} +#endif diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 69ab51d11e..0f14092f87 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,12 +22,14 @@ -module(crypto). -export([start/0, stop/0, info/0, info_lib/0, version/0]). +-export([hash/2]). -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). +-export([sha256_mac/2, sha256_mac_96/2, sha512_mac/2, sha512_mac/3, sha512_mac_96/2]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). @@ -68,6 +70,8 @@ sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, + sha256_mac, sha256_mac_96, + sha512_mac, sha512_mac_96, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -172,7 +176,7 @@ info_lib() -> ?nif_stub. %% (no version): Driver implementation %% 2.0 : NIF implementation, requires OTP R14 version() -> ?CRYPTO_VSN. - + %% Below Key and Data are binaries or IO-lists. IVec is a binary. %% Output is always a binary. Context is a binary. @@ -180,6 +184,15 @@ version() -> ?CRYPTO_VSN. %% MESSAGE DIGESTS %% +-spec hash(_, iodata()) -> binary(). +hash(md5, Data) -> md5(Data); +hash(md4, Data) -> md4(Data); +hash(sha, Data) -> sha(Data); +hash(sha1, Data) -> sha(Data); +hash(sha256, Data) -> sha256(Data); +hash(sha512, Data) -> sha512(Data). + + %% %% MD5 %% @@ -336,6 +349,52 @@ sha_mac_96(Key, Data) -> sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. +%% +%% SHA256_MAC +%% +-spec sha256_mac(iodata(), iodata()) -> binary(). +-spec sha256_mac_96(iodata(), iodata()) -> binary(). + +sha256_mac(Key, Data) -> + sha256_mac_n(Key,Data,32). + +sha256_mac(Key, Data, Size) -> + sha256_mac_n(Key, Data, Size). + +sha256_mac_96(Key, Data) -> + sha256_mac_n(Key,Data,12). + +sha256_mac_n(Key, Data, MacSz) -> + case sha256_mac_n_nif(Key, Data, MacSz) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha256_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. + +%% +%% SHA512_MAC +%% +-spec sha512_mac(iodata(), iodata()) -> binary(). +-spec sha512_mac_96(iodata(), iodata()) -> binary(). + +sha512_mac(Key, Data) -> + sha512_mac_n(Key,Data,64). + +sha512_mac(Key, Data, Size) -> + sha512_mac_n(Key, Data, Size). + +sha512_mac_96(Key, Data) -> + sha512_mac_n(Key,Data,12). + +sha512_mac_n(Key, Data, MacSz) -> + case sha512_mac_n_nif(Key, Data, MacSz) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha512_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. + %% %% CRYPTO FUNCTIONS %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 6cc00d85ad..01cdf9f001 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -33,6 +33,8 @@ sha_update/1, hmac_update_sha/1, hmac_update_sha_n/1, + hmac_update_sha256/1, + hmac_update_sha512/1, hmac_update_md5/1, hmac_update_md5_io/1, hmac_update_md5_n/1, @@ -84,8 +86,8 @@ groups() -> {rest, [], [md5, md5_update, md4, md4_update, md5_mac, md5_mac_io, sha, sha_update, - hmac_update_sha, hmac_update_sha_n, hmac_update_md5_n, - hmac_update_md5_io, hmac_update_md5, + hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512, + hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, des_cbc, aes_cfb, aes_cbc, aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, @@ -338,6 +340,44 @@ hmac_update_sha(Config) when is_list(Config) -> ?line Mac = crypto:hmac_final(Ctx3), ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). + +hmac_update_sha256(doc) -> + ["Generate an SHA256 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:sha256_mac." ]; +hmac_update_sha256(suite) -> + []; +hmac_update_sha256(Config) when is_list(Config) -> + ?line Key = hexstr2bin("00010203101112132021222330313233" + "04050607141516172425262734353637" + "08090a0b18191a1b28292a2b38393a3b" + "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"), + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(sha256, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final(Ctx3), + ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). + +hmac_update_sha512(doc) -> + ["Generate an SHA512 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:sha512_mac." ]; +hmac_update_sha512(suite) -> + []; +hmac_update_sha512(Config) when is_list(Config) -> + ?line Key = hexstr2bin("00010203101112132021222330313233" + "04050607141516172425262734353637" + "08090a0b18191a1b28292a2b38393a3b" + "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"), + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(sha512, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final(Ctx3), + ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). hmac_update_md5(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -1482,7 +1522,8 @@ worker_loop(N, Config) -> Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc, aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test, - hmac_update_md5, hmac_update_sha, aes_ctr_stream }, + hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512, + aes_ctr_stream }, F = element(random:uniform(size(Funcs)),Funcs), %%io:format("worker ~p calling ~p\n",[self(),F]), -- cgit v1.2.3 From 807fc6ec56e3e7a65d9de5884cf6ac9927e5c1aa Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 20:53:34 +0200 Subject: crypto: Cleanup code for sha256 and sha512 --- lib/crypto/c_src/crypto.c | 16 ++++++++++------ lib/crypto/src/crypto.erl | 35 +++++++++++++---------------------- 2 files changed, 23 insertions(+), 28 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index a1f2614f69..3b412e3c1b 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -149,8 +149,8 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -247,8 +247,8 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, - {"sha256_mac_n_nif", 3, sha256_mac_n_nif}, - {"sha512_mac_n_nif", 3, sha512_mac_n_nif}, + {"sha256_mac_nif", 3, sha256_mac_nif}, + {"sha512_mac_nif", 3, sha512_mac_nif}, {"hmac_init", 2, hmac_init}, {"hmac_update", 2, hmac_update}, {"hmac_final", 1, hmac_final}, @@ -780,7 +780,7 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } -static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA256 unsigned char hmacbuf[SHA256_DIGEST_LENGTH]; @@ -802,7 +802,7 @@ static ERL_NIF_TERM sha256_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER #endif } -static ERL_NIF_TERM sha512_mac_n_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA512 unsigned char hmacbuf[SHA512_DIGEST_LENGTH]; @@ -832,8 +832,12 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ const EVP_MD *md; if (argv[0] == atom_sha) md = EVP_sha1(); +#ifdef HAVE_SHA256 else if (argv[0] == atom_sha256) md = EVP_sha256(); +#endif +#ifdef HAVE_SHA512 else if (argv[0] == atom_sha512) md = EVP_sha512(); +#endif else if (argv[0] == atom_md5) md = EVP_md5(); else if (argv[0] == atom_ripemd160) md = EVP_ripemd160(); else goto badarg; diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 0f14092f87..cb1173f6be 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -29,7 +29,8 @@ -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). --export([sha256_mac/2, sha256_mac_96/2, sha512_mac/2, sha512_mac/3, sha512_mac_96/2]). +-export([sha256_mac/2, sha256_mac/3]). +-export([sha512_mac/2, sha512_mac/3]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). @@ -70,8 +71,7 @@ sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha256_mac, sha256_mac_96, - sha512_mac, sha512_mac_96, + sha256_mac, sha512_mac, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -353,47 +353,38 @@ sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. %% SHA256_MAC %% -spec sha256_mac(iodata(), iodata()) -> binary(). --spec sha256_mac_96(iodata(), iodata()) -> binary(). sha256_mac(Key, Data) -> - sha256_mac_n(Key,Data,32). + sha256_mac(Key, Data, 256 div 8). sha256_mac(Key, Data, Size) -> - sha256_mac_n(Key, Data, Size). + case sha256_mac_nif(Key, Data, Size) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. -sha256_mac_96(Key, Data) -> - sha256_mac_n(Key,Data,12). +sha256_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. -sha256_mac_n(Key, Data, MacSz) -> - case sha256_mac_n_nif(Key, Data, MacSz) of notsup -> erlang:error(notsup); Bin -> Bin end. -sha256_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% %% SHA512_MAC %% -spec sha512_mac(iodata(), iodata()) -> binary(). --spec sha512_mac_96(iodata(), iodata()) -> binary(). sha512_mac(Key, Data) -> - sha512_mac_n(Key,Data,64). - -sha512_mac(Key, Data, Size) -> - sha512_mac_n(Key, Data, Size). - -sha512_mac_96(Key, Data) -> - sha512_mac_n(Key,Data,12). + sha512_mac(Key, Data, 512 div 8). -sha512_mac_n(Key, Data, MacSz) -> - case sha512_mac_n_nif(Key, Data, MacSz) of +sha512_mac(Key, Data, MacSz) -> + case sha512_mac_nif(Key, Data, MacSz) of notsup -> erlang:error(notsup); Bin -> Bin end. -sha512_mac_n_nif(_Key,_Data,_MacSz) -> ?nif_stub. +sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% %% CRYPTO FUNCTIONS -- cgit v1.2.3 From 7553817a73f8409a789496964a5292627002e785 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 27 Jun 2012 20:55:04 +0200 Subject: crypto: Add sha384 --- lib/crypto/c_src/crypto.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 51 ++++++++++++++++- 2 files changed, 193 insertions(+), 1 deletion(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 3b412e3c1b..2ae34c9741 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -139,6 +139,10 @@ static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -150,6 +154,7 @@ static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -215,6 +220,11 @@ static void hmac_sha256(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); #endif +#ifdef HAVE_SHA384 +static void hmac_sha384(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif #ifdef HAVE_SHA512 static void hmac_sha512(unsigned char *key, int klen, unsigned char *dbuf, int dlen, @@ -237,6 +247,10 @@ static ErlNifFunc nif_funcs[] = { {"sha256_init_nif", 0, sha256_init_nif}, {"sha256_update_nif", 2, sha256_update_nif}, {"sha256_final_nif", 1, sha256_final_nif}, + {"sha384_nif", 1, sha384_nif}, + {"sha384_init_nif", 0, sha384_init_nif}, + {"sha384_update_nif", 2, sha384_update_nif}, + {"sha384_final_nif", 1, sha384_final_nif}, {"sha512_nif", 1, sha512_nif}, {"sha512_init_nif", 0, sha512_init_nif}, {"sha512_update_nif", 2, sha512_update_nif}, @@ -248,6 +262,7 @@ static ErlNifFunc nif_funcs[] = { {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, {"sha256_mac_nif", 3, sha256_mac_nif}, + {"sha384_mac_nif", 3, sha384_mac_nif}, {"sha512_mac_nif", 3, sha512_mac_nif}, {"hmac_init", 2, hmac_init}, {"hmac_update", 2, hmac_update}, @@ -638,6 +653,67 @@ static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER #endif } +static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Data) */ +#ifdef HAVE_SHA384 + ErlNifBinary ibin; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { + return enif_make_badarg(env); + } + SHA384((unsigned char *) ibin.data, ibin.size, + enif_make_new_binary(env,SHA384_LEN, &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* () */ +#ifdef HAVE_SHA384 + ERL_NIF_TERM ret; + SHA384_Init((SHA512_CTX *) enif_make_new_binary(env, sizeof(SHA512_CTX), &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ +#ifdef HAVE_SHA384 + SHA512_CTX* new_ctx; + ErlNifBinary ctx_bin, data_bin; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX) + || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret); + memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX)); + SHA384_Update(new_ctx, data_bin.data, data_bin.size); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context) */ +#ifdef HAVE_SHA384 + ErlNifBinary ctx_bin; + SHA512_CTX ctx_clone; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) { + return enif_make_badarg(env); + } + memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA512_CTX)); /* writable */ + SHA384_Final(enif_make_new_binary(env, SHA384_LEN, &ret), &ctx_clone); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Data) */ #ifdef HAVE_SHA512 @@ -802,6 +878,29 @@ static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM #endif } +static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA384 + unsigned char hmacbuf[SHA384_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA384_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + + static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA512 @@ -835,6 +934,9 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ #ifdef HAVE_SHA256 else if (argv[0] == atom_sha256) md = EVP_sha256(); #endif +#ifdef HAVE_SHA384 + else if (argv[0] == atom_sha384) md = EVP_sha384(); +#endif #ifdef HAVE_SHA512 else if (argv[0] == atom_sha512) md = EVP_sha512(); #endif @@ -2290,6 +2392,47 @@ static void hmac_sha256(unsigned char *key, int klen, } #endif +#ifdef HAVE_SHA384 +static void hmac_sha384(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA512_CTX ctx; + char ipad[HMAC_INT_LEN]; + char opad[HMAC_INT_LEN]; + unsigned char nkey[SHA384_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT_LEN) { + SHA384(key, klen, nkey); + key = nkey; + klen = SHA384_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA384_Init(&ctx); + SHA384_Update(&ctx, ipad, HMAC_INT_LEN); + SHA384_Update(&ctx, dbuf, dlen); + SHA384_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA384_Init(&ctx); + SHA384_Update(&ctx, opad, HMAC_INT_LEN); + SHA384_Update(&ctx, hmacbuf, SHA384_DIGEST_LENGTH); + SHA384_Final((unsigned char *) hmacbuf, &ctx); +} +#endif + #ifdef HAVE_SHA512 static void hmac_sha512(unsigned char *key, int klen, unsigned char *dbuf, int dlen, diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index cb1173f6be..177ccfeef7 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -27,9 +27,11 @@ -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). +-export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). -export([sha256_mac/2, sha256_mac/3]). +-export([sha384_mac/2, sha384_mac/3]). -export([sha512_mac/2, sha512_mac/3]). -export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). @@ -68,10 +70,11 @@ md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, sha256, sha256_init, sha256_update, sha256_final, + sha384, sha384_init, sha384_update, sha384_final, sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha256_mac, sha512_mac, + sha256_mac, sha384_mac, sha512_mac, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -190,6 +193,7 @@ hash(md4, Data) -> md4(Data); hash(sha, Data) -> sha(Data); hash(sha1, Data) -> sha(Data); hash(sha256, Data) -> sha256(Data); +hash(sha384, Data) -> sha384(Data); hash(sha512, Data) -> sha512(Data). @@ -267,6 +271,40 @@ sha256_init_nif() -> ?nif_stub. sha256_update_nif(_Context, _Data) -> ?nif_stub. sha256_final_nif(_Context) -> ?nif_stub. +% +%% SHA384 +%% +-spec sha384(iodata()) -> binary(). +-spec sha384_init() -> binary(). +-spec sha384_update(binary(), iodata()) -> binary(). +-spec sha384_final(binary()) -> binary(). + +sha384(Data) -> + case sha384_nif(Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha384_init() -> + case sha384_init_nif() of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha384_update(Context, Data) -> + case sha384_update_nif(Context, Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha384_final(Context) -> + case sha384_final_nif(Context) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha384_nif(_Data) -> ?nif_stub. +sha384_init_nif() -> ?nif_stub. +sha384_update_nif(_Context, _Data) -> ?nif_stub. +sha384_final_nif(_Context) -> ?nif_stub. + % %% SHA512 %% @@ -365,10 +403,21 @@ sha256_mac(Key, Data, Size) -> sha256_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. +%% +%% SHA384_MAC +%% +-spec sha384_mac(iodata(), iodata()) -> binary(). + +sha384_mac(Key, Data) -> + sha384_mac(Key, Data, 384 div 8). + +sha384_mac(Key, Data, Size) -> + case sha384_mac_nif(Key, Data, Size) of notsup -> erlang:error(notsup); Bin -> Bin end. +sha384_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. %% %% SHA512_MAC -- cgit v1.2.3 From 29ecf2ad4b046b6b76b9cefb18fcc1d635a06037 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Thu, 19 Jul 2012 12:12:17 +0200 Subject: crypto: fix hmac_sha384 and add hmac test cases from RFC-4231 --- lib/crypto/c_src/crypto.c | 12 +-- lib/crypto/test/crypto_SUITE.erl | 214 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+), 6 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 2ae34c9741..c64ad2b82d 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -2398,13 +2398,13 @@ static void hmac_sha384(unsigned char *key, int klen, unsigned char *hmacbuf) { SHA512_CTX ctx; - char ipad[HMAC_INT_LEN]; - char opad[HMAC_INT_LEN]; + char ipad[HMAC_INT2_LEN]; + char opad[HMAC_INT2_LEN]; unsigned char nkey[SHA384_DIGEST_LENGTH]; int i; /* Change key if longer than 64 bytes */ - if (klen > HMAC_INT_LEN) { + if (klen > HMAC_INT2_LEN) { SHA384(key, klen, nkey); key = nkey; klen = SHA384_DIGEST_LENGTH; @@ -2415,19 +2415,19 @@ static void hmac_sha384(unsigned char *key, int klen, memcpy(ipad, key, klen); memcpy(opad, key, klen); - for (i = 0; i < HMAC_INT_LEN; i++) { + for (i = 0; i < HMAC_INT2_LEN; i++) { ipad[i] ^= HMAC_IPAD; opad[i] ^= HMAC_OPAD; } /* inner SHA */ SHA384_Init(&ctx); - SHA384_Update(&ctx, ipad, HMAC_INT_LEN); + SHA384_Update(&ctx, ipad, HMAC_INT2_LEN); SHA384_Update(&ctx, dbuf, dlen); SHA384_Final((unsigned char *) hmacbuf, &ctx); /* outer SHA */ SHA384_Init(&ctx); - SHA384_Update(&ctx, opad, HMAC_INT_LEN); + SHA384_Update(&ctx, opad, HMAC_INT2_LEN); SHA384_Update(&ctx, hmacbuf, SHA384_DIGEST_LENGTH); SHA384_Final((unsigned char *) hmacbuf, &ctx); } diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 01cdf9f001..a21b74d5ae 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -38,6 +38,7 @@ hmac_update_md5/1, hmac_update_md5_io/1, hmac_update_md5_n/1, + hmac_rfc4231/1, sha256/1, sha256_update/1, sha512/1, @@ -88,6 +89,7 @@ groups() -> md5_mac_io, sha, sha_update, hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512, hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, + hmac_rfc4231, des_cbc, aes_cfb, aes_cbc, aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, @@ -397,7 +399,218 @@ hmac_update_md5(Config) when is_list(Config) -> ?line Mac2 = crypto:hmac_final(CtxD), ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])), ?line m(Exp2, Mac2). + +hmac_rfc4231(doc) -> + ["Generate an HMAC using crypto:shaXXX_mac and hmac_init, hmac_update, and hmac_final. " + "Testvectors are take from RFC4231." ]; +hmac_rfc4231(suite) -> + []; +hmac_rfc4231(Config) when is_list(Config) -> + %% Test Case 1 + Case1Key = binary:copy(<<16#0b>>, 20), + Case1Data = <<"Hi There">>, + Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" + "881dc200c9833da726e9376c2e32cff7"), + Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f" + "15f9dadbe4101ec682aa034c7cebc59c" + "faea9ea9076ede7f4af152e8b2fa9cb6"), + Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0" + "2379f4e2ce4ec2787ad0b30545e17cde" + "daa833b7d6b8a702038b274eaea3f4e4" + "be9d914eeb61f1702e696c203a126854"), + + ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key), + ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data), + ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2), + ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data), + ?line m(Case1Exp256, Case1Mac256_1), + ?line m(Case1Exp256, Case1Mac256_2), + + ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key), + ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data), + ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2), + ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data), + ?line m(Case1Exp384, Case1Mac384_1), + ?line m(Case1Exp384, Case1Mac384_2), + + ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key), + ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data), + ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2), + ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data), + ?line m(Case1Exp512, Case1Mac512_1), + ?line m(Case1Exp512, Case1Mac512_2), + + %% Test Case 2 + Case2Key = <<"Jefe">>, + Case2Data = <<"what do ya want for nothing?">>, + Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843"), + Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b" + "9c7ef464f5a01b47e42ec3736322445e" + "8e2240ca5e69e2c78b3239ecfab21649"), + Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3" + "87bd64222e831fd610270cd7ea250554" + "9758bf75c05a994a6d034f65f8f0e6fd" + "caeab1a34d4a6b4b636e070a38bce737"), + + ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key), + ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data), + ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2), + ?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data), + ?line m(Case2Exp256, Case2Mac256_1), + ?line m(Case2Exp256, Case2Mac256_2), + + ?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key), + ?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data), + ?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2), + ?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data), + ?line m(Case2Exp384, Case2Mac384_1), + ?line m(Case2Exp384, Case2Mac384_2), + + ?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key), + ?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data), + ?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2), + ?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data), + ?line m(Case2Exp512, Case2Mac512_1), + ?line m(Case2Exp512, Case2Mac512_2), + + %% Test Case 3 + Case3Key = binary:copy(<<16#aa>>, 20), + Case3Data = binary:copy(<<16#dd>>, 50), + Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7" + "2959098b3ef8c122d9635514ced565fe"), + Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f" + "0aa635d947ac9febe83ef4e55966144b" + "2a5ab39dc13814b94e3ab6e101a34f27"), + Case3Exp512 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9" + "b1b5dbdd8ee81a3655f83e33b2279d39" + "bf3e848279a722c806b485a47e67c807" + "b946a337bee8942674278859e13292fb"), + + ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key), + ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data), + ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2), + ?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data), + ?line m(Case3Exp256, Case3Mac256_1), + ?line m(Case3Exp256, Case3Mac256_2), + + ?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key), + ?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data), + ?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2), + ?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data), + ?line m(Case3Exp384, Case3Mac384_1), + ?line m(Case3Exp384, Case3Mac384_2), + + ?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key), + ?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data), + ?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2), + ?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data), + ?line m(Case3Exp512, Case3Mac512_1), + ?line m(Case3Exp512, Case3Mac512_2), + + %% Test Case 4 + Case4Key = list_to_binary(lists:seq(1, 16#19)), + Case4Data = binary:copy(<<16#cd>>, 50), + Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a" + "85f0faa3e578f8077a2e3ff46729665b"), + Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7" + "7a9981480850009cc5577c6e1f573b4e" + "6801dd23c4a7d679ccf8a386c674cffb"), + Case4Exp512 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7" + "e576d97ff94b872de76f8050361ee3db" + "a91ca5c11aa25eb4d679275cc5788063" + "a5f19741120c4f2de2adebeb10a298dd"), + + ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key), + ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data), + ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2), + ?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data), + ?line m(Case4Exp256, Case4Mac256_1), + ?line m(Case4Exp256, Case4Mac256_2), + + ?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key), + ?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data), + ?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2), + ?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data), + ?line m(Case4Exp384, Case4Mac384_1), + ?line m(Case4Exp384, Case4Mac384_2), + + ?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key), + ?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data), + ?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2), + ?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data), + ?line m(Case4Exp512, Case4Mac512_1), + ?line m(Case4Exp512, Case4Mac512_2), + + %% Test Case 6 + Case6Key = binary:copy(<<16#aa>>, 131), + Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, + Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f" + "8e0bc6213728c5140546040f0ee37f54"), + Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4" + "4f9ef1012a2b588f3cd11f05033ac4c6" + "0c2ef6ab4030fe8296248df163f44952"), + Case6Exp512 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4" + "9b46d1f41b4aeec1121b013783f8f352" + "6b56d037e05f2598bd0fd2215d6a1e52" + "95e64f73f63f0aec8b915a985d786598"), + + ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key), + ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data), + ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2), + ?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data), + ?line m(Case6Exp256, Case6Mac256_1), + ?line m(Case6Exp256, Case6Mac256_2), + + ?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key), + ?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data), + ?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2), + ?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data), + ?line m(Case6Exp384, Case6Mac384_1), + ?line m(Case6Exp384, Case6Mac384_2), + + ?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key), + ?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data), + ?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2), + ?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data), + ?line m(Case6Exp512, Case6Mac512_1), + ?line m(Case6Exp512, Case6Mac512_2), + %% Test Case 7 + Case7Key = binary:copy(<<16#aa>>, 131), + Case7Data = <<"This is a test using a larger than block-size key and a larger t", + "han block-size data. The key needs to be hashed before being use", + "d by the HMAC algorithm.">>, + Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" + "bfdc63644f0713938a7f51535c3a35e2"), + Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" + "602420feb0b8fb9adccebb82461e99c5" + "a678cc31e799176d3860e6110c46523e"), + Case7Exp512 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd" + "debd71f8867289865df5a32d20cdc944" + "b6022cac3c4982b10d5eeb55c3e4de15" + "134676fb6de0446065c97440fa8c6a58"), + + ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key), + ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data), + ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2), + ?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data), + ?line m(Case7Exp256, Case7Mac256_1), + ?line m(Case7Exp256, Case7Mac256_2), + + ?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key), + ?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data), + ?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2), + ?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data), + ?line m(Case7Exp384, Case7Mac384_1), + ?line m(Case7Exp384, Case7Mac384_2), + + ?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key), + ?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data), + ?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2), + ?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data), + ?line m(Case7Exp512, Case7Mac512_1), + ?line m(Case7Exp512, Case7Mac512_2). hmac_update_md5_io(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -1523,6 +1736,7 @@ worker_loop(N, Config) -> aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test, hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512, + hmac_rfc4231, aes_ctr_stream }, F = element(random:uniform(size(Funcs)),Funcs), -- cgit v1.2.3 From d830b644d86f07dbebd9c12926c22867442e1726 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 17 Aug 2012 19:28:08 +0200 Subject: crypto: Add sha224 --- lib/crypto/c_src/crypto.c | 149 +++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 59 +++++++++++++++- lib/crypto/test/crypto_SUITE.erl | 54 ++++++++++++++ 3 files changed, 259 insertions(+), 3 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index c64ad2b82d..d9ae8a87a3 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -53,6 +53,10 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224)\ + && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */ +# define HAVE_SHA224 +#endif #if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256) # define HAVE_SHA256 #endif @@ -135,6 +139,10 @@ static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -153,6 +161,7 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -215,6 +224,11 @@ static void hmac_md5(unsigned char *key, int klen, static void hmac_sha1(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); +#ifdef HAVE_SHA224 +static void hmac_sha224(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf); +#endif #ifdef HAVE_SHA256 static void hmac_sha256(unsigned char *key, int klen, unsigned char *dbuf, int dlen, @@ -243,6 +257,10 @@ static ErlNifFunc nif_funcs[] = { {"sha_init", 0, sha_init}, {"sha_update", 2, sha_update}, {"sha_final", 1, sha_final}, + {"sha224_nif", 1, sha224_nif}, + {"sha224_init_nif", 0, sha224_init_nif}, + {"sha224_update_nif", 2, sha224_update_nif}, + {"sha224_final_nif", 1, sha224_final_nif}, {"sha256_nif", 1, sha256_nif}, {"sha256_init_nif", 0, sha256_init_nif}, {"sha256_update_nif", 2, sha256_update_nif}, @@ -261,6 +279,7 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, + {"sha224_mac_nif", 3, sha224_mac_nif}, {"sha256_mac_nif", 3, sha256_mac_nif}, {"sha384_mac_nif", 3, sha384_mac_nif}, {"sha512_mac_nif", 3, sha512_mac_nif}, @@ -317,6 +336,7 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) #define SHA_CTX_LEN (sizeof(SHA_CTX)) #define SHA_LEN 20 #define SHA_LEN_96 12 +#define SHA224_LEN (224/8) #define SHA256_LEN (256/8) #define SHA384_LEN (384/8) #define SHA512_LEN (512/8) @@ -331,6 +351,7 @@ static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */ static ERL_NIF_TERM atom_true; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_sha; +static ERL_NIF_TERM atom_sha224; static ERL_NIF_TERM atom_sha256; static ERL_NIF_TERM atom_sha384; static ERL_NIF_TERM atom_sha512; @@ -406,6 +427,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_true = enif_make_atom(env,"true"); atom_false = enif_make_atom(env,"false"); atom_sha = enif_make_atom(env,"sha"); + atom_sha224 = enif_make_atom(env,"sha224"); atom_sha256 = enif_make_atom(env,"sha256"); atom_sha384 = enif_make_atom(env,"sha384"); atom_sha512 = enif_make_atom(env,"sha512"); @@ -592,6 +614,67 @@ static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Data) */ +#ifdef HAVE_SHA224 + ErlNifBinary ibin; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { + return enif_make_badarg(env); + } + SHA224((unsigned char *) ibin.data, ibin.size, + enif_make_new_binary(env,SHA224_LEN, &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* () */ +#ifdef HAVE_SHA224 + ERL_NIF_TERM ret; + SHA224_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret)); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ +#ifdef HAVE_SHA224 + SHA256_CTX* new_ctx; + ErlNifBinary ctx_bin, data_bin; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX) + || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret); + memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX)); + SHA224_Update(new_ctx, data_bin.data, data_bin.size); + return ret; +#else + return atom_notsup; +#endif +} +static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context) */ +#ifdef HAVE_SHA224 + ErlNifBinary ctx_bin; + SHA256_CTX ctx_clone; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) { + return enif_make_badarg(env); + } + memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA256_CTX)); /* writable */ + SHA224_Final(enif_make_new_binary(env, SHA224_LEN, &ret), &ctx_clone); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Data) */ #ifdef HAVE_SHA256 @@ -856,6 +939,28 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, Data, MacSize) */ +#ifdef HAVE_SHA224 + unsigned char hmacbuf[SHA224_DIGEST_LENGTH]; + ErlNifBinary key, data; + unsigned mac_sz; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA224_DIGEST_LENGTH) { + return enif_make_badarg(env); + } + hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf); + memcpy(enif_make_new_binary(env, mac_sz, &ret), + hmacbuf, mac_sz); + return ret; +#else + return atom_notsup; +#endif +} + static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Data, MacSize) */ #ifdef HAVE_SHA256 @@ -931,6 +1036,9 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ const EVP_MD *md; if (argv[0] == atom_sha) md = EVP_sha1(); +#ifdef HAVE_SHA224 + else if (argv[0] == atom_sha224) md = EVP_sha224(); +#endif #ifdef HAVE_SHA256 else if (argv[0] == atom_sha256) md = EVP_sha256(); #endif @@ -2351,6 +2459,47 @@ static void hmac_sha1(unsigned char *key, int klen, SHA1_Final((unsigned char *) hmacbuf, &ctx); } +#ifdef HAVE_SHA224 +static void hmac_sha224(unsigned char *key, int klen, + unsigned char *dbuf, int dlen, + unsigned char *hmacbuf) +{ + SHA256_CTX ctx; + char ipad[HMAC_INT_LEN]; + char opad[HMAC_INT_LEN]; + unsigned char nkey[SHA224_DIGEST_LENGTH]; + int i; + + /* Change key if longer than 64 bytes */ + if (klen > HMAC_INT_LEN) { + SHA224(key, klen, nkey); + key = nkey; + klen = SHA224_DIGEST_LENGTH; + } + + memset(ipad, '\0', sizeof(ipad)); + memset(opad, '\0', sizeof(opad)); + memcpy(ipad, key, klen); + memcpy(opad, key, klen); + + for (i = 0; i < HMAC_INT_LEN; i++) { + ipad[i] ^= HMAC_IPAD; + opad[i] ^= HMAC_OPAD; + } + + /* inner SHA */ + SHA224_Init(&ctx); + SHA224_Update(&ctx, ipad, HMAC_INT_LEN); + SHA224_Update(&ctx, dbuf, dlen); + SHA224_Final((unsigned char *) hmacbuf, &ctx); + /* outer SHA */ + SHA224_Init(&ctx); + SHA224_Update(&ctx, opad, HMAC_INT_LEN); + SHA224_Update(&ctx, hmacbuf, SHA224_DIGEST_LENGTH); + SHA224_Final((unsigned char *) hmacbuf, &ctx); +} +#endif + #ifdef HAVE_SHA256 static void hmac_sha256(unsigned char *key, int klen, unsigned char *dbuf, int dlen, diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 177ccfeef7..a07e7a30b4 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -26,10 +26,12 @@ -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). +-export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]). -export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). -export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]). -export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). +-export([sha224_mac/2, sha224_mac/3]). -export([sha256_mac/2, sha256_mac/3]). -export([sha384_mac/2, sha384_mac/3]). -export([sha512_mac/2, sha512_mac/3]). @@ -69,12 +71,13 @@ -define(FUNC_LIST, [md4, md4_init, md4_update, md4_final, md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, - sha256, sha256_init, sha256_update, sha256_final, + sha224, sha224_init, sha224_update, sha224_final, + sha256, sha256_init, sha256_update, sha256_final, sha384, sha384_init, sha384_update, sha384_final, - sha512, sha512_init, sha512_update, sha512_final, + sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha256_mac, sha384_mac, sha512_mac, + sha224_mac, sha256_mac, sha384_mac, sha512_mac, sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, @@ -237,6 +240,40 @@ sha_init() -> ?nif_stub. sha_update(_Context, _Data) -> ?nif_stub. sha_final(_Context) -> ?nif_stub. +% +%% SHA224 +%% +-spec sha224(iodata()) -> binary(). +-spec sha224_init() -> binary(). +-spec sha224_update(binary(), iodata()) -> binary(). +-spec sha224_final(binary()) -> binary(). + +sha224(Data) -> + case sha224_nif(Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha224_init() -> + case sha224_init_nif() of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha224_update(Context, Data) -> + case sha224_update_nif(Context, Data) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. +sha224_final(Context) -> + case sha224_final_nif(Context) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha224_nif(_Data) -> ?nif_stub. +sha224_init_nif() -> ?nif_stub. +sha224_update_nif(_Context, _Data) -> ?nif_stub. +sha224_final_nif(_Context) -> ?nif_stub. + % %% SHA256 %% @@ -387,6 +424,22 @@ sha_mac_96(Key, Data) -> sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. +%% +%% SHA224_MAC +%% +-spec sha224_mac(iodata(), iodata()) -> binary(). + +sha224_mac(Key, Data) -> + sha224_mac(Key, Data, 224 div 8). + +sha224_mac(Key, Data, Size) -> + case sha224_mac_nif(Key, Data, Size) of + notsup -> erlang:error(notsup); + Bin -> Bin + end. + +sha224_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. + %% %% SHA256_MAC %% diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index a21b74d5ae..bcd80c5a0f 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -409,6 +409,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 1 Case1Key = binary:copy(<<16#0b>>, 20), Case1Data = <<"Hi There">>, + Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f" + "47b4b1169912ba4f53684b22"), Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" "881dc200c9833da726e9376c2e32cff7"), Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f" @@ -419,6 +421,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "daa833b7d6b8a702038b274eaea3f4e4" "be9d914eeb61f1702e696c203a126854"), + ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key), + ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data), + ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2), + ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data), + ?line m(Case1Exp224, Case1Mac224_1), + ?line m(Case1Exp224, Case1Mac224_2), + ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key), ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data), ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2), @@ -443,6 +452,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 2 Case2Key = <<"Jefe">>, Case2Data = <<"what do ya want for nothing?">>, + Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f" + "8bbea2a39e6148008fd05e44"), Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7" "5a003f089d2739839dec58b964ec3843"), Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b" @@ -453,6 +464,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "9758bf75c05a994a6d034f65f8f0e6fd" "caeab1a34d4a6b4b636e070a38bce737"), + ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key), + ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data), + ?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2), + ?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data), + ?line m(Case2Exp224, Case2Mac224_1), + ?line m(Case2Exp224, Case2Mac224_2), + ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key), ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data), ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2), @@ -477,6 +495,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 3 Case3Key = binary:copy(<<16#aa>>, 20), Case3Data = binary:copy(<<16#dd>>, 50), + Case3Exp224 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264" + "9365b0c1f65d69d1ec8333ea"), Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7" "2959098b3ef8c122d9635514ced565fe"), Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f" @@ -487,6 +507,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "bf3e848279a722c806b485a47e67c807" "b946a337bee8942674278859e13292fb"), + ?line Case3Ctx224 = crypto:hmac_init(sha224, Case3Key), + ?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data), + ?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2), + ?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data), + ?line m(Case3Exp224, Case3Mac224_1), + ?line m(Case3Exp224, Case3Mac224_2), + ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key), ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data), ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2), @@ -511,6 +538,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 4 Case4Key = list_to_binary(lists:seq(1, 16#19)), Case4Data = binary:copy(<<16#cd>>, 50), + Case4Exp224 = hexstr2bin("6c11506874013cac6a2abc1bb382627c" + "ec6a90d86efc012de7afec5a"), Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a" "85f0faa3e578f8077a2e3ff46729665b"), Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7" @@ -521,6 +550,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "a91ca5c11aa25eb4d679275cc5788063" "a5f19741120c4f2de2adebeb10a298dd"), + ?line Case4Ctx224 = crypto:hmac_init(sha224, Case4Key), + ?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data), + ?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2), + ?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data), + ?line m(Case4Exp224, Case4Mac224_1), + ?line m(Case4Exp224, Case4Mac224_2), + ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key), ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data), ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2), @@ -545,6 +581,8 @@ hmac_rfc4231(Config) when is_list(Config) -> %% Test Case 6 Case6Key = binary:copy(<<16#aa>>, 131), Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, + Case6Exp224 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2" + "d499f112f2d2b7273fa6870e"), Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f" "8e0bc6213728c5140546040f0ee37f54"), Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4" @@ -555,6 +593,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "6b56d037e05f2598bd0fd2215d6a1e52" "95e64f73f63f0aec8b915a985d786598"), + ?line Case6Ctx224 = crypto:hmac_init(sha224, Case6Key), + ?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data), + ?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2), + ?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data), + ?line m(Case6Exp224, Case6Mac224_1), + ?line m(Case6Exp224, Case6Mac224_2), + ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key), ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data), ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2), @@ -581,6 +626,8 @@ hmac_rfc4231(Config) when is_list(Config) -> Case7Data = <<"This is a test using a larger than block-size key and a larger t", "han block-size data. The key needs to be hashed before being use", "d by the HMAC algorithm.">>, + Case7Exp224 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd" + "946770db9c2b95c9f6f565d1"), Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" "bfdc63644f0713938a7f51535c3a35e2"), Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" @@ -591,6 +638,13 @@ hmac_rfc4231(Config) when is_list(Config) -> "b6022cac3c4982b10d5eeb55c3e4de15" "134676fb6de0446065c97440fa8c6a58"), + ?line Case7Ctx224 = crypto:hmac_init(sha224, Case7Key), + ?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data), + ?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2), + ?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data), + ?line m(Case7Exp224, Case7Mac224_1), + ?line m(Case7Exp224, Case7Mac224_2), + ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key), ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data), ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2), -- cgit v1.2.3 From 42e65ffe5f2659d998ff0a7e5ebea2573c23a86f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 16 Aug 2012 16:38:31 +0200 Subject: crypto: Add more generic hash interface --- lib/crypto/doc/src/crypto.xml | 51 +++++++++++++++++++++++++++++++++++++++++++ lib/crypto/src/crypto.erl | 33 ++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 36f8bc6deb..0d78dbc426 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -255,6 +255,57 @@ Mpint() = >]]> the computed SHA message digest.

+ + hash(Type, Data) -> Digest + + + Type = md4 | md5 | sha | sha224 | sha256 | sha384 | sha512 + Data = iodata() + Digest = binary() + + +

Computes a message digest of type Type from Data.

+
+
+ + hash_init(Type) -> Context + + + Type = md4 | md5 | sha | sha224 | sha256 | sha384 | sha512 + + +

Initializes the context for streaming hash operations. Type determines + which digest to use. The returned context should be used as argument + to hash_update.

+
+
+ + hash_update(Context, Data) -> NewContext + + + Data = iodata() + + +

Updates the digest represented by Context using the given Data. Context + must have been generated using hash_init + or a previous call to this function. Data can be any length. NewContext + must be passed into the next call to hash_update + or hash_final.

+
+
+ + hash_final(Context) -> Digest + + + Digest = binary() + + +

Finalizes the hash operation referenced by Context returned + from a previous call to hash_update. + The size of Digest is determined by the type of hash + function used to generate it.

+
+
md5_mac(Key, Data) -> Mac Compute an MD5 MACmessage authentification code diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index a07e7a30b4..63043888b9 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -22,7 +22,7 @@ -module(crypto). -export([start/0, stop/0, info/0, info_lib/0, version/0]). --export([hash/2]). +-export([hash/2, hash_init/1, hash_update/2, hash_final/1]). -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). @@ -194,11 +194,40 @@ version() -> ?CRYPTO_VSN. hash(md5, Data) -> md5(Data); hash(md4, Data) -> md4(Data); hash(sha, Data) -> sha(Data); -hash(sha1, Data) -> sha(Data); +hash(sha224, Data) -> sha224(Data); hash(sha256, Data) -> sha256(Data); hash(sha384, Data) -> sha384(Data); hash(sha512, Data) -> sha512(Data). +-spec hash_init('md5'|'md4'|'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any(). + +hash_init(md5) -> {md5, md5_init()}; +hash_init(md4) -> {md4, md4_init()}; +hash_init(sha) -> {sha, sha_init()}; +hash_init(sha224) -> {sha224, sha224_init()}; +hash_init(sha256) -> {sha256, sha256_init()}; +hash_init(sha384) -> {sha384, sha384_init()}; +hash_init(sha512) -> {sha512, sha512_init()}. + +-spec hash_update(_, iodata()) -> any(). + +hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)}; +hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)}; +hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)}; +hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)}; +hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)}; +hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)}; +hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}. + +-spec hash_final(_) -> binary(). + +hash_final({md5,Context}) -> md5_final(Context); +hash_final({md4,Context}) -> md4_final(Context); +hash_final({sha,Context}) -> sha_final(Context); +hash_final({sha224,Context}) -> sha224_final(Context); +hash_final({sha256,Context}) -> sha256_final(Context); +hash_final({sha384,Context}) -> sha384_final(Context); +hash_final({sha512,Context}) -> sha512_final(Context). %% %% MD5 -- cgit v1.2.3 From c5541a4c03b89fcbcb0dd1bfab8460b1287cc6cb Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 20 Aug 2012 12:31:28 +0200 Subject: crypto: Add sha224 for rsa sign/verify --- lib/crypto/c_src/crypto.c | 13 +++++++++++++ lib/crypto/doc/src/crypto.xml | 4 ++-- lib/crypto/src/crypto.erl | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib/crypto') diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index d9ae8a87a3..9a1a6f6c55 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1564,6 +1564,12 @@ static void sha1_digest(unsigned char* in, unsigned int in_len, unsigned char* o { SHA1(in, in_len, out); } +#ifdef HAVE_SHA224 +static void sha224_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +{ + SHA224(in, in_len, out); +} +#endif #ifdef HAVE_SHA256 static void sha256_digest(unsigned char* in, unsigned int in_len, unsigned char* out) { @@ -1595,6 +1601,13 @@ struct digest_type_t digest_types[] = { {"md5", MD5_DIGEST_LENGTH, NID_md5, md5_digest}, {"sha", SHA_DIGEST_LENGTH, NID_sha1, sha1_digest}, + {"sha224", +#ifdef HAVE_SHA224 + SHA224_LEN, NID_sha224, sha224_digest +#else + 0 +#endif + }, {"sha256", #ifdef HAVE_SHA256 SHA256_LEN, NID_sha256, sha256_digest diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 0d78dbc426..48e35f8093 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -932,7 +932,7 @@ Mpint() = >]]> the calculation faster. P1,P2 are first and second prime factors. E1,E2 are first and second exponents. C is the CRT coefficient. Terminology is taken from RFC 3447. - DigestType = md5 | sha | sha256 | sha384 | sha512 + DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512 The default DigestType is sha. Mpint = binary() Signature = binary() @@ -957,7 +957,7 @@ Mpint() = >]]> Key = [E, N] E, N = Mpint Where E is the public exponent and N is public modulus. - DigestType = md5 | sha | sha256 | sha384 | sha512 + DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512 The default DigestType is sha. Mpint = binary() diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 63043888b9..0089e79a4f 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -105,7 +105,7 @@ aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, info_lib]). --type rsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'. +-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. -type data_or_digest() :: binary() | {digest, binary()}. -type crypto_integer() :: binary() | integer(). -- cgit v1.2.3