diff options
author | Eric Avdey <eiri@eiri.ca> | 2020-03-04 18:28:54 -0400 |
---|---|---|
committer | Eric Avdey <eiri@eiri.ca> | 2020-04-07 02:33:18 -0300 |
commit | e4af159a4e5ffe40b883c341d939fc4650efcf61 (patch) | |
tree | ee384fcc888c2e0d5fcc34439ea339d5602e1636 | |
parent | 72a3b5f6ef0dfc2e967ef00033af38b1ad5287bb (diff) | |
download | couchdb-e4af159a4e5ffe40b883c341d939fc4650efcf61.tar.gz |
Don't block encryption server on encode/decode operations
-rw-r--r-- | src/fabric/src/fabric2_encryption.erl | 97 |
1 files changed, 80 insertions, 17 deletions
diff --git a/src/fabric/src/fabric2_encryption.erl b/src/fabric/src/fabric2_encryption.erl index 5d8d389bc..6f8a488d3 100644 --- a/src/fabric/src/fabric2_encryption.erl +++ b/src/fabric/src/fabric2_encryption.erl @@ -32,6 +32,12 @@ ]). +-export([ + do_encode/5, + do_decode/5 +]). + + -define(INIT_TIMEOUT, 60000). -define(LABEL, "couchdb-aes256-gcm-encryption-key"). @@ -74,29 +80,51 @@ terminate(_, _St) -> ok. -handle_call({encode, DbName, DocId, DocRev, DocBody}, _From, St) -> - #{iid := InstanceId} = St, - {ok, AAD} = get_aad(InstanceId, DbName), - {ok, DEK} = get_dek(DbName, DocId, DocRev), - {CipherText, CipherTag} = crypto:crypto_one_time_aead( - aes_256_gcm, DEK, <<0:96>>, DocBody, AAD, 16, true), - Encoded = <<CipherTag/binary, CipherText/binary>>, - {reply, {ok, Encoded}, St}; +handle_call({encode, DbName, DocId, DocRev, DocBody}, From, St) -> + #{ + iid := InstanceId, + waiters := Waiters + } = St, + + {Pid, _Ref} = erlang:spawn_monitor(?MODULE, + do_encode, [InstanceId, DbName, DocId, DocRev, DocBody]), + + NewSt = St#{ + waiters := dict:store(Pid, From, Waiters) + }, + {noreply, NewSt}; + +handle_call({decode, DbName, DocId, DocRev, Encoded}, From, St) -> + #{ + iid := InstanceId, + waiters := Waiters + } = St, -handle_call({decode, DbName, DocId, DocRev, Encoded}, _From, St) -> - #{iid := InstanceId} = St, - {ok, AAD} = get_aad(InstanceId, DbName), - {ok, DEK} = get_dek(DbName, DocId, DocRev), - <<CipherTag:16/binary, CipherText/binary>> = Encoded, - DocBody = crypto:crypto_one_time_aead( - aes_256_gcm, DEK, <<0:96>>, CipherText, AAD, CipherTag, false), - {reply, {ok, DocBody}, St}. + {Pid, _Ref} = erlang:spawn_monitor(?MODULE, + do_decode, [InstanceId, DbName, DocId, DocRev, Encoded]), + + NewSt = St#{ + waiters := dict:store(Pid, From, Waiters) + }, + {noreply, NewSt}. handle_cast(Msg, St) -> {stop, {bad_cast, Msg}, St}. +handle_info({'DOWN', _, _, Pid, Resp}, #{waiters := Waiters} = St) -> + case dict:take(Pid, Waiters) of + {From, Waiters1} -> + gen_server:reply(From, Resp), + NewSt = St#{ + waiters := Waiters1 + }, + {noreply, NewSt}; + error -> + {noreply, St} + end; + handle_info(timeout, St) -> {stop, normal, St}. @@ -108,7 +136,42 @@ code_change(_OldVsn, St, _Extra) -> init_st() -> FdbDirs = fabric2_server:fdb_directory(), - {ok, #{iid => iolist_to_binary(FdbDirs)}}. + {ok, #{ + iid => iolist_to_binary(FdbDirs), + waiters => dict:new() + }}. + + +do_encode(InstanceId, DbName, DocId, DocRev, DocBody) -> + try + {ok, AAD} = get_aad(InstanceId, DbName), + {ok, DEK} = get_dek(DbName, DocId, DocRev), + {CipherText, CipherTag} = crypto:crypto_one_time_aead( + aes_256_gcm, DEK, <<0:96>>, DocBody, AAD, 16, true), + <<CipherTag/binary, CipherText/binary>> + of + Resp -> + exit({ok, Resp}) + catch + _:Error -> + exit({error, Error}) + end. + + +do_decode(InstanceId, DbName, DocId, DocRev, Encoded) -> + try + <<CipherTag:16/binary, CipherText/binary>> = Encoded, + {ok, AAD} = get_aad(InstanceId, DbName), + {ok, DEK} = get_dek(DbName, DocId, DocRev), + crypto:crypto_one_time_aead( + aes_256_gcm, DEK, <<0:96>>, CipherText, AAD, CipherTag, false) + of + Resp -> + exit({ok, Resp}) + catch + _:Error -> + exit({error, Error}) + end. get_aad(InstanceId, DbName) when is_binary(InstanceId), is_binary(DbName) -> |