]>
Commit | Line | Data |
---|---|---|
bd989745 AP |
1 | /* ==================================================================== |
2 | * Copyright (c) 2014 The OpenSSL Project. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in | |
13 | * the documentation and/or other materials provided with the | |
14 | * distribution. | |
15 | * | |
16 | * 3. All advertising materials mentioning features or use of this | |
17 | * software must display the following acknowledgment: | |
18 | * "This product includes software developed by the OpenSSL Project | |
19 | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" | |
20 | * | |
21 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
22 | * endorse or promote products derived from this software without | |
23 | * prior written permission. For written permission, please contact | |
24 | * openssl-core@openssl.org. | |
25 | * | |
26 | * 5. Products derived from this software may not be called "OpenSSL" | |
27 | * nor may "OpenSSL" appear in their names without prior written | |
28 | * permission of the OpenSSL Project. | |
29 | * | |
30 | * 6. Redistributions of any form whatsoever must retain the following | |
31 | * acknowledgment: | |
32 | * "This product includes software developed by the OpenSSL Project | |
33 | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" | |
34 | * | |
35 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
36 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
37 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
38 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
39 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
40 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
41 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
42 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
44 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
45 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
46 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
47 | * ==================================================================== | |
48 | * | |
49 | */ | |
50 | ||
51 | #include <stdio.h> | |
52 | #include "internal/cryptlib.h" | |
53 | ||
54 | #ifndef OPENSSL_NO_CHACHA | |
55 | ||
56 | # include <openssl/evp.h> | |
57 | # include <openssl/objects.h> | |
58 | # include "evp_locl.h" | |
59 | # include "internal/evp_int.h" | |
60 | # include "internal/chacha.h" | |
61 | ||
62 | typedef struct { | |
63 | union { | |
64 | double align; /* this ensures even sizeof(EVP_CHACHA_KEY)%8==0 */ | |
65 | unsigned int d[CHACHA_KEY_SIZE / 4]; | |
66 | } key; | |
67 | unsigned int counter[CHACHA_CTR_SIZE / 4]; | |
68 | unsigned char buf[CHACHA_BLK_SIZE]; | |
69 | unsigned int partial_len; | |
70 | } EVP_CHACHA_KEY; | |
71 | ||
72 | #define data(ctx) ((EVP_CHACHA_KEY *)(ctx)->cipher_data) | |
73 | ||
74 | static int chacha_init_key(EVP_CIPHER_CTX *ctx, | |
75 | const unsigned char user_key[CHACHA_KEY_SIZE], | |
76 | const unsigned char iv[CHACHA_CTR_SIZE], int enc) | |
77 | { | |
78 | EVP_CHACHA_KEY *key = data(ctx); | |
79 | unsigned int i; | |
80 | ||
81 | if (user_key) | |
82 | for (i = 0; i < CHACHA_KEY_SIZE; i+=4) { | |
83 | key->key.d[i/4] = CHACHA_U8TOU32(user_key+i); | |
84 | } | |
85 | ||
86 | if (iv) | |
87 | for (i = 0; i < CHACHA_CTR_SIZE; i+=4) { | |
88 | key->counter[i/4] = CHACHA_U8TOU32(iv+i); | |
89 | } | |
90 | ||
91 | key->partial_len = 0; | |
92 | ||
93 | return 1; | |
94 | } | |
95 | ||
96 | static int chacha_cipher(EVP_CIPHER_CTX * ctx, unsigned char *out, | |
97 | const unsigned char *inp, size_t len) | |
98 | { | |
99 | EVP_CHACHA_KEY *key = data(ctx); | |
100 | unsigned int n, rem, ctr32; | |
101 | ||
102 | if ((n = key->partial_len)) { | |
103 | while (len && n < CHACHA_BLK_SIZE) { | |
104 | *out++ = *inp++ ^ key->buf[n++]; | |
105 | len--; | |
106 | } | |
107 | key->partial_len = n; | |
108 | ||
109 | if (len == 0) | |
110 | return 1; | |
111 | ||
112 | if (n == CHACHA_BLK_SIZE) { | |
113 | key->partial_len = 0; | |
114 | key->counter[0]++; | |
115 | if (key->counter[0] == 0) | |
116 | key->counter[1]++; | |
117 | } | |
118 | } | |
119 | ||
120 | rem = (unsigned int)(len % CHACHA_BLK_SIZE); | |
121 | len -= rem; | |
122 | ctr32 = key->counter[0]; | |
123 | while (len >= CHACHA_BLK_SIZE) { | |
124 | size_t blocks = len / CHACHA_BLK_SIZE; | |
125 | /* | |
126 | * 1<<28 is just a not-so-small yet not-so-large number... | |
127 | * Below condition is practically never met, but it has to | |
128 | * be checked for code correctness. | |
129 | */ | |
130 | if (sizeof(size_t)>sizeof(unsigned int) && blocks>(1U<<28)) | |
131 | blocks = (1U<<28); | |
132 | ||
133 | /* | |
134 | * As ChaCha20_ctr32 operates on 32-bit counter, caller | |
135 | * has to handle overflow. 'if' below detects the | |
136 | * overflow, which is then handled by limiting the | |
137 | * amount of blocks to the exact overflow point... | |
138 | */ | |
139 | ctr32 += (unsigned int)blocks; | |
140 | if (ctr32 < blocks) { | |
141 | blocks -= ctr32; | |
142 | ctr32 = 0; | |
143 | } | |
144 | blocks *= CHACHA_BLK_SIZE; | |
145 | ChaCha20_ctr32(out, inp, blocks, key->key.d, key->counter); | |
146 | len -= blocks; | |
147 | inp += blocks; | |
148 | out += blocks; | |
149 | ||
150 | key->counter[0] = ctr32; | |
151 | if (ctr32 == 0) key->counter[1]++; | |
152 | } | |
153 | ||
154 | if (rem) { | |
155 | memset(key->buf, 0, sizeof(key->buf)); | |
156 | ChaCha20_ctr32(key->buf, key->buf, CHACHA_BLK_SIZE, | |
157 | key->key.d, key->counter); | |
158 | for (n = 0; n < rem; n++) | |
159 | out[n] = inp[n] ^ key->buf[n]; | |
160 | key->partial_len = rem; | |
161 | } | |
162 | ||
163 | return 1; | |
164 | } | |
165 | ||
166 | static const EVP_CIPHER chacha20 = { | |
167 | NID_chacha20, | |
168 | 1, /* block_size */ | |
169 | CHACHA_KEY_SIZE, /* key_len */ | |
170 | CHACHA_CTR_SIZE, /* iv_len, 128-bit counter in the context */ | |
171 | 0, /* flags */ | |
172 | chacha_init_key, | |
173 | chacha_cipher, | |
174 | NULL, | |
175 | sizeof(EVP_CHACHA_KEY), | |
176 | NULL, | |
177 | NULL, | |
178 | NULL, | |
179 | NULL | |
180 | }; | |
181 | ||
182 | const EVP_CIPHER *EVP_chacha20(void) | |
183 | { | |
184 | return (&chacha20); | |
185 | } | |
186 | ||
187 | # ifndef OPENSSL_NO_POLY1305 | |
188 | # include "internal/poly1305.h" | |
189 | ||
190 | typedef struct { | |
191 | EVP_CHACHA_KEY key; | |
192 | unsigned int nonce[12/4]; | |
193 | unsigned char tag[POLY1305_BLOCK_SIZE]; | |
194 | struct { uint64_t aad, text; } len; | |
195 | int aad, mac_inited, tag_len, nonce_len; | |
196 | size_t tls_payload_length; | |
197 | } EVP_CHACHA_AEAD_CTX; | |
198 | ||
199 | # define NO_TLS_PAYLOAD_LENGTH ((size_t)-1) | |
200 | # define aead_data(ctx) ((EVP_CHACHA_AEAD_CTX *)(ctx)->cipher_data) | |
201 | # define POLY1305_ctx(actx) ((POLY1305 *)(actx + 1)) | |
202 | ||
203 | static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx, | |
204 | const unsigned char *inkey, | |
205 | const unsigned char *iv, int enc) | |
206 | { | |
207 | EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx); | |
208 | unsigned char temp[CHACHA_CTR_SIZE]; | |
209 | ||
210 | if (!inkey && !iv) | |
211 | return 1; | |
212 | ||
213 | actx->len.aad = 0; | |
214 | actx->len.text = 0; | |
215 | actx->aad = 0; | |
216 | actx->mac_inited = 0; | |
217 | actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; | |
218 | ||
219 | /* pad on the left */ | |
220 | memset(temp, 0, sizeof(temp)); | |
221 | if (actx->nonce_len <= CHACHA_CTR_SIZE) | |
222 | memcpy(temp + CHACHA_CTR_SIZE - actx->nonce_len, iv, actx->nonce_len); | |
223 | ||
224 | chacha_init_key(ctx, inkey, temp, enc); | |
225 | ||
226 | actx->nonce[0] = actx->key.counter[1]; | |
227 | actx->nonce[1] = actx->key.counter[2]; | |
228 | actx->nonce[2] = actx->key.counter[3]; | |
229 | ||
230 | return 1; | |
231 | } | |
232 | ||
233 | static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, | |
234 | const unsigned char *in, size_t len) | |
235 | { | |
236 | EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx); | |
237 | size_t rem, plen = actx->tls_payload_length; | |
238 | static const unsigned char zero[POLY1305_BLOCK_SIZE] = { 0 }; | |
239 | ||
240 | if (!actx->mac_inited) { | |
241 | actx->key.counter[0] = 0; | |
242 | memset(actx->key.buf, 0, sizeof(actx->key.buf)); | |
243 | ChaCha20_ctr32(actx->key.buf, actx->key.buf, CHACHA_BLK_SIZE, | |
244 | actx->key.key.d, actx->key.counter); | |
245 | Poly1305_Init(POLY1305_ctx(actx), actx->key.buf); | |
246 | actx->key.counter[0] = 1; | |
30a5f322 AP |
247 | actx->key.partial_len = 0; |
248 | actx->len.aad = actx->len.text = 0; | |
bd989745 AP |
249 | actx->mac_inited = 1; |
250 | } | |
251 | ||
252 | if (in) { /* aad or text */ | |
253 | if (out == NULL) { /* aad */ | |
254 | Poly1305_Update(POLY1305_ctx(actx), in, len); | |
255 | actx->len.aad += len; | |
256 | actx->aad = 1; | |
257 | return len; | |
258 | } else { /* plain- or ciphertext */ | |
259 | if (actx->aad) { /* wrap up aad */ | |
260 | if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE)) | |
261 | Poly1305_Update(POLY1305_ctx(actx), zero, | |
262 | POLY1305_BLOCK_SIZE - rem); | |
263 | actx->aad = 0; | |
264 | } | |
265 | ||
266 | actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; | |
267 | if (plen == NO_TLS_PAYLOAD_LENGTH) | |
268 | plen = len; | |
269 | else if (len != plen + POLY1305_BLOCK_SIZE) | |
270 | return -1; | |
271 | ||
272 | if (ctx->encrypt) { /* plaintext */ | |
273 | chacha_cipher(ctx, out, in, plen); | |
274 | Poly1305_Update(POLY1305_ctx(actx), out, plen); | |
275 | in += plen; | |
276 | out += plen; | |
277 | actx->len.text += plen; | |
278 | } else { /* ciphertext */ | |
279 | Poly1305_Update(POLY1305_ctx(actx), in, plen); | |
280 | chacha_cipher(ctx, out, in, plen); | |
281 | in += plen; | |
282 | out += plen; | |
283 | actx->len.text += plen; | |
284 | } | |
285 | } | |
286 | } | |
287 | if (in == NULL /* explicit final */ | |
288 | || plen != len) { /* or tls mode */ | |
289 | const union { | |
290 | long one; | |
291 | char little; | |
292 | } is_endian = { 1 }; | |
293 | unsigned char temp[POLY1305_BLOCK_SIZE]; | |
294 | ||
295 | if (actx->aad) { /* wrap up aad */ | |
296 | if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE)) | |
297 | Poly1305_Update(POLY1305_ctx(actx), zero, | |
298 | POLY1305_BLOCK_SIZE - rem); | |
299 | actx->aad = 0; | |
300 | } | |
301 | ||
302 | if ((rem = (size_t)actx->len.text % POLY1305_BLOCK_SIZE)) | |
303 | Poly1305_Update(POLY1305_ctx(actx), zero, | |
304 | POLY1305_BLOCK_SIZE - rem); | |
305 | ||
306 | if (is_endian.little) { | |
307 | Poly1305_Update(POLY1305_ctx(actx), | |
308 | (unsigned char *)&actx->len, POLY1305_BLOCK_SIZE); | |
309 | } else { | |
310 | temp[0] = (unsigned char)(actx->len.aad); | |
311 | temp[1] = (unsigned char)(actx->len.aad>>8); | |
312 | temp[2] = (unsigned char)(actx->len.aad>>16); | |
313 | temp[3] = (unsigned char)(actx->len.aad>>24); | |
314 | temp[4] = (unsigned char)(actx->len.aad>>32); | |
315 | temp[5] = (unsigned char)(actx->len.aad>>40); | |
316 | temp[6] = (unsigned char)(actx->len.aad>>48); | |
317 | temp[7] = (unsigned char)(actx->len.aad>>56); | |
318 | ||
319 | temp[8] = (unsigned char)(actx->len.text); | |
320 | temp[9] = (unsigned char)(actx->len.text>>8); | |
321 | temp[10] = (unsigned char)(actx->len.text>>16); | |
322 | temp[11] = (unsigned char)(actx->len.text>>24); | |
323 | temp[12] = (unsigned char)(actx->len.text>>32); | |
324 | temp[13] = (unsigned char)(actx->len.text>>40); | |
325 | temp[14] = (unsigned char)(actx->len.text>>48); | |
326 | temp[15] = (unsigned char)(actx->len.text>>56); | |
327 | ||
328 | Poly1305_Update(POLY1305_ctx(actx), temp, POLY1305_BLOCK_SIZE); | |
329 | } | |
330 | Poly1305_Final(POLY1305_ctx(actx), ctx->encrypt ? actx->tag | |
331 | : temp); | |
332 | actx->mac_inited = 0; | |
333 | ||
334 | if (in != NULL && len != plen) { /* tls mode */ | |
335 | if (ctx->encrypt) { | |
336 | memcpy(out, actx->tag, POLY1305_BLOCK_SIZE); | |
337 | } else { | |
338 | if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) { | |
339 | memset(out, 0, plen); | |
340 | return -1; | |
341 | } | |
342 | } | |
343 | } | |
344 | else if (!ctx->encrypt) { | |
345 | if (CRYPTO_memcmp(temp, actx->tag, actx->tag_len)) | |
346 | return -1; | |
347 | } | |
348 | } | |
349 | return len; | |
350 | } | |
351 | ||
352 | static int chacha20_poly1305_cleanup(EVP_CIPHER_CTX *ctx) | |
353 | { | |
354 | EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx); | |
355 | if (actx) | |
356 | OPENSSL_cleanse(ctx->cipher_data, sizeof(*ctx) + Poly1305_ctx_size()); | |
357 | return 1; | |
358 | } | |
359 | ||
360 | static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, | |
361 | void *ptr) | |
362 | { | |
363 | EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx); | |
364 | ||
365 | switch(type) { | |
366 | case EVP_CTRL_INIT: | |
367 | if (actx == NULL) | |
368 | actx = ctx->cipher_data | |
369 | = OPENSSL_zalloc(sizeof(*actx) + Poly1305_ctx_size()); | |
370 | if (actx == NULL) { | |
371 | EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_INITIALIZATION_ERROR); | |
372 | return 0; | |
373 | } | |
374 | actx->len.aad = 0; | |
375 | actx->len.text = 0; | |
376 | actx->aad = 0; | |
377 | actx->mac_inited = 0; | |
378 | actx->tag_len = 0; | |
379 | actx->nonce_len = 12; | |
380 | actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH; | |
381 | return 1; | |
382 | ||
383 | case EVP_CTRL_COPY: | |
384 | if (actx) { | |
385 | if ((((EVP_CIPHER_CTX *)ptr)->cipher_data = | |
7644a9ae | 386 | OPENSSL_memdup(actx,sizeof(*actx) + Poly1305_ctx_size())) |
bd989745 AP |
387 | == NULL) { |
388 | EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_COPY_ERROR); | |
389 | return 0; | |
390 | } | |
391 | } | |
392 | return 1; | |
393 | ||
394 | case EVP_CTRL_AEAD_SET_IVLEN: | |
395 | if (arg <= 0 || arg > CHACHA_CTR_SIZE) | |
396 | return 0; | |
397 | actx->nonce_len = arg; | |
398 | return 1; | |
399 | ||
400 | case EVP_CTRL_AEAD_SET_IV_FIXED: | |
401 | if (arg != 12) | |
402 | return 0; | |
403 | actx->nonce[0] = actx->key.counter[1] | |
404 | = CHACHA_U8TOU32((unsigned char *)ptr); | |
405 | actx->nonce[1] = actx->key.counter[2] | |
406 | = CHACHA_U8TOU32((unsigned char *)ptr+4); | |
407 | actx->nonce[2] = actx->key.counter[3] | |
408 | = CHACHA_U8TOU32((unsigned char *)ptr+8); | |
409 | return 1; | |
410 | ||
411 | case EVP_CTRL_AEAD_SET_TAG: | |
412 | if (arg <= 0 || arg > POLY1305_BLOCK_SIZE) | |
413 | return 0; | |
414 | if (ptr != NULL) { | |
415 | memcpy(actx->tag, ptr, arg); | |
416 | actx->tag_len = arg; | |
417 | } | |
418 | return 1; | |
419 | ||
420 | case EVP_CTRL_AEAD_GET_TAG: | |
421 | if (arg <= 0 || arg > POLY1305_BLOCK_SIZE || !ctx->encrypt) | |
422 | return 0; | |
423 | memcpy(ptr, actx->tag, arg); | |
424 | return 1; | |
425 | ||
426 | case EVP_CTRL_AEAD_TLS1_AAD: | |
427 | if (arg != EVP_AEAD_TLS1_AAD_LEN) | |
428 | return 0; | |
429 | { | |
430 | unsigned int len; | |
30a5f322 | 431 | unsigned char *aad = ptr, temp[POLY1305_BLOCK_SIZE]; |
bd989745 | 432 | |
30a5f322 AP |
433 | len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 | |
434 | aad[EVP_AEAD_TLS1_AAD_LEN - 1]; | |
bd989745 AP |
435 | if (!ctx->encrypt) { |
436 | len -= POLY1305_BLOCK_SIZE; /* discount attached tag */ | |
30a5f322 AP |
437 | memcpy(temp, aad, EVP_AEAD_TLS1_AAD_LEN - 2); |
438 | aad = temp; | |
bd989745 AP |
439 | temp[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8); |
440 | temp[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len; | |
441 | } | |
442 | actx->tls_payload_length = len; | |
443 | ||
444 | /* | |
445 | * merge record sequence number as per | |
446 | * draft-ietf-tls-chacha20-poly1305-03 | |
447 | */ | |
448 | actx->key.counter[1] = actx->nonce[0]; | |
30a5f322 AP |
449 | actx->key.counter[2] = actx->nonce[1] ^ CHACHA_U8TOU32(aad); |
450 | actx->key.counter[3] = actx->nonce[2] ^ CHACHA_U8TOU32(aad+4); | |
bd989745 | 451 | actx->mac_inited = 0; |
30a5f322 | 452 | chacha20_poly1305_cipher(ctx, NULL, aad, EVP_AEAD_TLS1_AAD_LEN); |
bd989745 AP |
453 | return POLY1305_BLOCK_SIZE; /* tag length */ |
454 | } | |
455 | ||
456 | case EVP_CTRL_AEAD_SET_MAC_KEY: | |
457 | /* no-op */ | |
458 | return 1; | |
459 | ||
460 | default: | |
461 | return -1; | |
462 | } | |
463 | } | |
464 | ||
465 | static EVP_CIPHER chacha20_poly1305 = { | |
466 | NID_chacha20_poly1305, | |
467 | 1, /* block_size */ | |
468 | CHACHA_KEY_SIZE, /* key_len */ | |
469 | 12, /* iv_len, 96-bit nonce in the context */ | |
470 | EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_CUSTOM_IV | | |
471 | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | | |
472 | EVP_CIPH_CUSTOM_COPY | EVP_CIPH_FLAG_CUSTOM_CIPHER, | |
473 | chacha20_poly1305_init_key, | |
474 | chacha20_poly1305_cipher, | |
475 | chacha20_poly1305_cleanup, | |
476 | 0, /* 0 moves context-specific structure allocation to ctrl */ | |
477 | NULL, /* set_asn1_parameters */ | |
478 | NULL, /* get_asn1_parameters */ | |
479 | chacha20_poly1305_ctrl, | |
480 | NULL /* app_data */ | |
481 | }; | |
482 | ||
483 | const EVP_CIPHER *EVP_chacha20_poly1305(void) | |
484 | { | |
485 | return(&chacha20_poly1305); | |
486 | } | |
487 | # endif | |
488 | #endif |