enoise/src/enoise_cipher_state.erl
Ulf Wiger 479ec70870 Update enacl dep and fix some minor details (#1)
Co-authored-by: Ulf Wiger <ulf@wiger.net>
Reviewed-on: #1
2025-03-08 00:28:12 +09:00

83 lines
2.7 KiB
Erlang

%%% ------------------------------------------------------------------
%%% @copyright 2018, Aeternity Anstalt
%%%
%%% @doc Module encapsulating a Noise Cipher state
%%%
%%% @end
%%% ------------------------------------------------------------------
-module(enoise_cipher_state).
-export([ cipher/1
, decrypt_with_ad/3
, encrypt_with_ad/3
, has_key/1
, init/2
, key/1
, rekey/1
, set_key/2
, set_nonce/2
]).
-include("enoise.hrl").
-type noise_cipher() :: 'ChaChaPoly' | 'AESGCM'.
-type nonce() :: non_neg_integer().
-type key() :: empty | binary().
-record(noise_cs, { k = empty :: key()
, n = 0 :: nonce()
, cipher = 'ChaChaPoly' :: noise_cipher() }).
-opaque state() :: #noise_cs{}.
-export_type([noise_cipher/0, state/0]).
-spec init(Key :: key(), Cipher :: noise_cipher()) -> state().
init(Key, Cipher) ->
#noise_cs{ k = Key, n = 0, cipher = Cipher }.
-spec set_key(CState :: state(), NewKey :: key()) -> state().
set_key(CState, NewKey) ->
CState#noise_cs{ k = NewKey, n = 0 }.
-spec has_key(CState :: state()) -> boolean().
has_key(#noise_cs{ k = Key }) ->
Key =/= empty.
-spec set_nonce(CState :: state(), NewNonce :: nonce()) -> state().
set_nonce(CState = #noise_cs{}, Nonce) ->
CState#noise_cs{ n = Nonce }.
-spec encrypt_with_ad(CState :: state(), AD :: binary(), PlainText :: binary()) ->
{ok, state(), binary()} | {error, term()}.
encrypt_with_ad(CState = #noise_cs{ k = empty }, _AD, PlainText) ->
{ok, CState, PlainText};
encrypt_with_ad(CState = #noise_cs{ k = K, n = N, cipher = Cipher }, AD, PlainText) ->
Encrypted = enoise_crypto:encrypt(Cipher, K, N, AD, PlainText),
{ok, CState#noise_cs{ n = N+1 }, Encrypted}.
-spec decrypt_with_ad(CState :: state(), AD :: binary(), CipherText :: binary()) ->
{ok, state(), binary()} | {error, term()}.
decrypt_with_ad(CState = #noise_cs{ k = empty }, _AD, CipherText) ->
{ok, CState, CipherText};
decrypt_with_ad(CState = #noise_cs{ k = K, n = N, cipher = Cipher }, AD, CipherText) ->
case enoise_crypto:decrypt(Cipher, K, N, AD, CipherText) of
PlainText when is_binary(PlainText) ->
{ok, CState#noise_cs{ n = N+1 }, PlainText};
Err = {error, _} ->
Err
end.
-spec rekey(CState :: state()) -> state().
rekey(CState = #noise_cs{ k = K, cipher = Cipher }) ->
CState#noise_cs{ k = enoise_crypto:rekey(Cipher, K) }.
-spec cipher(CState :: state()) -> noise_cipher().
cipher(#noise_cs{ cipher = Cipher }) ->
Cipher.
-spec key(CState :: state()) -> key().
key(#noise_cs{ k = K }) ->
K.