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) ->

Reply via email to