You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2020/03/25 17:16:46 UTC

[couchdb] branch couch-keywrap created (now c62ac44)

This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a change to branch couch-keywrap
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


      at c62ac44  Implement AES KW algorithm*

This branch includes the following new commits:

     new c62ac44  Implement AES KW algorithm*

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb] 01/01: Implement AES KW algorithm*

Posted by rn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a commit to branch couch-keywrap
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit c62ac441a10abeb544343261f738b74bf0567e54
Author: Robert Newson <rn...@apache.org>
AuthorDate: Wed Mar 25 17:08:35 2020 +0000

    Implement AES KW algorithm*
    
    For use by the native couchdb at-rest encryption feature.
    
    * From NIST Special Publication 800-38F.
---
 src/couch/src/couch_keywrap.erl | 82 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/src/couch/src/couch_keywrap.erl b/src/couch/src/couch_keywrap.erl
new file mode 100644
index 0000000..828adf2
--- /dev/null
+++ b/src/couch/src/couch_keywrap.erl
@@ -0,0 +1,82 @@
+-module(couch_keywrap).
+
+%% Implementation of NIST Special Publication 800-38F
+%% For wrapping and unwrapping 256 bit values only.
+
+-export([key_wrap/2, key_unwrap/2]).
+
+-define(ICV1, 16#A6A6A6A6A6A6A6A6).
+
+%% Assume old crypto api
+-define(aes_256_ecb_encrypt(Key, Data),
+        crypto:block_encrypt(aes_256_ecb, Key, Data)).
+-define(aes_256_ecb_decrypt(Key, Data),
+        crypto:block_decrypt(aes_256_ecb, Key, Data)).
+
+%% Replace macros if new crypto api is available
+-ifdef(OTP_RELEASE).
+-if(?OTP_RELEASE >= 22).
+-undef(aes_256_ecb_encrypt).
+-define(aes_256_ecb_encrypt(Key, Data),
+        crypto:crypto_one_time(aes_256_ecb, Key, Data, true)).
+-undef(aes_256_ecb_decrypt).
+-define(aes_256_ecb_decrypt(Key, Data),
+        crypto:crypto_one_time(aes_256_ecb, Key, Data, false)).
+-endif.
+-endif.
+
+-spec key_wrap(WrappingKey :: <<_:256>>, KeyToWrap :: <<_:256>>) -> <<_:320>>.
+key_wrap(WrappingKey, KeyToWrap)
+  when bit_size(WrappingKey) == 256, bit_size(KeyToWrap) == 256 ->
+    wrap(WrappingKey, <<?ICV1:64>>, KeyToWrap, 1).
+
+wrap(_WrappingKey, A, R, 25) ->
+    <<A/binary, R/binary>>;
+wrap(WrappingKey, A, R, T) ->
+    <<R1: 64, R2: 64, R3: 64, R4: 64>> = R,
+    <<MSB_B:64, LSB_B:64>> = ?aes_256_ecb_encrypt(WrappingKey, <<A/binary, R1:64>>),
+    wrap(WrappingKey, <<(MSB_B bxor T):64>>, <<R2:64, R3:64, R4:64, LSB_B:64>>, T + 1).
+
+
+-spec key_unwrap(WrappingKey :: <<_:256>>, KeyToUnwrap :: <<_:320>>) -> <<_:256>> | fail.
+key_unwrap(WrappingKey, KeyToUnwrap)
+  when bit_size(WrappingKey) == 256, bit_size(KeyToUnwrap) == 320 ->
+    <<A:64, R:256>> = KeyToUnwrap,
+    case unwrap(WrappingKey, <<A:64>>, <<R:256>>, 24) of
+        <<?ICV1:64, UnwrappedKey/binary>> ->
+            UnwrappedKey;
+        _ ->
+            fail
+    end.
+
+unwrap(_WrappingKey, A, R, 0) ->
+    <<A/binary, R/binary>>;
+unwrap(WrappingKey, A, R, T) ->
+    <<R1: 64, R2: 64, R3: 64, R4: 64>> = R,
+    <<AN:64>> = A,
+    <<MSB_B:64, LSB_B:64>> = ?aes_256_ecb_decrypt(WrappingKey, <<(AN bxor T):64, R4:64>>),
+    unwrap(WrappingKey, <<MSB_B:64>>, <<LSB_B:64, R1:64, R2:64, R3:64>>, T - 1).
+
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+wrap_test() ->
+    KEK = <<16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:256>>,
+    KeyData = <<16#00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F:256>>,
+    CipherText = <<16#28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21:320>>,
+    ?assertEqual(CipherText, key_wrap(KEK, KeyData)).
+
+unwrap_test() ->
+    KEK = <<16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:256>>,
+    KeyData = <<16#00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F:256>>,
+    CipherText = <<16#28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21:320>>,
+    ?assertEqual(KeyData, key_unwrap(KEK, CipherText)).
+
+fail_test() ->
+    KEK = <<16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:256>>,
+    KeyData = <<16#00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F:256>>,
+    CipherText = <<16#28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD20:320>>,
+    ?assertEqual(fail, key_unwrap(KEK, CipherText)).
+
+-endif.