aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Schultz <[email protected]>2012-05-31 13:08:03 +0200
committerIngela Anderton Andin <[email protected]>2012-08-22 14:00:41 +0200
commit2702f65e834a65d05d82cebf77bc7385becbf3a7 (patch)
treef74e20bb9b086f59491853159ddfb54d689c5e0a
parentceb32eb2239d0031d0f55c84b3007b50e1a6a7d1 (diff)
downloadotp-2702f65e834a65d05d82cebf77bc7385becbf3a7.tar.gz
otp-2702f65e834a65d05d82cebf77bc7385becbf3a7.tar.bz2
otp-2702f65e834a65d05d82cebf77bc7385becbf3a7.zip
crypto: Add rsa and dss hash signing support
-rw-r--r--lib/crypto/c_src/crypto.c139
-rw-r--r--lib/crypto/src/crypto.erl30
-rw-r--r--lib/crypto/test/crypto_SUITE.erl63
3 files changed, 227 insertions, 5 deletions
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."];