Zum Hauptinhalt springen

2.3 The ChaCha20 Block Function (Die ChaCha20-Blockfunktion)

2.3 The ChaCha20 Block Function (Die ChaCha20-Blockfunktion)

Die ChaCha-Blockfunktion transformiert einen ChaCha-Zustand durch Ausführen mehrerer Viertelrunden.

Die Eingaben für ChaCha20 sind:

  • Ein 256-Bit-Schlüssel, behandelt als Verkettung von acht 32-Bit-Little-Endian-Ganzzahlen.

  • Eine 96-Bit-Nonce, behandelt als Verkettung von drei 32-Bit-Little-Endian-Ganzzahlen.

  • Ein 32-Bit-Blockzählerparameter, behandelt als 32-Bit-Little-Endian-Ganzzahl.

Die Ausgabe sind 64 zufällig aussehende Bytes.

Der hier beschriebene ChaCha-Algorithmus verwendet einen 256-Bit-Schlüssel. Der ursprüngliche Algorithmus spezifizierte auch 128-Bit-Schlüssel und Varianten mit 8 und 12 Runden, aber diese liegen außerhalb des Umfangs dieses Dokuments. In diesem Abschnitt beschreiben wir die ChaCha-Blockfunktion.

Beachten Sie auch, dass das ursprüngliche ChaCha eine 64-Bit-Nonce und einen 64-Bit-Blockzähler hatte. Wir haben dies hier geändert, um konsistenter mit den Empfehlungen in Abschnitt 3.2 von [RFC5116] zu sein. Dies begrenzt die Verwendung einer einzelnen (Schlüssel,Nonce)-Kombination auf 2^32 Blöcke oder 256 GB, aber das ist für die meisten Anwendungen ausreichend. In Fällen, in denen ein einzelner Schlüssel von mehreren Sendern verwendet wird, ist es wichtig sicherzustellen, dass sie nicht dieselben Nonces verwenden. Dies kann durch Partitionierung des Nonce-Raums gewährleistet werden, sodass die ersten 32 Bits pro Sender eindeutig sind, während die anderen 64 Bits von einem Zähler stammen.

Der ChaCha20-Zustand wird wie folgt initialisiert:

  • Die ersten vier Wörter (0-3) sind Konstanten: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574.

  • Die nächsten acht Wörter (4-11) werden aus dem 256-Bit-Schlüssel entnommen, indem die Bytes in Little-Endian-Reihenfolge in 4-Byte-Blöcken gelesen werden.

  • Wort 12 ist ein Blockzähler. Da jeder Block 64 Byte groß ist, reicht ein 32-Bit-Wort für 256 Gigabyte Daten aus.

  • Die Wörter 13-15 sind eine Nonce, die für denselben Schlüssel NICHT wiederholt werden DARF. Das 13. Wort sind die ersten 32 Bits der Eingabe-Nonce als Little-Endian-Ganzzahl, während das 15. Wort die letzten 32 Bits sind.

    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 führt 20 Runden aus und wechselt zwischen "Spaltenrunden" und "Diagonalrunden" ab. Jede Runde besteht aus vier Viertelrunden, und sie werden wie folgt ausgeführt. Die Viertelrunden 1-4 sind Teil einer "Spalten"-Runde, während 5-8 Teil einer "Diagonal"-Runde sind:

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)

Am Ende von 20 Runden (oder 10 Iterationen der obigen Liste) addieren wir die ursprünglichen Eingabewörter zu den Ausgabewörtern und serialisieren das Ergebnis, indem wir die Wörter nacheinander in Little-Endian-Reihenfolge anordnen.

Hinweis: Die "Addition" im obigen Absatz erfolgt modulo 2^32. In einigen Maschinensprachen wird dies als übertragslose Addition auf einem 32-Bit-Wort bezeichnet.

2.3.1 The ChaCha20 Block Function in Pseudocode (Die ChaCha20-Blockfunktion in Pseudocode)

Hinweis: Dieser Abschnitt und einige andere enthalten Pseudocode für den in einem vorherigen Abschnitt erklärten Algorithmus. Es wurde jede Anstrengung unternommen, damit der Pseudocode den Algorithmus, wie er im vorherigen Abschnitt beschrieben ist, genau widerspiegelt. Wenn noch ein Konflikt besteht, sind die textuelle Erklärung und die Testvektoren normativ.

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

Wobei das Pipe-Zeichen ("|") die Verkettung bezeichnet.

2.3.2 Test Vector for the ChaCha20 Block Function (Testvektor für die ChaCha20-Blockfunktion)

Für einen Testvektor verwenden wir die folgenden Eingaben für die ChaCha20-Blockfunktion:

  • 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. Der Schlüssel ist eine Sequenz von Oktetten ohne besondere Struktur, bevor wir ihn in den ChaCha-Zustand kopieren.

  • Nonce = (00:00:00:09:00:00:00:4a:00:00:00:00)

  • Block Count = 1.

Nach dem Einrichten des ChaCha-Zustands sieht er so aus:

ChaCha state with the key setup. (ChaCha-Zustand mit Schlüsseleinrichtung)

    61707865  3320646e  79622d32  6b206574
03020100 07060504 0b0a0908 0f0e0d0c
13121110 17161514 1b1a1918 1f1e1d1c
00000001 09000000 4a000000 00000000

Nach dem Ausführen von 20 Runden (10 Spaltenrunden verschachtelt mit 10 "Diagonalrunden") sieht der ChaCha-Zustand so aus:

ChaCha state after 20 rounds (ChaCha-Zustand nach 20 Runden)

    837778ab  e238d763  a67ae21e  5950bb2f
c4f2d0c7 fc62bb2f 8fa018fc 3f5ec7b7
335271c2 f29489f3 eabda8fc 82e46ebd
d19c12b4 b04e16de 9e83d0cb 4e3c50a2

Schließlich addieren wir den ursprünglichen Zustand zum Ergebnis (einfache Vektor- oder Matrixaddition), was dies ergibt:

ChaCha state at the end of the ChaCha20 operation (ChaCha-Zustand am Ende der ChaCha20-Operation)

    e4e7f110  15593bd1  1fdd0f50  c47120a3
c7f4d1c7 0368c033 9aaa2204 4e6cd4c3
466482d2 09aa9f07 05d7c214 a2028bd9
d19c12b5 b94e16de e883d0cb 4e3c50a2

Nach der Serialisierung des Zustands erhalten wir dies:

Serialized Block: (Serialisierter Block)

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