Current section

Files

Jump to
ca src aes_kw.erl
Raw

src/aes_kw.erl

-module(aes_kw).
-export([wrap/2]).
-export([wrap/3]).
-export([unwrap/2]).
-export([unwrap/3]).
-export([test/0]).
-define(MSB64, 1/unsigned-big-integer-unit:64).
-define(DEFAULT_IV, << 16#A6A6A6A6A6A6A6A6:?MSB64 >>).
wrap(PlainText, KEK) -> wrap(PlainText, KEK, ?DEFAULT_IV).
wrap(PlainText, KEK, IV)
when (byte_size(PlainText) rem 8) =:= 0
andalso (bit_size(KEK) =:= 128
orelse bit_size(KEK) =:= 192
orelse bit_size(KEK) =:= 256) ->
Buffer = << IV/binary, PlainText/binary >>,
BlockCount = (byte_size(Buffer) div 8) - 1,
do_wrap(Buffer, 0, BlockCount, KEK).
unwrap(CipherText, KEK) -> unwrap(CipherText, KEK, ?DEFAULT_IV).
unwrap(CipherText, KEK, IV)
when (byte_size(CipherText) rem 8) =:= 0
andalso (bit_size(KEK) =:= 128
orelse bit_size(KEK) =:= 192
orelse bit_size(KEK) =:= 256) ->
BlockCount = (byte_size(CipherText) div 8) - 1,
IVSize = byte_size(IV),
case do_unwrap(CipherText, 5, BlockCount, KEK) of
<< IV:IVSize/binary, PlainText/binary >> ->
PlainText;
_ ->
erlang:error({badarg, [CipherText, KEK, IV]})
end.
do_wrap(Buffer, 6, _BlockCount, _KEK) -> Buffer;
do_wrap(Buffer, J, BlockCount, KEK) -> do_wrap(do_wrap(Buffer, J, 1, BlockCount, KEK), J + 1, BlockCount, KEK).
codec(128) -> aes_128_ecb;
codec(192) -> aes_192_ecb;
codec(256) -> aes_256_ecb.
do_wrap(Buffer, _J, I, BlockCount, _KEK) when I > BlockCount -> Buffer;
do_wrap(<< A0:8/binary, Rest/binary >>, J, I, BlockCount, KEK) ->
HeadSize = (I - 1) * 8,
<< Head:HeadSize/binary, B0:8/binary, Tail/binary >> = Rest,
Round = (BlockCount * J) + I,
Data = << A0/binary, B0/binary >>,
<< A1:?MSB64, B1/binary >> = crypto:crypto_one_time(codec(bit_size(KEK)), KEK, <<>>, Data, [{encrypt,true}]),
A2 = A1 bxor Round,
do_wrap(<< A2:?MSB64, Head/binary, B1/binary, Tail/binary >>, J, I + 1, BlockCount, KEK).
do_unwrap(Buffer, J, _BlockCount, _KEK) when J < 0 -> Buffer;
do_unwrap(Buffer, J, BlockCount, KEK) -> do_unwrap(do_unwrap(Buffer, J, BlockCount, BlockCount, KEK), J - 1, BlockCount, KEK).
do_unwrap(Buffer, _J, I, _BlockCount, _KEK) when I < 1 -> Buffer;
do_unwrap(<< A0:?MSB64, Rest/binary >>, J, I, BlockCount, KEK) ->
HeadSize = (I - 1) * 8,
<< Head:HeadSize/binary, B0:8/binary, Tail/binary >> = Rest,
Round = (BlockCount * J) + I,
A1 = A0 bxor Round,
Data = << A1:?MSB64, B0/binary >>,
<< A2:8/binary, B1/binary >> = crypto:crypto_one_time(codec(bit_size(KEK)), KEK, ?DEFAULT_IV, Data, [{encrypt,false}]),
do_unwrap(<< A2/binary, Head/binary, B1/binary, Tail/binary >>, J, I - 1, BlockCount, KEK).
test() ->
KEK = << 16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:1/unsigned-big-integer-unit:256 >>,
KeyData = << 16#00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F:1/unsigned-big-integer-unit:256 >>,
CipherText = << 16#28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21:2/unsigned-big-integer-unit:160 >>,
CipherText = wrap(KeyData, KEK),
KeyData = unwrap(CipherText, KEK),
true.