1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <limits.h>
4 #include <string.h>
5 
6 #include "core.h"
7 #include "crypto_aead_chacha20poly1305.h"
8 #include "crypto_aead_xchacha20poly1305.h"
9 #include "crypto_core_hchacha20.h"
10 #include "crypto_onetimeauth_poly1305.h"
11 #include "crypto_secretstream_xchacha20poly1305.h"
12 #include "randombytes.h"
13 #include "utils.h"
14 
15 #include "private/common.h"
16 
17 #define crypto_secretstream_xchacha20poly1305_COUNTERBYTES  4U
18 #define crypto_secretstream_xchacha20poly1305_INONCEBYTES   8U
19 
20 #define STATE_COUNTER(STATE) ((STATE)->nonce)
21 #define STATE_INONCE(STATE)  ((STATE)->nonce + \
22                               crypto_secretstream_xchacha20poly1305_COUNTERBYTES)
23 
24 static const unsigned char _pad0[16] = { 0 };
25 
26 static inline void
27 _crypto_secretstream_xchacha20poly1305_counter_reset
28     (crypto_secretstream_xchacha20poly1305_state *state)
29 {
30     memset(STATE_COUNTER(state), 0,
31            crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
32     STATE_COUNTER(state)[0] = 1;
33 }
34 
35 void
36 crypto_secretstream_xchacha20poly1305_keygen
37    (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
38 {
39     randombytes_buf(k, crypto_secretstream_xchacha20poly1305_KEYBYTES);
40 }
41 
42 int
43 crypto_secretstream_xchacha20poly1305_init_push
44    (crypto_secretstream_xchacha20poly1305_state *state,
45     unsigned char out[crypto_secretstream_xchacha20poly1305_HEADERBYTES],
46     const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
47 {
48     COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_HEADERBYTES ==
49                     crypto_core_hchacha20_INPUTBYTES +
50                     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
51     COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_HEADERBYTES ==
52                     crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
53     COMPILER_ASSERT(sizeof state->nonce ==
54                     crypto_secretstream_xchacha20poly1305_INONCEBYTES +
55                     crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
56 
57     randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
58     crypto_core_hchacha20(state->k, out, k, NULL);
59     _crypto_secretstream_xchacha20poly1305_counter_reset(state);
60     memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
61            crypto_secretstream_xchacha20poly1305_INONCEBYTES);
62     memset(state->_pad, 0, sizeof state->_pad);
63 
64     return 0;
65 }
66 
67 int
68 crypto_secretstream_xchacha20poly1305_init_pull
69    (crypto_secretstream_xchacha20poly1305_state *state,
70     const unsigned char in[crypto_secretstream_xchacha20poly1305_HEADERBYTES],
71     const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
72 {
73     crypto_core_hchacha20(state->k, in, k, NULL);
74     _crypto_secretstream_xchacha20poly1305_counter_reset(state);
75     memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
76            crypto_secretstream_xchacha20poly1305_INONCEBYTES);
77     memset(state->_pad, 0, sizeof state->_pad);
78 
79     return 0;
80 }
81 
82 void
83 crypto_secretstream_xchacha20poly1305_rekey
84     (crypto_secretstream_xchacha20poly1305_state *state)
85 {
86     unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
87                                      crypto_secretstream_xchacha20poly1305_INONCEBYTES];
88     size_t        i;
89 
90     for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
91         new_key_and_inonce[i] = state->k[i];
92     }
93     for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
94         new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
95             STATE_INONCE(state)[i];
96     }
97     crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
98                                     sizeof new_key_and_inonce,
99                                     state->nonce, state->k);
100     for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
101         state->k[i] = new_key_and_inonce[i];
102     }
103     for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
104         STATE_INONCE(state)[i] =
105             new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
106     }
107     _crypto_secretstream_xchacha20poly1305_counter_reset(state);
108 }
109 
110 int
111 crypto_secretstream_xchacha20poly1305_push
112    (crypto_secretstream_xchacha20poly1305_state *state,
113     unsigned char *out, unsigned long long *outlen_p,
114     const unsigned char *m, unsigned long long mlen,
115     const unsigned char *ad, unsigned long long adlen, unsigned char tag)
116 {
117     crypto_onetimeauth_poly1305_state poly1305_state;
118     unsigned char                     block[64U];
119     unsigned char                     slen[8U];
120     unsigned char                    *c;
121     unsigned char                    *mac;
122 
123     if (outlen_p != NULL) {
124         *outlen_p = 0U;
125     }
126     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
127         sodium_misuse();
128     }
129     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
130     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
131     sodium_memzero(block, sizeof block);
132 
133     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
134     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
135                                        (0x10 - adlen) & 0xf);
136     memset(block, 0, sizeof block);
137     block[0] = tag;
138 
139     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
140                                        state->nonce, 1U, state->k);
141     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
142     out[0] = block[0];
143 
144     c = out + (sizeof tag);
145     crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
146     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
147     crypto_onetimeauth_poly1305_update
148         (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
149 
150     STORE64_LE(slen, (uint64_t) adlen);
151     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
152     STORE64_LE(slen, (sizeof block) + mlen);
153     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
154 
155     mac = c + mlen;
156     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
157     sodium_memzero(&poly1305_state, sizeof poly1305_state);
158 
159     COMPILER_ASSERT(crypto_onetimeauth_poly1305_BYTES >=
160                     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
161     XOR_BUF(STATE_INONCE(state), mac,
162             crypto_secretstream_xchacha20poly1305_INONCEBYTES);
163     sodium_increment(STATE_COUNTER(state),
164                      crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
165     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
166         sodium_is_zero(STATE_COUNTER(state),
167                        crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
168         crypto_secretstream_xchacha20poly1305_rekey(state);
169     }
170     if (outlen_p != NULL) {
171         *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
172     }
173     return 0;
174 }
175 
176 int
177 crypto_secretstream_xchacha20poly1305_pull
178    (crypto_secretstream_xchacha20poly1305_state *state,
179     unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
180     const unsigned char *in, unsigned long long inlen,
181     const unsigned char *ad, unsigned long long adlen)
182 {
183     crypto_onetimeauth_poly1305_state poly1305_state;
184     unsigned char                     block[64U];
185     unsigned char                     slen[8U];
186     unsigned char                     mac[crypto_onetimeauth_poly1305_BYTES];
187     const unsigned char              *c;
188     const unsigned char              *stored_mac;
189     unsigned long long                mlen;
190     unsigned char                     tag;
191 
192     if (mlen_p != NULL) {
193         *mlen_p = 0U;
194     }
195     if (tag_p != NULL) {
196         *tag_p = 0xff;
197     }
198     if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) {
199         return -1;
200     }
201     mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
202     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
203         sodium_misuse();
204     }
205     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
206     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
207     sodium_memzero(block, sizeof block);
208 
209     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
210     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
211                                        (0x10 - adlen) & 0xf);
212 
213     memset(block, 0, sizeof block);
214     block[0] = in[0];
215     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
216                                        state->nonce, 1U, state->k);
217     tag = block[0];
218     block[0] = in[0];
219     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
220 
221     c = in + (sizeof tag);
222     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
223     crypto_onetimeauth_poly1305_update
224         (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
225 
226     STORE64_LE(slen, (uint64_t) adlen);
227     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
228     STORE64_LE(slen, (sizeof block) + mlen);
229     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
230 
231     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
232     sodium_memzero(&poly1305_state, sizeof poly1305_state);
233 
234     stored_mac = c + mlen;
235     if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
236         sodium_memzero(mac, sizeof mac);
237         return -1;
238     }
239 
240     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
241     XOR_BUF(STATE_INONCE(state), mac,
242             crypto_secretstream_xchacha20poly1305_INONCEBYTES);
243     sodium_increment(STATE_COUNTER(state),
244                      crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
245     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
246         sodium_is_zero(STATE_COUNTER(state),
247                        crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
248         crypto_secretstream_xchacha20poly1305_rekey(state);
249     }
250     if (mlen_p != NULL) {
251         *mlen_p = mlen;
252     }
253     if (tag_p != NULL) {
254         *tag_p = tag;
255     }
256     return 0;
257 }
258 
259 size_t
260 crypto_secretstream_xchacha20poly1305_statebytes(void)
261 {
262     return sizeof(crypto_secretstream_xchacha20poly1305_state);
263 }
264 
265 size_t
266 crypto_secretstream_xchacha20poly1305_abytes(void)
267 {
268     return crypto_secretstream_xchacha20poly1305_ABYTES;
269 }
270 
271 size_t
272 crypto_secretstream_xchacha20poly1305_headerbytes(void)
273 {
274     return crypto_secretstream_xchacha20poly1305_HEADERBYTES;
275 }
276 
277 size_t
278 crypto_secretstream_xchacha20poly1305_keybytes(void)
279 {
280     return crypto_secretstream_xchacha20poly1305_KEYBYTES;
281 }
282 
283 size_t
284 crypto_secretstream_xchacha20poly1305_messagebytes_max(void)
285 {
286     return crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX;
287 }
288 
289 unsigned char
290 crypto_secretstream_xchacha20poly1305_tag_message(void)
291 {
292     return crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
293 }
294 
295 unsigned char
296 crypto_secretstream_xchacha20poly1305_tag_push(void)
297 {
298     return crypto_secretstream_xchacha20poly1305_TAG_PUSH;
299 }
300 
301 unsigned char
302 crypto_secretstream_xchacha20poly1305_tag_rekey(void)
303 {
304     return crypto_secretstream_xchacha20poly1305_TAG_REKEY;
305 }
306 
307 unsigned char
308 crypto_secretstream_xchacha20poly1305_tag_final(void)
309 {
310     return crypto_secretstream_xchacha20poly1305_TAG_FINAL;
311 }
312