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
_crypto_secretstream_xchacha20poly1305_counter_reset(crypto_secretstream_xchacha20poly1305_state * state)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
crypto_secretstream_xchacha20poly1305_keygen(unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])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
crypto_secretstream_xchacha20poly1305_init_push(crypto_secretstream_xchacha20poly1305_state * state,unsigned char out[crypto_secretstream_xchacha20poly1305_HEADERBYTES],const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])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
crypto_secretstream_xchacha20poly1305_init_pull(crypto_secretstream_xchacha20poly1305_state * state,const unsigned char in[crypto_secretstream_xchacha20poly1305_HEADERBYTES],const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])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
crypto_secretstream_xchacha20poly1305_rekey(crypto_secretstream_xchacha20poly1305_state * state)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
crypto_secretstream_xchacha20poly1305_push(crypto_secretstream_xchacha20poly1305_state * state,unsigned char * out,unsigned long long * outlen_p,const unsigned char * m,unsigned long long mlen,const unsigned char * ad,unsigned long long adlen,unsigned char tag)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
crypto_secretstream_xchacha20poly1305_pull(crypto_secretstream_xchacha20poly1305_state * state,unsigned char * m,unsigned long long * mlen_p,unsigned char * tag_p,const unsigned char * in,unsigned long long inlen,const unsigned char * ad,unsigned long long adlen)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
crypto_secretstream_xchacha20poly1305_statebytes(void)260 crypto_secretstream_xchacha20poly1305_statebytes(void)
261 {
262 return sizeof(crypto_secretstream_xchacha20poly1305_state);
263 }
264
265 size_t
crypto_secretstream_xchacha20poly1305_abytes(void)266 crypto_secretstream_xchacha20poly1305_abytes(void)
267 {
268 return crypto_secretstream_xchacha20poly1305_ABYTES;
269 }
270
271 size_t
crypto_secretstream_xchacha20poly1305_headerbytes(void)272 crypto_secretstream_xchacha20poly1305_headerbytes(void)
273 {
274 return crypto_secretstream_xchacha20poly1305_HEADERBYTES;
275 }
276
277 size_t
crypto_secretstream_xchacha20poly1305_keybytes(void)278 crypto_secretstream_xchacha20poly1305_keybytes(void)
279 {
280 return crypto_secretstream_xchacha20poly1305_KEYBYTES;
281 }
282
283 size_t
crypto_secretstream_xchacha20poly1305_messagebytes_max(void)284 crypto_secretstream_xchacha20poly1305_messagebytes_max(void)
285 {
286 return crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX;
287 }
288
289 unsigned char
crypto_secretstream_xchacha20poly1305_tag_message(void)290 crypto_secretstream_xchacha20poly1305_tag_message(void)
291 {
292 return crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
293 }
294
295 unsigned char
crypto_secretstream_xchacha20poly1305_tag_push(void)296 crypto_secretstream_xchacha20poly1305_tag_push(void)
297 {
298 return crypto_secretstream_xchacha20poly1305_TAG_PUSH;
299 }
300
301 unsigned char
crypto_secretstream_xchacha20poly1305_tag_rekey(void)302 crypto_secretstream_xchacha20poly1305_tag_rekey(void)
303 {
304 return crypto_secretstream_xchacha20poly1305_TAG_REKEY;
305 }
306
307 unsigned char
crypto_secretstream_xchacha20poly1305_tag_final(void)308 crypto_secretstream_xchacha20poly1305_tag_final(void)
309 {
310 return crypto_secretstream_xchacha20poly1305_TAG_FINAL;
311 }
312