diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/crypto/src/crypto.erl | 1404 |
1 files changed, 677 insertions, 727 deletions
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index e042545094..d7b1603eeb 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -35,7 +35,6 @@ -export([private_encrypt/4, public_decrypt/4]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see - %% DEPRECATED %% Replaced by hash_* -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). @@ -165,61 +164,6 @@ -export([info/0]). -deprecated({info, 0, next_major_release}). --define(FUNC_LIST, [hash, hash_init, hash_update, hash_final, - hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, - %% deprecated - md4, md4_init, md4_update, md4_final, - md5, md5_init, md5_update, md5_final, - sha, sha_init, sha_update, sha_final, - md5_mac, md5_mac_96, - sha_mac, sha_mac_96, - %% - block_encrypt, block_decrypt, - %% deprecated - des_cbc_encrypt, des_cbc_decrypt, - des_cfb_encrypt, des_cfb_decrypt, - des_ecb_encrypt, des_ecb_decrypt, - des3_cbc_encrypt, des3_cbc_decrypt, - des3_cfb_encrypt, des3_cfb_decrypt, - aes_cfb_128_encrypt, aes_cfb_128_decrypt, - rc2_cbc_encrypt, rc2_cbc_decrypt, - rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, - aes_cbc_128_encrypt, aes_cbc_128_decrypt, - aes_cbc_256_encrypt, aes_cbc_256_decrypt, - blowfish_cbc_encrypt, blowfish_cbc_decrypt, - blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, - blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, - %% - rand_bytes, - strong_rand_bytes, - rand_uniform, - mod_pow, - exor, - %% deprecated - mod_exp,strong_rand_mpint,erlint, mpint, - %% - sign, verify, generate_key, compute_key, - %% deprecated - 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, - %% - stream_init, stream_encrypt, stream_decrypt, - %% deprecated - rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, - aes_ctr_encrypt, aes_ctr_decrypt, - aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, - %% - next_iv, - %% deprecated - aes_cbc_ivec, - des_cbc_ivec, des_cfb_ivec, - info, - %% - info_lib, supports]). - -type mpint() :: binary(). -type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. @@ -235,11 +179,360 @@ %%-type ec_curve() :: ec_named_curve() | ec_curve_spec(). %%-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}. +-on_load(on_load/0). +-define(CRYPTO_NIF_VSN,201). + -define(nif_stub,nif_stub_error(?LINE)). +nif_stub_error(Line) -> + erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). --on_load(on_load/0). +%%-------------------------------------------------------------------- +%%% API +%%-------------------------------------------------------------------- +%% Crypto app version history: +%% (no version): Driver implementation +%% 2.0 : NIF implementation, requires OTP R14 +version() -> ?CRYPTO_VSN. --define(CRYPTO_NIF_VSN,201). +start() -> + application:start(crypto). + +stop() -> + application:stop(crypto). + +supports()-> + Algs = algorithms(), + PubKeyAlgs = + case lists:member(ec, Algs) of + true -> + {public_keys, [rsa, dss, ecdsa, dh, srp, ecdh]}; + false -> + {public_keys, [rsa, dss, dh, srp]} + end, + [{hashs, Algs -- [ec]}, + {ciphers, [des_cbc, des_cfb, des3_cbc, des3_cbf, des_ede3, blowfish_cbc, + blowfish_cfb64, blowfish_ofb64, blowfish_ecb, aes_cbc128, aes_cfb128, + aes_cbc256, rc2_cbc, aes_ctr, rc4 + ]}, + PubKeyAlgs + ]. + +info_lib() -> ?nif_stub. + +-spec hash(_, iodata()) -> binary(). + +-spec hash_init('md5'|'md4'|'ripemd160'| + '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(ripemd160) -> {ripemd160, ripemd160_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()}. +%% Ecrypt/decrypt %%% + +-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_encrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_encrypt(Key, Ivec, Data); +block_encrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_encrypt(Key, Ivec, Data); +block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_ofb64, Key, Ivec, Data) -> + blowfish_ofb64_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_encrypt(Key, Ivec, Data); +block_encrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_encrypt(Key, Ivec, Data); +block_encrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_encrypt(Key, Ivec, Data). + +-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_decrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_decrypt(Key, Ivec, Data); +block_decrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_decrypt(Key, Ivec, Data); +block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_ofb64, Key, Ivec, Data) -> + blowfish_ofb64_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_decrypt(Key, Ivec, Data); +block_decrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_decrypt(Key, Ivec, Data); +block_decrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_decrypt(Key, Ivec, Data). + +-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_encrypt(des_ecb, Key, Data) -> + des_ecb_encrypt(Key, Data); +block_encrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_encrypt(Key, Data). + +-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_decrypt(des_ecb, Key, Data) -> + des_ecb_decrypt(Key, Data); +block_decrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_decrypt(Key, Data). + +-spec next_iv(des_cbc | des3_cbc | aes_cbc, Data::iodata()) -> binary(). + +next_iv(des_cbc, Data) -> + des_cbc_ivec(Data); +next_iv(des3_cbc, Data) -> + des_cbc_ivec(Data); +next_iv(aes_cbc, Data) -> + aes_cbc_ivec(Data). + +-spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary(). + +next_iv(des_cfb, Data, Ivec) -> + des_cfb_ivec(Ivec, Data); +next_iv(Type, Data, _Ivec) -> + next_iv(Type, Data). + + +-spec hash_update(_, iodata()) -> any(). +%% +%% RAND - pseudo random numbers using RN_ functions in crypto lib +%% +-spec rand_bytes(non_neg_integer()) -> binary(). +-spec strong_rand_bytes(non_neg_integer()) -> binary(). +-spec rand_uniform(crypto_integer(), crypto_integer()) -> + crypto_integer(). + +rand_bytes(_Bytes) -> ?nif_stub. + +strong_rand_bytes(Bytes) -> + case strong_rand_bytes_nif(Bytes) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_bytes_nif(_Bytes) -> ?nif_stub. + +rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. + + +rand_uniform(From,To) when is_binary(From), is_binary(To) -> + case rand_uniform_nif(From,To) of + <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 -> + <<(Len + 1):32/integer, 0, MSB, Rest/binary>>; + Whatever -> + Whatever + end; +rand_uniform(From,To) when is_integer(From),is_integer(To) -> + if From < 0 -> + rand_uniform_pos(0, To - From) + From; + true -> + rand_uniform_pos(From, To) + end. + +rand_uniform_pos(From,To) when From < To -> + BinFrom = mpint(From), + BinTo = mpint(To), + case rand_uniform(BinFrom, BinTo) of + Result when is_binary(Result) -> + erlint(Result); + Other -> + Other + end; +rand_uniform_pos(_,_) -> + error(badarg). + +rand_uniform_nif(_From,_To) -> ?nif_stub. + + +-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. +mod_pow(Base, Exponent, Prime) -> + case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of + <<0>> -> error; + R -> R + end. + +verify(dss, Type, Data, Signature, Key) -> + dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); + +verify(rsa, Type, DataOrDigest, Signature, Key) -> + case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of + notsup -> erlang:error(notsup); + Bool -> Bool + end; +verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) -> + case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of + notsup -> erlang:error(notsup); + Bool -> Bool + end. + +sign(rsa, Type, DataOrDigest, Key) -> + case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end; +sign(dss, Type, DataOrDigest, Key) -> + case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [DataOrDigest, Key]); + Sign -> Sign + end; +sign(ecdsa, Type, DataOrDigest, [Key, Curve]) -> + case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end. + + +-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) -> + binary(). +-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). + +public_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N,D] +private_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + + +%% Binary, Key = [E,N,D] +private_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N] +public_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +generate_key(Type, Params) -> + generate_key(Type, Params, undefined). + +generate_key(dh, DHParameters, PrivateKey) -> + dh_generate_key_nif(ensure_int_as_bin(PrivateKey), + map_ensure_int_as_bin(DHParameters), 0); + +generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) + when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivArg of + undefined -> random_bytes(32); + _ -> ensure_int_as_bin(PrivArg) + end, + host_srp_gen_key(Private, Verifier, Generator, Prime, Version); + +generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg) + when is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivateArg of + undefined -> random_bytes(32); + _ -> PrivateArg + end, + user_srp_gen_key(Private, Generator, Prime); + +generate_key(ecdh, Curve, undefined) -> + ec_key_to_term_nif(ec_key_generate(Curve)). + + +compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> + case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey), + ensure_int_as_bin(MyPrivateKey), + map_ensure_int_as_bin(DHParameters)) of + error -> erlang:error(computation_failed, + [OthersPublicKey,MyPrivateKey,DHParameters]); + Ret -> Ret + end; + +compute_key(srp, HostPublic, {UserPublic, UserPrivate}, + {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when + is_binary(Prime), + is_binary(Generator), + is_atom(Version) -> + HostPubBin = ensure_int_as_bin(HostPublic), + Multiplier = srp_multiplier(Version, Generator, Prime), + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic), + HostPubBin, Prime); + [S] -> S + end, + srp_user_secret_nif(ensure_int_as_bin(UserPrivate), Scrambler, HostPubBin, + Multiplier, Generator, DerivedKey, Prime); + +compute_key(srp, UserPublic, {HostPublic, HostPrivate}, + {host,[Verifier, Prime, Version | ScramblerArg]}) when + is_binary(Verifier), + is_binary(Prime), + is_atom(Version) -> + UserPubBin = ensure_int_as_bin(UserPublic), + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime); + [S] -> S + end, + srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler, + UserPubBin, Prime); + +compute_key(ecdh, Others, My, Curve) -> + ecdh_compute_key_nif(ensure_int_as_bin(Others), + term_to_ec_key(Curve,My,undefined)). + + +random_bytes(N) -> + try strong_rand_bytes(N) of + RandBytes -> + RandBytes + catch + error:low_entropy -> + rand_bytes(N) + end. + +%%-------------------------------------------------------------------- +%%% On load +%%-------------------------------------------------------------------- on_load() -> LibBaseName = "crypto", @@ -257,7 +550,7 @@ on_load() -> (filelib:wildcard( filename:join( [PrivDir, - "lib", + "lib", erlang:system_info(system_architecture), LibTypeName ++ "*"])) /= []) of true -> LibTypeName; @@ -268,8 +561,8 @@ on_load() -> Status = case erlang:load_nif(Lib, {?CRYPTO_NIF_VSN,Lib}) of ok -> ok; {error, {load_failed, _}}=Error1 -> - ArchLibDir = - filename:join([PrivDir, "lib", + ArchLibDir = + filename:join([PrivDir, "lib", erlang:system_info(system_architecture)]), Candidate = filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), @@ -288,84 +581,7 @@ on_load() -> "OpenSSL might not be installed on this system.~n",[E,Str]), Status end. - -nif_stub_error(Line) -> - erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). - -start() -> - application:start(crypto). - -stop() -> - application:stop(crypto). - -info() -> - ?FUNC_LIST. - -info_lib() -> ?nif_stub. - -algorithms() -> ?nif_stub. - -supports()-> - Algs = algorithms(), - PubKeyAlgs = - case lists:member(ec, Algs) of - true -> - {public_keys, [rsa, dss, ecdsa, dh, srp, ecdh]}; - false -> - {public_keys, [rsa, dss, dh, srp]} - end, - [{hashs, Algs -- [ec]}, - {ciphers, [des_cbc, des_cfb, des3_cbc, des3_cbf, des_ede3, blowfish_cbc, - blowfish_cfb64, blowfish_ofb64, blowfish_ecb, aes_cbc128, aes_cfb128, aes_cbc256, rc2_cbc, aes_ctr, rc4 - ]}, - PubKeyAlgs - ]. - -%% Crypto app version history: -%% (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. - -%% -%% MESSAGE DIGESTS -%% - --spec hash(_, iodata()) -> binary(). -hash(md5, Data) -> md5(Data); -hash(md4, Data) -> md4(Data); -hash(sha, Data) -> sha(Data); -hash(ripemd160, Data) -> ripemd160(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'|'ripemd160'| - '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(ripemd160) -> {ripemd160, ripemd160_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({ripemd160,Context}, Data) -> {ripemd160, ripemd160_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); @@ -567,6 +783,7 @@ sha512_init_nif() -> ?nif_stub. sha512_update_nif(_Context, _Data) -> ?nif_stub. sha512_final_nif(_Context) -> ?nif_stub. +%% HMAC -------------------------------------------------------------------- %% %% MESSAGE AUTHENTICATION CODES %% @@ -696,172 +913,8 @@ sha512_mac(Key, Data, MacSz) -> sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. +%% CIPHERS -------------------------------------------------------------------- -%% Ecrypt/decrypt %%% - --spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, - Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). - -block_encrypt(des_cbc, Key, Ivec, Data) -> - des_cbc_encrypt(Key, Ivec, Data); -block_encrypt(des_cfb, Key, Ivec, Data) -> - des_cfb_encrypt(Key, Ivec, Data); -block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> - des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); -block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> - des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data); -block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> - des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); -block_encrypt(blowfish_cbc, Key, Ivec, Data) -> - blowfish_cbc_encrypt(Key, Ivec, Data); -block_encrypt(blowfish_cfb64, Key, Ivec, Data) -> - blowfish_cfb64_encrypt(Key, Ivec, Data); -block_encrypt(blowfish_ofb64, Key, Ivec, Data) -> - blowfish_ofb64_encrypt(Key, Ivec, Data); -block_encrypt(aes_cbc128, Key, Ivec, Data) -> - aes_cbc_128_encrypt(Key, Ivec, Data); -block_encrypt(aes_cbc256, Key, Ivec, Data) -> - aes_cbc_256_encrypt(Key, Ivec, Data); -block_encrypt(aes_cfb128, Key, Ivec, Data) -> - aes_cfb_128_encrypt(Key, Ivec, Data); -block_encrypt(rc2_cbc, Key, Ivec, Data) -> - rc2_cbc_encrypt(Key, Ivec, Data). - --spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | - blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, - Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). - -block_decrypt(des_cbc, Key, Ivec, Data) -> - des_cbc_decrypt(Key, Ivec, Data); -block_decrypt(des_cfb, Key, Ivec, Data) -> - des_cfb_decrypt(Key, Ivec, Data); -block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> - des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); -block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> - des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data); -block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> - des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); -block_decrypt(blowfish_cbc, Key, Ivec, Data) -> - blowfish_cbc_decrypt(Key, Ivec, Data); -block_decrypt(blowfish_cfb64, Key, Ivec, Data) -> - blowfish_cfb64_decrypt(Key, Ivec, Data); -block_decrypt(blowfish_ofb64, Key, Ivec, Data) -> - blowfish_ofb64_decrypt(Key, Ivec, Data); -block_decrypt(aes_cbc128, Key, Ivec, Data) -> - aes_cbc_128_decrypt(Key, Ivec, Data); -block_decrypt(aes_cbc256, Key, Ivec, Data) -> - aes_cbc_256_decrypt(Key, Ivec, Data); -block_decrypt(aes_cfb128, Key, Ivec, Data) -> - aes_cfb_128_decrypt(Key, Ivec, Data); -block_decrypt(rc2_cbc, Key, Ivec, Data) -> - rc2_cbc_decrypt(Key, Ivec, Data). - --spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). - -block_encrypt(des_ecb, Key, Data) -> - des_ecb_encrypt(Key, Data); -block_encrypt(blowfish_ecb, Key, Data) -> - blowfish_ecb_encrypt(Key, Data). - --spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). - -block_decrypt(des_ecb, Key, Data) -> - des_ecb_decrypt(Key, Data); -block_decrypt(blowfish_ecb, Key, Data) -> - blowfish_ecb_decrypt(Key, Data). - --spec next_iv(des_cbc | des3_cbc | aes_cbc, Data::iodata()) -> binary(). - -next_iv(des_cbc, Data) -> - des_cbc_ivec(Data); -next_iv(des3_cbc, Data) -> - des_cbc_ivec(Data); -next_iv(aes_cbc, Data) -> - aes_cbc_ivec(Data). - --spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary(). - -next_iv(des_cfb, Data, Ivec) -> - des_cfb_ivec(Ivec, Data); -next_iv(Type, Data, _Ivec) -> - next_iv(Type, Data). - -stream_init(aes_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}. -stream_init(rc4, Key) -> - {rc4, rc4_set_key(Key)}. -stream_encrypt({aes_ctr, State0}, Data) -> - {State, Cipher} = aes_ctr_stream_encrypt(State0, Data), - {{aes_ctr, State}, Cipher}; -stream_encrypt({rc4, State0}, Data) -> - {State, Cipher} = rc4_encrypt_with_state(State0, Data), - {{rc4, State}, Cipher}. -stream_decrypt({aes_ctr, State0}, Data) -> - {State, Text} = aes_ctr_stream_decrypt(State0, Data), - {{aes_ctr, State}, Text}; -stream_decrypt({rc4, State0}, Data) -> - {State, Text} = rc4_encrypt_with_state (State0, Data), - {{rc4, State}, Text}. - -%% -%% CRYPTO FUNCTIONS -%% - -%% -%% DES - in cipher block chaining mode (CBC) -%% --spec des_cbc_encrypt(iodata(), binary(), iodata()) -> binary(). --spec des_cbc_decrypt(iodata(), binary(), iodata()) -> binary(). - -des_cbc_encrypt(Key, IVec, Data) -> - des_cbc_crypt(Key, IVec, Data, true). - -des_cbc_decrypt(Key, IVec, Data) -> - des_cbc_crypt(Key, IVec, Data, false). - -des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. - -%% -%% dec_cbc_ivec(Data) -> binary() -%% -%% Returns the IVec to be used in the next iteration of -%% des_cbc_[encrypt|decrypt]. -%% --spec des_cbc_ivec(iodata()) -> binary(). - -des_cbc_ivec(Data) when is_binary(Data) -> - {_, IVec} = split_binary(Data, size(Data) - 8), - IVec; -des_cbc_ivec(Data) when is_list(Data) -> - des_cbc_ivec(list_to_binary(Data)). - -%% -%% DES - in 8-bits cipher feedback mode (CFB) -%% --spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary(). --spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary(). - -des_cfb_encrypt(Key, IVec, Data) -> - des_cfb_crypt(Key, IVec, Data, true). - -des_cfb_decrypt(Key, IVec, Data) -> - des_cfb_crypt(Key, IVec, Data, false). - -des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. - -%% -%% dec_cfb_ivec(IVec, Data) -> binary() -%% -%% Returns the IVec to be used in the next iteration of -%% des_cfb_[encrypt|decrypt]. -%% --spec des_cfb_ivec(iodata(), iodata()) -> binary(). - -des_cfb_ivec(IVec, Data) -> - IVecAndData = list_to_binary([IVec, Data]), - {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8), - NewIVec. %% %% DES - in electronic codebook mode (ECB) @@ -973,292 +1026,63 @@ aes_cfb_128_decrypt(Key, IVec, Data) -> aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. -%% -%% RAND - pseudo random numbers using RN_ functions in crypto lib %% --spec rand_bytes(non_neg_integer()) -> binary(). --spec strong_rand_bytes(non_neg_integer()) -> binary(). --spec rand_uniform(crypto_integer(), crypto_integer()) -> - crypto_integer(). --spec strong_rand_mpint(Bits::non_neg_integer(), - Top::-1..1, - Bottom::0..1) -> binary(). - -rand_bytes(_Bytes) -> ?nif_stub. - -strong_rand_bytes(Bytes) -> - case strong_rand_bytes_nif(Bytes) of - false -> erlang:error(low_entropy); - Bin -> Bin - end. -strong_rand_bytes_nif(_Bytes) -> ?nif_stub. - -rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. - -strong_rand_mpint(Bits, Top, Bottom) -> - case strong_rand_mpint_nif(Bits,Top,Bottom) of - false -> erlang:error(low_entropy); - Bin -> Bin - end. -strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub. - +%% DES - in cipher block chaining mode (CBC) +%% +-spec des_cbc_encrypt(iodata(), binary(), iodata()) -> binary(). +-spec des_cbc_decrypt(iodata(), binary(), iodata()) -> binary(). -rand_uniform(From,To) when is_binary(From), is_binary(To) -> - case rand_uniform_nif(From,To) of - <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 -> - <<(Len + 1):32/integer, 0, MSB, Rest/binary>>; - Whatever -> - Whatever - end; -rand_uniform(From,To) when is_integer(From),is_integer(To) -> - if From < 0 -> - rand_uniform_pos(0, To - From) + From; - true -> - rand_uniform_pos(From, To) - end. +des_cbc_encrypt(Key, IVec, Data) -> + des_cbc_crypt(Key, IVec, Data, true). -rand_uniform_pos(From,To) when From < To -> - BinFrom = mpint(From), - BinTo = mpint(To), - case rand_uniform(BinFrom, BinTo) of - Result when is_binary(Result) -> - erlint(Result); - Other -> - Other - end; -rand_uniform_pos(_,_) -> - error(badarg). +des_cbc_decrypt(Key, IVec, Data) -> + des_cbc_crypt(Key, IVec, Data, false). -rand_uniform_nif(_From,_To) -> ?nif_stub. +des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. %% -%% mod_exp - utility for rsa generation and SRP +%% dec_cbc_ivec(Data) -> binary() %% -mod_exp(Base, Exponent, Modulo) - when is_integer(Base), is_integer(Exponent), is_integer(Modulo) -> - bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0)); - -mod_exp(Base, Exponent, Modulo) -> - mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). - --spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. -mod_pow(Base, Exponent, Prime) -> - case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of - <<0>> -> error; - R -> R - end. - +%% Returns the IVec to be used in the next iteration of +%% des_cbc_[encrypt|decrypt]. +%% +-spec des_cbc_ivec(iodata()) -> binary(). -mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub. +des_cbc_ivec(Data) when is_binary(Data) -> + {_, IVec} = split_binary(Data, size(Data) - 8), + IVec; +des_cbc_ivec(Data) when is_list(Data) -> + des_cbc_ivec(list_to_binary(Data)). %% -%% DSS, RSA - verify +%% DES - in 8-bits cipher feedback mode (CFB) %% --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 -dss_verify(Data,Signature,Key) -> - dss_verify(sha, Data, Signature, Key). - -dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none -> - verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key)); -dss_verify(Type,Digest,Signature,Key) -> - verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)). - -% Key = [E,N] E=PublicExponent N=PublicModulus -rsa_verify(Data,Signature,Key) -> - rsa_verify(sha, Data,Signature,Key). -rsa_verify(Type, Data, Signature, Key) when is_binary(Data) -> - verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key)); -rsa_verify(Type, Digest, Signature, Key) -> - verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)). - - -verify(dss, Type, Data, Signature, Key) -> - dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); - -verify(rsa, Type, DataOrDigest, Signature, Key) -> - case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of - notsup -> erlang:error(notsup); - Bool -> Bool - end; -verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) -> - case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of - notsup -> erlang:error(notsup); - Bool -> Bool - end. +-spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary(). +-spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary(). +des_cfb_encrypt(Key, IVec, Data) -> + des_cfb_crypt(Key, IVec, Data, true). -dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. -rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. -ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. +des_cfb_decrypt(Key, IVec, Data) -> + des_cfb_crypt(Key, IVec, Data, false). +des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. %% -%% DSS, RSA - sign +%% dec_cfb_ivec(IVec, Data) -> binary() %% -%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey --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, Data, Key) when is_binary(Data), Type=/=none -> - sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); -dss_sign(Type, Digest, Key) -> - sign(dss, Type, Digest, map_mpint_to_bin(Key)). - - -%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent -rsa_sign(DataOrDigest,Key) -> - rsa_sign(sha, DataOrDigest, Key). - -rsa_sign(Type, Data, Key) when is_binary(Data) -> - sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); -rsa_sign(Type, Digest, Key) -> - sign(rsa, Type, Digest, map_mpint_to_bin(Key)). - -map_mpint_to_bin(List) -> - lists:map(fun(E) -> mpint_to_bin(E) end, List ). - -map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> - lists:map(fun(E) -> int_to_bin(E) end, List); -map_ensure_int_as_bin(List) -> - List. - -ensure_int_as_bin(Int) when is_integer(Int) -> - int_to_bin(Int); -ensure_int_as_bin(Bin) -> - Bin. - -map_to_norm_bin([H|_]=List) when is_integer(H) -> - lists:map(fun(E) -> int_to_bin(E) end, List); -map_to_norm_bin(List) -> - lists:map(fun(E) -> mpint_to_bin(E) end, List). - - -sign(rsa, Type, DataOrDigest, Key) -> - case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of - error -> erlang:error(badkey, [Type,DataOrDigest,Key]); - Sign -> Sign - end; -sign(dss, Type, DataOrDigest, Key) -> - case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of - error -> erlang:error(badkey, [DataOrDigest, Key]); - Sign -> Sign - end; -sign(ecdsa, Type, DataOrDigest, [Key, Curve]) -> - case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of - error -> erlang:error(badkey, [Type,DataOrDigest,Key]); - Sign -> Sign - end. - -rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. - - - - --spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) -> - binary(). --spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> - binary(). --spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> - binary(). --spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> - binary(). - -public_encrypt(rsa, BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -%% Binary, Key = [E,N,D] -private_decrypt(rsa, BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - - -%% Binary, Key = [E,N,D] -private_encrypt(rsa, BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -%% Binary, Key = [E,N] -public_decrypt(rsa, BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - - +%% Returns the IVec to be used in the next iteration of +%% des_cfb_[encrypt|decrypt]. %% -%% rsa_public_encrypt -%% rsa_private_decrypt --type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. - --spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) -> - binary(). --spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> - binary(). --spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) -> - binary(). --spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> - binary(). -%% Binary, Key = [E,N] -rsa_public_encrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - -rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. - -%% Binary, Key = [E,N,D] -rsa_private_decrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. +-spec des_cfb_ivec(iodata(), iodata()) -> binary(). -rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. +des_cfb_ivec(IVec, Data) -> + IVecAndData = list_to_binary([IVec, Data]), + {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8), + NewIVec. - -%% Binary, Key = [E,N,D] -rsa_private_encrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of - error -> - erlang:error(encrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. -%% Binary, Key = [E,N] -rsa_public_decrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of - error -> - erlang:error(decrypt_failed, [BinMesg,Key, Padding]); - Sign -> Sign - end. - %% %% AES - with 128 or 256 bit key in cipher block chaining mode (CBC) %% @@ -1326,15 +1150,6 @@ aes_ctr_stream_encrypt({_Key, _IVec, _ECount, _Num}=_State, _Data) -> ?nif_stub. aes_ctr_stream_decrypt({_Key, _IVec, _ECount, _Num}=_State, _Cipher) -> ?nif_stub. %% -%% XOR - xor to iolists and return a binary -%% NB doesn't check that they are the same size, just concatenates -%% them and sends them to the driver -%% --spec exor(iodata(), iodata()) -> binary(). - -exor(_A, _B) -> ?nif_stub. - -%% %% RC4 - symmetric stream cipher %% -spec rc4_encrypt(iodata(), iodata()) -> binary(). @@ -1363,7 +1178,76 @@ rc2_40_cbc_encrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 -> rc2_40_cbc_decrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 -> rc2_cbc_crypt(Key,IVec,Data,false). -%% + +%% Secure remote password ------------------------------------------------------------------- + +user_srp_gen_key(Private, Generator, Prime) -> + case mod_pow(Generator, Private, Prime) of + error -> + error; + Public -> + {Public, Private} + end. + +host_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> + Multiplier = srp_multiplier(Version, Generator, Prime), + case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of + error -> + error; + Public -> + {Public, Private} + end. + +srp_multiplier('6a', Generator, Prime) -> + %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html + C0 = sha_init(), + C1 = sha_update(C0, Prime), + C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)), + sha_final(C2); +srp_multiplier('6', _, _) -> + <<3/integer>>; +srp_multiplier('3', _, _) -> + <<1/integer>>. + +srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'-> + %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html + PadLength = erlang:byte_size(Prime), + C0 = sha_init(), + C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)), + C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)), + sha_final(C2); +srp_scrambler('3', _, HostPublic, _Prime) -> + %% The parameter u is a 32-bit unsigned integer which takes its value + %% from the first 32 bits of the SHA1 hash of B, MSB first. + <<U:32/bits, _/binary>> = sha(HostPublic), + U. + +srp_pad_length(Width, Length) -> + (Width - Length rem Width) rem Width. + +srp_pad_to(Width, Binary) -> + case srp_pad_length(Width, size(Binary)) of + 0 -> Binary; + N -> << 0:(N*8), Binary/binary>> + end. + +srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. + +srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. + +srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. + + +%% Digital signatures -------------------------------------------------------------------- +rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. + +dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. + +%% Public Keys -------------------------------------------------------------------- %% DH Diffie-Hellman functions %% @@ -1412,80 +1296,10 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) -> dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub. -generate_key(Type, Params) -> - generate_key(Type, Params, undefined). - -generate_key(dh, DHParameters, PrivateKey) -> - dh_generate_key_nif(ensure_int_as_bin(PrivateKey), - map_ensure_int_as_bin(DHParameters), 0); - -generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) - when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> - Private = case PrivArg of - undefined -> random_bytes(32); - _ -> ensure_int_as_bin(PrivArg) - end, - host_srp_gen_key(Private, Verifier, Generator, Prime, Version); - -generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg) - when is_binary(Generator), is_binary(Prime), is_atom(Version) -> - Private = case PrivateArg of - undefined -> random_bytes(32); - _ -> PrivateArg - end, - user_srp_gen_key(Private, Generator, Prime); - -generate_key(ecdh, Curve, undefined) -> - ec_key_to_term_nif(ec_key_generate(Curve)). - - ec_key_generate(_Key) -> ?nif_stub. - -compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> - case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey), - ensure_int_as_bin(MyPrivateKey), - map_ensure_int_as_bin(DHParameters)) of - error -> erlang:error(computation_failed, - [OthersPublicKey,MyPrivateKey,DHParameters]); - Ret -> Ret - end; - -compute_key(srp, HostPublic, {UserPublic, UserPrivate}, - {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when - is_binary(Prime), - is_binary(Generator), - is_atom(Version) -> - HostPubBin = ensure_int_as_bin(HostPublic), - Multiplier = srp_multiplier(Version, Generator, Prime), - Scrambler = case ScramblerArg of - [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic), - HostPubBin, Prime); - [S] -> S - end, - srp_user_secret_nif(ensure_int_as_bin(UserPrivate), Scrambler, HostPubBin, - Multiplier, Generator, DerivedKey, Prime); - -compute_key(srp, UserPublic, {HostPublic, HostPrivate}, - {host,[Verifier, Prime, Version | ScramblerArg]}) when - is_binary(Verifier), - is_binary(Prime), - is_atom(Version) -> - UserPubBin = ensure_int_as_bin(UserPublic), - Scrambler = case ScramblerArg of - [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime); - [S] -> S - end, - srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler, - UserPubBin, Prime); - -compute_key(ecdh, Others, My, Curve) -> - ecdh_compute_key_nif(ensure_int_as_bin(Others), - term_to_ec_key(Curve,My,undefined)). - ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. - %% %% EC %% @@ -1511,65 +1325,167 @@ term_to_ec_key(Curve, PrivKey, PubKey) -> term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. +algorithms() -> ?nif_stub. + +int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); +int_to_bin(X) -> int_to_bin_pos(X, []). + +int_to_bin_pos(0,Ds=[_|_]) -> + list_to_binary(Ds); +int_to_bin_pos(X,Ds) -> + int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). + +int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> + list_to_binary(Ds); +int_to_bin_neg(X,Ds) -> + int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). + +bytes_to_integer(Bin) -> + bin_to_int(Bin). -%% LOCAL FUNCTIONS +bin_to_int(Bin) when is_binary(Bin) -> + Bits = bit_size(Bin), + <<Integer:Bits/integer>> = Bin, + Integer; +bin_to_int(undefined) -> + undefined. + +map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_ensure_int_as_bin(List) -> + List. + +ensure_int_as_bin(Int) when is_integer(Int) -> + int_to_bin(Int); +ensure_int_as_bin(Bin) -> + Bin. + +map_to_norm_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_to_norm_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List). + + +%%-------------------------------------------------------------------- +%%% Deprecated +%%-------------------------------------------------------------------- %% +%% rsa_public_encrypt +%% rsa_private_decrypt +-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -user_srp_gen_key(Private, Generator, Prime) -> - case mod_pow(Generator, Private, Prime) of +-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) -> + binary(). +-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> + binary(). +-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) -> + binary(). +-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> + binary(). + +%% Binary, Key = [E,N] +rsa_public_encrypt(BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of error -> - error; - Public -> - {Public, Private} + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign end. -host_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> - Multiplier = srp_multiplier(Version, Generator, Prime), - case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of - error -> - error; - Public -> - {Public, Private} - end. +rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. -srp_multiplier('6a', Generator, Prime) -> - %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html - C0 = sha_init(), - C1 = sha_update(C0, Prime), - C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)), - sha_final(C2); -srp_multiplier('6', _, _) -> - <<3/integer>>; -srp_multiplier('3', _, _) -> - <<1/integer>>. +%% Binary, Key = [E,N,D] +rsa_private_decrypt(BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. -srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'-> - %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html - PadLength = erlang:byte_size(Prime), - C0 = sha_init(), - C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)), - C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)), - sha_final(C2); -srp_scrambler('3', _, HostPublic, _Prime) -> - %% The parameter u is a 32-bit unsigned integer which takes its value - %% from the first 32 bits of the SHA1 hash of B, MSB first. - <<U:32/bits, _/binary>> = sha(HostPublic), - U. +rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. -srp_pad_length(Width, Length) -> - (Width - Length rem Width) rem Width. -srp_pad_to(Width, Binary) -> - case srp_pad_length(Width, size(Binary)) of - 0 -> Binary; - N -> << 0:(N*8), Binary/binary>> +%% Binary, Key = [E,N,D] +rsa_private_encrypt(BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign end. -srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. +%% Binary, Key = [E,N] +rsa_public_decrypt(BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. -srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. +map_mpint_to_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List ). + +%% +%% DSS, RSA - sign +%% +%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey +-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, Data, Key) when is_binary(Data), Type=/=none -> + sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +dss_sign(Type, Digest, Key) -> + sign(dss, Type, Digest, map_mpint_to_bin(Key)). + + +%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent +rsa_sign(DataOrDigest,Key) -> + rsa_sign(sha, DataOrDigest, Key). + +rsa_sign(Type, Data, Key) when is_binary(Data) -> + sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +rsa_sign(Type, Digest, Key) -> + sign(rsa, Type, Digest, map_mpint_to_bin(Key)). + +%% +%% DSS, RSA - verify +%% +-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 +dss_verify(Data,Signature,Key) -> + dss_verify(sha, Data, Signature, Key). + +dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none -> + verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key)); +dss_verify(Type,Digest,Signature,Key) -> + verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)). + +% Key = [E,N] E=PublicExponent N=PublicModulus +rsa_verify(Data,Signature,Key) -> + rsa_verify(sha, Data,Signature,Key). +rsa_verify(Type, Data, Signature, Key) when is_binary(Data) -> + verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key)); +rsa_verify(Type, Digest, Signature, Key) -> + verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)). + +-spec strong_rand_mpint(Bits::non_neg_integer(), + Top::-1..1, + Bottom::0..1) -> binary(). + +strong_rand_mpint(Bits, Top, Bottom) -> + case strong_rand_mpint_nif(Bits,Top,Bottom) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub. -srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. %% large integer in a binary with 32bit length %% MP representaion (SSH2) @@ -1594,32 +1510,6 @@ mpint_pos(X) -> <<?UINT32(Sz), Bin/binary>> end. -int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); -int_to_bin(X) -> int_to_bin_pos(X, []). - -%%int_to_bin_pos(X) when X >= 0 -> -%% int_to_bin_pos(X, []). - -int_to_bin_pos(0,Ds=[_|_]) -> - list_to_binary(Ds); -int_to_bin_pos(X,Ds) -> - int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). - -int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> - list_to_binary(Ds); -int_to_bin_neg(X,Ds) -> - int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). - -bytes_to_integer(Bin) -> - bin_to_int(Bin). - -bin_to_int(Bin) when is_binary(Bin) -> - Bits = bit_size(Bin), - <<Integer:Bits/integer>> = Bin, - Integer; -bin_to_int(undefined) -> - undefined. - %% int from integer in a binary with 32bit length erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) -> Bits= MPIntSize * 8, @@ -1629,11 +1519,71 @@ erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) -> mpint_to_bin(<<Len:32, Bin:Len/binary>>) -> Bin. -random_bytes(N) -> - try strong_rand_bytes(N) of - RandBytes -> - RandBytes - catch - error:low_entropy -> - rand_bytes(N) - end. +%% +%% mod_exp - utility for rsa generation and SRP +%% +mod_exp(Base, Exponent, Modulo) + when is_integer(Base), is_integer(Exponent), is_integer(Modulo) -> + bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0)); + +mod_exp(Base, Exponent, Modulo) -> + mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). + +mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub. + +-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final, + hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, + %% deprecated + md4, md4_init, md4_update, md4_final, + md5, md5_init, md5_update, md5_final, + sha, sha_init, sha_update, sha_final, + md5_mac, md5_mac_96, + sha_mac, sha_mac_96, + %% + block_encrypt, block_decrypt, + %% deprecated + des_cbc_encrypt, des_cbc_decrypt, + des_cfb_encrypt, des_cfb_decrypt, + des_ecb_encrypt, des_ecb_decrypt, + des3_cbc_encrypt, des3_cbc_decrypt, + des3_cfb_encrypt, des3_cfb_decrypt, + aes_cfb_128_encrypt, aes_cfb_128_decrypt, + rc2_cbc_encrypt, rc2_cbc_decrypt, + rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, + aes_cbc_128_encrypt, aes_cbc_128_decrypt, + aes_cbc_256_encrypt, aes_cbc_256_decrypt, + blowfish_cbc_encrypt, blowfish_cbc_decrypt, + blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, + blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, + %% + rand_bytes, + strong_rand_bytes, + rand_uniform, + mod_pow, + exor, + %% deprecated + mod_exp,strong_rand_mpint,erlint, mpint, + %% + sign, verify, generate_key, compute_key, + %% deprecated + 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, + %% + stream_init, stream_encrypt, stream_decrypt, + %% deprecated + rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, + aes_ctr_encrypt, aes_ctr_decrypt, + aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, + %% + next_iv, + %% deprecated + aes_cbc_ivec, + des_cbc_ivec, des_cfb_ivec, + info, + %% + info_lib, supports]). +info() -> + ?FUNC_LIST. |