diff options
author | Eric Biggers <ebiggers@google.com> | 2018-06-18 13:22:38 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-07-01 09:00:42 -0400 |
commit | bb29648102335586e9a66289a1d98a0cb392b6e5 (patch) | |
tree | 774c44127cdf8b60de47878351fcbf1c7a8c4de5 /crypto/vmac.c | |
parent | 73bf20ef3df262026c3470241ae4ac8196943ffa (diff) |
crypto: vmac - separate tfm and request context
syzbot reported a crash in vmac_final() when multiple threads
concurrently use the same "vmac(aes)" transform through AF_ALG. The bug
is pretty fundamental: the VMAC template doesn't separate per-request
state from per-tfm (per-key) state like the other hash algorithms do,
but rather stores it all in the tfm context. That's wrong.
Also, vmac_final() incorrectly zeroes most of the state including the
derived keys and cached pseudorandom pad. Therefore, only the first
VMAC invocation with a given key calculates the correct digest.
Fix these bugs by splitting the per-tfm state from the per-request state
and using the proper init/update/final sequencing for requests.
Reproducer for the crash:
#include <linux/if_alg.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int fd;
struct sockaddr_alg addr = {
.salg_type = "hash",
.salg_name = "vmac(aes)",
};
char buf[256] = { 0 };
fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(fd, (void *)&addr, sizeof(addr));
setsockopt(fd, SOL_ALG, ALG_SET_KEY, buf, 16);
fork();
fd = accept(fd, NULL, NULL);
for (;;)
write(fd, buf, 256);
}
The immediate cause of the crash is that vmac_ctx_t.partial_size exceeds
VMAC_NHBYTES, causing vmac_final() to memset() a negative length.
Reported-by: syzbot+264bca3a6e8d645550d3@syzkaller.appspotmail.com
Fixes: f1939f7c5645 ("crypto: vmac - New hash algorithm for intel_txt support")
Cc: <stable@vger.kernel.org> # v2.6.32+
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/vmac.c')
-rw-r--r-- | crypto/vmac.c | 408 |
1 files changed, 181 insertions, 227 deletions
diff --git a/crypto/vmac.c b/crypto/vmac.c index 3034454a3713..bb2fc787d615 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c | |||
@@ -1,6 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Modified to interface to the Linux kernel | 2 | * VMAC: Message Authentication Code using Universal Hashing |
3 | * | ||
4 | * Reference: https://tools.ietf.org/html/draft-krovetz-vmac-01 | ||
5 | * | ||
3 | * Copyright (c) 2009, Intel Corporation. | 6 | * Copyright (c) 2009, Intel Corporation. |
7 | * Copyright (c) 2018, Google Inc. | ||
4 | * | 8 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms and conditions of the GNU General Public License, | 10 | * under the terms and conditions of the GNU General Public License, |
@@ -16,14 +20,15 @@ | |||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | 20 | * Place - Suite 330, Boston, MA 02111-1307 USA. |
17 | */ | 21 | */ |
18 | 22 | ||
19 | /* -------------------------------------------------------------------------- | 23 | /* |
20 | * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. | 24 | * Derived from: |
21 | * This implementation is herby placed in the public domain. | 25 | * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. |
22 | * The authors offers no warranty. Use at your own risk. | 26 | * This implementation is herby placed in the public domain. |
23 | * Please send bug reports to the authors. | 27 | * The authors offers no warranty. Use at your own risk. |
24 | * Last modified: 17 APR 08, 1700 PDT | 28 | * Last modified: 17 APR 08, 1700 PDT |
25 | * ----------------------------------------------------------------------- */ | 29 | */ |
26 | 30 | ||
31 | #include <asm/unaligned.h> | ||
27 | #include <linux/init.h> | 32 | #include <linux/init.h> |
28 | #include <linux/types.h> | 33 | #include <linux/types.h> |
29 | #include <linux/crypto.h> | 34 | #include <linux/crypto.h> |
@@ -31,10 +36,36 @@ | |||
31 | #include <linux/scatterlist.h> | 36 | #include <linux/scatterlist.h> |
32 | #include <asm/byteorder.h> | 37 | #include <asm/byteorder.h> |
33 | #include <crypto/scatterwalk.h> | 38 | #include <crypto/scatterwalk.h> |
34 | #include <crypto/vmac.h> | ||
35 | #include <crypto/internal/hash.h> | 39 | #include <crypto/internal/hash.h> |
36 | 40 | ||
37 | /* | 41 | /* |
42 | * User definable settings. | ||
43 | */ | ||
44 | #define VMAC_TAG_LEN 64 | ||
45 | #define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ | ||
46 | #define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) | ||
47 | #define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ | ||
48 | |||
49 | /* per-transform (per-key) context */ | ||
50 | struct vmac_tfm_ctx { | ||
51 | struct crypto_cipher *cipher; | ||
52 | u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; | ||
53 | u64 polykey[2*VMAC_TAG_LEN/64]; | ||
54 | u64 l3key[2*VMAC_TAG_LEN/64]; | ||
55 | }; | ||
56 | |||
57 | /* per-request context */ | ||
58 | struct vmac_desc_ctx { | ||
59 | union { | ||
60 | u8 partial[VMAC_NHBYTES]; /* partial block */ | ||
61 | __le64 partial_words[VMAC_NHBYTES / 8]; | ||
62 | }; | ||
63 | unsigned int partial_size; /* size of the partial block */ | ||
64 | bool first_block_processed; | ||
65 | u64 polytmp[2*VMAC_TAG_LEN/64]; /* running total of L2-hash */ | ||
66 | }; | ||
67 | |||
68 | /* | ||
38 | * Constants and masks | 69 | * Constants and masks |
39 | */ | 70 | */ |
40 | #define UINT64_C(x) x##ULL | 71 | #define UINT64_C(x) x##ULL |
@@ -318,13 +349,6 @@ static void poly_step_func(u64 *ahi, u64 *alo, | |||
318 | } while (0) | 349 | } while (0) |
319 | #endif | 350 | #endif |
320 | 351 | ||
321 | static void vhash_abort(struct vmac_ctx *ctx) | ||
322 | { | ||
323 | ctx->polytmp[0] = ctx->polykey[0] ; | ||
324 | ctx->polytmp[1] = ctx->polykey[1] ; | ||
325 | ctx->first_block_processed = 0; | ||
326 | } | ||
327 | |||
328 | static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) | 352 | static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) |
329 | { | 353 | { |
330 | u64 rh, rl, t, z = 0; | 354 | u64 rh, rl, t, z = 0; |
@@ -364,280 +388,209 @@ static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) | |||
364 | return rl; | 388 | return rl; |
365 | } | 389 | } |
366 | 390 | ||
367 | static void vhash_update(const unsigned char *m, | 391 | /* L1 and L2-hash one or more VMAC_NHBYTES-byte blocks */ |
368 | unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */ | 392 | static void vhash_blocks(const struct vmac_tfm_ctx *tctx, |
369 | struct vmac_ctx *ctx) | 393 | struct vmac_desc_ctx *dctx, |
394 | const __le64 *mptr, unsigned int blocks) | ||
370 | { | 395 | { |
371 | u64 rh, rl, *mptr; | 396 | const u64 *kptr = tctx->nhkey; |
372 | const u64 *kptr = (u64 *)ctx->nhkey; | 397 | const u64 pkh = tctx->polykey[0]; |
373 | int i; | 398 | const u64 pkl = tctx->polykey[1]; |
374 | u64 ch, cl; | 399 | u64 ch = dctx->polytmp[0]; |
375 | u64 pkh = ctx->polykey[0]; | 400 | u64 cl = dctx->polytmp[1]; |
376 | u64 pkl = ctx->polykey[1]; | 401 | u64 rh, rl; |
377 | 402 | ||
378 | if (!mbytes) | 403 | if (!dctx->first_block_processed) { |
379 | return; | 404 | dctx->first_block_processed = true; |
380 | |||
381 | BUG_ON(mbytes % VMAC_NHBYTES); | ||
382 | |||
383 | mptr = (u64 *)m; | ||
384 | i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ | ||
385 | |||
386 | ch = ctx->polytmp[0]; | ||
387 | cl = ctx->polytmp[1]; | ||
388 | |||
389 | if (!ctx->first_block_processed) { | ||
390 | ctx->first_block_processed = 1; | ||
391 | nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); | 405 | nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); |
392 | rh &= m62; | 406 | rh &= m62; |
393 | ADD128(ch, cl, rh, rl); | 407 | ADD128(ch, cl, rh, rl); |
394 | mptr += (VMAC_NHBYTES/sizeof(u64)); | 408 | mptr += (VMAC_NHBYTES/sizeof(u64)); |
395 | i--; | 409 | blocks--; |
396 | } | 410 | } |
397 | 411 | ||
398 | while (i--) { | 412 | while (blocks--) { |
399 | nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); | 413 | nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); |
400 | rh &= m62; | 414 | rh &= m62; |
401 | poly_step(ch, cl, pkh, pkl, rh, rl); | 415 | poly_step(ch, cl, pkh, pkl, rh, rl); |
402 | mptr += (VMAC_NHBYTES/sizeof(u64)); | 416 | mptr += (VMAC_NHBYTES/sizeof(u64)); |
403 | } | 417 | } |
404 | 418 | ||
405 | ctx->polytmp[0] = ch; | 419 | dctx->polytmp[0] = ch; |
406 | ctx->polytmp[1] = cl; | 420 | dctx->polytmp[1] = cl; |
407 | } | 421 | } |
408 | 422 | ||
409 | static u64 vhash(unsigned char m[], unsigned int mbytes, | 423 | static int vmac_setkey(struct crypto_shash *tfm, |
410 | u64 *tagl, struct vmac_ctx *ctx) | 424 | const u8 *key, unsigned int keylen) |
411 | { | 425 | { |
412 | u64 rh, rl, *mptr; | 426 | struct vmac_tfm_ctx *tctx = crypto_shash_ctx(tfm); |
413 | const u64 *kptr = (u64 *)ctx->nhkey; | 427 | __be64 out[2]; |
414 | int i, remaining; | 428 | u8 in[16] = { 0 }; |
415 | u64 ch, cl; | 429 | unsigned int i; |
416 | u64 pkh = ctx->polykey[0]; | 430 | int err; |
417 | u64 pkl = ctx->polykey[1]; | ||
418 | |||
419 | mptr = (u64 *)m; | ||
420 | i = mbytes / VMAC_NHBYTES; | ||
421 | remaining = mbytes % VMAC_NHBYTES; | ||
422 | |||
423 | if (ctx->first_block_processed) { | ||
424 | ch = ctx->polytmp[0]; | ||
425 | cl = ctx->polytmp[1]; | ||
426 | } else if (i) { | ||
427 | nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, ch, cl); | ||
428 | ch &= m62; | ||
429 | ADD128(ch, cl, pkh, pkl); | ||
430 | mptr += (VMAC_NHBYTES/sizeof(u64)); | ||
431 | i--; | ||
432 | } else if (remaining) { | ||
433 | nh_16(mptr, kptr, 2*((remaining+15)/16), ch, cl); | ||
434 | ch &= m62; | ||
435 | ADD128(ch, cl, pkh, pkl); | ||
436 | mptr += (VMAC_NHBYTES/sizeof(u64)); | ||
437 | goto do_l3; | ||
438 | } else {/* Empty String */ | ||
439 | ch = pkh; cl = pkl; | ||
440 | goto do_l3; | ||
441 | } | ||
442 | |||
443 | while (i--) { | ||
444 | nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); | ||
445 | rh &= m62; | ||
446 | poly_step(ch, cl, pkh, pkl, rh, rl); | ||
447 | mptr += (VMAC_NHBYTES/sizeof(u64)); | ||
448 | } | ||
449 | if (remaining) { | ||
450 | nh_16(mptr, kptr, 2*((remaining+15)/16), rh, rl); | ||
451 | rh &= m62; | ||
452 | poly_step(ch, cl, pkh, pkl, rh, rl); | ||
453 | } | ||
454 | |||
455 | do_l3: | ||
456 | vhash_abort(ctx); | ||
457 | remaining *= 8; | ||
458 | return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1], remaining); | ||
459 | } | ||
460 | 431 | ||
461 | static u64 vmac(unsigned char m[], unsigned int mbytes, | 432 | if (keylen != VMAC_KEY_LEN) { |
462 | const unsigned char n[16], u64 *tagl, | 433 | crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); |
463 | struct vmac_ctx_t *ctx) | 434 | return -EINVAL; |
464 | { | ||
465 | u64 *in_n, *out_p; | ||
466 | u64 p, h; | ||
467 | int i; | ||
468 | |||
469 | in_n = ctx->__vmac_ctx.cached_nonce; | ||
470 | out_p = ctx->__vmac_ctx.cached_aes; | ||
471 | |||
472 | i = n[15] & 1; | ||
473 | if ((*(u64 *)(n+8) != in_n[1]) || (*(u64 *)(n) != in_n[0])) { | ||
474 | in_n[0] = *(u64 *)(n); | ||
475 | in_n[1] = *(u64 *)(n+8); | ||
476 | ((unsigned char *)in_n)[15] &= 0xFE; | ||
477 | crypto_cipher_encrypt_one(ctx->child, | ||
478 | (unsigned char *)out_p, (unsigned char *)in_n); | ||
479 | |||
480 | ((unsigned char *)in_n)[15] |= (unsigned char)(1-i); | ||
481 | } | 435 | } |
482 | p = be64_to_cpup(out_p + i); | ||
483 | h = vhash(m, mbytes, (u64 *)0, &ctx->__vmac_ctx); | ||
484 | return le64_to_cpu(p + h); | ||
485 | } | ||
486 | 436 | ||
487 | static int vmac_set_key(unsigned char user_key[], struct vmac_ctx_t *ctx) | 437 | err = crypto_cipher_setkey(tctx->cipher, key, keylen); |
488 | { | ||
489 | u64 in[2] = {0}, out[2]; | ||
490 | unsigned i; | ||
491 | int err = 0; | ||
492 | |||
493 | err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN); | ||
494 | if (err) | 438 | if (err) |
495 | return err; | 439 | return err; |
496 | 440 | ||
497 | /* Fill nh key */ | 441 | /* Fill nh key */ |
498 | ((unsigned char *)in)[0] = 0x80; | 442 | in[0] = 0x80; |
499 | for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i += 2) { | 443 | for (i = 0; i < ARRAY_SIZE(tctx->nhkey); i += 2) { |
500 | crypto_cipher_encrypt_one(ctx->child, | 444 | crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); |
501 | (unsigned char *)out, (unsigned char *)in); | 445 | tctx->nhkey[i] = be64_to_cpu(out[0]); |
502 | ctx->__vmac_ctx.nhkey[i] = be64_to_cpup(out); | 446 | tctx->nhkey[i+1] = be64_to_cpu(out[1]); |
503 | ctx->__vmac_ctx.nhkey[i+1] = be64_to_cpup(out+1); | 447 | in[15]++; |
504 | ((unsigned char *)in)[15] += 1; | ||
505 | } | 448 | } |
506 | 449 | ||
507 | /* Fill poly key */ | 450 | /* Fill poly key */ |
508 | ((unsigned char *)in)[0] = 0xC0; | 451 | in[0] = 0xC0; |
509 | in[1] = 0; | 452 | in[15] = 0; |
510 | for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i += 2) { | 453 | for (i = 0; i < ARRAY_SIZE(tctx->polykey); i += 2) { |
511 | crypto_cipher_encrypt_one(ctx->child, | 454 | crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); |
512 | (unsigned char *)out, (unsigned char *)in); | 455 | tctx->polykey[i] = be64_to_cpu(out[0]) & mpoly; |
513 | ctx->__vmac_ctx.polytmp[i] = | 456 | tctx->polykey[i+1] = be64_to_cpu(out[1]) & mpoly; |
514 | ctx->__vmac_ctx.polykey[i] = | 457 | in[15]++; |
515 | be64_to_cpup(out) & mpoly; | ||
516 | ctx->__vmac_ctx.polytmp[i+1] = | ||
517 | ctx->__vmac_ctx.polykey[i+1] = | ||
518 | be64_to_cpup(out+1) & mpoly; | ||
519 | ((unsigned char *)in)[15] += 1; | ||
520 | } | 458 | } |
521 | 459 | ||
522 | /* Fill ip key */ | 460 | /* Fill ip key */ |
523 | ((unsigned char *)in)[0] = 0xE0; | 461 | in[0] = 0xE0; |
524 | in[1] = 0; | 462 | in[15] = 0; |
525 | for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i += 2) { | 463 | for (i = 0; i < ARRAY_SIZE(tctx->l3key); i += 2) { |
526 | do { | 464 | do { |
527 | crypto_cipher_encrypt_one(ctx->child, | 465 | crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); |
528 | (unsigned char *)out, (unsigned char *)in); | 466 | tctx->l3key[i] = be64_to_cpu(out[0]); |
529 | ctx->__vmac_ctx.l3key[i] = be64_to_cpup(out); | 467 | tctx->l3key[i+1] = be64_to_cpu(out[1]); |
530 | ctx->__vmac_ctx.l3key[i+1] = be64_to_cpup(out+1); | 468 | in[15]++; |
531 | ((unsigned char *)in)[15] += 1; | 469 | } while (tctx->l3key[i] >= p64 || tctx->l3key[i+1] >= p64); |
532 | } while (ctx->__vmac_ctx.l3key[i] >= p64 | ||
533 | || ctx->__vmac_ctx.l3key[i+1] >= p64); | ||
534 | } | 470 | } |
535 | 471 | ||
536 | /* Invalidate nonce/aes cache and reset other elements */ | 472 | return 0; |
537 | ctx->__vmac_ctx.cached_nonce[0] = (u64)-1; /* Ensure illegal nonce */ | ||
538 | ctx->__vmac_ctx.cached_nonce[1] = (u64)0; /* Ensure illegal nonce */ | ||
539 | ctx->__vmac_ctx.first_block_processed = 0; | ||
540 | |||
541 | return err; | ||
542 | } | 473 | } |
543 | 474 | ||
544 | static int vmac_setkey(struct crypto_shash *parent, | 475 | static int vmac_init(struct shash_desc *desc) |
545 | const u8 *key, unsigned int keylen) | ||
546 | { | 476 | { |
547 | struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); | 477 | const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); |
548 | 478 | struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); | |
549 | if (keylen != VMAC_KEY_LEN) { | ||
550 | crypto_shash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN); | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | |||
554 | return vmac_set_key((u8 *)key, ctx); | ||
555 | } | ||
556 | 479 | ||
557 | static int vmac_init(struct shash_desc *pdesc) | 480 | dctx->partial_size = 0; |
558 | { | 481 | dctx->first_block_processed = false; |
482 | memcpy(dctx->polytmp, tctx->polykey, sizeof(dctx->polytmp)); | ||
559 | return 0; | 483 | return 0; |
560 | } | 484 | } |
561 | 485 | ||
562 | static int vmac_update(struct shash_desc *pdesc, const u8 *p, | 486 | static int vmac_update(struct shash_desc *desc, const u8 *p, unsigned int len) |
563 | unsigned int len) | ||
564 | { | 487 | { |
565 | struct crypto_shash *parent = pdesc->tfm; | 488 | const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); |
566 | struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); | 489 | struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); |
567 | int expand; | 490 | unsigned int n; |
568 | int min; | 491 | |
569 | 492 | if (dctx->partial_size) { | |
570 | expand = VMAC_NHBYTES - ctx->partial_size > 0 ? | 493 | n = min(len, VMAC_NHBYTES - dctx->partial_size); |
571 | VMAC_NHBYTES - ctx->partial_size : 0; | 494 | memcpy(&dctx->partial[dctx->partial_size], p, n); |
572 | 495 | dctx->partial_size += n; | |
573 | min = len < expand ? len : expand; | 496 | p += n; |
574 | 497 | len -= n; | |
575 | memcpy(ctx->partial + ctx->partial_size, p, min); | 498 | if (dctx->partial_size == VMAC_NHBYTES) { |
576 | ctx->partial_size += min; | 499 | vhash_blocks(tctx, dctx, dctx->partial_words, 1); |
577 | 500 | dctx->partial_size = 0; | |
578 | if (len < expand) | 501 | } |
579 | return 0; | 502 | } |
580 | |||
581 | vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx); | ||
582 | ctx->partial_size = 0; | ||
583 | |||
584 | len -= expand; | ||
585 | p += expand; | ||
586 | 503 | ||
587 | if (len % VMAC_NHBYTES) { | 504 | if (len >= VMAC_NHBYTES) { |
588 | memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES), | 505 | n = round_down(len, VMAC_NHBYTES); |
589 | len % VMAC_NHBYTES); | 506 | /* TODO: 'p' may be misaligned here */ |
590 | ctx->partial_size = len % VMAC_NHBYTES; | 507 | vhash_blocks(tctx, dctx, (const __le64 *)p, n / VMAC_NHBYTES); |
508 | p += n; | ||
509 | len -= n; | ||
591 | } | 510 | } |
592 | 511 | ||
593 | vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx); | 512 | if (len) { |
513 | memcpy(dctx->partial, p, len); | ||
514 | dctx->partial_size = len; | ||
515 | } | ||
594 | 516 | ||
595 | return 0; | 517 | return 0; |
596 | } | 518 | } |
597 | 519 | ||
598 | static int vmac_final(struct shash_desc *pdesc, u8 *out) | 520 | static u64 vhash_final(const struct vmac_tfm_ctx *tctx, |
521 | struct vmac_desc_ctx *dctx) | ||
599 | { | 522 | { |
600 | struct crypto_shash *parent = pdesc->tfm; | 523 | unsigned int partial = dctx->partial_size; |
601 | struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); | 524 | u64 ch = dctx->polytmp[0]; |
602 | vmac_t mac; | 525 | u64 cl = dctx->polytmp[1]; |
603 | u8 nonce[16] = {}; | 526 | |
604 | 527 | /* L1 and L2-hash the final block if needed */ | |
605 | /* vmac() ends up accessing outside the array bounds that | 528 | if (partial) { |
606 | * we specify. In appears to access up to the next 2-word | 529 | /* Zero-pad to next 128-bit boundary */ |
607 | * boundary. We'll just be uber cautious and zero the | 530 | unsigned int n = round_up(partial, 16); |
608 | * unwritten bytes in the buffer. | 531 | u64 rh, rl; |
609 | */ | 532 | |
610 | if (ctx->partial_size) { | 533 | memset(&dctx->partial[partial], 0, n - partial); |
611 | memset(ctx->partial + ctx->partial_size, 0, | 534 | nh_16(dctx->partial_words, tctx->nhkey, n / 8, rh, rl); |
612 | VMAC_NHBYTES - ctx->partial_size); | 535 | rh &= m62; |
536 | if (dctx->first_block_processed) | ||
537 | poly_step(ch, cl, tctx->polykey[0], tctx->polykey[1], | ||
538 | rh, rl); | ||
539 | else | ||
540 | ADD128(ch, cl, rh, rl); | ||
613 | } | 541 | } |
614 | mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); | 542 | |
615 | memcpy(out, &mac, sizeof(vmac_t)); | 543 | /* L3-hash the 128-bit output of L2-hash */ |
616 | memzero_explicit(&mac, sizeof(vmac_t)); | 544 | return l3hash(ch, cl, tctx->l3key[0], tctx->l3key[1], partial * 8); |
617 | memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); | 545 | } |
618 | ctx->partial_size = 0; | 546 | |
547 | static int vmac_final(struct shash_desc *desc, u8 *out) | ||
548 | { | ||
549 | const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); | ||
550 | struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); | ||
551 | static const u8 nonce[16] = {}; /* TODO: this is insecure */ | ||
552 | union { | ||
553 | u8 bytes[16]; | ||
554 | __be64 pads[2]; | ||
555 | } block; | ||
556 | int index; | ||
557 | u64 hash, pad; | ||
558 | |||
559 | /* Finish calculating the VHASH of the message */ | ||
560 | hash = vhash_final(tctx, dctx); | ||
561 | |||
562 | /* Generate pseudorandom pad by encrypting the nonce */ | ||
563 | memcpy(&block, nonce, 16); | ||
564 | index = block.bytes[15] & 1; | ||
565 | block.bytes[15] &= ~1; | ||
566 | crypto_cipher_encrypt_one(tctx->cipher, block.bytes, block.bytes); | ||
567 | pad = be64_to_cpu(block.pads[index]); | ||
568 | |||
569 | /* The VMAC is the sum of VHASH and the pseudorandom pad */ | ||
570 | put_unaligned_le64(hash + pad, out); | ||
619 | return 0; | 571 | return 0; |
620 | } | 572 | } |
621 | 573 | ||
622 | static int vmac_init_tfm(struct crypto_tfm *tfm) | 574 | static int vmac_init_tfm(struct crypto_tfm *tfm) |
623 | { | 575 | { |
624 | struct crypto_cipher *cipher; | 576 | struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); |
625 | struct crypto_instance *inst = (void *)tfm->__crt_alg; | ||
626 | struct crypto_spawn *spawn = crypto_instance_ctx(inst); | 577 | struct crypto_spawn *spawn = crypto_instance_ctx(inst); |
627 | struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); | 578 | struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); |
579 | struct crypto_cipher *cipher; | ||
628 | 580 | ||
629 | cipher = crypto_spawn_cipher(spawn); | 581 | cipher = crypto_spawn_cipher(spawn); |
630 | if (IS_ERR(cipher)) | 582 | if (IS_ERR(cipher)) |
631 | return PTR_ERR(cipher); | 583 | return PTR_ERR(cipher); |
632 | 584 | ||
633 | ctx->child = cipher; | 585 | tctx->cipher = cipher; |
634 | return 0; | 586 | return 0; |
635 | } | 587 | } |
636 | 588 | ||
637 | static void vmac_exit_tfm(struct crypto_tfm *tfm) | 589 | static void vmac_exit_tfm(struct crypto_tfm *tfm) |
638 | { | 590 | { |
639 | struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); | 591 | struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); |
640 | crypto_free_cipher(ctx->child); | 592 | |
593 | crypto_free_cipher(tctx->cipher); | ||
641 | } | 594 | } |
642 | 595 | ||
643 | static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) | 596 | static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) |
@@ -674,11 +627,12 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) | |||
674 | inst->alg.base.cra_blocksize = alg->cra_blocksize; | 627 | inst->alg.base.cra_blocksize = alg->cra_blocksize; |
675 | inst->alg.base.cra_alignmask = alg->cra_alignmask; | 628 | inst->alg.base.cra_alignmask = alg->cra_alignmask; |
676 | 629 | ||
677 | inst->alg.digestsize = sizeof(vmac_t); | 630 | inst->alg.base.cra_ctxsize = sizeof(struct vmac_tfm_ctx); |
678 | inst->alg.base.cra_ctxsize = sizeof(struct vmac_ctx_t); | ||
679 | inst->alg.base.cra_init = vmac_init_tfm; | 631 | inst->alg.base.cra_init = vmac_init_tfm; |
680 | inst->alg.base.cra_exit = vmac_exit_tfm; | 632 | inst->alg.base.cra_exit = vmac_exit_tfm; |
681 | 633 | ||
634 | inst->alg.descsize = sizeof(struct vmac_desc_ctx); | ||
635 | inst->alg.digestsize = VMAC_TAG_LEN / 8; | ||
682 | inst->alg.init = vmac_init; | 636 | inst->alg.init = vmac_init; |
683 | inst->alg.update = vmac_update; | 637 | inst->alg.update = vmac_update; |
684 | inst->alg.final = vmac_final; | 638 | inst->alg.final = vmac_final; |