148 lines
5.0 KiB
Nix
148 lines
5.0 KiB
Nix
{
|
|
authData ? [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ],
|
|
counter ? [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ],
|
|
key,
|
|
text
|
|
}:
|
|
let
|
|
inherit(builtins) bitAnd bitXor concatStringsSep elemAt foldl' map trace deepSeq stringLength substring;
|
|
inherit(import ./ascii.nix) toDWords hex;
|
|
encryptAES = import ./aes.nix;
|
|
|
|
trace'
|
|
= x: trace (deepSeq x x);
|
|
|
|
traceHex
|
|
= value:
|
|
trace' (map hex value);
|
|
|
|
key' = toDWords key;
|
|
counter' = toDWords counter;
|
|
encryptChunk = encryptAES key';
|
|
|
|
shift1 = 256;
|
|
shift2 = 256 * 256;
|
|
shift3 = 256 * 256 * 256;
|
|
|
|
byteAt
|
|
= dword:
|
|
index:
|
|
if index == 0 then bitAnd dword 255
|
|
else if index == 1 then bitAnd (dword / shift1) 255
|
|
else if index == 2 then bitAnd (dword / shift2) 255
|
|
else if index == 3 then dword / shift3
|
|
else null;
|
|
|
|
H = encryptChunk [ 0 0 0 0 ];
|
|
|
|
max = 256 * 256 * 256 * 256 - 1;
|
|
increment
|
|
= counter:
|
|
let
|
|
a = elemAt counter 0;
|
|
b = elemAt counter 1;
|
|
c = elemAt counter 2;
|
|
d = elemAt counter 3;
|
|
|
|
inc
|
|
= value:
|
|
let
|
|
a = byteAt value 0;
|
|
b = byteAt value 1;
|
|
c = byteAt value 2;
|
|
d = byteAt value 3;
|
|
in
|
|
if d == 255
|
|
then
|
|
if c == 255
|
|
then
|
|
if b == 255
|
|
then
|
|
if a == 255
|
|
then
|
|
{ value = 0; carry = true; }
|
|
else
|
|
{ value = bitAnd value (shift1 - 1) + 1; carry = false; }
|
|
else
|
|
{ value = bitAnd value (shift2 - 1) + shift1; carry = false; }
|
|
else
|
|
{ value = bitAnd value (shift3 - 1) + shift2; carry = false; }
|
|
else
|
|
{ value = value + shift3; carry = false; };
|
|
|
|
a' = inc a;
|
|
b' = inc b;
|
|
c' = inc c;
|
|
d' = inc d;
|
|
in
|
|
if !d'.carry then [ a b c d'.value ]
|
|
else if !c'.carry then [ a b c'.value 0 ]
|
|
else if !b'.carry then [ a b'.value 0 0 ]
|
|
else if !a'.carry then [ a'.value 0 0 0 ]
|
|
else [ 0 0 0 0 ];
|
|
|
|
multiply
|
|
= authData:
|
|
[ 0 0 0 0 ]; # ghash
|
|
|
|
encrypted
|
|
= foldl'
|
|
(
|
|
{ auth, authData, cipherText, counter, index, key }:
|
|
plain:
|
|
let
|
|
auth'
|
|
= if index == 3
|
|
then
|
|
elemAt (multiply authData)
|
|
else
|
|
auth;
|
|
authData'
|
|
= if index == 3
|
|
then
|
|
[]
|
|
else
|
|
authData;
|
|
counter'
|
|
= if index == 3
|
|
then
|
|
increment counter
|
|
else
|
|
counter;
|
|
index'
|
|
= if index == 3
|
|
then
|
|
0
|
|
else
|
|
index + 1;
|
|
key'
|
|
= if index == 3
|
|
then
|
|
elemAt (encryptChunk counter)
|
|
else
|
|
key;
|
|
cipher = bitXor plain ( key' index' );
|
|
in
|
|
# trace "${hex plain} ^ ${hex (key' index')} = ${hex cipher}"
|
|
{
|
|
auth = auth';
|
|
authData = authData ++ [ (bitXor cipher (auth' index')) ];
|
|
cipherText = cipherText ++ [ cipher ];
|
|
counter = counter';
|
|
index = index';
|
|
key = key';
|
|
}
|
|
)
|
|
{
|
|
auth = elemAt (toDWords authData);
|
|
authData = [];
|
|
cipherText = [];
|
|
counter = counter';
|
|
index = 3;
|
|
key = null;
|
|
}
|
|
(toDWords text);
|
|
in
|
|
# traceHex key'
|
|
substring 0 (stringLength text) (concatStringsSep "" (map hex encrypted.cipherText))
|