1
2#define TEST_NAME "secretstream"
3#include "cmptest.h"
4
5int
6main(void)
7{
8    crypto_secretstream_xchacha20poly1305_state *state, *statesave;
9    crypto_secretstream_xchacha20poly1305_state state_copy;
10    unsigned char      *ad;
11    unsigned char      *header;
12    unsigned char      *k;
13    unsigned char      *c1, *c2, *c3, *csave;
14    unsigned char      *m1, *m2, *m3;
15    unsigned char      *m1_, *m2_, *m3_;
16    unsigned long long  res_len;
17    size_t              ad_len;
18    size_t              m1_len, m2_len, m3_len;
19    int                 ret;
20    unsigned char       tag;
21
22    state = (crypto_secretstream_xchacha20poly1305_state *)
23        sodium_malloc(crypto_secretstream_xchacha20poly1305_statebytes());
24    statesave = (crypto_secretstream_xchacha20poly1305_state *)
25        sodium_malloc(crypto_secretstream_xchacha20poly1305_statebytes());
26    header = (unsigned char *)
27        sodium_malloc(crypto_secretstream_xchacha20poly1305_HEADERBYTES);
28
29    ad_len = randombytes_uniform(100);
30    m1_len = randombytes_uniform(1000);
31    m2_len = randombytes_uniform(1000);
32    m3_len = randombytes_uniform(1000);
33
34    c1 = (unsigned char *)
35        sodium_malloc(m1_len + crypto_secretstream_xchacha20poly1305_ABYTES);
36    c2 = (unsigned char *)
37        sodium_malloc(m2_len + crypto_secretstream_xchacha20poly1305_ABYTES);
38    c3 = (unsigned char *)
39        sodium_malloc(m3_len + crypto_secretstream_xchacha20poly1305_ABYTES);
40    csave = (unsigned char *)
41        sodium_malloc((m1_len | m2_len | m3_len) + crypto_secretstream_xchacha20poly1305_ABYTES);
42
43    ad  = (unsigned char *) sodium_malloc(ad_len);
44    m1  = (unsigned char *) sodium_malloc(m1_len);
45    m2  = (unsigned char *) sodium_malloc(m2_len);
46    m3  = (unsigned char *) sodium_malloc(m3_len);
47    m1_ = (unsigned char *) sodium_malloc(m1_len);
48    m2_ = (unsigned char *) sodium_malloc(m2_len);
49    m3_ = (unsigned char *) sodium_malloc(m3_len);
50
51    randombytes_buf(ad, ad_len);
52
53    randombytes_buf(m1, m1_len);
54    memcpy(m1_, m1, m1_len);
55    randombytes_buf(m2, m2_len);
56    memcpy(m2_, m2, m2_len);
57    randombytes_buf(m3, m3_len);
58    memcpy(m3_, m3, m3_len);
59
60    k = (unsigned char *)
61        sodium_malloc(crypto_secretstream_xchacha20poly1305_KEYBYTES);
62    crypto_secretstream_xchacha20poly1305_keygen(k);
63
64    /* push */
65
66    ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k);
67    assert(ret == 0);
68
69    ret = crypto_secretstream_xchacha20poly1305_push
70        (state, c1, &res_len, m1, m1_len, NULL, 0, 0);
71    assert(ret == 0);
72    assert(res_len == m1_len + crypto_secretstream_xchacha20poly1305_ABYTES);
73
74    ret = crypto_secretstream_xchacha20poly1305_push
75        (state, c2, NULL, m2, m2_len, ad, 0, 0);
76    assert(ret == 0);
77
78    ret = crypto_secretstream_xchacha20poly1305_push
79        (state, c3, NULL, m3, m3_len, ad, ad_len,
80         crypto_secretstream_xchacha20poly1305_TAG_FINAL);
81    assert(ret == 0);
82
83    /* pull */
84
85    ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k);
86    assert(ret == 0);
87
88    ret = crypto_secretstream_xchacha20poly1305_pull
89        (state, m1, &res_len, &tag,
90         c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
91    assert(ret == 0);
92    assert(tag == 0);
93    assert(memcmp(m1, m1_, m1_len) == 0);
94    assert(res_len == m1_len);
95
96    ret = crypto_secretstream_xchacha20poly1305_pull
97        (state, m2, NULL, &tag,
98         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
99    assert(ret == 0);
100    assert(tag == 0);
101    assert(memcmp(m2, m2_, m2_len) == 0);
102
103    if (ad_len > 0) {
104        ret = crypto_secretstream_xchacha20poly1305_pull
105            (state, m3, NULL, &tag,
106             c3, m3_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
107        assert(ret == -1);
108    }
109    ret = crypto_secretstream_xchacha20poly1305_pull
110        (state, m3, NULL, &tag,
111         c3, m3_len + crypto_secretstream_xchacha20poly1305_ABYTES, ad, ad_len);
112    assert(ret == 0);
113    assert(tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL);
114    assert(memcmp(m3, m3_, m3_len) == 0);
115
116    /* previous with FINAL tag */
117
118    ret = crypto_secretstream_xchacha20poly1305_pull
119        (state, m3, NULL, &tag,
120         c3, m3_len + crypto_secretstream_xchacha20poly1305_ABYTES, ad, ad_len);
121    assert(ret == -1);
122
123    /* previous without a tag */
124
125    ret = crypto_secretstream_xchacha20poly1305_pull
126        (state, m2, NULL, &tag,
127         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
128    assert(ret == -1);
129
130    /* short ciphertext */
131
132    ret = crypto_secretstream_xchacha20poly1305_pull
133        (state, m2, NULL, &tag, c2,
134         randombytes_uniform(crypto_secretstream_xchacha20poly1305_ABYTES),
135         NULL, 0);
136    assert(ret == -1);
137    ret = crypto_secretstream_xchacha20poly1305_pull
138        (state, m2, NULL, &tag, c2, 0, NULL, 0);
139    assert(ret == -1);
140
141    /* empty ciphertext */
142
143    ret = crypto_secretstream_xchacha20poly1305_pull
144        (state, m2, NULL, &tag, c2,
145         crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
146    assert(ret == -1);
147
148    /* without explicit rekeying */
149
150    ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k);
151    assert(ret == 0);
152    ret = crypto_secretstream_xchacha20poly1305_push
153        (state, c1, NULL, m1, m1_len, NULL, 0, 0);
154    assert(ret == 0);
155    ret = crypto_secretstream_xchacha20poly1305_push
156        (state, c2, NULL, m2, m2_len, NULL, 0, 0);
157    assert(ret == 0);
158
159    ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k);
160    assert(ret == 0);
161    ret = crypto_secretstream_xchacha20poly1305_pull
162        (state, m1, NULL, &tag,
163         c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
164    assert(ret == 0);
165    ret = crypto_secretstream_xchacha20poly1305_pull
166        (state, m2, NULL, &tag,
167         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
168    assert(ret == 0);
169
170    /* with explicit rekeying */
171
172    ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k);
173    assert(ret == 0);
174    ret = crypto_secretstream_xchacha20poly1305_push
175        (state, c1, NULL, m1, m1_len, NULL, 0, 0);
176    assert(ret == 0);
177
178    crypto_secretstream_xchacha20poly1305_rekey(state);
179
180    ret = crypto_secretstream_xchacha20poly1305_push
181        (state, c2, NULL, m2, m2_len, NULL, 0, 0);
182    assert(ret == 0);
183
184    ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k);
185    assert(ret == 0);
186    ret = crypto_secretstream_xchacha20poly1305_pull
187        (state, m1, NULL, &tag,
188         c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
189    assert(ret == 0);
190
191    ret = crypto_secretstream_xchacha20poly1305_pull
192        (state, m2, NULL, &tag,
193         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
194    assert(ret == -1);
195
196    crypto_secretstream_xchacha20poly1305_rekey(state);
197
198    ret = crypto_secretstream_xchacha20poly1305_pull
199        (state, m2, NULL, &tag,
200         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
201    assert(ret == 0);
202
203    /* with explicit rekeying using TAG_REKEY */
204
205    ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k);
206    assert(ret == 0);
207
208    memcpy(statesave, state, sizeof *state);
209
210    ret = crypto_secretstream_xchacha20poly1305_push
211        (state, c1, NULL, m1, m1_len, NULL, 0, crypto_secretstream_xchacha20poly1305_TAG_REKEY);
212    assert(ret == 0);
213
214    ret = crypto_secretstream_xchacha20poly1305_push
215        (state, c2, NULL, m2, m2_len, NULL, 0, 0);
216    assert(ret == 0);
217
218    memcpy(csave, c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES);
219
220    ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k);
221    assert(ret == 0);
222    ret = crypto_secretstream_xchacha20poly1305_pull
223        (state, m1, NULL, &tag,
224         c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, &tag, 0);
225    assert(ret == 0);
226    assert(tag == crypto_secretstream_xchacha20poly1305_TAG_REKEY);
227
228    ret = crypto_secretstream_xchacha20poly1305_pull
229        (state, m2, NULL, &tag,
230         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, &tag, 0);
231    assert(ret == 0);
232    assert(tag == 0);
233
234    memcpy(state, statesave, sizeof *state);
235
236    ret = crypto_secretstream_xchacha20poly1305_push
237        (state, c1, NULL, m1, m1_len, NULL, 0, 0);
238    assert(ret == 0);
239
240    ret = crypto_secretstream_xchacha20poly1305_push
241        (state, c2, NULL, m2, m2_len, NULL, 0, 0);
242    assert(ret == 0);
243
244    assert(memcmp(csave, c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES) != 0);
245
246    /* New stream */
247
248    ret = crypto_secretstream_xchacha20poly1305_init_push(state, header, k);
249    assert(ret == 0);
250
251    ret = crypto_secretstream_xchacha20poly1305_push
252        (state, c1, &res_len, m1, m1_len, NULL, 0,
253         crypto_secretstream_xchacha20poly1305_TAG_PUSH);
254    assert(ret == 0);
255    assert(res_len == m1_len + crypto_secretstream_xchacha20poly1305_ABYTES);
256
257    /* Force a counter overflow, check that the key has been updated
258     * even though the tag was not changed to REKEY */
259
260    memset(state->nonce, 0xff, 4U);
261    state_copy = *state;
262
263    ret = crypto_secretstream_xchacha20poly1305_push
264        (state, c2, NULL, m2, m2_len, ad, 0, 0);
265    assert(ret == 0);
266
267    assert(memcmp(state_copy.k, state->k, sizeof state->k) != 0);
268    assert(memcmp(state_copy.nonce, state->nonce, sizeof state->nonce) != 0);
269    assert(state->nonce[0] == 1U);
270    assert(sodium_is_zero(state->nonce + 1, 3U));
271
272    ret = crypto_secretstream_xchacha20poly1305_init_pull(state, header, k);
273    assert(ret == 0);
274
275    ret = crypto_secretstream_xchacha20poly1305_pull
276        (state, m1, &res_len, &tag,
277         c1, m1_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
278    assert(ret == 0);
279    assert(tag == crypto_secretstream_xchacha20poly1305_TAG_PUSH);
280    assert(memcmp(m1, m1_, m1_len) == 0);
281    assert(res_len == m1_len);
282
283    memset(state->nonce, 0xff, 4U);
284
285    ret = crypto_secretstream_xchacha20poly1305_pull
286        (state, m2, NULL, &tag,
287         c2, m2_len + crypto_secretstream_xchacha20poly1305_ABYTES, NULL, 0);
288    assert(ret == 0);
289    assert(tag == 0);
290    assert(memcmp(m2, m2_, m2_len) == 0);
291
292    sodium_free(m3_);
293    sodium_free(m2_);
294    sodium_free(m1_);
295    sodium_free(m3);
296    sodium_free(m2);
297    sodium_free(m1);
298    sodium_free(ad);
299    sodium_free(csave);
300    sodium_free(c3);
301    sodium_free(c2);
302    sodium_free(c1);
303    sodium_free(k);
304    sodium_free(header);
305    sodium_free(statesave);
306    sodium_free(state);
307
308    assert(crypto_secretstream_xchacha20poly1305_abytes() ==
309           crypto_secretstream_xchacha20poly1305_ABYTES);
310    assert(crypto_secretstream_xchacha20poly1305_headerbytes() ==
311           crypto_secretstream_xchacha20poly1305_HEADERBYTES);
312    assert(crypto_secretstream_xchacha20poly1305_keybytes() ==
313           crypto_secretstream_xchacha20poly1305_KEYBYTES);
314    assert(crypto_secretstream_xchacha20poly1305_messagebytes_max() ==
315           crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX);
316
317    assert(crypto_secretstream_xchacha20poly1305_tag_message() ==
318           crypto_secretstream_xchacha20poly1305_TAG_MESSAGE);
319    assert(crypto_secretstream_xchacha20poly1305_tag_push() ==
320           crypto_secretstream_xchacha20poly1305_TAG_PUSH);
321    assert(crypto_secretstream_xchacha20poly1305_tag_rekey() ==
322           crypto_secretstream_xchacha20poly1305_TAG_REKEY);
323    assert(crypto_secretstream_xchacha20poly1305_tag_final() ==
324           crypto_secretstream_xchacha20poly1305_TAG_FINAL);
325
326    printf("OK\n");
327
328    return 0;
329}
330