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