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
20struct chacha_ctx {
21    uint32_t input[16];
22};
23
24typedef 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
45static void
46chacha_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
62static void
63chacha_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
71static void
72chacha_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
80static void
81chacha20_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
226static int
227stream_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
245static int
246stream_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
264static int
265stream_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
289static int
290stream_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
309struct 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