2.3 The ChaCha20 Block Function (La funzione di blocco ChaCha20)
2.3 The ChaCha20 Block Function (La funzione di blocco ChaCha20)
La funzione di blocco ChaCha trasforma uno stato ChaCha eseguendo più quarti di round.
Gli input per ChaCha20 sono:
-
Una chiave di 256 bit, trattata come concatenazione di otto interi little-endian a 32 bit.
-
Un nonce di 96 bit, trattato come concatenazione di tre interi little-endian a 32 bit.
-
Un parametro contatore di blocchi a 32 bit, trattato come intero little-endian a 32 bit.
L'output è di 64 byte dall'aspetto casuale.
L'algoritmo ChaCha descritto qui utilizza una chiave a 256 bit. L'algoritmo originale specificava anche chiavi a 128 bit e varianti a 8 e 12 round, ma queste sono al di fuori dello scopo di questo documento. In questa sezione descriviamo la funzione di blocco ChaCha.
Notare inoltre che il ChaCha originale aveva un nonce a 64 bit e un contatore di blocchi a 64 bit. Abbiamo modificato questo qui per essere più coerenti con le raccomandazioni nella Sezione 3.2 di [RFC5116]. Questo limita l'uso di una singola combinazione (chiave,nonce) a 2^32 blocchi, o 256 GB, ma questo è sufficiente per la maggior parte degli usi. Nei casi in cui una singola chiave viene utilizzata da più mittenti, è importante assicurarsi che non utilizzino gli stessi nonce. Questo può essere garantito partizionando lo spazio dei nonce in modo che i primi 32 bit siano univoci per mittente, mentre gli altri 64 bit provengono da un contatore.
Lo stato ChaCha20 è inizializzato come segue:
-
Le prime quattro parole (0-3) sono costanti: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574.
-
Le successive otto parole (4-11) sono prese dalla chiave a 256 bit leggendo i byte in ordine little-endian, in blocchi di 4 byte.
-
La parola 12 è un contatore di blocchi. Poiché ogni blocco è di 64 byte, una parola a 32 bit è sufficiente per 256 gigabyte di dati.
-
Le parole 13-15 sono un nonce, che NON DEVE essere ripetuto per la stessa chiave. La 13ª parola è i primi 32 bit del nonce di input presi come intero little-endian, mentre la 15ª parola è gli ultimi 32 bit.
cccccccc cccccccc cccccccc cccccccc
kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
bbbbbbbb nnnnnnnn nnnnnnnn nnnnnnnn
c=constant k=key b=blockcount n=nonce
ChaCha20 esegue 20 round, alternando tra "round di colonna" e "round diagonali". Ogni round consiste di quattro quarti di round, e vengono eseguiti come segue. I quarti di round 1-4 fanno parte di un round di "colonna", mentre 5-8 fanno parte di un round "diagonale":
QUARTERROUND(0, 4, 8, 12)
QUARTERROUND(1, 5, 9, 13)
QUARTERROUND(2, 6, 10, 14)
QUARTERROUND(3, 7, 11, 15)
QUARTERROUND(0, 5, 10, 15)
QUARTERROUND(1, 6, 11, 12)
QUARTERROUND(2, 7, 8, 13)
QUARTERROUND(3, 4, 9, 14)
Alla fine di 20 round (o 10 iterazioni dell'elenco sopra), aggiungiamo le parole di input originali alle parole di output e serializziamo il risultato disponendo le parole una per una in ordine little-endian.
Nota: l'"addizione" nel paragrafo sopra viene eseguita modulo 2^32. In alcuni linguaggi macchina, questo è chiamato addizione senza riporto su una parola a 32 bit.
2.3.1 The ChaCha20 Block Function in Pseudocode (La funzione di blocco ChaCha20 in pseudocodice)
Nota: Questa sezione e alcune altre contengono pseudocodice per l'algoritmo spiegato in una sezione precedente. È stato fatto ogni sforzo affinché lo pseudocodice rifletta accuratamente l'algoritmo come descritto nella sezione precedente. Se è ancora presente un conflitto, la spiegazione testuale e i vettori di test sono normativi.
inner_block (state):
Qround(state, 0, 4, 8, 12)
Qround(state, 1, 5, 9, 13)
Qround(state, 2, 6, 10, 14)
Qround(state, 3, 7, 11, 15)
Qround(state, 0, 5, 10, 15)
Qround(state, 1, 6, 11, 12)
Qround(state, 2, 7, 8, 13)
Qround(state, 3, 4, 9, 14)
end
chacha20_block(key, counter, nonce):
state = constants | key | counter | nonce
initial_state = state
for i=1 upto 10
inner_block(state)
end
state += initial_state
return serialize(state)
end
Dove il carattere pipe ("|") denota la concatenazione.
2.3.2 Test Vector for the ChaCha20 Block Function (Vettore di test per la funzione di blocco ChaCha20)
Per un vettore di test, useremo i seguenti input per la funzione di blocco ChaCha20:
-
Key = 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f. La chiave è una sequenza di ottetti senza struttura particolare prima di copiarla nello stato ChaCha.
-
Nonce = (00:00:00:09:00:00:00:4a:00:00:00:00)
-
Block Count = 1.
Dopo aver impostato lo stato ChaCha, appare così:
ChaCha state with the key setup. (Stato ChaCha con configurazione della chiave)
61707865 3320646e 79622d32 6b206574
03020100 07060504 0b0a0908 0f0e0d0c
13121110 17161514 1b1a1918 1f1e1d1c
00000001 09000000 4a000000 00000000
Dopo aver eseguito 20 round (10 round di colonna intercalati con 10 "round diagonali"), lo stato ChaCha appare così:
ChaCha state after 20 rounds (Stato ChaCha dopo 20 round)
837778ab e238d763 a67ae21e 5950bb2f
c4f2d0c7 fc62bb2f 8fa018fc 3f5ec7b7
335271c2 f29489f3 eabda8fc 82e46ebd
d19c12b4 b04e16de 9e83d0cb 4e3c50a2
Infine, aggiungiamo lo stato originale al risultato (semplice addizione vettoriale o matriciale), ottenendo questo:
ChaCha state at the end of the ChaCha20 operation (Stato ChaCha alla fine dell'operazione ChaCha20)
e4e7f110 15593bd1 1fdd0f50 c47120a3
c7f4d1c7 0368c033 9aaa2204 4e6cd4c3
466482d2 09aa9f07 05d7c214 a2028bd9
d19c12b5 b94e16de e883d0cb 4e3c50a2
Dopo aver serializzato lo stato, otteniamo questo:
Serialized Block: (Blocco serializzato)
000 10 f1 e7 e4 d1 3b 59 15 50 0f dd 1f a3 20 71 c4 .....;Y.P.... q.
016 c7 d1 f4 c7 33 c0 68 03 04 22 aa 9a c3 d4 6c 4e ....3.h.."....lN
032 d2 82 64 46 07 9f aa 09 14 c2 d7 05 d9 8b 02 a2 ..dF............
048 b5 12 9c d1 de 16 4e b9 cb d0 83 e8 a2 50 3c 4e ......N......P<N