This is an automated email from the ASF dual-hosted git repository. rnewson pushed a commit to branch database_encryption in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 9b6a0dc6ca2596bf15cd7bc062411571d671e433 Author: Robert Newson <[email protected]> AuthorDate: Mon May 23 17:35:17 2022 +0100 erlang 20-21 compatibility... probably --- src/aegis/src/aegis_cmac.erl | 20 ++++++++---------- src/aegis/src/aegis_compat.hrl | 42 ++++++++++++++++++++++++++++++++++++++ src/aegis/src/aegis_siv.erl | 10 +++------ src/aegis/src/aegis_util.erl | 10 +++++---- src/couch/src/couch_file.erl | 46 ++++++++++++++++++++++++++++++++++-------- 5 files changed, 97 insertions(+), 31 deletions(-) diff --git a/src/aegis/src/aegis_cmac.erl b/src/aegis/src/aegis_cmac.erl index 9f1f05fcd..1ba73415e 100644 --- a/src/aegis/src/aegis_cmac.erl +++ b/src/aegis/src/aegis_cmac.erl @@ -14,34 +14,30 @@ -export([cmac/2]). +-include("aegis_compat.hrl"). + cmac(Key, Message) -> cmac(Key, <<0:128>>, Message). cmac(Key, X, <<Last:16/binary>>) -> {K1, _K2} = generate_subkeys(Key), - crypto:crypto_one_time(cmac_cipher(Key), Key, crypto:exor(X, crypto:exor(Last, K1)), true); + ?block_encrypt(?ecb(Key), Key, crypto:exor(X, crypto:exor(Last, K1))); cmac(Key, X, <<Block:16/binary, Rest/binary>>) -> - cmac(Key, crypto:crypto_one_time(cmac_cipher(Key), Key, crypto:exor(X, Block), true), Rest); + cmac(Key, ?block_encrypt(?ecb(Key), Key, crypto:exor(X, Block)), Rest); cmac(Key, X, Last) -> {_K1, K2} = generate_subkeys(Key), - crypto:crypto_one_time( - cmac_cipher(Key), + ?block_encrypt( + ?ecb(Key), Key, - crypto:exor(X, crypto:exor(aegis_util:pad(Last), K2)), - true + crypto:exor(X, crypto:exor(aegis_util:pad(Last), K2)) ). generate_subkeys(Key) -> - L = crypto:crypto_one_time(cmac_cipher(Key), Key, <<0:128>>, true), + L = ?block_encrypt(?ecb(Key), Key, <<0:128>>), K1 = aegis_util:double(L), K2 = aegis_util:double(K1), {K1, K2}. -cmac_cipher(Key) when bit_size(Key) == 128 -> - aes_128_ecb; -cmac_cipher(Key) when bit_size(Key) == 256 -> - aes_256_ecb. - -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). diff --git a/src/aegis/src/aegis_compat.hrl b/src/aegis/src/aegis_compat.hrl new file mode 100644 index 000000000..9de05eb27 --- /dev/null +++ b/src/aegis/src/aegis_compat.hrl @@ -0,0 +1,42 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +%% Assume old crypto api + +-define(block_encrypt(Cipher, Key, Data), crypto:block_encrypt(Cipher, Key, Data)). + +-define(stream_encrypt(Cipher, Key, IVec, Data), element(2, crypto:stream_encrypt(crypto:stream_init(Cipher, Key, IVec), Data))). + +-define(ecb(Key), aes_ecb). + +-define(ctr(Key), aes_ctr). + +%% Replace macros if new crypto api is available +-ifdef(OTP_RELEASE). +-if(?OTP_RELEASE >= 22). + +-undef(block_encrypt). +-define(block_encrypt(Cipher, Key, Data), crypto:crypto_one_time(Cipher, Key, Data, true)). + +-undef(stream_encrypt). +-define(stream_encrypt(Cipher, Key, IVec, Data), crypto:crypto_one_time(Cipher, Key, IVec, Data, true)). + +-undef(ecb). +-define(ecb(Key), case bit_size(Key) of + 128 -> aes_128_ecb; 192 -> aes_192_ecb; 256 -> aes_256_ecb end). + +-undef(ctr). +-define(ctr(Key), case bit_size(Key) of + 128 -> aes_128_ctr; 192 -> aes_192_ctr; 256 -> aes_256_ctr end). + +-endif. +-endif. \ No newline at end of file diff --git a/src/aegis/src/aegis_siv.erl b/src/aegis/src/aegis_siv.erl index efe3a1809..83d3b69ea 100644 --- a/src/aegis/src/aegis_siv.erl +++ b/src/aegis/src/aegis_siv.erl @@ -14,6 +14,8 @@ -export([block_encrypt/3, block_decrypt/3]). +-include("aegis_compat.hrl"). + -spec block_encrypt(binary(), list(), binary()) -> {binary(), binary()}. block_encrypt(Key, AAD, PlainText) when bit_size(Key) == 256; bit_size(Key) == 512 @@ -44,13 +46,7 @@ split(Key) -> {K1, K2}. aes_ctr(Key, IV, Data) -> - Cipher = ctr_cipher(Key), - crypto:crypto_one_time(Cipher, Key, IV, Data, true). - -ctr_cipher(Key) when bit_size(Key) == 128 -> - aes_128_ctr; -ctr_cipher(Key) when bit_size(Key) == 256 -> - aes_256_ctr. + ?stream_encrypt(?ctr(Key), Key, IV, Data). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). diff --git a/src/aegis/src/aegis_util.erl b/src/aegis/src/aegis_util.erl index ec60338c3..7303b67e4 100644 --- a/src/aegis/src/aegis_util.erl +++ b/src/aegis/src/aegis_util.erl @@ -19,6 +19,8 @@ xorend/2 ]). +-include("aegis_compat.hrl"). + %% @doc double %% is the multiplication of S and 0...010 in the finite field %% represented using the primitive polynomial @@ -36,10 +38,10 @@ double(<<1:1, Lo:127>>) -> %% threshold of 256. expand(Key) when bit_size(Key) == 256 -> %% expansion technique from Bjoern Tackmann - IBM Zurich - K0 = crypto:crypto_one_time(aes_256_ecb, Key, <<0:128>>, true), - K1 = crypto:crypto_one_time(aes_256_ecb, Key, <<1:128>>, true), - K2 = crypto:crypto_one_time(aes_256_ecb, Key, <<2:128>>, true), - K3 = crypto:crypto_one_time(aes_256_ecb, Key, <<3:128>>, true), + K0 = ?block_encrypt(?ecb(Key), Key, <<0:128>>), + K1 = ?block_encrypt(?ecb(Key), Key, <<1:128>>), + K2 = ?block_encrypt(?ecb(Key), Key, <<2:128>>), + K3 = ?block_encrypt(?ecb(Key), Key, <<3:128>>), <<K0/binary, K1/binary, K2/binary, K3/binary>>. %% @doc pad diff --git a/src/couch/src/couch_file.erl b/src/couch/src/couch_file.erl index 801b98b3a..2e2ef4c7e 100644 --- a/src/couch/src/couch_file.erl +++ b/src/couch/src/couch_file.erl @@ -48,10 +48,27 @@ db_monitor, pread_limit = 0, iv, + key, enc, dec }). +-define(init_ciphers(File, DataEncryptionKey, IV), init_ciphers_20(File, DataEncryptionKey, IV)). +-define(encrypt(File, Pos, Data), encrypt_20(File, Pos, Data)). +-define(decrypt(File, Pos, Data), decrypt_20(File, Pos, Data)). +-ifdef(OTP_RELEASE). +-if(?OTP_RELEASE >= 22). +-undef(init_ciphers). +-define(init_ciphers(File, DataEncryptionKey, IV), init_ciphers_22(File, DataEncryptionKey, IV)). + +-undef(encrypt). +-define(encrypt(File, Pos, Data), encrypt_22(File, Pos, Data)). + +-undef(decrypt). +-define(decrypt(File, Pos, Data), decrypt_22(File, Pos, Data)). +-endif. +-endif. + % public API -export([open/1, open/2, close/1, bytes/1, sync/1, truncate/2, set_db_pid/2]). -export([pread_term/2, pread_iolist/2, pread_binary/2]). @@ -937,7 +954,7 @@ init_crypto(#file{eof = 0} = File0) -> case write_encryption_header(File0, WrappedKey, IV) of {ok, File1} -> ok = file:sync(File1#file.fd), - {ok, init_ciphers(File1, DataEncryptionKey, IV)}; + {ok, ?init_ciphers(File1, DataEncryptionKey, IV)}; {error, Reason} -> {error, Reason} end; @@ -950,7 +967,7 @@ init_crypto(#file{eof = Pos, enc = undefined, dec = undefined} = File) when Pos {ok, WrappedKey, IV} -> case aegis_key_manager:unwrap_key(WrappedKey) of {ok, DataEncryptionKey} -> - {ok, init_ciphers(File, DataEncryptionKey, IV)}; + {ok, ?init_ciphers(File, DataEncryptionKey, IV)}; {error, Reason} -> {error, Reason} end; @@ -960,7 +977,12 @@ init_crypto(#file{eof = Pos, enc = undefined, dec = undefined} = File) when Pos {error, Reason} end. -init_ciphers(#file{} = File, DataEncryptionKey, IV) when +init_ciphers_20(#file{} = File, DataEncryptionKey, IV) when + is_binary(DataEncryptionKey), is_binary(IV) +-> + File#file{iv = crypto:bytes_to_integer(IV), key = DataEncryptionKey}. + +init_ciphers_22(#file{} = File, DataEncryptionKey, IV) when is_binary(DataEncryptionKey), is_binary(IV) -> EncState = crypto:crypto_dyn_iv_init(aes_256_ctr, DataEncryptionKey, true), @@ -1005,7 +1027,7 @@ read_encryption_header(#file{} = File) -> encrypted_write(#file{enc = undefined} = File, Data) -> file:write(File#file.fd, Data); encrypted_write(#file{} = File, Data) -> - CipherText = encrypt(File#file.enc, File#file.iv, File#file.eof, pad(File#file.eof, Data)), + CipherText = ?encrypt(File, File#file.eof, pad(File#file.eof, Data)), file:write(File#file.fd, unpad(File#file.eof, CipherText)). encrypted_pread(#file{dec = undefined} = File, LocNums) -> @@ -1016,7 +1038,7 @@ encrypted_pread(#file{} = File, LocNums) -> {ok, lists:zipwith( fun({Pos, _Len}, CipherText) -> - PlainText = decrypt(File#file.dec, File#file.iv, Pos, pad(Pos, CipherText)), + PlainText = ?decrypt(File, Pos, pad(Pos, CipherText)), unpad(Pos, PlainText) end, LocNums, @@ -1031,16 +1053,24 @@ encrypted_pread(#file{dec = undefined} = File, Pos, Len) -> encrypted_pread(#file{} = File, Pos, Len) -> case file:pread(File#file.fd, Pos, Len) of {ok, CipherText} -> - PlainText = decrypt(File#file.dec, File#file.iv, Pos, pad(Pos, CipherText)), + PlainText = ?decrypt(File, Pos, pad(Pos, CipherText)), {ok, unpad(Pos, PlainText)}; Else -> Else end. -encrypt(Enc, IV, Pos, Data) -> +encrypt_20(#file{key = Key, iv = IV}, Pos, Data) -> + State = crypto:stream_init(aes_ctr, Key, aes_ctr(IV, Pos)), + crypto:stream_encrypt(State, Data). + +decrypt_20(#file{key = Key, iv = IV}, Pos, Data) -> + State = crypto:stream_init(aes_ctr, Key, aes_ctr(IV, Pos)), + crypto:stream_decrypt(State, Data). + +encrypt_22(#file{enc = Enc, iv = IV}, Pos, Data) -> crypto:crypto_dyn_iv_update(Enc, Data, aes_ctr(IV, Pos)). -decrypt(Dec, IV, Pos, Data) -> +decrypt_22(#file{dec = Dec, iv = IV}, Pos, Data) -> crypto:crypto_dyn_iv_update(Dec, Data, aes_ctr(IV, Pos)). aes_ctr(IV, Pos) ->
