summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/evp/e_chacha20poly1305.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/evp/e_chacha20poly1305.c')
-rw-r--r--src/lib/libcrypto/evp/e_chacha20poly1305.c123
1 files changed, 122 insertions, 1 deletions
diff --git a/src/lib/libcrypto/evp/e_chacha20poly1305.c b/src/lib/libcrypto/evp/e_chacha20poly1305.c
index 089ef12fb3..a5cf8a19f2 100644
--- a/src/lib/libcrypto/evp/e_chacha20poly1305.c
+++ b/src/lib/libcrypto/evp/e_chacha20poly1305.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: e_chacha20poly1305.c,v 1.18 2017/08/28 17:48:02 jsing Exp $ */ 1/* $OpenBSD: e_chacha20poly1305.c,v 1.19 2019/01/22 00:59:21 dlg Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org> 4 * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org>
@@ -36,6 +36,7 @@
36#define CHACHA20_CONSTANT_LEN 4 36#define CHACHA20_CONSTANT_LEN 4
37#define CHACHA20_IV_LEN 8 37#define CHACHA20_IV_LEN 8
38#define CHACHA20_NONCE_LEN (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN) 38#define CHACHA20_NONCE_LEN (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN)
39#define XCHACHA20_NONCE_LEN 24
39 40
40struct aead_chacha20_poly1305_ctx { 41struct aead_chacha20_poly1305_ctx {
41 unsigned char key[32]; 42 unsigned char key[32];
@@ -246,6 +247,108 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
246 return 1; 247 return 1;
247} 248}
248 249
250static int
251aead_xchacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
252 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
253 size_t nonce_len, const unsigned char *in, size_t in_len,
254 const unsigned char *ad, size_t ad_len)
255{
256 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
257 unsigned char poly1305_key[32];
258 unsigned char subkey[32];
259 poly1305_state poly1305;
260
261 if (max_out_len < in_len + c20_ctx->tag_len) {
262 EVPerror(EVP_R_BUFFER_TOO_SMALL);
263 return 0;
264 }
265
266 if (nonce_len != ctx->aead->nonce_len) {
267 EVPerror(EVP_R_IV_TOO_LARGE);
268 return 0;
269 }
270
271 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce);
272
273 CRYPTO_chacha_20(out, in, in_len, subkey, nonce + 16, 1);
274
275 memset(poly1305_key, 0, sizeof(poly1305_key));
276 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
277 subkey, nonce + 16, 0);
278
279 CRYPTO_poly1305_init(&poly1305, poly1305_key);
280 poly1305_update_with_pad16(&poly1305, ad, ad_len);
281 poly1305_update_with_pad16(&poly1305, out, in_len);
282 poly1305_update_with_length(&poly1305, NULL, ad_len);
283 poly1305_update_with_length(&poly1305, NULL, in_len);
284
285 if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
286 unsigned char tag[POLY1305_TAG_LEN];
287 CRYPTO_poly1305_finish(&poly1305, tag);
288 memcpy(out + in_len, tag, c20_ctx->tag_len);
289 *out_len = in_len + c20_ctx->tag_len;
290 return 1;
291 }
292
293 CRYPTO_poly1305_finish(&poly1305, out + in_len);
294 *out_len = in_len + POLY1305_TAG_LEN;
295 return 1;
296}
297
298static int
299aead_xchacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
300 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
301 size_t nonce_len, const unsigned char *in, size_t in_len,
302 const unsigned char *ad, size_t ad_len)
303{
304 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
305 unsigned char mac[POLY1305_TAG_LEN];
306 unsigned char poly1305_key[32];
307 unsigned char subkey[32];
308 poly1305_state poly1305;
309 size_t plaintext_len;
310
311 if (in_len < c20_ctx->tag_len) {
312 EVPerror(EVP_R_BAD_DECRYPT);
313 return 0;
314 }
315
316 if (nonce_len != ctx->aead->nonce_len) {
317 EVPerror(EVP_R_IV_TOO_LARGE);
318 return 0;
319 }
320
321 plaintext_len = in_len - c20_ctx->tag_len;
322
323 if (max_out_len < plaintext_len) {
324 EVPerror(EVP_R_BUFFER_TOO_SMALL);
325 return 0;
326 }
327
328 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce);
329
330 memset(poly1305_key, 0, sizeof(poly1305_key));
331 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
332 subkey, nonce + 16, 0);
333
334 CRYPTO_poly1305_init(&poly1305, poly1305_key);
335 poly1305_update_with_pad16(&poly1305, ad, ad_len);
336 poly1305_update_with_pad16(&poly1305, in, plaintext_len);
337 poly1305_update_with_length(&poly1305, NULL, ad_len);
338 poly1305_update_with_length(&poly1305, NULL, plaintext_len);
339
340 CRYPTO_poly1305_finish(&poly1305, mac);
341 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
342 EVPerror(EVP_R_BAD_DECRYPT);
343 return 0;
344 }
345
346 CRYPTO_chacha_20(out, in, plaintext_len, subkey, nonce + 16, 1);
347
348 *out_len = plaintext_len;
349 return 1;
350}
351
249/* RFC 7539 */ 352/* RFC 7539 */
250static const EVP_AEAD aead_chacha20_poly1305 = { 353static const EVP_AEAD aead_chacha20_poly1305 = {
251 .key_len = 32, 354 .key_len = 32,
@@ -265,4 +368,22 @@ EVP_aead_chacha20_poly1305()
265 return &aead_chacha20_poly1305; 368 return &aead_chacha20_poly1305;
266} 369}
267 370
371static const EVP_AEAD aead_xchacha20_poly1305 = {
372 .key_len = 32,
373 .nonce_len = XCHACHA20_NONCE_LEN,
374 .overhead = POLY1305_TAG_LEN,
375 .max_tag_len = POLY1305_TAG_LEN,
376
377 .init = aead_chacha20_poly1305_init,
378 .cleanup = aead_chacha20_poly1305_cleanup,
379 .seal = aead_xchacha20_poly1305_seal,
380 .open = aead_xchacha20_poly1305_open,
381};
382
383const EVP_AEAD *
384EVP_aead_xchacha20_poly1305()
385{
386 return &aead_xchacha20_poly1305;
387}
388
268#endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ 389#endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */