跳到主要内容

2.4 The ChaCha20 Encryption Algorithm (ChaCha20 加密算法)

2.4 The ChaCha20 Encryption Algorithm (ChaCha20 加密算法)

ChaCha20 是由 D. J. Bernstein 设计的流密码。它是 Salsa20 算法的改进版本, 使用 256 位密钥。

ChaCha20 连续调用 ChaCha20 块函数, 使用相同的密钥和 nonce, 以及连续递增的块计数器参数。然后 ChaCha20 通过以小端顺序写入数字来序列化生成的状态, 创建一个密钥流块。将来自连续块的密钥流块连接起来形成密钥流。然后 ChaCha20 函数对此密钥流与明文执行 XOR 操作。或者, 可以在继续创建下一个块之前将每个密钥流块与明文块进行 XOR 操作, 从而节省一些内存。对明文没有要求必须是 512 位的整数倍。如果最后一个块有额外的密钥流, 则将其丢弃。特定协议可能要求明文和密文具有特定长度。此类协议需要指定如何填充明文以及接收多少填充。

ChaCha20 的输入包括:

  • 一个 256 位密钥

  • 一个 32 位初始计数器。这可以设置为任何数字, 但通常为零或一。如果我们将零块用于其他用途, 例如作为 AEAD 算法的一部分生成一次性认证器密钥, 则使用一是有意义的。

  • 一个 96 位 nonce。在某些协议中, 这被称为初始化向量 (Initialization Vector)。

  • 任意长度的明文

输出是相同长度的加密消息或"密文"。

解密以相同的方式完成。ChaCha20 块函数用于将密钥扩展为密钥流, 该密钥流与密文进行 XOR 操作以返回明文。

2.4.1 The ChaCha20 Encryption Algorithm in Pseudocode (伪代码中的 ChaCha20 加密算法)

chacha20_encrypt(key, counter, nonce, plaintext):
for j = 0 upto floor(len(plaintext)/64)-1
key_stream = chacha20_block(key, counter+j, nonce)
block = plaintext[(j*64)..(j*64+63)]
encrypted_message += block ^ key_stream
end
if ((len(plaintext) % 64) != 0)
j = floor(len(plaintext)/64)
key_stream = chacha20_block(key, counter+j, nonce)
block = plaintext[(j*64)..len(plaintext)-1]
encrypted_message += (block^key_stream)[0..len(plaintext)%64]
end
return encrypted_message
end

2.4.2 Example and Test Vector for the ChaCha20 Cipher (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.

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

  • Initial Counter = 1.

我们使用以下内容作为明文。选择它的长度足以需要多于一个块, 但又不至于使此示例变得繁琐 (因此, 少于 3 个块):

Plaintext Sunscreen: (明文防晒霜)

000  4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c  Ladies and Gentl
016 65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73 emen of the clas
032 73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63 s of '99: If I c
048 6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f ould offer you o
064 6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20 nly one tip for
080 74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73 the future, suns
096 63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69 creen would be i
112 74 2e t.

下图显示了四个 ChaCha 状态矩阵:

  1. 设置后的第一个块。

  2. 设置后的第二个块。请注意, 这些块仅相差两位 -- 仅位置 12 的计数器不同。

  3. 第三个块是应用 ChaCha20 块操作后的第一个块。

  4. 最后一个块是应用 ChaCha20 块操作后的第二个块。

之后, 我们显示密钥流。

First block setup: (第一块设置)

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

Second block setup: (第二块设置)

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

First block after block operation: (块操作后的第一块)

    f3514f22  e1d91b40  6f27de2f  ed1d63b8
821f138c e2062c3d ecca4f7e 78cff39e
a30a3b8a 920a6072 cd7479b5 34932bed
40ba4c79 cd343ec6 4c2c21ea b7417df0

Second block after block operation: (块操作后的第二块)

    9f74a669  410f633f  28feca22  7ec44dec
6d34d426 738cb970 3ac5e9f3 45590cc4
da6e8b39 892c831a cdea67c1 2b7e1d90
037463f3 a11a2073 e8bcfb88 edc49139

Keystream: (密钥流)

22:4f:51:f3:40:1b:d9:e1:2f:de:27:6f:b8:63:1d:ed:8c:13:1f:82:3d:2c:06
e2:7e:4f:ca:ec:9e:f3:cf:78:8a:3b:0a:a3:72:60:0a:92:b5:79:74:cd:ed:2b
93:34:79:4c:ba:40:c6:3e:34:cd:ea:21:2c:4c:f0:7d:41:b7:69:a6:74:9f:3f
63:0f:41:22:ca:fe:28:ec:4d:c4:7e:26:d4:34:6d:70:b9:8c:73:f3:e9:c5:3a
c4:0c:59:45:39:8b:6e:da:1a:83:2c:89:c1:67:ea:cd:90:1d:7e:2b:f3:63

最后, 我们对密钥流和明文进行 XOR 操作, 得到密文:

Ciphertext Sunscreen: (密文防晒霜)

000  6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81  n.5.%h..A..(..i.
016 e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b .~z..C`..'......
032 f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57 ..e.RG3..Y=..b.W
048 16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8 .9.$.QR..S.5..a.
064 07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e ....P.jaV....".^
080 52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36 R.QM.........y76
096 5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42 Z...t.[......x^B
112 87 4d .M