diff options
Diffstat (limited to 'lib/crypto/src/crypto.erl')
-rw-r--r-- | lib/crypto/src/crypto.erl | 1109 |
1 files changed, 859 insertions, 250 deletions
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index bc8b124b10..8ffdde2b90 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -24,6 +24,7 @@ -export([start/0, stop/0, info_lib/0, info_fips/0, supports/0, enable_fips_mode/1, version/0, bytes_to_integer/1]). +-export([cipher_info/1, hash_info/1]). -export([hash/2, hash_init/1, hash_update/2, hash_final/1]). -export([sign/4, sign/5, verify/5, verify/6]). -export([generate_key/2, generate_key/3, compute_key/4]). @@ -31,21 +32,40 @@ -export([cmac/3, cmac/4]). -export([poly1305/2]). -export([exor/2, strong_rand_bytes/1, mod_pow/3]). --export([rand_seed/0, rand_seed_alg/1]). --export([rand_seed_s/0, rand_seed_alg_s/1]). +-export([rand_seed/0, rand_seed_alg/1, rand_seed_alg/2]). +-export([rand_seed_s/0, rand_seed_alg_s/1, rand_seed_alg_s/2]). -export([rand_plugin_next/1]). +-export([rand_plugin_aes_next/1, rand_plugin_aes_jump/1]). -export([rand_plugin_uniform/1]). -export([rand_plugin_uniform/2]). -export([rand_cache_plugin_next/1]). -export([rand_uniform/2]). --export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]). -export([next_iv/2, next_iv/3]). --export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]). -export([public_encrypt/4, private_decrypt/4]). -export([private_encrypt/4, public_decrypt/4]). -export([privkey_to_pubkey/2]). -export([ec_curve/1, ec_curves/0]). -export([rand_seed/1]). + +%% Old interface. Now implemented with the New interface +-export([stream_init/2, stream_init/3, + stream_encrypt/2, + stream_decrypt/2, + block_encrypt/3, block_encrypt/4, + block_decrypt/3, block_decrypt/4 + ]). + +%% New interface +-export([crypto_init/4, crypto_init/3, + crypto_update/2, + crypto_one_time/4, crypto_one_time/5, + crypto_one_time_aead/6, crypto_one_time_aead/7, + crypto_dyn_iv_init/3, + crypto_dyn_iv_update/3, + supports/1 + ]). + + %% Engine -export([ engine_get_all_methods/0, @@ -88,11 +108,14 @@ -export_type([ stream_state/0, hmac_state/0, - hash_state/0 + hash_state/0, + crypto_state/0 ]). %% Private. For tests. --export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2, get_test_engine/0]). +-export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2, + get_test_engine/0]). +-export([rand_plugin_aes_jump_2pow20/1]). -deprecated({rand_uniform, 2, next_major_release}). @@ -255,23 +278,153 @@ -type edwards_curve_ed() :: ed25519 | ed448 . -%%% +%%%---------------------------------------------------------------- +%%% New cipher schema +%%% +-type cipher() :: cipher_no_iv() + | cipher_iv() + | cipher_aead() . + +-type cipher_no_iv() :: aes_128_ecb + | aes_192_ecb + | aes_256_ecb + + | blowfish_ecb + | des_ecb + | rc4 . + +-type cipher_iv() :: aes_128_cbc + | aes_192_cbc + | aes_256_cbc + + | aes_128_cfb128 + | aes_192_cfb128 + | aes_256_cfb128 + + | aes_128_cfb8 + | aes_192_cfb8 + | aes_256_cfb8 + + | aes_128_ctr + | aes_192_ctr + | aes_256_ctr + + | aes_ige256 + + | blowfish_cbc + | blowfish_cfb64 + | blowfish_ofb64 + | chacha20 + | des_ede3_cbc + | des_ede3_cfb + + | des_cbc + | des_cfb + | rc2_cbc . + + +-type cipher_aead() :: aes_128_ccm + | aes_192_ccm + | aes_256_ccm + + | aes_128_gcm + | aes_192_gcm + | aes_256_gcm + + | chacha20_poly1305 . + + +%% -type retired_cipher_no_iv_aliases() :: aes_ecb . + +%% -type retired_cipher_iv_aliases() :: aes_cbc +%% | aes_cbc128 % aes_128_cbc +%% | aes_cbc256 % aes_256_cbc +%% | aes_cfb128 +%% | aes_cfb8 +%% | aes_ctr +%% | des3_cbc % des_ede3_cbc +%% | des_ede3 % des_ede3_cbc +%% | des_ede3_cbf % des_ede3_cfb +%% | des3_cbf % des_ede3_cfb +%% | des3_cfb . % des_ede3_cfb + +%% -type retired_cipher_aead_aliases() :: aes_ccm +%% | aes_gcm . + +%%%---------------------------------------------------------------- +%%% Old cipher scheme +%%% +%%% +-type block_cipher_without_iv() :: ecb_cipher() . + -type block_cipher_with_iv() :: cbc_cipher() | cfb_cipher() - | aes_cbc128 - | aes_cbc256 - | aes_ige256 | blowfish_ofb64 - | des3_cbf % cfb misspelled - | des_ede3 - | rc2_cbc . - --type cbc_cipher() :: des_cbc | des3_cbc | aes_cbc | blowfish_cbc . + | aes_ige256 . + +-type stream_cipher() :: ctr_cipher() + | chacha20 + | rc4 . + + +%%%---- +-type cbc_cipher() :: aes_128_cbc + | aes_192_cbc + | aes_256_cbc + | blowfish_cbc + | des_cbc + | des_ede3_cbc + | rc2_cbc + | retired_cbc_cipher_aliases() . + +-type retired_cbc_cipher_aliases() :: aes_cbc % aes_*_cbc + | aes_cbc128 % aes_128_cbc + | aes_cbc256 % aes_256_cbc + | des3_cbc % des_ede3_cbc + | des_ede3 . % des_ede3_cbc + +%%%---- +-type cfb_cipher() :: aes_128_cfb128 + | aes_192_cfb128 + | aes_256_cfb128 + | aes_128_cfb8 + | aes_192_cfb8 + | aes_256_cfb8 + | blowfish_cfb64 + | des_cfb + | des_ede3_cfb + | retired_cfb_cipher_aliases() . + +-type retired_cfb_cipher_aliases() :: aes_cfb8 % aes_*_cfb8 + | aes_cfb128 % aes_*_cfb128 + | des3_cbf % des_ede3_cfb, cfb misspelled + | des3_cfb % des_ede3_cfb + | des_ede3_cbf .% cfb misspelled + + +%%%---- +-type ctr_cipher() :: aes_128_ctr + | aes_192_ctr + | aes_256_ctr + | retired_ctr_cipher_aliases() . + +-type retired_ctr_cipher_aliases() :: aes_ctr . % aes_*_ctr + +%%%---- +-type ecb_cipher() :: aes_128_ecb + | aes_192_ecb + | aes_256_ecb + | blowfish_ecb + | retired_ecb_cipher_aliases() . + +-type retired_ecb_cipher_aliases() :: aes_ecb . + +%%%---- -type aead_cipher() :: aes_gcm | aes_ccm | chacha20_poly1305 . --type cfb_cipher() :: aes_cfb128 | aes_cfb8 | blowfish_cfb64 | des3_cfb | des_cfb . --type block_cipher_without_iv() :: ecb_cipher() . --type ecb_cipher() :: des_ecb | blowfish_ecb | aes_ecb . + +%%%----- end old cipher schema ------------------------------------ +%%%---------------------------------------------------------------- -type key() :: iodata(). -type des3_key() :: [key()]. @@ -284,11 +437,26 @@ -type sha1() :: sha . -type sha2() :: sha224 | sha256 | sha384 | sha512 . -type sha3() :: sha3_224 | sha3_256 | sha3_384 | sha3_512 . +-type blake2() :: blake2b | blake2s . -type compatibility_only_hash() :: md5 | md4 . -type crypto_integer() :: binary() | integer(). +%%% +%% Exceptions +%% error:badarg +%% error:notsup +-type run_time_error() :: no_return(). + +%% Exceptions +%% error:{badarg,Reason::term()} +%% error:{notsup,Reason::term()} +%% error:{error,Reason::term()} +-type descriptive_error() :: no_return() . + + +%%-------------------------------------------------------------------- -compile(no_native). -on_load(on_load/0). -define(CRYPTO_NIF_VSN,302). @@ -326,24 +494,49 @@ stop() -> | {macs, Macs} | {curves, Curves} | {rsa_opts, RSAopts}, - Hashs :: [sha1() | sha2() | sha3() | ripemd160 | compatibility_only_hash()], - Ciphers :: [stream_cipher() - | block_cipher_with_iv() | block_cipher_without_iv() - | aead_cipher() - ], + Hashs :: [sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash()], + Ciphers :: [cipher()], + PKs :: [rsa | dss | ecdsa | dh | ecdh | ec_gf2m], + Macs :: [hmac | cmac | poly1305], + Curves :: [ec_named_curve() | edwards_curve_dh() | edwards_curve_ed()], + RSAopts :: [rsa_sign_verify_opt() | rsa_opt()] . +supports() -> + [{hashs, hash_algorithms()}, + {ciphers, prepend_old_aliases( cipher_algorithms())}, + {public_keys, pubkey_algorithms()}, + {macs, mac_algorithms()}, + {curves, curve_algorithms()}, + {rsa_opts, rsa_opts_algorithms()} + ]. + + +-spec supports(Type) -> Support + when Type :: hashs + | ciphers + | public_keys + | macs + | curves + | rsa_opts, + Support :: Hashs + | Ciphers + | PKs + | Macs + | Curves + | RSAopts, + Hashs :: [sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash()], + Ciphers :: [cipher()], PKs :: [rsa | dss | ecdsa | dh | ecdh | ec_gf2m], Macs :: [hmac | cmac | poly1305], Curves :: [ec_named_curve() | edwards_curve_dh() | edwards_curve_ed()], RSAopts :: [rsa_sign_verify_opt() | rsa_opt()] . -supports()-> - {Hashs, PubKeys, Ciphers, Macs, Curves, RsaOpts} = algorithms(), - [{hashs, Hashs}, - {ciphers, Ciphers}, - {public_keys, PubKeys}, - {macs, Macs}, - {curves, Curves}, - {rsa_opts, RsaOpts} - ]. + +supports(hashs) -> hash_algorithms(); +supports(public_keys) -> pubkey_algorithms(); +supports(ciphers) -> cipher_algorithms(); +supports(macs) -> mac_algorithms(); +supports(curves) -> curve_algorithms(); +supports(rsa_opts) -> rsa_opts_algorithms(). + -spec info_lib() -> [{Name,VerNum,VerStr}] when Name :: binary(), VerNum :: integer(), @@ -364,9 +557,18 @@ enable_fips_mode(_) -> ?nif_stub. %%% %%%================================================================ --define(HASH_HASH_ALGORITHM, sha1() | sha2() | sha3() | ripemd160 | compatibility_only_hash() ). +-type hash_algorithm() :: sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash() . + +-spec hash_info(Type) -> Result | run_time_error() + when Type :: hash_algorithm(), + Result :: #{size := integer(), + block_size := integer(), + type := integer() + } . +hash_info(Type) -> + notsup_to_error(hash_info_nif(Type)). --spec hash(Type, Data) -> Digest when Type :: ?HASH_HASH_ALGORITHM, +-spec hash(Type, Data) -> Digest when Type :: hash_algorithm(), Data :: iodata(), Digest :: binary(). hash(Type, Data) -> @@ -376,7 +578,7 @@ hash(Type, Data) -> -opaque hash_state() :: reference(). --spec hash_init(Type) -> State when Type :: ?HASH_HASH_ALGORITHM, +-spec hash_init(Type) -> State when Type :: hash_algorithm(), State :: hash_state(). hash_init(Type) -> notsup_to_error(hash_init_nif(Type)). @@ -402,12 +604,12 @@ hash_final(Context) -> %%%---- HMAC --define(HMAC_HASH_ALGORITHM, sha1() | sha2() | sha3() | compatibility_only_hash()). +-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash(). %%%---- hmac/3,4 -spec hmac(Type, Key, Data) -> - Mac when Type :: ?HMAC_HASH_ALGORITHM, + Mac when Type :: hmac_hash_algorithm(), Key :: iodata(), Data :: iodata(), Mac :: binary() . @@ -416,7 +618,7 @@ hmac(Type, Key, Data) -> hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()). -spec hmac(Type, Key, Data, MacLength) -> - Mac when Type :: ?HMAC_HASH_ALGORITHM, + Mac when Type :: hmac_hash_algorithm(), Key :: iodata(), Data :: iodata(), MacLength :: integer(), @@ -431,7 +633,7 @@ hmac(Type, Key, Data, MacLength) -> -opaque hmac_state() :: binary(). -spec hmac_init(Type, Key) -> - State when Type :: ?HMAC_HASH_ALGORITHM, + State when Type :: hmac_hash_algorithm(), Key :: iodata(), State :: hmac_state() . hmac_init(Type, Key) -> @@ -469,7 +671,7 @@ hmac_final_n(Context, HashLen) -> Data :: iodata(), Mac :: binary(). cmac(Type, Key, Data) -> - notsup_to_error(cmac_nif(Type, Key, Data)). + notsup_to_error(cmac_nif(alias(Type), Key, Data)). -spec cmac(Type, Key, Data, MacLength) -> Mac when Type :: ?CMAC_CIPHER_ALGORITHM, @@ -477,8 +679,9 @@ cmac(Type, Key, Data) -> Data :: iodata(), MacLength :: integer(), Mac :: binary(). + cmac(Type, Key, Data, MacLength) -> - erlang:binary_part(cmac(Type, Key, Data), 0, MacLength). + erlang:binary_part(cmac(alias(Type), Key, Data), 0, MacLength). %%%---- POLY1305 @@ -489,97 +692,209 @@ poly1305(Key, Data) -> %%%================================================================ %%% -%%% Encrypt/decrypt +%%% Encrypt/decrypt, The "Old API" %%% %%%================================================================ -%%%---- Block ciphers +-define(COMPAT(CALL), + try begin CALL end + catch + error:{error, {_File,_Line}, _Reason} -> + error(badarg); + error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg -> + error(E) + end). --spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) -> binary(); +%%%---- Cipher info +%%%---------------------------------------------------------------- +-spec cipher_info(Type) -> Result | run_time_error() + when Type :: cipher(), + Result :: #{key_length := integer(), + iv_length := integer(), + block_size := integer(), + mode := CipherModes, + type := undefined | integer() + }, + CipherModes :: undefined + | cbc_mode + | ccm_mode + | cfb_mode + | ctr_mode + | ecb_mode + | gcm_mode + | ige_mode + | ocb_mode + | ofb_mode + | wrap_mode + | xts_mode + . + +%% %% These ciphers are not available via the EVP interface on older cryptolibs. +cipher_info(aes_ctr) -> + #{block_size => 1,iv_length => 16,key_length => 32,mode => ctr_mode,type => undefined}; +cipher_info(aes_128_ctr) -> + #{block_size => 1,iv_length => 16,key_length => 16,mode => ctr_mode,type => undefined}; +cipher_info(aes_192_ctr) -> + #{block_size => 1,iv_length => 16,key_length => 24,mode => ctr_mode,type => undefined}; +cipher_info(aes_256_ctr) -> + #{block_size => 1,iv_length => 16,key_length => 32,mode => ctr_mode,type => undefined}; +%% %% This cipher is handled specialy. +cipher_info(aes_ige256) -> + #{block_size => 16,iv_length => 32,key_length => 16,mode => ige_mode,type => undefined}; +%% %% These ciphers belong to the "old" interface: +%% cipher_info(aes_cbc) -> +%% #{block_size => 16,iv_length => 16,key_length => 24,mode => cbc_mode,type => 423}; +%% cipher_info(aes_cbc128) -> +%% #{block_size => 16,iv_length => 16,key_length => 16,mode => cbc_mode,type => 419}; +%% cipher_info(aes_cbc256) -> +%% #{block_size => 16,iv_length => 16,key_length => 32,mode => cbc_mode,type => 427}; +%% cipher_info(aes_ccm) -> +%% #{block_size => 1,iv_length => 12,key_length => 24,mode => ccm_mode,type => 899}; +%% cipher_info(aes_cfb128) -> +%% #{block_size => 1,iv_length => 16,key_length => 32,mode => cfb_mode,type => 429}; +%% cipher_info(aes_cfb8) -> +%% #{block_size => 1,iv_length => 16,key_length => 32,mode => cfb_mode,type => 429}; +%% cipher_info(aes_ecb) -> +%% #{block_size => 16,iv_length => 0,key_length => 24,mode => ecb_mode,type => 422}; +%% cipher_info(aes_gcm) -> +%% #{block_size => 1,iv_length => 12,key_length => 24,mode => gcm_mode,type => 898}; +%% cipher_info(des3_cbc) -> +%% #{block_size => 8,iv_length => 8,key_length => 24,mode => cbc_mode,type => 44}; +%% cipher_info(des3_cbf) -> +%% #{block_size => 1,iv_length => 8,key_length => 24,mode => cfb_mode,type => 30}; +%% cipher_info(des3_cfb) -> +%% #{block_size => 1,iv_length => 8,key_length => 24,mode => cfb_mode,type => 30}; +%% cipher_info(des_ede3) -> +%% #{block_size => 8,iv_length => 8,key_length => 24,mode => cbc_mode,type => 44}; +%% cipher_info(des_ede3_cbf) -> +%% #{block_size => 1,iv_length => 8,key_length => 24,mode => cfb_mode,type => 30}; +cipher_info(Type) -> + cipher_info_nif(alias(Type)). + +%%%---- Block ciphers +%%%---------------------------------------------------------------- +-spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) -> + binary() | run_time_error(); (Type::aead_cipher(), Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata()}) -> - {binary(), binary()}; + {binary(), binary()} | run_time_error(); (aes_gcm | aes_ccm, Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata(), TagLength::1..16}) -> - {binary(), binary()}. - -block_encrypt(Type, Key, Ivec, PlainText) when Type =:= des_cbc; - Type =:= des_cfb; - Type =:= blowfish_cbc; - Type =:= blowfish_cfb64; - Type =:= blowfish_ofb64; - Type =:= aes_cbc128; - Type =:= aes_cfb8; - Type =:= aes_cfb128; - Type =:= aes_cbc256; - Type =:= aes_cbc; - Type =:= rc2_cbc -> - notsup_to_error(block_crypt_nif(Type, Key, Ivec, PlainText, true)); -block_encrypt(Type, Key0, Ivec, PlainText) when Type =:= des3_cbc; - Type =:= des_ede3 -> - Key = check_des3_key(Key0), - notsup_to_error(block_crypt_nif(des_ede3_cbc, Key, Ivec, PlainText, true)); -block_encrypt(des3_cbf, Key0, Ivec, PlainText) -> % cfb misspelled - Key = check_des3_key(Key0), - notsup_to_error(block_crypt_nif(des_ede3_cbf, Key, Ivec, PlainText, true)); -block_encrypt(des3_cfb, Key0, Ivec, PlainText) -> - Key = check_des3_key(Key0), - notsup_to_error(block_crypt_nif(des_ede3_cfb, Key, Ivec, PlainText, true)); + {binary(), binary()} | run_time_error(). + + block_encrypt(aes_ige256, Key, Ivec, PlainText) -> notsup_to_error(aes_ige_crypt_nif(Key, Ivec, PlainText, true)); -block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= aes_gcm; - Type =:= aes_ccm -> - aead_encrypt(Type, Key, Ivec, AAD, PlainText); -block_encrypt(Type, Key, Ivec, {AAD, PlainText, TagLength}) when Type =:= aes_gcm; - Type =:= aes_ccm -> - aead_encrypt(Type, Key, Ivec, AAD, PlainText, TagLength); -block_encrypt(chacha20_poly1305=Type, Key, Ivec, {AAD, PlainText}) -> - aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16). +block_encrypt(Type, Key0, Ivec, Data) -> + Key = iolist_to_binary(Key0), + ?COMPAT( + case Data of + {AAD, PlainText} -> + crypto_one_time_aead(alias(Type,Key), Key, Ivec, PlainText, AAD, true); + {AAD, PlainText, TagLength} -> + crypto_one_time_aead(alias(Type,Key), Key, Ivec, PlainText, AAD, TagLength, true); + PlainText -> + crypto_one_time(alias(Type,Key), Key, Ivec, PlainText, true) + end). --spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> binary(); - (Type::aead_cipher(), Key::iodata(), Ivec::binary(), - {AAD::binary(), Data::iodata(), Tag::binary()}) -> binary() | error. -block_decrypt(Type, Key, Ivec, Data) when Type =:= des_cbc; - Type =:= des_cfb; - Type =:= blowfish_cbc; - Type =:= blowfish_cfb64; - Type =:= blowfish_ofb64; - Type =:= aes_cbc; - Type =:= aes_cbc128; - Type =:= aes_cfb8; - Type =:= aes_cfb128; - Type =:= aes_cbc256; - Type =:= rc2_cbc -> - notsup_to_error(block_crypt_nif(Type, Key, Ivec, Data, false)); -block_decrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc; - Type =:= des_ede3 -> - Key = check_des3_key(Key0), - notsup_to_error(block_crypt_nif(des_ede3_cbc, Key, Ivec, Data, false)); -block_decrypt(des3_cbf, Key0, Ivec, Data) -> % cfb misspelled - Key = check_des3_key(Key0), - notsup_to_error(block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, false)); -block_decrypt(des3_cfb, Key0, Ivec, Data) -> - Key = check_des3_key(Key0), - notsup_to_error(block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, false)); -block_decrypt(aes_ige256, Key, Ivec, Data) -> - notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false)); -block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm; - Type =:= aes_ccm; - Type =:= chacha20_poly1305 -> - aead_decrypt(Type, Key, Ivec, AAD, Data, Tag). +-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> + binary() | run_time_error(). +block_encrypt(Type, Key0, PlainText) -> + Key = iolist_to_binary(Key0), + ?COMPAT(crypto_one_time(alias(Type,Key), Key, PlainText, true)). --spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary(). -block_encrypt(Type, Key, PlainText) -> - notsup_to_error(block_crypt_nif(Type, Key, PlainText, true)). +%%%---------------------------------------------------------------- +%%%---------------------------------------------------------------- +-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> + binary() | run_time_error(); + (Type::aead_cipher(), Key::iodata(), Ivec::binary(), + {AAD::binary(), Data::iodata(), Tag::binary()}) -> + binary() | error | run_time_error() . +block_decrypt(aes_ige256, Key, Ivec, Data) -> + notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false)); + +block_decrypt(Type, Key0, Ivec, Data) -> + Key = iolist_to_binary(Key0), + ?COMPAT( + case Data of + {AAD, CryptoText, Tag} -> + crypto_one_time_aead(alias(Type,Key), Key, Ivec, CryptoText, AAD, Tag, false); + CryptoText -> + crypto_one_time(alias(Type,Key), Key, Ivec, CryptoText, false) + end). + + +-spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) -> + binary() | run_time_error(). + +block_decrypt(Type, Key0, CryptoText) -> + Key = iolist_to_binary(Key0), + ?COMPAT(crypto_one_time(alias(Type,Key), Key, CryptoText, false)). + +%%%-------- Stream ciphers API + +-opaque stream_state() :: {stream_cipher(), + crypto_state() | {crypto_state(),flg_undefined} + }. + +%%%---- stream_init +-spec stream_init(Type, Key, IVec) -> State | run_time_error() + when Type :: stream_cipher(), + Key :: iodata(), + IVec ::binary(), + State :: stream_state() . +stream_init(Type, Key0, IVec) when is_binary(IVec) -> + Key = iolist_to_binary(Key0), + Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key), + Key, iolist_to_binary(IVec), + undefined) + ), + {Type, {Ref,flg_undefined}}. + + +-spec stream_init(Type, Key) -> State | run_time_error() + when Type :: rc4, + Key :: iodata(), + State :: stream_state() . +stream_init(rc4 = Type, Key0) -> + Key = iolist_to_binary(Key0), + Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key), + Key, <<>>, + undefined) + ), + {Type, {Ref,flg_undefined}}. + +%%%---- stream_encrypt +-spec stream_encrypt(State, PlainText) -> {NewState, CipherText} | run_time_error() + when State :: stream_state(), + PlainText :: iodata(), + NewState :: stream_state(), + CipherText :: iodata() . +stream_encrypt(State, Data) -> + crypto_stream_emulate(State, Data, true). --spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) -> binary(). +%%%---- stream_decrypt +-spec stream_decrypt(State, CipherText) -> {NewState, PlainText} | run_time_error() + when State :: stream_state(), + CipherText :: iodata(), + NewState :: stream_state(), + PlainText :: iodata() . +stream_decrypt(State, Data) -> + crypto_stream_emulate(State, Data, false). -block_decrypt(Type, Key, Data) -> - notsup_to_error(block_crypt_nif(Type, Key, Data, false)). +%%%-------- helpers +crypto_stream_emulate({Cipher,{Ref0,flg_undefined}}, Data, EncryptFlag) when is_reference(Ref0) -> + ?COMPAT(begin + Ref = ng_crypto_init_nif(Ref0, <<>>, <<>>, EncryptFlag), + {{Cipher,Ref}, crypto_update(Ref, Data)} + end); +crypto_stream_emulate({Cipher,Ref}, Data, _) when is_reference(Ref) -> + ?COMPAT({{Cipher,Ref}, crypto_update(Ref, Data)}). +%%%---------------------------------------------------------------- -spec next_iv(Type:: cbc_cipher(), Data) -> NextIVec when % Type :: cbc_cipher(), %des_cbc | des3_cbc | aes_cbc | aes_ige, Data :: iodata(), NextIVec :: binary(). @@ -606,47 +921,274 @@ next_iv(des_cfb, Data, IVec) -> next_iv(Type, Data, _Ivec) -> next_iv(Type, Data). -%%%---- Stream ciphers +%%%================================================================ +%%% +%%% Encrypt/decrypt, The "New API" +%%% +%%%================================================================ --opaque stream_state() :: {stream_cipher(), reference()}. +-opaque crypto_state() :: reference() . --type stream_cipher() :: rc4 | aes_ctr | chacha20 . --spec stream_init(Type, Key, IVec) -> State when Type :: aes_ctr | chacha20, - Key :: iodata(), - IVec :: binary(), - State :: stream_state() . -stream_init(aes_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}; -stream_init(chacha20, Key, Ivec) -> - {chacha20, chacha20_stream_init(Key,Ivec)}. +%%%---------------------------------------------------------------- +%%% +%%% Create and initialize a new state for encryption or decryption +%%% --spec stream_init(Type, Key) -> State when Type :: rc4, - Key :: iodata(), - State :: stream_state() . -stream_init(rc4, Key) -> - {rc4, notsup_to_error(rc4_set_key(Key))}. +-spec crypto_init(Cipher, Key, EncryptFlag) -> State | descriptive_error() + when Cipher :: cipher_no_iv(), + Key :: iodata(), + EncryptFlag :: boolean(), + State :: crypto_state() . +crypto_init(Cipher, Key, EncryptFlag) -> + %% The IV is supposed to be supplied by calling crypto_update/3 + ng_crypto_init_nif(Cipher, iolist_to_binary(Key), <<>>, EncryptFlag). --spec stream_encrypt(State, PlainText) -> {NewState, CipherText} - when State :: stream_state(), - PlainText :: iodata(), - NewState :: stream_state(), - CipherText :: iodata() . -stream_encrypt(State, Data0) -> - Data = iolist_to_binary(Data0), - MaxByts = max_bytes(), - stream_crypt(fun do_stream_encrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []). --spec stream_decrypt(State, CipherText) -> {NewState, PlainText} - when State :: stream_state(), - CipherText :: iodata(), - NewState :: stream_state(), - PlainText :: iodata() . -stream_decrypt(State, Data0) -> - Data = iolist_to_binary(Data0), - MaxByts = max_bytes(), - stream_crypt(fun do_stream_decrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []). +-spec crypto_init(Cipher, Key, IV, EncryptFlag) -> State | descriptive_error() + when Cipher :: cipher_iv(), + Key :: iodata(), + IV :: iodata(), + EncryptFlag :: boolean(), + State :: crypto_state() . +crypto_init(Cipher, Key, IV, EncryptFlag) -> + ng_crypto_init_nif(Cipher, iolist_to_binary(Key), iolist_to_binary(IV), EncryptFlag). + + + +%%%---------------------------------------------------------------- +-spec crypto_dyn_iv_init(Cipher, Key, EncryptFlag) -> State | descriptive_error() + when Cipher :: cipher_iv(), + Key :: iodata(), + EncryptFlag :: boolean(), + State :: crypto_state() . +crypto_dyn_iv_init(Cipher, Key, EncryptFlag) -> + %% The IV is supposed to be supplied by calling crypto_update/3 + ng_crypto_init_nif(Cipher, iolist_to_binary(Key), undefined, EncryptFlag). + +%%%---------------------------------------------------------------- +%%% +%%% Encrypt/decrypt a sequence of bytes. The sum of the sizes +%%% of all blocks must be an integer multiple of the crypto's +%%% blocksize. +%%% + +-spec crypto_update(State, Data) -> Result | descriptive_error() + when State :: crypto_state(), + Data :: iodata(), + Result :: binary() . +crypto_update(State, Data0) -> + case iolist_to_binary(Data0) of + <<>> -> + <<>>; % Known to fail on OpenSSL 0.9.8h + Data -> + ng_crypto_update_nif(State, Data) + end. + + +%%%---------------------------------------------------------------- +-spec crypto_dyn_iv_update(State, Data, IV) -> Result | descriptive_error() + when State :: crypto_state(), + Data :: iodata(), + IV :: iodata(), + Result :: binary() . +crypto_dyn_iv_update(State, Data0, IV) -> + %% When State is from State = crypto_init(Cipher, Key, undefined, EncryptFlag) + case iolist_to_binary(Data0) of + <<>> -> + <<>>; % Known to fail on OpenSSL 0.9.8h + Data -> + ng_crypto_update_nif(State, Data, iolist_to_binary(IV)) + end. + +%%%---------------------------------------------------------------- +%%% +%%% Encrypt/decrypt one set bytes. +%%% The size must be an integer multiple of the crypto's blocksize. +%%% + +-spec crypto_one_time(Cipher, Key, Data, EncryptFlag) -> + Result | descriptive_error() + when Cipher :: cipher_no_iv(), + Key :: iodata(), + Data :: iodata(), + EncryptFlag :: boolean(), + Result :: binary() . +crypto_one_time(Cipher, Key, Data, EncryptFlag) -> + crypto_one_time(Cipher, Key, <<>>, Data, EncryptFlag). + +-spec crypto_one_time(Cipher, Key, IV, Data, EncryptFlag) -> + Result | descriptive_error() + when Cipher :: cipher_iv(), + Key :: iodata(), + IV :: iodata(), + Data :: iodata(), + EncryptFlag :: boolean(), + Result :: binary() . + +crypto_one_time(Cipher, Key, IV, Data0, EncryptFlag) -> + case iolist_to_binary(Data0) of + <<>> -> + <<>>; % Known to fail on OpenSSL 0.9.8h + Data -> + ng_crypto_one_time_nif(Cipher, + iolist_to_binary(Key), iolist_to_binary(IV), Data, + EncryptFlag) + end. + + +-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, EncFlag::true) -> + Result | descriptive_error() + when Cipher :: cipher_aead(), + Key :: iodata(), + IV :: iodata(), + InText :: iodata(), + AAD :: iodata(), + Result :: EncryptResult, + EncryptResult :: {OutCryptoText, OutTag}, + OutCryptoText :: binary(), + OutTag :: binary(). + +crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, true) -> + crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, aead_tag_len(Cipher), true). + + +-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, TagOrTagLength, EncFlag) -> + Result | descriptive_error() + when Cipher :: cipher_aead(), + Key :: iodata(), + IV :: iodata(), + InText :: iodata(), + AAD :: iodata(), + TagOrTagLength :: EncryptTagLength | DecryptTag, + EncryptTagLength :: non_neg_integer(), % or pos_integer() 1.. + DecryptTag :: iodata(), + EncFlag :: boolean(), + Result :: EncryptResult | DecryptResult, + EncryptResult :: {OutCryptoText, OutTag}, + DecryptResult :: OutPlainText | error, + OutCryptoText :: binary(), + OutTag :: binary(), + OutPlainText :: binary(). + +crypto_one_time_aead(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg) -> + aead_cipher(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg). + + +aead_tag_len(chacha20_poly1305) -> 16; +aead_tag_len(aes_ccm ) -> 12; +aead_tag_len(aes_128_ccm) -> 12; +aead_tag_len(aes_192_ccm) -> 12; +aead_tag_len(aes_256_ccm) -> 12; +aead_tag_len(aes_gcm ) -> 16; +aead_tag_len(aes_128_gcm) -> 16; +aead_tag_len(aes_192_gcm) -> 16; +aead_tag_len(aes_256_gcm) -> 16; +aead_tag_len(_) -> error({badarg, "Not an AEAD cipher"}). + +%%%---------------------------------------------------------------- +%%% NIFs + +-spec ng_crypto_init_nif(atom(), binary(), binary()|undefined, boolean()|undefined ) -> + crypto_state() | descriptive_error() + ; (crypto_state(), <<>>, <<>>, boolean()) + -> crypto_state() | descriptive_error(). + +ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlg) -> ?nif_stub. + + +-spec ng_crypto_update_nif(crypto_state(), binary()) -> + binary() | descriptive_error() . +ng_crypto_update_nif(_State, _Data) -> ?nif_stub. + +-spec ng_crypto_update_nif(crypto_state(), binary(), binary()) -> + binary() | descriptive_error() . +ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub. + + +-spec ng_crypto_one_time_nif(atom(), binary(), binary(), binary(), boolean() ) -> + binary() | descriptive_error(). +ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub. + +%%%---------------------------------------------------------------- +%%% Cipher aliases +%%% +-define(if_also(Cipher, Ciphers, AliasCiphers), + case lists:member(Cipher, Ciphers) of + true -> + AliasCiphers; + false -> + Ciphers + end). + + +prepend_old_aliases(L0) -> + L1 = ?if_also(des_ede3_cbc, L0, + [des3_cbc, des_ede3, des_ede3_cbf, des3_cbf, des3_cfb | L0]), + L2 = ?if_also(aes_128_cbc, L1, + [aes_cbc, aes_cbc128, aes_cbc256 | L1]), + L3 = ?if_also(aes_128_ctr, L2, + [aes_ctr | L2]), + L4 = ?if_also(aes_128_ccm, L3, + [aes_ccm | L3]), + L5 = ?if_also(aes_128_gcm, L4, + [aes_gcm | L4]), + L6 = ?if_also(aes_128_cfb8, L5, + [aes_cfb8 | L5]), + L7 = ?if_also(aes_128_cfb128, L6, + [aes_cfb128 | L6]), + L8 = ?if_also(aes_128_ecb, L7, + [aes_ecb | L7]), + L8. + + + +%%%---- des_ede3_cbc +alias(des3_cbc) -> des_ede3_cbc; +alias(des_ede3) -> des_ede3_cbc; +%%%---- des_ede3_cfb +alias(des_ede3_cbf) -> des_ede3_cfb; +alias(des3_cbf) -> des_ede3_cfb; +alias(des3_cfb) -> des_ede3_cfb; +%%%---- aes_*_cbc +alias(aes_cbc128) -> aes_128_cbc; +alias(aes_cbc256) -> aes_256_cbc; + +alias(Alg) -> Alg. + + +alias(Ciph, Key) -> alias2(alias(Ciph), Key). + +alias2(aes_cbc, Key) when size(Key)==16 -> aes_128_cbc; +alias2(aes_cbc, Key) when size(Key)==24 -> aes_192_cbc; +alias2(aes_cbc, Key) when size(Key)==32 -> aes_256_cbc; + +alias2(aes_cfb8, Key) when size(Key)==16 -> aes_128_cfb8; +alias2(aes_cfb8, Key) when size(Key)==24 -> aes_192_cfb8; +alias2(aes_cfb8, Key) when size(Key)==32 -> aes_256_cfb8; + +alias2(aes_cfb128, Key) when size(Key)==16 -> aes_128_cfb128; +alias2(aes_cfb128, Key) when size(Key)==24 -> aes_192_cfb128; +alias2(aes_cfb128, Key) when size(Key)==32 -> aes_256_cfb128; + +alias2(aes_ctr, Key) when size(Key)==16 -> aes_128_ctr; +alias2(aes_ctr, Key) when size(Key)==24 -> aes_192_ctr; +alias2(aes_ctr, Key) when size(Key)==32 -> aes_256_ctr; + +alias2(aes_ecb, Key) when size(Key)==16 -> aes_128_ecb; +alias2(aes_ecb, Key) when size(Key)==24 -> aes_192_ecb; +alias2(aes_ecb, Key) when size(Key)==32 -> aes_256_ecb; + +alias2(aes_gcm, Key) when size(Key)==16 -> aes_128_gcm; +alias2(aes_gcm, Key) when size(Key)==24 -> aes_192_gcm; +alias2(aes_gcm, Key) when size(Key)==32 -> aes_256_gcm; + +alias2(aes_ccm, Key) when size(Key)==16 -> aes_128_ccm; +alias2(aes_ccm, Key) when size(Key)==24 -> aes_192_ccm; +alias2(aes_ccm, Key) when size(Key)==32 -> aes_256_ccm; + +alias2(Alg, _) -> Alg. %%%================================================================ %%% @@ -679,34 +1221,73 @@ rand_seed_s() -> rand_seed_alg(Alg) -> rand:seed(rand_seed_alg_s(Alg)). +-spec rand_seed_alg(Alg :: atom(), Seed :: term()) -> + {rand:alg_handler(), + atom() | rand_cache_seed()}. +rand_seed_alg(Alg, Seed) -> + rand:seed(rand_seed_alg_s(Alg, Seed)). + -define(CRYPTO_CACHE_BITS, 56). +-define(CRYPTO_AES_BITS, 58). + -spec rand_seed_alg_s(Alg :: atom()) -> {rand:alg_handler(), atom() | rand_cache_seed()}. -rand_seed_alg_s(?MODULE) -> - {#{ type => ?MODULE, - bits => 64, - next => fun ?MODULE:rand_plugin_next/1, - uniform => fun ?MODULE:rand_plugin_uniform/1, - uniform_n => fun ?MODULE:rand_plugin_uniform/2}, - no_seed}; -rand_seed_alg_s(crypto_cache) -> +rand_seed_alg_s({AlgHandler, _AlgState} = State) when is_map(AlgHandler) -> + State; +rand_seed_alg_s({Alg, AlgState}) when is_atom(Alg) -> + {mk_alg_handler(Alg),AlgState}; + rand_seed_alg_s(Alg) when is_atom(Alg) -> + {mk_alg_handler(Alg),mk_alg_state(Alg)}. +%% +-spec rand_seed_alg_s(Alg :: atom(), Seed :: term()) -> + {rand:alg_handler(), + atom() | rand_cache_seed()}. +rand_seed_alg_s(Alg, Seed) when is_atom(Alg) -> + {mk_alg_handler(Alg),mk_alg_state({Alg,Seed})}. + +mk_alg_handler(?MODULE = Alg) -> + #{ type => Alg, + bits => 64, + next => fun ?MODULE:rand_plugin_next/1, + uniform => fun ?MODULE:rand_plugin_uniform/1, + uniform_n => fun ?MODULE:rand_plugin_uniform/2}; +mk_alg_handler(crypto_cache = Alg) -> + #{ type => Alg, + bits => ?CRYPTO_CACHE_BITS, + next => fun ?MODULE:rand_cache_plugin_next/1}; +mk_alg_handler(crypto_aes = Alg) -> + #{ type => Alg, + bits => ?CRYPTO_AES_BITS, + next => fun ?MODULE:rand_plugin_aes_next/1, + jump => fun ?MODULE:rand_plugin_aes_jump/1}. + +mk_alg_state(?MODULE) -> + no_seed; +mk_alg_state(crypto_cache) -> CacheBits = ?CRYPTO_CACHE_BITS, - EnvCacheSize = - application:get_env( - crypto, rand_cache_size, CacheBits * 16), % Cache 16 * 8 words - Bytes = (CacheBits + 7) div 8, + BytesPerWord = (CacheBits + 7) div 8, + GenBytes = + ((rand_cache_size() + (2*BytesPerWord - 1)) div BytesPerWord) + * BytesPerWord, + {CacheBits, GenBytes, <<>>}; +mk_alg_state({crypto_aes,Seed}) -> + %% 16 byte words (128 bit crypto blocks) + GenWords = (rand_cache_size() + 31) div 16, + Key = crypto:hash(sha256, Seed), + {F,Count} = longcount_seed(Seed), + {Key,GenWords,F,Count}. + +rand_cache_size() -> + DefaultCacheSize = 1024, CacheSize = - case ((EnvCacheSize + (Bytes - 1)) div Bytes) * Bytes of - Sz when is_integer(Sz), Bytes =< Sz -> - Sz; - _ -> - Bytes - end, - {#{ type => crypto_cache, - bits => CacheBits, - next => fun ?MODULE:rand_cache_plugin_next/1}, - {CacheBits, CacheSize, <<>>}}. + application:get_env(crypto, rand_cache_size, DefaultCacheSize), + if + is_integer(CacheSize), 0 =< CacheSize -> + CacheSize; + true -> + DefaultCacheSize + end. rand_plugin_next(Seed) -> {bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}. @@ -717,12 +1298,97 @@ rand_plugin_uniform(State) -> rand_plugin_uniform(Max, State) -> {bytes_to_integer(strong_rand_range(Max)) + 1, State}. -rand_cache_plugin_next({CacheBits, CacheSize, <<>>}) -> + +rand_cache_plugin_next({CacheBits, GenBytes, <<>>}) -> rand_cache_plugin_next( - {CacheBits, CacheSize, strong_rand_bytes(CacheSize)}); -rand_cache_plugin_next({CacheBits, CacheSize, Cache}) -> + {CacheBits, GenBytes, strong_rand_bytes(GenBytes)}); +rand_cache_plugin_next({CacheBits, GenBytes, Cache}) -> <<I:CacheBits, NewCache/binary>> = Cache, - {I, {CacheBits, CacheSize, NewCache}}. + {I, {CacheBits, GenBytes, NewCache}}. + + +%% Encrypt 128 bit counter values and use the 58 lowest +%% encrypted bits as random numbers. +%% +%% The 128 bit counter is handled as 4 32 bit words +%% to avoid bignums. Generate a bunch of numbers +%% at the time and cache them. +%% +-dialyzer({no_improper_lists, rand_plugin_aes_next/1}). +rand_plugin_aes_next([V|Cache]) -> + {V,Cache}; +rand_plugin_aes_next({Key,GenWords,F,Count}) -> + rand_plugin_aes_next(Key, GenWords, F, Count); +rand_plugin_aes_next({Key,GenWords,F,_JumpBase,Count}) -> + rand_plugin_aes_next(Key, GenWords, F, Count). +%% +rand_plugin_aes_next(Key, GenWords, F, Count) -> + {Cleartext,NewCount} = aes_cleartext(<<>>, F, Count, GenWords), + Encrypted = crypto:block_encrypt(aes_ecb, Key, Cleartext), + [V|Cache] = aes_cache(Encrypted, {Key,GenWords,F,Count,NewCount}), + {V,Cache}. + +%% A jump advances the counter 2^512 steps; the jump function +%% is applied to the jump base and then the number of used +%% numbers from the cache has to be wasted for the jump to be correct +%% +rand_plugin_aes_jump({#{type := crypto_aes} = Alg, Cache}) -> + {Alg,rand_plugin_aes_jump(fun longcount_jump/1, 0, Cache)}. +%% Count cached words and subtract their number from jump +-dialyzer({no_improper_lists, rand_plugin_aes_jump/3}). +rand_plugin_aes_jump(Jump, J, [_|Cache]) -> + rand_plugin_aes_jump(Jump, J + 1, Cache); +rand_plugin_aes_jump(Jump, J, {Key,GenWords,F,JumpBase, _Count}) -> + rand_plugin_aes_jump(Jump, GenWords - J, Key, GenWords, F, JumpBase); +rand_plugin_aes_jump(Jump, 0, {Key,GenWords,F,JumpBase}) -> + rand_plugin_aes_jump(Jump, 0, Key, GenWords, F, JumpBase). +%% +rand_plugin_aes_jump(Jump, Skip, Key, GenWords, F, JumpBase) -> + Count = longcount_next_count(Skip, Jump(JumpBase)), + {Key,GenWords,F,Count}. + +rand_plugin_aes_jump_2pow20(Cache) -> + rand_plugin_aes_jump(fun longcount_jump_2pow20/1, 0, Cache). + + +longcount_seed(Seed) -> + <<X:64, _:6, F:12, S2:58, S1:58, S0:58>> = + crypto:hash(sha256, [Seed,<<"Xoroshiro928">>]), + {F,rand:exro928_seed([S0,S1,S2|rand:seed58(13, X)])}. + +longcount_next_count(0, Count) -> + Count; +longcount_next_count(N, Count) -> + longcount_next_count(N - 1, rand:exro928_next_state(Count)). + +longcount_next(Count) -> + rand:exro928_next(Count). + +longcount_jump(Count) -> + rand:exro928_jump_2pow512(Count). + +longcount_jump_2pow20(Count) -> + rand:exro928_jump_2pow20(Count). + + +%% Build binary with counter values to cache +aes_cleartext(Cleartext, _F, Count, 0) -> + {Cleartext,Count}; +aes_cleartext(Cleartext, F, Count, GenWords) -> + {{S0,S1}, NewCount} = longcount_next(Count), + aes_cleartext( + <<Cleartext/binary, F:12, S1:58, S0:58>>, + F, NewCount, GenWords - 1). + +%% Parse and cache encrypted counter values aka random numbers +-dialyzer({no_improper_lists, aes_cache/2}). +aes_cache(<<>>, Cache) -> + Cache; +aes_cache( + <<_:(128 - ?CRYPTO_AES_BITS), V:?CRYPTO_AES_BITS, Encrypted/binary>>, + Cache) -> + [V|aes_cache(Encrypted, Cache)]. + strong_rand_range(Range) when is_integer(Range), Range > 0 -> BinRange = int_to_bin(Range), @@ -787,7 +1453,8 @@ rand_seed_nif(_Seed) -> ?nif_stub. -type pk_sign_verify_opts() :: [ rsa_sign_verify_opt() ] . -type rsa_sign_verify_opt() :: {rsa_padding, rsa_sign_verify_padding()} - | {rsa_pss_saltlen, integer()} . + | {rsa_pss_saltlen, integer()} + | {rsa_mgf1_md, sha2()}. -type rsa_sign_verify_padding() :: rsa_pkcs1_padding | rsa_pkcs1_pss_padding | rsa_x931_padding | rsa_no_padding @@ -803,7 +1470,7 @@ rand_seed_nif(_Seed) -> ?nif_stub. DigestType :: rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(), - Msg :: binary() | {digest,binary()}, + Msg :: iodata() | {digest,iodata()}, Key :: rsa_private() | dss_private() | [ecdsa_private() | ecdsa_params()] @@ -822,7 +1489,7 @@ sign(Algorithm, Type, Data, Key) -> | dss_digest_type() | ecdsa_digest_type() | none, - Msg :: binary() | {digest,binary()}, + Msg :: iodata() | {digest,iodata()}, Key :: rsa_private() | dss_private() | [ecdsa_private() | ecdsa_params()] @@ -851,7 +1518,7 @@ pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub. | dss_digest_type() | ecdsa_digest_type() | none, - Msg :: binary() | {digest,binary()}, + Msg :: iodata() | {digest,iodata()}, Signature :: binary(), Key :: rsa_public() | dss_public() @@ -869,7 +1536,7 @@ verify(Algorithm, Type, Data, Signature, Key) -> DigestType :: rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(), - Msg :: binary() | {digest,binary()}, + Msg :: iodata() | {digest,iodata()}, Signature :: binary(), Key :: rsa_public() | dss_public() @@ -1562,6 +2229,7 @@ hash_update(State0, Data, _, MaxBytes) -> State = notsup_to_error(hash_update_nif(State0, Increment)), hash_update(State, Rest, erlang:byte_size(Rest), MaxBytes). +hash_info_nif(_Hash) -> ?nif_stub. hash_nif(_Hash, _Data) -> ?nif_stub. hash_init_nif(_Hash) -> ?nif_stub. hash_update_nif(_State, _Data) -> ?nif_stub. @@ -1606,28 +2274,13 @@ poly1305_nif(_Key, _Data) -> ?nif_stub. %% CIPHERS -------------------------------------------------------------------- -block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub. -block_crypt_nif(_Type, _Key, _Text, _IsEncrypt) -> ?nif_stub. - -check_des3_key(Key) -> - case lists:map(fun erlang:iolist_to_binary/1, Key) of - ValidKey = [B1, B2, B3] when byte_size(B1) =:= 8, - byte_size(B2) =:= 8, - byte_size(B3) =:= 8 -> - ValidKey; - _ -> - error(badarg) - end. +cipher_info_nif(_Type) -> ?nif_stub. %% %% AES - in Galois/Counter Mode (GCM) %% %% The default tag length is EVP_GCM_TLS_TAG_LEN(16), -aead_encrypt(Type=aes_ccm, Key, Ivec, AAD, In) -> aead_encrypt(Type, Key, Ivec, AAD, In, 12); -aead_encrypt(Type=aes_gcm, Key, Ivec, AAD, In) -> aead_encrypt(Type, Key, Ivec, AAD, In, 16). - -aead_encrypt(_Type, _Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub. -aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub. +aead_cipher(_Type, _Key, _Ivec, _AAD, _In, _TagOrTagLength, _EncFlg) -> ?nif_stub. %% %% AES - with 256 bit key in infinite garble extension mode (IGE) @@ -1635,59 +2288,7 @@ aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub. aes_ige_crypt_nif(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. - -%% Stream ciphers -------------------------------------------------------------------- - -stream_crypt(Fun, State, Data, Size, MaxByts, []) when Size =< MaxByts -> - Fun(State, Data); -stream_crypt(Fun, State0, Data, Size, MaxByts, Acc) when Size =< MaxByts -> - {State, Cipher} = Fun(State0, Data), - {State, list_to_binary(lists:reverse([Cipher | Acc]))}; -stream_crypt(Fun, State0, Data, _, MaxByts, Acc) -> - <<Increment:MaxByts/binary, Rest/binary>> = Data, - {State, CipherText} = Fun(State0, Increment), - stream_crypt(Fun, State, Rest, erlang:byte_size(Rest), MaxByts, [CipherText | Acc]). - -do_stream_encrypt({aes_ctr, State0}, Data) -> - {State, Cipher} = aes_ctr_stream_encrypt(State0, Data), - {{aes_ctr, State}, Cipher}; -do_stream_encrypt({rc4, State0}, Data) -> - {State, Cipher} = rc4_encrypt_with_state(State0, Data), - {{rc4, State}, Cipher}; -do_stream_encrypt({chacha20, State0}, Data) -> - {State, Cipher} = chacha20_stream_encrypt(State0, Data), - {{chacha20, State}, Cipher}. - -do_stream_decrypt({aes_ctr, State0}, Data) -> - {State, Text} = aes_ctr_stream_decrypt(State0, Data), - {{aes_ctr, State}, Text}; -do_stream_decrypt({rc4, State0}, Data) -> - {State, Text} = rc4_encrypt_with_state(State0, Data), - {{rc4, State}, Text}; -do_stream_decrypt({chacha20, State0}, Data) -> - {State, Cipher} = chacha20_stream_decrypt(State0, Data), - {{chacha20, State}, Cipher}. - - -%% -%% AES - in counter mode (CTR) with state maintained for multi-call streaming -%% -aes_ctr_stream_init(_Key, _IVec) -> ?nif_stub. -aes_ctr_stream_encrypt(_State, _Data) -> ?nif_stub. -aes_ctr_stream_decrypt(_State, _Cipher) -> ?nif_stub. - -%% -%% RC4 - symmetric stream cipher -%% -rc4_set_key(_Key) -> ?nif_stub. -rc4_encrypt_with_state(_State, _Data) -> ?nif_stub. - -%% -%% CHACHA20 - stream cipher -%% -chacha20_stream_init(_Key, _IVec) -> ?nif_stub. -chacha20_stream_encrypt(_State, _Data) -> ?nif_stub. -chacha20_stream_decrypt(_State, _Data) -> ?nif_stub. +%%%================================================================ %% Secure remote password ------------------------------------------------------------------- @@ -1851,7 +2452,13 @@ exor(Data1, Data2, _Size, MaxByts, Acc) -> do_exor(_A, _B) -> ?nif_stub. -algorithms() -> ?nif_stub. +hash_algorithms() -> ?nif_stub. +pubkey_algorithms() -> ?nif_stub. +cipher_algorithms() -> ?nif_stub. +mac_algorithms() -> ?nif_stub. +curve_algorithms() -> ?nif_stub. +rsa_opts_algorithms() -> ?nif_stub. + int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); int_to_bin(X) -> int_to_bin_pos(X, []). @@ -2051,3 +2658,5 @@ check_otp_test_engine(LibDir) -> {error, notexist} end end. + + |