Line data Source code
1 : // Copyright (c) 2017 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : // Based on the public domain implementation 'merged' by D. J. Bernstein
6 : // See https://cr.yp.to/chacha.html.
7 :
8 : #include "crypto/common.h"
9 : #include "crypto/chacha20.h"
10 :
11 : #include <string.h>
12 :
13 148379500 : constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
14 :
15 : #define QUARTERROUND(a,b,c,d) \
16 : a += b; d = rotl32(d ^ a, 16); \
17 : c += d; b = rotl32(b ^ c, 12); \
18 : a += b; d = rotl32(d ^ a, 8); \
19 : c += d; b = rotl32(b ^ c, 7);
20 :
21 : static const unsigned char sigma[] = "expand 32-byte k";
22 : static const unsigned char tau[] = "expand 16-byte k";
23 :
24 2566690 : void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
25 : {
26 2566690 : const unsigned char *constants;
27 :
28 2566690 : input[4] = ReadLE32(k + 0);
29 2566690 : input[5] = ReadLE32(k + 4);
30 2566690 : input[6] = ReadLE32(k + 8);
31 2566690 : input[7] = ReadLE32(k + 12);
32 2566690 : if (keylen == 32) { /* recommended */
33 2566690 : k += 16;
34 2566690 : constants = sigma;
35 : } else { /* keylen == 16 */
36 : constants = tau;
37 : }
38 2566690 : input[8] = ReadLE32(k + 0);
39 2566690 : input[9] = ReadLE32(k + 4);
40 2566690 : input[10] = ReadLE32(k + 8);
41 2566690 : input[11] = ReadLE32(k + 12);
42 2566690 : input[0] = ReadLE32(constants + 0);
43 2566690 : input[1] = ReadLE32(constants + 4);
44 2566690 : input[2] = ReadLE32(constants + 8);
45 2566690 : input[3] = ReadLE32(constants + 12);
46 2566690 : input[12] = 0;
47 2566690 : input[13] = 0;
48 2566690 : input[14] = 0;
49 2566690 : input[15] = 0;
50 2566690 : }
51 :
52 2571246 : ChaCha20::ChaCha20()
53 : {
54 2571246 : memset(input, 0, sizeof(input));
55 2571246 : }
56 :
57 7 : ChaCha20::ChaCha20(const unsigned char* k, size_t keylen)
58 : {
59 7 : SetKey(k, keylen);
60 7 : }
61 :
62 8 : void ChaCha20::SetIV(uint64_t iv)
63 : {
64 8 : input[14] = iv;
65 8 : input[15] = iv >> 32;
66 8 : }
67 :
68 8 : void ChaCha20::Seek(uint64_t pos)
69 : {
70 8 : input[12] = pos;
71 8 : input[13] = pos >> 32;
72 8 : }
73 :
74 14836900 : void ChaCha20::Keystream(unsigned char* c, size_t bytes)
75 : {
76 14836900 : uint32_t x[16];
77 14836900 : uint32_t j[16];
78 14836900 : unsigned char *ctarget = nullptr;
79 14836900 : unsigned char tmp[64];
80 14836900 : unsigned int i;
81 :
82 14836900 : if (!bytes) return;
83 :
84 252227700 : for (uint32_t i=0; i<16; i++) {
85 237390600 : j[i] = input[i];
86 : }
87 :
88 14838990 : for (;;) {
89 14837940 : if (bytes < 64) {
90 1003 : ctarget = c;
91 1003 : c = tmp;
92 : }
93 252245500 : for (uint32_t i=0; i<16; i++) {
94 237407300 : x[i] = j[i];
95 : }
96 163217600 : for (i = 20;i > 0;i -= 2) {
97 148379400 : QUARTERROUND( x[0], x[4], x[8],x[12])
98 148379400 : QUARTERROUND( x[1], x[5], x[9],x[13])
99 148379400 : QUARTERROUND( x[2], x[6],x[10],x[14])
100 148379400 : QUARTERROUND( x[3], x[7],x[11],x[15])
101 148379400 : QUARTERROUND( x[0], x[5],x[10],x[15])
102 148379400 : QUARTERROUND( x[1], x[6],x[11],x[12])
103 148379400 : QUARTERROUND( x[2], x[7], x[8],x[13])
104 148379400 : QUARTERROUND( x[3], x[4], x[9],x[14])
105 : }
106 252245500 : for (uint32_t i=0; i<16; i++) {
107 237407300 : x[i] += j[i];
108 : }
109 :
110 14837940 : ++j[12];
111 14837940 : if (!j[12]) ++j[13];
112 :
113 252245500 : for (uint32_t i=0; i<16; i++) {
114 237407300 : WriteLE32(c + 4*i, x[i]);
115 : }
116 :
117 14837940 : if (bytes <= 64) {
118 14836900 : if (bytes < 64) {
119 31387 : for (i = 0;i < bytes;++i) ctarget[i] = c[i];
120 : }
121 14836900 : input[12] = j[12];
122 14836900 : input[13] = j[13];
123 14836900 : return;
124 : }
125 1044 : bytes -= 64;
126 1044 : c += 64;
127 1044 : }
128 : }
129 :
130 1 : void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
131 : {
132 1 : uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
133 1 : uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
134 1 : unsigned char *ctarget = nullptr;
135 1 : unsigned char tmp[64];
136 1 : unsigned int i;
137 :
138 1 : if (!bytes) return;
139 :
140 1 : j0 = input[0];
141 1 : j1 = input[1];
142 1 : j2 = input[2];
143 1 : j3 = input[3];
144 1 : j4 = input[4];
145 1 : j5 = input[5];
146 1 : j6 = input[6];
147 1 : j7 = input[7];
148 1 : j8 = input[8];
149 1 : j9 = input[9];
150 1 : j10 = input[10];
151 1 : j11 = input[11];
152 1 : j12 = input[12];
153 1 : j13 = input[13];
154 1 : j14 = input[14];
155 1 : j15 = input[15];
156 :
157 3 : for (;;) {
158 2 : if (bytes < 64) {
159 : // if m has fewer than 64 bytes available, copy m to tmp and
160 : // read from tmp instead
161 51 : for (i = 0;i < bytes;++i) tmp[i] = m[i];
162 : m = tmp;
163 : ctarget = c;
164 : c = tmp;
165 : }
166 2 : x0 = j0;
167 2 : x1 = j1;
168 2 : x2 = j2;
169 2 : x3 = j3;
170 2 : x4 = j4;
171 2 : x5 = j5;
172 2 : x6 = j6;
173 2 : x7 = j7;
174 2 : x8 = j8;
175 2 : x9 = j9;
176 2 : x10 = j10;
177 2 : x11 = j11;
178 2 : x12 = j12;
179 2 : x13 = j13;
180 2 : x14 = j14;
181 2 : x15 = j15;
182 22 : for (i = 20;i > 0;i -= 2) {
183 20 : QUARTERROUND( x0, x4, x8,x12)
184 20 : QUARTERROUND( x1, x5, x9,x13)
185 20 : QUARTERROUND( x2, x6,x10,x14)
186 20 : QUARTERROUND( x3, x7,x11,x15)
187 20 : QUARTERROUND( x0, x5,x10,x15)
188 20 : QUARTERROUND( x1, x6,x11,x12)
189 20 : QUARTERROUND( x2, x7, x8,x13)
190 20 : QUARTERROUND( x3, x4, x9,x14)
191 : }
192 2 : x0 += j0;
193 2 : x1 += j1;
194 2 : x2 += j2;
195 2 : x3 += j3;
196 2 : x4 += j4;
197 2 : x5 += j5;
198 2 : x6 += j6;
199 2 : x7 += j7;
200 2 : x8 += j8;
201 2 : x9 += j9;
202 2 : x10 += j10;
203 2 : x11 += j11;
204 2 : x12 += j12;
205 2 : x13 += j13;
206 2 : x14 += j14;
207 2 : x15 += j15;
208 :
209 2 : x0 ^= ReadLE32(m + 0);
210 2 : x1 ^= ReadLE32(m + 4);
211 2 : x2 ^= ReadLE32(m + 8);
212 2 : x3 ^= ReadLE32(m + 12);
213 2 : x4 ^= ReadLE32(m + 16);
214 2 : x5 ^= ReadLE32(m + 20);
215 2 : x6 ^= ReadLE32(m + 24);
216 2 : x7 ^= ReadLE32(m + 28);
217 2 : x8 ^= ReadLE32(m + 32);
218 2 : x9 ^= ReadLE32(m + 36);
219 2 : x10 ^= ReadLE32(m + 40);
220 2 : x11 ^= ReadLE32(m + 44);
221 2 : x12 ^= ReadLE32(m + 48);
222 2 : x13 ^= ReadLE32(m + 52);
223 2 : x14 ^= ReadLE32(m + 56);
224 2 : x15 ^= ReadLE32(m + 60);
225 :
226 2 : ++j12;
227 2 : if (!j12) ++j13;
228 :
229 2 : WriteLE32(c + 0, x0);
230 2 : WriteLE32(c + 4, x1);
231 2 : WriteLE32(c + 8, x2);
232 2 : WriteLE32(c + 12, x3);
233 2 : WriteLE32(c + 16, x4);
234 2 : WriteLE32(c + 20, x5);
235 2 : WriteLE32(c + 24, x6);
236 2 : WriteLE32(c + 28, x7);
237 2 : WriteLE32(c + 32, x8);
238 2 : WriteLE32(c + 36, x9);
239 2 : WriteLE32(c + 40, x10);
240 2 : WriteLE32(c + 44, x11);
241 2 : WriteLE32(c + 48, x12);
242 2 : WriteLE32(c + 52, x13);
243 2 : WriteLE32(c + 56, x14);
244 2 : WriteLE32(c + 60, x15);
245 :
246 2 : if (bytes <= 64) {
247 1 : if (bytes < 64) {
248 51 : for (i = 0;i < bytes;++i) ctarget[i] = c[i];
249 : }
250 1 : input[12] = j12;
251 1 : input[13] = j13;
252 1 : return;
253 : }
254 1 : bytes -= 64;
255 1 : c += 64;
256 1 : m += 64;
257 : }
258 : }
|