View Source jose_xchacha20_poly1305_crypto (JOSE v1.11.10)
Summary
Functions
Short example of why this works: HChaCha20 = ChaCha20 - State0
Types
-type chacha20_key() :: <<_:256>>.
-type chacha20_nonce() :: <<_:96>>.
-type hchacha20_block() :: <<_:256>>.
-type hchacha20_nonce() :: <<_:128>>.
-type poly1305_otk() :: <<_:256>>.
-type xchacha20_nonce() :: <<_:192>>.
Functions
-spec hchacha20(Key :: chacha20_key(), Nonce :: hchacha20_nonce()) -> hchacha20_block().
Short example of why this works: HChaCha20 = ChaCha20 - State0
Longer example of why this works:
K = 256-bit key
C = 32-bit counter
N = 96-bit nonce
X = 128-bit nonce
|| = concatenation
++ = 32-bit word little endian addition
-- = 32-bit word little endian subtraction
ChaCha20(K, C, N) =
State0 = "expand 32-byte k" || K || C || N
State1 = Rounds(State0, 10)
State2 = State1 ++ State2
return State2
HChaCha20(K, X) =
State0 = "expand 32-byte k" || K || X
State1 = Rounds(State0, 10)
return FirstBits(State1, 128) || LastBits(State1, 128)
# Let's rewrite HChaCha20 to use ChaCha20 with State0 subtraction:
HChaCha20(K, X) =
C = FirstBits(X, 32)
N = LastBits(X, 96)
State0 = "expand 32-byte k" || K || X
State2 = ChaCha20(K, C, N)
State1 = State2 -- State0
return FirstBits(State1, 128) || LastBits(State1, 128)
# Let's further reduce to not use K and use a Mask for blinding:
HChaCha20(K, X) =
Mask = CSPRNG(512)
C = FirstBits(X, 32)
N = LastBits(X, 96)
KeyStream = ChaCha20(K, C, N) ^ Mask
State2 = (FirstBits(KeyStream, 128) || LastBits(KeyStream, 128)) ^
(FirstBits(Mask, 128) || LastBits(Mask, 128))
State0 = "expand 32-byte k" || X
State1 = State2 -- State0
return State1
See: https://tools.ietf.org/html/rfc7539#section-2.3
See: https://tools.ietf.org/html/draft-irtf-cfrg-xchacha-03#section-2.2
-spec poly1305_key_gen(Key :: chacha20_key(), Nonce :: chacha20_nonce()) -> poly1305_otk().
-spec xchacha20_subkey_and_nonce(Key :: chacha20_key(), Nonce :: xchacha20_nonce()) -> {chacha20_key(), chacha20_nonce()}.