1 
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <limits.h>
5 #include <string.h>
6 
7 #include "core.h"
8 #include "crypto_aead_chacha20poly1305.h"
9 #include "crypto_onetimeauth_poly1305.h"
10 #include "crypto_stream_chacha20.h"
11 #include "crypto_verify_16.h"
12 #include "randombytes.h"
13 #include "utils.h"
14 
15 #include "private/common.h"
16 
17 static const unsigned char _pad0[16] = { 0 };
18 
19 int
crypto_aead_chacha20poly1305_encrypt_detached(unsigned char * c,unsigned char * mac,unsigned long long * maclen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)20 crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c,
21                                               unsigned char *mac,
22                                               unsigned long long *maclen_p,
23                                               const unsigned char *m,
24                                               unsigned long long mlen,
25                                               const unsigned char *ad,
26                                               unsigned long long adlen,
27                                               const unsigned char *nsec,
28                                               const unsigned char *npub,
29                                               const unsigned char *k)
30 {
31     crypto_onetimeauth_poly1305_state state;
32     unsigned char                     block0[64U];
33     unsigned char                     slen[8U];
34 
35     (void) nsec;
36     crypto_stream_chacha20(block0, sizeof block0, npub, k);
37     crypto_onetimeauth_poly1305_init(&state, block0);
38     sodium_memzero(block0, sizeof block0);
39 
40     crypto_onetimeauth_poly1305_update(&state, ad, adlen);
41     STORE64_LE(slen, (uint64_t) adlen);
42     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
43 
44     crypto_stream_chacha20_xor_ic(c, m, mlen, npub, 1U, k);
45 
46     crypto_onetimeauth_poly1305_update(&state, c, mlen);
47     STORE64_LE(slen, (uint64_t) mlen);
48     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
49 
50     crypto_onetimeauth_poly1305_final(&state, mac);
51     sodium_memzero(&state, sizeof state);
52 
53     if (maclen_p != NULL) {
54         *maclen_p = crypto_aead_chacha20poly1305_ABYTES;
55     }
56     return 0;
57 }
58 
59 int
crypto_aead_chacha20poly1305_encrypt(unsigned char * c,unsigned long long * clen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)60 crypto_aead_chacha20poly1305_encrypt(unsigned char *c,
61                                      unsigned long long *clen_p,
62                                      const unsigned char *m,
63                                      unsigned long long mlen,
64                                      const unsigned char *ad,
65                                      unsigned long long adlen,
66                                      const unsigned char *nsec,
67                                      const unsigned char *npub,
68                                      const unsigned char *k)
69 {
70     unsigned long long clen = 0ULL;
71     int                ret;
72 
73     if (mlen > crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX) {
74         sodium_misuse();
75     }
76     ret = crypto_aead_chacha20poly1305_encrypt_detached(c,
77                                                         c + mlen, NULL,
78                                                         m, mlen,
79                                                         ad, adlen,
80                                                         nsec, npub, k);
81     if (clen_p != NULL) {
82         if (ret == 0) {
83             clen = mlen + crypto_aead_chacha20poly1305_ABYTES;
84         }
85         *clen_p = clen;
86     }
87     return ret;
88 }
89 
90 int
crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char * c,unsigned char * mac,unsigned long long * maclen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)91 crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c,
92                                                    unsigned char *mac,
93                                                    unsigned long long *maclen_p,
94                                                    const unsigned char *m,
95                                                    unsigned long long mlen,
96                                                    const unsigned char *ad,
97                                                    unsigned long long adlen,
98                                                    const unsigned char *nsec,
99                                                    const unsigned char *npub,
100                                                    const unsigned char *k)
101 {
102     crypto_onetimeauth_poly1305_state state;
103     unsigned char                     block0[64U];
104     unsigned char                     slen[8U];
105 
106     (void) nsec;
107     crypto_stream_chacha20_ietf(block0, sizeof block0, npub, k);
108     crypto_onetimeauth_poly1305_init(&state, block0);
109     sodium_memzero(block0, sizeof block0);
110 
111     crypto_onetimeauth_poly1305_update(&state, ad, adlen);
112     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf);
113 
114     crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, npub, 1U, k);
115 
116     crypto_onetimeauth_poly1305_update(&state, c, mlen);
117     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf);
118 
119     STORE64_LE(slen, (uint64_t) adlen);
120     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
121 
122     STORE64_LE(slen, (uint64_t) mlen);
123     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
124 
125     crypto_onetimeauth_poly1305_final(&state, mac);
126     sodium_memzero(&state, sizeof state);
127 
128     if (maclen_p != NULL) {
129         *maclen_p = crypto_aead_chacha20poly1305_ietf_ABYTES;
130     }
131     return 0;
132 }
133 
134 int
crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char * c,unsigned long long * clen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,const unsigned char * nsec,const unsigned char * npub,const unsigned char * k)135 crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c,
136                                           unsigned long long *clen_p,
137                                           const unsigned char *m,
138                                           unsigned long long mlen,
139                                           const unsigned char *ad,
140                                           unsigned long long adlen,
141                                           const unsigned char *nsec,
142                                           const unsigned char *npub,
143                                           const unsigned char *k)
144 {
145     unsigned long long clen = 0ULL;
146     int                ret;
147 
148     if (mlen > crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX) {
149         sodium_misuse();
150     }
151     ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c,
152                                                              c + mlen, NULL,
153                                                              m, mlen,
154                                                              ad, adlen,
155                                                              nsec, npub, k);
156     if (clen_p != NULL) {
157         if (ret == 0) {
158             clen = mlen + crypto_aead_chacha20poly1305_ietf_ABYTES;
159         }
160         *clen_p = clen;
161     }
162     return ret;
163 }
164 
165 int
crypto_aead_chacha20poly1305_decrypt_detached(unsigned char * m,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * mac,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)166 crypto_aead_chacha20poly1305_decrypt_detached(unsigned char *m,
167                                               unsigned char *nsec,
168                                               const unsigned char *c,
169                                               unsigned long long clen,
170                                               const unsigned char *mac,
171                                               const unsigned char *ad,
172                                               unsigned long long adlen,
173                                               const unsigned char *npub,
174                                               const unsigned char *k)
175 {
176     crypto_onetimeauth_poly1305_state state;
177     unsigned char                     block0[64U];
178     unsigned char                     slen[8U];
179     unsigned char                     computed_mac[crypto_aead_chacha20poly1305_ABYTES];
180     unsigned long long                mlen;
181     int                               ret;
182 
183     (void) nsec;
184     crypto_stream_chacha20(block0, sizeof block0, npub, k);
185     crypto_onetimeauth_poly1305_init(&state, block0);
186     sodium_memzero(block0, sizeof block0);
187 
188     crypto_onetimeauth_poly1305_update(&state, ad, adlen);
189     STORE64_LE(slen, (uint64_t) adlen);
190     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
191 
192     mlen = clen;
193     crypto_onetimeauth_poly1305_update(&state, c, mlen);
194     STORE64_LE(slen, (uint64_t) mlen);
195     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
196 
197     crypto_onetimeauth_poly1305_final(&state, computed_mac);
198     sodium_memzero(&state, sizeof state);
199 
200     COMPILER_ASSERT(sizeof computed_mac == 16U);
201     ret = crypto_verify_16(computed_mac, mac);
202     sodium_memzero(computed_mac, sizeof computed_mac);
203     if (m == NULL) {
204         return ret;
205     }
206     if (ret != 0) {
207         memset(m, 0, mlen);
208         return -1;
209     }
210     crypto_stream_chacha20_xor_ic(m, c, mlen, npub, 1U, k);
211 
212     return 0;
213 }
214 
215 int
crypto_aead_chacha20poly1305_decrypt(unsigned char * m,unsigned long long * mlen_p,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)216 crypto_aead_chacha20poly1305_decrypt(unsigned char *m,
217                                      unsigned long long *mlen_p,
218                                      unsigned char *nsec,
219                                      const unsigned char *c,
220                                      unsigned long long clen,
221                                      const unsigned char *ad,
222                                      unsigned long long adlen,
223                                      const unsigned char *npub,
224                                      const unsigned char *k)
225 {
226     unsigned long long mlen = 0ULL;
227     int                ret = -1;
228 
229     if (clen >= crypto_aead_chacha20poly1305_ABYTES) {
230         ret = crypto_aead_chacha20poly1305_decrypt_detached
231             (m, nsec,
232              c, clen - crypto_aead_chacha20poly1305_ABYTES,
233              c + clen - crypto_aead_chacha20poly1305_ABYTES,
234              ad, adlen, npub, k);
235     }
236     if (mlen_p != NULL) {
237         if (ret == 0) {
238             mlen = clen - crypto_aead_chacha20poly1305_ABYTES;
239         }
240         *mlen_p = mlen;
241     }
242     return ret;
243 }
244 
245 int
crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char * m,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * mac,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)246 crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char *m,
247                                                    unsigned char *nsec,
248                                                    const unsigned char *c,
249                                                    unsigned long long clen,
250                                                    const unsigned char *mac,
251                                                    const unsigned char *ad,
252                                                    unsigned long long adlen,
253                                                    const unsigned char *npub,
254                                                    const unsigned char *k)
255 {
256     crypto_onetimeauth_poly1305_state state;
257     unsigned char                     block0[64U];
258     unsigned char                     slen[8U];
259     unsigned char                     computed_mac[crypto_aead_chacha20poly1305_ietf_ABYTES];
260     unsigned long long                mlen;
261     int                               ret;
262 
263     (void) nsec;
264     crypto_stream_chacha20_ietf(block0, sizeof block0, npub, k);
265     crypto_onetimeauth_poly1305_init(&state, block0);
266     sodium_memzero(block0, sizeof block0);
267 
268     crypto_onetimeauth_poly1305_update(&state, ad, adlen);
269     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf);
270 
271     mlen = clen;
272     crypto_onetimeauth_poly1305_update(&state, c, mlen);
273     crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf);
274 
275     STORE64_LE(slen, (uint64_t) adlen);
276     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
277 
278     STORE64_LE(slen, (uint64_t) mlen);
279     crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
280 
281     crypto_onetimeauth_poly1305_final(&state, computed_mac);
282     sodium_memzero(&state, sizeof state);
283 
284     COMPILER_ASSERT(sizeof computed_mac == 16U);
285     ret = crypto_verify_16(computed_mac, mac);
286     sodium_memzero(computed_mac, sizeof computed_mac);
287     if (m == NULL) {
288         return ret;
289     }
290     if (ret != 0) {
291         memset(m, 0, mlen);
292         return -1;
293     }
294     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, npub, 1U, k);
295 
296     return 0;
297 }
298 
299 int
crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char * m,unsigned long long * mlen_p,unsigned char * nsec,const unsigned char * c,unsigned long long clen,const unsigned char * ad,unsigned long long adlen,const unsigned char * npub,const unsigned char * k)300 crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m,
301                                           unsigned long long *mlen_p,
302                                           unsigned char *nsec,
303                                           const unsigned char *c,
304                                           unsigned long long clen,
305                                           const unsigned char *ad,
306                                           unsigned long long adlen,
307                                           const unsigned char *npub,
308                                           const unsigned char *k)
309 {
310     unsigned long long mlen = 0ULL;
311     int                ret = -1;
312 
313     if (clen >= crypto_aead_chacha20poly1305_ietf_ABYTES) {
314         ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached
315             (m, nsec,
316              c, clen - crypto_aead_chacha20poly1305_ietf_ABYTES,
317              c + clen - crypto_aead_chacha20poly1305_ietf_ABYTES,
318              ad, adlen, npub, k);
319     }
320     if (mlen_p != NULL) {
321         if (ret == 0) {
322             mlen = clen - crypto_aead_chacha20poly1305_ietf_ABYTES;
323         }
324         *mlen_p = mlen;
325     }
326     return ret;
327 }
328 
329 size_t
crypto_aead_chacha20poly1305_ietf_keybytes(void)330 crypto_aead_chacha20poly1305_ietf_keybytes(void)
331 {
332     return crypto_aead_chacha20poly1305_ietf_KEYBYTES;
333 }
334 
335 size_t
crypto_aead_chacha20poly1305_ietf_npubbytes(void)336 crypto_aead_chacha20poly1305_ietf_npubbytes(void)
337 {
338     return crypto_aead_chacha20poly1305_ietf_NPUBBYTES;
339 }
340 
341 size_t
crypto_aead_chacha20poly1305_ietf_nsecbytes(void)342 crypto_aead_chacha20poly1305_ietf_nsecbytes(void)
343 {
344     return crypto_aead_chacha20poly1305_ietf_NSECBYTES;
345 }
346 
347 size_t
crypto_aead_chacha20poly1305_ietf_abytes(void)348 crypto_aead_chacha20poly1305_ietf_abytes(void)
349 {
350     return crypto_aead_chacha20poly1305_ietf_ABYTES;
351 }
352 
353 size_t
crypto_aead_chacha20poly1305_ietf_messagebytes_max(void)354 crypto_aead_chacha20poly1305_ietf_messagebytes_max(void)
355 {
356     return crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX;
357 }
358 
359 void
crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES])360 crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES])
361 {
362     randombytes_buf(k, crypto_aead_chacha20poly1305_ietf_KEYBYTES);
363 }
364 
365 size_t
crypto_aead_chacha20poly1305_keybytes(void)366 crypto_aead_chacha20poly1305_keybytes(void)
367 {
368     return crypto_aead_chacha20poly1305_KEYBYTES;
369 }
370 
371 size_t
crypto_aead_chacha20poly1305_npubbytes(void)372 crypto_aead_chacha20poly1305_npubbytes(void)
373 {
374     return crypto_aead_chacha20poly1305_NPUBBYTES;
375 }
376 
377 size_t
crypto_aead_chacha20poly1305_nsecbytes(void)378 crypto_aead_chacha20poly1305_nsecbytes(void)
379 {
380     return crypto_aead_chacha20poly1305_NSECBYTES;
381 }
382 
383 size_t
crypto_aead_chacha20poly1305_abytes(void)384 crypto_aead_chacha20poly1305_abytes(void)
385 {
386     return crypto_aead_chacha20poly1305_ABYTES;
387 }
388 
389 size_t
crypto_aead_chacha20poly1305_messagebytes_max(void)390 crypto_aead_chacha20poly1305_messagebytes_max(void)
391 {
392     return crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX;
393 }
394 
395 void
crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES])396 crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES])
397 {
398     randombytes_buf(k, crypto_aead_chacha20poly1305_KEYBYTES);
399 }
400