1
2 /*
3 chacha-merged.c version 20080118
4 D. J. Bernstein
5 Public domain.
6 */
7
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "core.h"
13 #include "crypto_stream_chacha20.h"
14 #include "private/common.h"
15 #include "utils.h"
16
17 #include "../stream_chacha20.h"
18 #include "chacha20_ref.h"
19
20 struct chacha_ctx {
21 uint32_t input[16];
22 };
23
24 typedef struct chacha_ctx chacha_ctx;
25
26 #define U32C(v) (v##U)
27
28 #define U32V(v) ((uint32_t)(v) &U32C(0xFFFFFFFF))
29
30 #define ROTATE(v, c) (ROTL32(v, c))
31 #define XOR(v, w) ((v) ^ (w))
32 #define PLUS(v, w) (U32V((v) + (w)))
33 #define PLUSONE(v) (PLUS((v), 1))
34
35 #define QUARTERROUND(a, b, c, d) \
36 a = PLUS(a, b); \
37 d = ROTATE(XOR(d, a), 16); \
38 c = PLUS(c, d); \
39 b = ROTATE(XOR(b, c), 12); \
40 a = PLUS(a, b); \
41 d = ROTATE(XOR(d, a), 8); \
42 c = PLUS(c, d); \
43 b = ROTATE(XOR(b, c), 7);
44
45 static void
chacha_keysetup(chacha_ctx * ctx,const uint8_t * k)46 chacha_keysetup(chacha_ctx *ctx, const uint8_t *k)
47 {
48 ctx->input[0] = U32C(0x61707865);
49 ctx->input[1] = U32C(0x3320646e);
50 ctx->input[2] = U32C(0x79622d32);
51 ctx->input[3] = U32C(0x6b206574);
52 ctx->input[4] = LOAD32_LE(k + 0);
53 ctx->input[5] = LOAD32_LE(k + 4);
54 ctx->input[6] = LOAD32_LE(k + 8);
55 ctx->input[7] = LOAD32_LE(k + 12);
56 ctx->input[8] = LOAD32_LE(k + 16);
57 ctx->input[9] = LOAD32_LE(k + 20);
58 ctx->input[10] = LOAD32_LE(k + 24);
59 ctx->input[11] = LOAD32_LE(k + 28);
60 }
61
62 static void
chacha_ivsetup(chacha_ctx * ctx,const uint8_t * iv,const uint8_t * counter)63 chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter)
64 {
65 ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0);
66 ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4);
67 ctx->input[14] = LOAD32_LE(iv + 0);
68 ctx->input[15] = LOAD32_LE(iv + 4);
69 }
70
71 static void
chacha_ietf_ivsetup(chacha_ctx * ctx,const uint8_t * iv,const uint8_t * counter)72 chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter)
73 {
74 ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter);
75 ctx->input[13] = LOAD32_LE(iv + 0);
76 ctx->input[14] = LOAD32_LE(iv + 4);
77 ctx->input[15] = LOAD32_LE(iv + 8);
78 }
79
80 static void
chacha20_encrypt_bytes(chacha_ctx * ctx,const uint8_t * m,uint8_t * c,unsigned long long bytes)81 chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c,
82 unsigned long long bytes)
83 {
84 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
85 x15;
86 uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14,
87 j15;
88 uint8_t *ctarget = NULL;
89 uint8_t tmp[64];
90 unsigned int i;
91
92 if (!bytes) {
93 return; /* LCOV_EXCL_LINE */
94 }
95 if (bytes > crypto_stream_chacha20_MESSAGEBYTES_MAX) {
96 sodium_misuse();
97 }
98 j0 = ctx->input[0];
99 j1 = ctx->input[1];
100 j2 = ctx->input[2];
101 j3 = ctx->input[3];
102 j4 = ctx->input[4];
103 j5 = ctx->input[5];
104 j6 = ctx->input[6];
105 j7 = ctx->input[7];
106 j8 = ctx->input[8];
107 j9 = ctx->input[9];
108 j10 = ctx->input[10];
109 j11 = ctx->input[11];
110 j12 = ctx->input[12];
111 j13 = ctx->input[13];
112 j14 = ctx->input[14];
113 j15 = ctx->input[15];
114
115 for (;;) {
116 if (bytes < 64) {
117 memset(tmp, 0, 64);
118 for (i = 0; i < bytes; ++i) {
119 tmp[i] = m[i];
120 }
121 m = tmp;
122 ctarget = c;
123 c = tmp;
124 }
125 x0 = j0;
126 x1 = j1;
127 x2 = j2;
128 x3 = j3;
129 x4 = j4;
130 x5 = j5;
131 x6 = j6;
132 x7 = j7;
133 x8 = j8;
134 x9 = j9;
135 x10 = j10;
136 x11 = j11;
137 x12 = j12;
138 x13 = j13;
139 x14 = j14;
140 x15 = j15;
141 for (i = 20; i > 0; i -= 2) {
142 QUARTERROUND(x0, x4, x8, x12)
143 QUARTERROUND(x1, x5, x9, x13)
144 QUARTERROUND(x2, x6, x10, x14)
145 QUARTERROUND(x3, x7, x11, x15)
146 QUARTERROUND(x0, x5, x10, x15)
147 QUARTERROUND(x1, x6, x11, x12)
148 QUARTERROUND(x2, x7, x8, x13)
149 QUARTERROUND(x3, x4, x9, x14)
150 }
151 x0 = PLUS(x0, j0);
152 x1 = PLUS(x1, j1);
153 x2 = PLUS(x2, j2);
154 x3 = PLUS(x3, j3);
155 x4 = PLUS(x4, j4);
156 x5 = PLUS(x5, j5);
157 x6 = PLUS(x6, j6);
158 x7 = PLUS(x7, j7);
159 x8 = PLUS(x8, j8);
160 x9 = PLUS(x9, j9);
161 x10 = PLUS(x10, j10);
162 x11 = PLUS(x11, j11);
163 x12 = PLUS(x12, j12);
164 x13 = PLUS(x13, j13);
165 x14 = PLUS(x14, j14);
166 x15 = PLUS(x15, j15);
167
168 x0 = XOR(x0, LOAD32_LE(m + 0));
169 x1 = XOR(x1, LOAD32_LE(m + 4));
170 x2 = XOR(x2, LOAD32_LE(m + 8));
171 x3 = XOR(x3, LOAD32_LE(m + 12));
172 x4 = XOR(x4, LOAD32_LE(m + 16));
173 x5 = XOR(x5, LOAD32_LE(m + 20));
174 x6 = XOR(x6, LOAD32_LE(m + 24));
175 x7 = XOR(x7, LOAD32_LE(m + 28));
176 x8 = XOR(x8, LOAD32_LE(m + 32));
177 x9 = XOR(x9, LOAD32_LE(m + 36));
178 x10 = XOR(x10, LOAD32_LE(m + 40));
179 x11 = XOR(x11, LOAD32_LE(m + 44));
180 x12 = XOR(x12, LOAD32_LE(m + 48));
181 x13 = XOR(x13, LOAD32_LE(m + 52));
182 x14 = XOR(x14, LOAD32_LE(m + 56));
183 x15 = XOR(x15, LOAD32_LE(m + 60));
184
185 j12 = PLUSONE(j12);
186 /* LCOV_EXCL_START */
187 if (!j12) {
188 j13 = PLUSONE(j13);
189 }
190 /* LCOV_EXCL_STOP */
191
192 STORE32_LE(c + 0, x0);
193 STORE32_LE(c + 4, x1);
194 STORE32_LE(c + 8, x2);
195 STORE32_LE(c + 12, x3);
196 STORE32_LE(c + 16, x4);
197 STORE32_LE(c + 20, x5);
198 STORE32_LE(c + 24, x6);
199 STORE32_LE(c + 28, x7);
200 STORE32_LE(c + 32, x8);
201 STORE32_LE(c + 36, x9);
202 STORE32_LE(c + 40, x10);
203 STORE32_LE(c + 44, x11);
204 STORE32_LE(c + 48, x12);
205 STORE32_LE(c + 52, x13);
206 STORE32_LE(c + 56, x14);
207 STORE32_LE(c + 60, x15);
208
209 if (bytes <= 64) {
210 if (bytes < 64) {
211 for (i = 0; i < (unsigned int) bytes; ++i) {
212 ctarget[i] = c[i]; /* ctarget cannot be NULL */
213 }
214 }
215 ctx->input[12] = j12;
216 ctx->input[13] = j13;
217
218 return;
219 }
220 bytes -= 64;
221 c += 64;
222 m += 64;
223 }
224 }
225
226 static int
stream_ref(unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)227 stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n,
228 const unsigned char *k)
229 {
230 struct chacha_ctx ctx;
231
232 if (!clen) {
233 return 0;
234 }
235 COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8);
236 chacha_keysetup(&ctx, k);
237 chacha_ivsetup(&ctx, n, NULL);
238 memset(c, 0, clen);
239 chacha20_encrypt_bytes(&ctx, c, c, clen);
240 sodium_memzero(&ctx, sizeof ctx);
241
242 return 0;
243 }
244
245 static int
stream_ietf_ref(unsigned char * c,unsigned long long clen,const unsigned char * n,const unsigned char * k)246 stream_ietf_ref(unsigned char *c, unsigned long long clen,
247 const unsigned char *n, const unsigned char *k)
248 {
249 struct chacha_ctx ctx;
250
251 if (!clen) {
252 return 0;
253 }
254 COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8);
255 chacha_keysetup(&ctx, k);
256 chacha_ietf_ivsetup(&ctx, n, NULL);
257 memset(c, 0, clen);
258 chacha20_encrypt_bytes(&ctx, c, c, clen);
259 sodium_memzero(&ctx, sizeof ctx);
260
261 return 0;
262 }
263
264 static int
stream_ref_xor_ic(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,uint64_t ic,const unsigned char * k)265 stream_ref_xor_ic(unsigned char *c, const unsigned char *m,
266 unsigned long long mlen, const unsigned char *n, uint64_t ic,
267 const unsigned char *k)
268 {
269 struct chacha_ctx ctx;
270 uint8_t ic_bytes[8];
271 uint32_t ic_high;
272 uint32_t ic_low;
273
274 if (!mlen) {
275 return 0;
276 }
277 ic_high = U32V(ic >> 32);
278 ic_low = U32V(ic);
279 STORE32_LE(&ic_bytes[0], ic_low);
280 STORE32_LE(&ic_bytes[4], ic_high);
281 chacha_keysetup(&ctx, k);
282 chacha_ivsetup(&ctx, n, ic_bytes);
283 chacha20_encrypt_bytes(&ctx, m, c, mlen);
284 sodium_memzero(&ctx, sizeof ctx);
285
286 return 0;
287 }
288
289 static int
stream_ietf_ref_xor_ic(unsigned char * c,const unsigned char * m,unsigned long long mlen,const unsigned char * n,uint32_t ic,const unsigned char * k)290 stream_ietf_ref_xor_ic(unsigned char *c, const unsigned char *m,
291 unsigned long long mlen, const unsigned char *n,
292 uint32_t ic, const unsigned char *k)
293 {
294 struct chacha_ctx ctx;
295 uint8_t ic_bytes[4];
296
297 if (!mlen) {
298 return 0;
299 }
300 STORE32_LE(ic_bytes, ic);
301 chacha_keysetup(&ctx, k);
302 chacha_ietf_ivsetup(&ctx, n, ic_bytes);
303 chacha20_encrypt_bytes(&ctx, m, c, mlen);
304 sodium_memzero(&ctx, sizeof ctx);
305
306 return 0;
307 }
308
309 struct crypto_stream_chacha20_implementation
310 crypto_stream_chacha20_ref_implementation = {
311 SODIUM_C99(.stream =) stream_ref,
312 SODIUM_C99(.stream_ietf =) stream_ietf_ref,
313 SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic,
314 SODIUM_C99(.stream_ietf_xor_ic =) stream_ietf_ref_xor_ic
315 };
316