diff options
author | Hans Nilsson <[email protected]> | 2019-03-07 12:19:18 +0100 |
---|---|---|
committer | Hans Nilsson <[email protected]> | 2019-03-19 12:45:54 +0100 |
commit | cd08c844693fbb26d545f9cd981bfa9ae2d08042 (patch) | |
tree | c2d1395e95d4ea0710884b9ab9ff61614af2ac18 | |
parent | c209e1ecc6aac833b8a1d5da86d86ca04c7d7085 (diff) | |
download | otp-cd08c844693fbb26d545f9cd981bfa9ae2d08042.tar.gz otp-cd08c844693fbb26d545f9cd981bfa9ae2d08042.tar.bz2 otp-cd08c844693fbb26d545f9cd981bfa9ae2d08042.zip |
crypto: Use/implement new funcs for stream-api
-rw-r--r-- | lib/crypto/c_src/api_ng.c | 54 | ||||
-rw-r--r-- | lib/crypto/c_src/crypto.c | 11 | ||||
-rw-r--r-- | lib/crypto/src/crypto.erl | 278 |
3 files changed, 158 insertions, 185 deletions
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c index 50c0e9fcf6..1a5867eaaf 100644 --- a/lib/crypto/c_src/api_ng.c +++ b/lib/crypto/c_src/api_ng.c @@ -159,12 +159,6 @@ static int get_init_args(ErlNifEnv* env, goto err; } - if (encflg == -1) - { - *return_term = atom_undefined; - goto err; // Yes... - } - /* Initialize the EVP_CIPHER_CTX */ ctx_res->ctx = EVP_CIPHER_CTX_new(); @@ -198,7 +192,7 @@ static int get_init_args(ErlNifEnv* env, } } - if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, ivec_bin.data, encflg)) { + if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, ivec_bin.data, -1)) { *return_term = ERROR_Str(env, "Can't initialize key and/or iv"); goto err; } @@ -254,6 +248,7 @@ static int get_update_args(ErlNifEnv* env, if (enif_get_tuple(env, newstate_and_outdata, &tuple_argc, &tuple_argv) && (tuple_argc == 2)) { /* newstate_and_outdata = {NewState, OutData} */ ctx_res->state = enif_make_copy(ctx_res->env, tuple_argv[0]); + /* Return the OutData (from the newstate_and_outdata tuple) only: */ *return_term = tuple_argv[1]; } } @@ -281,6 +276,7 @@ static int get_update_args(ErlNifEnv* env, } CONSUME_REDS(env, in_data_bin); + /* return the result text as a binary: */ *return_term = enif_make_binary(env, &out_data_bin); } @@ -301,17 +297,43 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg struct evp_cipher_ctx *ctx_res = NULL; const struct cipher_type_t *cipherp; ERL_NIF_TERM ret; - - if ((ctx_res = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL) - return ERROR_Str(env, "Can't allocate resource"); - - if (!get_init_args(env, ctx_res, argv[0], argv[1], argv[2], argv[argc-1], - &cipherp, &ret)) - /* Error msg in &ret */ + int encflg; + + if (enif_is_atom(env, argv[0])) { + if ((ctx_res = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL) + return ERROR_Str(env, "Can't allocate resource"); + + if (!get_init_args(env, ctx_res, argv[0], argv[1], argv[2], argv[argc-1], + &cipherp, &ret)) + /* Error msg in &ret */ + goto ret; + + ret = enif_make_resource(env, ctx_res); + if(ctx_res) enif_release_resource(ctx_res); + + } else if (enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx_res)) { + /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */ + if (argv[3] == atom_true) + encflg = 1; + else if (argv[3] == atom_false) + encflg = 0; + else { + ret = ERROR_Str(env, "Bad enc flag"); + goto ret; + } + if (ctx_res->ctx) { + /* It is *not* a ctx_res for the compatibility handling of non-EVP aes_ctr */ + if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, NULL, NULL, encflg)) { + ret = ERROR_Str(env, "Can't initialize encflag"); + goto ret; + } + } + ret = argv[0]; + } else { + ret = ERROR_Str(env, "Bad 1:st arg"); goto ret; + } - ret = enif_make_resource(env, ctx_res); - if(ctx_res) enif_release_resource(ctx_res); ret: return ret; } diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index ac9823887a..501c1ffb42 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -30,7 +30,6 @@ #include "algorithms.h" #include "api_ng.h" #include "bn.h" -#include "chacha20.h" #include "cipher.h" #include "cmac.h" #include "dh.h" @@ -49,7 +48,6 @@ #include "pkey.h" #include "poly1305.h" #include "rand.h" -#include "rc4.h" #include "rsa.h" #include "srp.h" @@ -80,9 +78,6 @@ static ErlNifFunc nif_funcs[] = { {"cmac_nif", 3, cmac_nif, 0}, {"cipher_info_nif", 1, cipher_info_nif, 0}, {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0}, - {"aes_ctr_stream_init", 2, aes_ctr_stream_init, 0}, - {"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt, 0}, - {"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt, 0}, {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0}, {"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0}, {"ng_crypto_one_shot_nif", 5, ng_crypto_one_shot_nif, 0}, @@ -91,8 +86,6 @@ static ErlNifFunc nif_funcs[] = { {"rand_uniform_nif", 2, rand_uniform_nif, 0}, {"mod_exp_nif", 4, mod_exp_nif, 0}, {"do_exor", 2, do_exor, 0}, - {"rc4_set_key", 1, rc4_set_key, 0}, - {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state, 0}, {"pkey_sign_nif", 5, pkey_sign_nif, 0}, {"pkey_verify_nif", 6, pkey_verify_nif, 0}, {"pkey_crypt_nif", 6, pkey_crypt_nif, 0}, @@ -114,10 +107,6 @@ static ErlNifFunc nif_funcs[] = { {"aead_encrypt", 6, aead_encrypt, 0}, {"aead_decrypt", 6, aead_decrypt, 0}, - {"chacha20_stream_init", 2, chacha20_stream_init, 0}, - {"chacha20_stream_encrypt", 2, chacha20_stream_crypt, 0}, - {"chacha20_stream_decrypt", 2, chacha20_stream_crypt, 0}, - {"poly1305_nif", 2, poly1305_nif, 0}, {"engine_by_id_nif", 1, engine_by_id_nif, 0}, diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 96213fa6e6..608610f85e 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -50,14 +50,9 @@ -export([rand_seed/1]). %% Experiment --export([crypto_init/4, +-export([crypto_init/4, crypto_init/3, crypto_init/2, crypto_update/2, - crypto_one_shot/5, - - %% Emulates old api: - crypto_stream_init/2, crypto_stream_init/3, - crypto_stream_encrypt/2, - crypto_stream_decrypt/2 + crypto_one_shot/5 ]). @@ -633,9 +628,11 @@ next_iv(des_cfb, Data, IVec) -> next_iv(Type, Data, _Ivec) -> next_iv(Type, Data). -%%%---- Stream ciphers +%%%-------- Stream ciphers API --opaque stream_state() :: {stream_cipher(), reference()}. +-opaque stream_state() :: {stream_cipher(), + crypto_state() | {crypto_state(),flg_undefined} + }. -type stream_cipher() :: stream_cipher_iv() | stream_cipher_no_iv() . -type stream_cipher_no_iv() :: rc4 . @@ -645,47 +642,67 @@ next_iv(Type, Data, _Ivec) -> | aes_256_ctr | chacha20 . --spec stream_init(Type, Key, IVec) -> State when Type :: stream_cipher_iv(), - Key :: iodata(), - IVec :: binary(), - State :: stream_state() . -stream_init(aes_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}; -stream_init(aes_128_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}; -stream_init(aes_192_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}; -stream_init(aes_256_ctr, Key, Ivec) -> - {aes_ctr, aes_ctr_stream_init(Key, Ivec)}; -stream_init(chacha20, Key, Ivec) -> - {chacha20, chacha20_stream_init(Key,Ivec)}. - --spec stream_init(Type, Key) -> State when Type :: stream_cipher_no_iv(), - Key :: iodata(), - State :: stream_state() . -stream_init(rc4, Key) -> - {rc4, notsup_to_error(rc4_set_key(Key))}. - --spec stream_encrypt(State, PlainText) -> {NewState, CipherText} +%%%---- stream_init +-spec stream_init(Type, Key, IVec) -> State | no_return() + when Type :: stream_cipher_iv(), + Key :: iodata(), + IVec :: binary(), + State :: stream_state() . +stream_init(Type, Key, IVec) when is_binary(IVec) -> + case crypto_init(Type, Key, IVec) of + {ok,Ref} -> + {Type, {Ref,flg_undefined}}; + {error,_} -> + error(badarg) + end. + + +-spec stream_init(Type, Key) -> State | no_return() + when Type :: stream_cipher_no_iv(), + Key :: iodata(), + State :: stream_state() . +stream_init(rc4 = Type, Key) -> + case crypto_init(Type, Key, undefined) of + {ok,Ref} -> + {Type, {Ref,flg_undefined}}; + {error,_} -> + error(badarg) + end. + +%%%---- stream_encrypt +-spec stream_encrypt(State, PlainText) -> {NewState, CipherText} | no_return() 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, []). +stream_encrypt(State, Data) -> + crypto_stream_emulate(State, Data, true). --spec stream_decrypt(State, CipherText) -> {NewState, PlainText} +%%%---- stream_decrypt +-spec stream_decrypt(State, CipherText) -> {NewState, PlainText} | no_return() 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, []). +stream_decrypt(State, Data) -> + crypto_stream_emulate(State, Data, false). + +%%%-------- helpers +crypto_stream_emulate({Cipher,{Ref,flg_undefined}}, Data, EncryptFlag) when is_reference(Ref) -> + case crypto_init(Ref, EncryptFlag) of + {error,_} -> + error(badarg); + MaybeNewRef when is_reference(MaybeNewRef) -> + crypto_stream_emulate({Cipher,MaybeNewRef}, Data, EncryptFlag) + end; +crypto_stream_emulate({Cipher,Ref}, Data, _) when is_reference(Ref) -> + case crypto_update(Ref, Data) of + {error,_} -> + error(badarg); + Bin when is_binary(Bin) -> + {{Cipher,Ref},Bin} + end. %%%================================================================ %%% @@ -1789,59 +1806,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 ------------------------------------------------------------------- @@ -2214,7 +2179,7 @@ check_otp_test_engine(LibDir) -> %%% -> {ok,State::ref()} | {error,Reason} --opaque crypto_state() :: reference() | {any(),any(),any(),any()}. +-opaque crypto_state() :: reference() . %%%---------------------------------------------------------------- @@ -2222,32 +2187,64 @@ check_otp_test_engine(LibDir) -> %%% Create and initialize a new state for encryption or decryption %%% --spec crypto_init(Cipher, Key, IV, EncryptFlag) -> {ok,State} | {error,term()} | undefined +-spec crypto_init(Cipher, Key, IV, EncryptFlag) -> {ok,State} | {error,term()} when Cipher :: stream_cipher() | block_cipher_with_iv() - | block_cipher_without_iv() , + | block_cipher_without_iv(), Key :: iodata(), - IV :: iodata(), - EncryptFlag :: boolean() | undefined, + IV :: iodata() | undefined, + EncryptFlag :: boolean(), State :: crypto_state() . +crypto_init(Cipher, Key, undefined, EncryptFlag) -> + crypto_init(Cipher, Key, <<>>, EncryptFlag); crypto_init(Cipher, Key, IV, EncryptFlag) -> - case ng_crypto_init_nif(alias(Cipher), + case ng_crypto_init_nif(alias(Cipher), iolist_to_binary(Key), iolist_to_binary(IV), EncryptFlag) of - {error,Error} -> - {error,Error}; - undefined -> % For compatibility function crypto_stream_init/3 - undefined; Ref when is_reference(Ref) -> {ok,Ref}; - State when is_tuple(State), - size(State)==4 -> - {ok,State} % compatibility with old cryptolibs < 1.0.1 + {error,Error} -> + {error,Error} + end. + + +-spec crypto_init(Cipher, Key, IV) -> {ok,State} | {error,term()} + when Cipher :: stream_cipher() + | block_cipher_with_iv() + | block_cipher_without_iv(), + Key :: iodata(), + IV :: iodata() | undefined, + State :: crypto_state() . +crypto_init(Cipher, Key, undefined) -> + crypto_init(Cipher, Key, <<>>); + +crypto_init(Cipher, Key, IV) when is_atom(Cipher) -> + case ng_crypto_init_nif(alias(Cipher), + iolist_to_binary(Key), + iolist_to_binary(IV), + undefined) of + Ref when is_reference(Ref) -> + {ok,Ref}; + {error,Error} -> + {error,Error} end. +-spec crypto_init(Ref, EncryptFlag) -> crypto_state() | {error,term()} + when Ref :: crypto_state(), + EncryptFlag :: boolean() . + +crypto_init(Ref, EncryptFlag) when is_reference(Ref), + is_atom(EncryptFlag) -> + case ng_crypto_init_nif(Ref, <<>>, <<>>, EncryptFlag) of + {error,Error} -> + {error,Error}; + R when is_reference(R) -> + R + end. + %%%---------------------------------------------------------------- %%% %%% Encrypt/decrypt a sequence of bytes. The sum of the sizes @@ -2255,10 +2252,10 @@ crypto_init(Cipher, Key, IV, EncryptFlag) -> %%% blocksize. %%% --spec crypto_update(State, Data) -> {ok,Result} | {error,term()} +-spec crypto_update(State, Data) -> Result | {error,term()} when State :: crypto_state(), Data :: iodata(), - Result :: binary() | {crypto_state(),binary()}. + Result :: binary() . crypto_update(State, Data0) -> case iolist_to_binary(Data0) of <<>> -> @@ -2267,19 +2264,12 @@ crypto_update(State, Data0) -> ng_crypto_update_nif(State, Data) end. -%%%---------------------------------------------------------------- -%%% NIFs - -ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlg) -> ?nif_stub. - -%% _Data MUST be binary() -ng_crypto_update_nif(_State, _Data) -> ?nif_stub. - -%% _Data MUST be binary() -ng_crypto_one_shot_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub. -%%%================================================================ -%%% Compatibility functions to be called by "old" api functions. +%%%---------------------------------------------------------------- +%%% +%%% Encrypt/decrypt one set bytes. +%%% The size must be an integer multiple of the crypto's blocksize. +%%% crypto_one_shot(Cipher, Key, IV, Data0, EncryptFlag) -> case iolist_to_binary(Data0) of @@ -2289,51 +2279,23 @@ crypto_one_shot(Cipher, Key, IV, Data0, EncryptFlag) -> ng_crypto_one_shot_nif(Cipher, iolist_to_binary(Key), iolist_to_binary(IV), Data, EncryptFlag) end. -%%%-------------------------------- -%%%---- stream init, encrypt/decrypt - -crypto_stream_init(Cipher, Key) -> - crypto_stream_init(Cipher, Key, <<>>). - -crypto_stream_init(Cipher, Key0, IV0) -> - Key = iolist_to_binary(Key0), - IV = iolist_to_binary(IV0), - %% First check the argumensts: - case crypto_init(Cipher, Key, IV, undefined) of - undefined -> - {Cipher, {Key, IV}}; - {error,_} -> - {error,badarg} - end. - -crypto_stream_encrypt(State, PlainText) -> - crypto_stream_emulate(State, PlainText, true). - -crypto_stream_decrypt(State, CryptoText) -> - crypto_stream_emulate(State, CryptoText, false). +%%%---------------------------------------------------------------- +%%% NIFs +ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlg) -> ?nif_stub. -%%%---- helper -crypto_stream_emulate({Cipher,{Key,IV}}, Data, EncryptFlag) -> - case crypto_init(Cipher, Key, IV, EncryptFlag) of - {ok,State} -> - crypto_stream_emulate({Cipher,State}, Data, EncryptFlag); - {error,_} -> - error(badarg) - end; -crypto_stream_emulate({Cipher,State}, Data, _) -> - case crypto_update(State, Data) of - {ok, {State1,Bin}} when is_binary(Bin) -> {{Cipher,State1},Bin}; - {ok,Bin} when is_binary(Bin) -> {{Cipher,State},Bin}; - {error,_} -> error(badarg) - end. +%% _Data MUST be binary() +ng_crypto_update_nif(_State, _Data) -> ?nif_stub. -%%%================================================================ +%% _Data MUST be binary() +ng_crypto_one_shot_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub. +%%%---------------------------------------------------------------- +%%% Cipher aliases +%%% prepend_cipher_aliases(L) -> [des3_cbc, des_ede3, des_ede3_cbf, des3_cbf, des3_cfb, aes_cbc128, aes_cbc256 | L]. - %%%---- des_ede3_cbc alias(des3_cbc) -> des_ede3_cbc; alias(des_ede3) -> des_ede3_cbc; |