xref: /freebsd/sys/contrib/libsodium/src/libsodium/crypto_stream/chacha20/ref/chacha20_ref.c (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
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