aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2019-03-07 12:19:18 +0100
committerHans Nilsson <[email protected]>2019-03-19 12:45:54 +0100
commitcd08c844693fbb26d545f9cd981bfa9ae2d08042 (patch)
treec2d1395e95d4ea0710884b9ab9ff61614af2ac18
parentc209e1ecc6aac833b8a1d5da86d86ca04c7d7085 (diff)
downloadotp-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.c54
-rw-r--r--lib/crypto/c_src/crypto.c11
-rw-r--r--lib/crypto/src/crypto.erl278
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;