Skip to content

Commit 6aaf5c0

Browse files
committed
Implement HChaCha20 from ChaCha20-IETF
1 parent d87f506 commit 6aaf5c0

1 file changed

Lines changed: 38 additions & 52 deletions

File tree

draft-denis-dprive-dnscrypt.md

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -308,81 +308,67 @@ This document has no IANA actions.
308308

309309
The `Box-XChaChaPoly` algorithm combines the `X25519` {{!RFC7748}} key exchange mechanism with a variant of the ChaCha20-Poly1305 construction specified in {{!RFC8439}}.
310310

311-
## HChaCha20
311+
## Conventions and Definitions
312312

313-
`HChaCha20` is an intermediate step based on the construction and security proof used to create `XSalsa20`, an extended-nonce Salsa20 variant.
313+
- `x[a..]`: the subarray of `x` starting at index `a`, and extending to the last index of `x`
314+
- `x[a..b]`: the subarray of `x` starting at index `a` and ending at index `b`.
315+
- `LOAD32_LE(p)`: returns a 32-bit unsigned integer from the 4-byte array `p`
316+
- `STORE32_LE(p, x)`: stores the 32-bit unsigned integer `x` into the 4-byte array `p`
314317

315-
`HChaCha20` is initialized in the same way as the ChaCha20 cipher defined in {{!RFC8439}}, except that `HChaCha20` uses a 128-bit nonce and has no counter. Instead, the block counter is replaced by the first 32 bits of the nonce.
318+
## HChaCha20
316319

317-
Consider the two figures below, where each non-whitespace character represents one nibble of information about the ChaCha states (all numbers little-endian):
320+
`HChaCha20` is based on the construction and security proof used to create XSalsa20, an extended-nonce variant of Salsa20.
318321

319-
~~~
320-
cccccccc cccccccc cccccccc cccccccc
321-
kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
322-
kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
323-
bbbbbbbb nnnnnnnn nnnnnnnn nnnnnnnn
322+
The `HChaCha20` function takes the following input paramters:
324323

325-
ChaCha20 State: c=constant k=key b=blockcount n=nonce
324+
- `<k>`: secret key
325+
- `<in>`: a 128-bit input
326326

327+
and returns a 256-bit keyed hash.
327328

328-
cccccccc cccccccc cccccccc cccccccc
329-
kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
330-
kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
331-
nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn
329+
The function can be implemented using an existing IETF-compliant `ChaCha20` implementation as follows:
332330

333-
HChaCha20 State: c=constant k=key n=nonce
334331
~~~
335-
336-
After initialization, proceed through the ChaCha rounds as usual. Once the 20 ChaCha rounds have been completed, the first 128 bits and last 128 bits of the ChaCha state (both little-endian) are concatenated, and this 256-bit subkey is returned.
337-
338-
## Test Vector For The HChaCha20 Block Function
339-
332+
block_bytes = ChaCha20(msg={0}**64, nonce=in[4..16],
333+
counter=LOAD32_LE(in[0..4]), key=k)
334+
335+
block_out[0] = LOAD32_LE(block_bytes[ 0..][0..4]) - 0x61707865
336+
block_out[1] = LOAD32_LE(block_bytes[ 4..][0..4]) - 0x3320646e
337+
block_out[2] = LOAD32_LE(block_bytes[ 8..][0..4]) - 0x79622d32
338+
block_out[3] = LOAD32_LE(block_bytes[12..][0..4]) - 0x6b206574
339+
block_out[4] =
340+
LOAD32_LE(block_bytes[48..][0..4]) - LOAD32_LE(in[ 0..][0..4])
341+
block_out[5] =
342+
LOAD32_LE(block_bytes[52..][0..4]) - LOAD32_LE(in[ 4..][0..4])
343+
block_out[6] =
344+
LOAD32_LE(block_bytes[56..][0..4]) - LOAD32_LE(in[ 8..][0..4])
345+
block_out[7] =
346+
LOAD32_LE(block_bytes[60..][0..4]) - LOAD32_LE(in[12..][0..4])
347+
348+
for i in 0..8:
349+
STORE32_LE(out[i * 4..][0..4], blocks_out[i])
350+
351+
return out
340352
~~~
341-
o Key = 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:
342-
14:15:16:17:18:19:1a:1b:1c:1d:1e:1f. The key is a sequence of
343-
octets with no particular structure before we copy it into the
344-
HChaCha state.
345-
346-
o Nonce = (00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27)
347353

348-
After setting up the HChaCha state, it looks like this:
349-
350-
61707865 3320646e 79622d32 6b206574
351-
03020100 07060504 0b0a0908 0f0e0d0c
352-
13121110 17161514 1b1a1918 1f1e1d1c
353-
09000000 4a000000 00000000 27594131
354-
355-
ChaCha state with the key setup.
356-
357-
After running 20 rounds (10 column rounds interleaved with 10
358-
"diagonal rounds"), the HChaCha state looks like this:
359-
360-
423b4182 fe7bb227 50420ed3 737d878a
361-
0aa76448 7954cdf3 846acd37 7b3c58ad
362-
77e35583 83e77c12 e0076a2d bc6cd0e5
363-
d5e4f9a0 53a8748a 13c42ec1 dcecd326
364-
365-
HChaCha state after 20 rounds
354+
## Test Vector For The HChaCha20 Block Function
366355

367-
HChaCha20 will then return only the first and last rows, in little
368-
endian, resulting in the following 256-bit key:
356+
~~~ test-vectors
357+
k: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
369358

370-
82413b42 27b27bfe d30e4250 8a877d73
371-
a0f9e4d5 8a74a853 c12ec413 26d3ecdc
359+
in: 000102030405060708090a0b0c0d0e0f
372360

373-
Resultant HChaCha20 subkey
361+
out: 51e3ff45a895675c4b33b46c64f4a9ace110d34df6a2ceab486372bacbd3eff6
374362
~~~
375363

376364
## ChaCha20_DJB
377365

378-
ChaCha20 was originally designed to have a 8 byte nonce.
366+
As opposed to the version standardized for IETF protocols, ChaCha20 was originally designed to have a 8 byte nonce.
379367

380368
For the needs of TLS, {{!RFC8439}} changed this by setting `N_MIN` and `N_MAX` to `12`, at the expense of a smaller internal counter.
381369

382370
DNSCrypt uses ChaCha20 as originally specified, with `N_MIN = N_MAX = 8`. We refer to this variant as `ChaCha20_DJB`.
383371

384-
Common implementations may just refer to it as `ChaCha20`, and the IETF version as `ChaCha20-IETF`.
385-
386372
The internal counter in `ChaCha20_DJB` is 4 bytes larger than `ChaCha20`. There are no other differences between `ChaCha20_DJB` and `ChaCha20`.
387373

388374
## XChaCha20_DJB

0 commit comments

Comments
 (0)