2.3 The ChaCha20 Block Function (ChaCha20 块函数)
2.3 The ChaCha20 Block Function (ChaCha20 块函数)
ChaCha 块函数通过运行多个四分之一轮来转换 ChaCha 状态。
ChaCha20 的输入包括:
-
一个 256 位密钥, 被视为八个 32 位小端整数的连接。
-
一个 96 位 nonce, 被视为三个 32 位小端整数的连接。
-
一个 32 位块计数参数, 被视为 32 位小端整数。
输出是 64 个看似随机的字节。
这里描述的 ChaCha 算法使用 256 位密钥。原始算法还指定了 128 位密钥以及 8 轮和 12 轮变体, 但这些超出了本文档的范围。在本节中, 我们描述 ChaCha 块函数。
还要注意, 原始 ChaCha 有 64 位 nonce 和 64 位块计数。我们在此处对其进行了修改, 以更符合 [RFC5116] 第 3.2 节中的建议。这将单个 (key,nonce) 组合的使用限制为 2^32 块, 或 256 GB, 但这对于大多数用途来说已经足够了。在多个发送方使用单个密钥的情况下, 确保它们不使用相同的 nonce 非常重要。这可以通过分区 nonce 空间来保证, 使前 32 位对每个发送方都是唯一的, 而其他 64 位来自计数器。
ChaCha20 状态初始化如下:
-
前四个字 (0-3) 是常量: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574。
-
接下来的八个字 (4-11) 从 256 位密钥中获取, 以小端顺序按 4 字节块读取字节。
-
字 12 是块计数器。由于每个块是 64 字节, 32 位字足以处理 256 GB 的数据。
-
字 13-15 是 nonce, 对于相同的密钥绝对不能重复。第 13 个字是输入 nonce 的前 32 位, 作为小端整数, 而第 15 个字是最后 32 位。
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 运行 20 轮, 在"列轮次"和"对角轮次"之间交替。每一轮由四个四分之一轮组成, 按如下方式运行。四分之一轮 1-4 是"列"轮的一部分, 而 5-8 是"对角"轮的一部分:
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)
在 20 轮结束时 (或上述列表的 10 次迭代), 我们将原始输入字添加到输出字, 并通过以小端顺序逐个排列字来序列化结果。
注意: 上述段落中的"加法"是模 2^32 完成的。在某些机器语言中, 这被称为 32 位字上的无进位加法。
2.3.1 The ChaCha20 Block Function in Pseudocode (伪代码中的 ChaCha20 块函数)
注意: 本节和其他几节包含前一节中解释的算法的伪代码。我们尽一切努力使伪代码准确反映前一节中描述的算法。如果仍然存在冲突, 则文本说明和测试向量是规范的。
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
其中管道字符 ("|") 表示连接。
2.3.2 Test Vector for the ChaCha20 Block Function (ChaCha20 块函数的测试向量)
对于测试向量, 我们将使用以下输入到 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。在我们将密钥复制到 ChaCha 状态之前, 密钥是一系列没有特定结构的八位字节。
-
Nonce = (00:00:00:09:00:00:00:4a:00:00:00:00)
-
Block Count = 1。
设置 ChaCha 状态后, 它看起来像这样:
ChaCha state with the key setup. (密钥设置后的 ChaCha 状态)
61707865 3320646e 79622d32 6b206574
03020100 07060504 0b0a0908 0f0e0d0c
13121110 17161514 1b1a1918 1f1e1d1c
00000001 09000000 4a000000 00000000
运行 20 轮 (10 个列轮次与 10 个"对角轮次"交错) 后, ChaCha 状态看起来像这样:
ChaCha state after 20 rounds (20 轮后的 ChaCha 状态)
837778ab e238d763 a67ae21e 5950bb2f
c4f2d0c7 fc62bb2f 8fa018fc 3f5ec7b7
335271c2 f29489f3 eabda8fc 82e46ebd
d19c12b4 b04e16de 9e83d0cb 4e3c50a2
最后, 我们将原始状态添加到结果 (简单的向量或矩阵加法), 得到:
ChaCha state at the end of the ChaCha20 operation (ChaCha20 操作结束时的 ChaCha 状态)
e4e7f110 15593bd1 1fdd0f50 c47120a3
c7f4d1c7 0368c033 9aaa2204 4e6cd4c3
466482d2 09aa9f07 05d7c214 a2028bd9
d19c12b5 b94e16de e883d0cb 4e3c50a2
序列化状态后, 我们得到:
Serialized 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