Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: vmac - Make VMAC work when blocks aren't aligned

VMAC implementation, as it is, does not work with blocks that
are not multiples of 128-bytes. Furthermore, this is a problem
when using the implementation on scatterlists, even
when the complete plain text is 128-byte multiple, as the pieces
that get passed to vmac_update can be pretty much any size.

I also added test cases for unaligned blocks.

Signed-off-by: Salman Qazi <sqazi@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Salman Qazi and committed by
Herbert Xu
ba1ee070 7291a932

+77 -5
+32 -1
crypto/testmgr.h
··· 1707 1707 } 1708 1708 }; 1709 1709 1710 - #define VMAC_AES_TEST_VECTORS 8 1710 + #define VMAC_AES_TEST_VECTORS 11 1711 1711 static char vmac_string1[128] = {'\x01', '\x01', '\x01', '\x01', 1712 1712 '\x02', '\x03', '\x02', '\x02', 1713 1713 '\x02', '\x04', '\x01', '\x07', ··· 1722 1722 'a', 'b', 'c', 'a', 'b', 'c', 1723 1723 'a', 'b', 'c', 'a', 'b', 'c', 1724 1724 }; 1725 + 1726 + static char vmac_string4[17] = {'b', 'c', 'e', 'f', 1727 + 'i', 'j', 'l', 'm', 1728 + 'o', 'p', 'r', 's', 1729 + 't', 'u', 'w', 'x', 'z'}; 1730 + 1731 + static char vmac_string5[127] = {'r', 'm', 'b', 't', 'c', 1732 + 'o', 'l', 'k', ']', '%', 1733 + '9', '2', '7', '!', 'A'}; 1734 + 1735 + static char vmac_string6[129] = {'p', 't', '*', '7', 'l', 1736 + 'i', '!', '#', 'w', '0', 1737 + 'z', '/', '4', 'A', 'n'}; 1725 1738 1726 1739 static struct hash_testvec aes_vmac128_tv_template[] = { 1727 1740 { ··· 1789 1776 .digest = "\x8b\x32\x8f\xe1\xed\x8f\xfa\xd4", 1790 1777 .psize = 128, 1791 1778 .ksize = 16, 1779 + }, { 1780 + .key = "a09b5cd!f#07K\x00\x00\x00", 1781 + .plaintext = vmac_string4, 1782 + .digest = "\xab\xa5\x0f\xea\x42\x4e\xa1\x5f", 1783 + .psize = sizeof(vmac_string4), 1784 + .ksize = 16, 1785 + }, { 1786 + .key = "a09b5cd!f#07K\x00\x00\x00", 1787 + .plaintext = vmac_string5, 1788 + .digest = "\x25\x31\x98\xbc\x1d\xe8\x67\x60", 1789 + .psize = sizeof(vmac_string5), 1790 + .ksize = 16, 1791 + }, { 1792 + .key = "a09b5cd!f#07K\x00\x00\x00", 1793 + .plaintext = vmac_string6, 1794 + .digest = "\xc4\xae\x9b\x47\x95\x65\xeb\x41", 1795 + .psize = sizeof(vmac_string6), 1796 + .ksize = 16, 1792 1797 }, 1793 1798 }; 1794 1799
+43 -4
crypto/vmac.c
··· 375 375 u64 pkh = ctx->polykey[0]; 376 376 u64 pkl = ctx->polykey[1]; 377 377 378 + if (!mbytes) 379 + return; 380 + 381 + BUG_ON(mbytes % VMAC_NHBYTES); 382 + 378 383 mptr = (u64 *)m; 379 384 i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ 380 385 ··· 459 454 } 460 455 461 456 static u64 vmac(unsigned char m[], unsigned int mbytes, 462 - unsigned char n[16], u64 *tagl, 457 + const unsigned char n[16], u64 *tagl, 463 458 struct vmac_ctx_t *ctx) 464 459 { 465 460 u64 *in_n, *out_p; ··· 564 559 { 565 560 struct crypto_shash *parent = pdesc->tfm; 566 561 struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); 562 + int expand; 563 + int min; 567 564 568 - vhash_update(p, len, &ctx->__vmac_ctx); 565 + expand = VMAC_NHBYTES - ctx->partial_size > 0 ? 566 + VMAC_NHBYTES - ctx->partial_size : 0; 567 + 568 + min = len < expand ? len : expand; 569 + 570 + memcpy(ctx->partial + ctx->partial_size, p, min); 571 + ctx->partial_size += min; 572 + 573 + if (len < expand) 574 + return 0; 575 + 576 + vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx); 577 + ctx->partial_size = 0; 578 + 579 + len -= expand; 580 + p += expand; 581 + 582 + if (len % VMAC_NHBYTES) { 583 + memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES), 584 + len % VMAC_NHBYTES); 585 + ctx->partial_size = len % VMAC_NHBYTES; 586 + } 587 + 588 + vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx); 569 589 570 590 return 0; 571 591 } ··· 602 572 vmac_t mac; 603 573 u8 nonce[16] = {}; 604 574 605 - mac = vmac(NULL, 0, nonce, NULL, ctx); 575 + /* vmac() ends up accessing outside the array bounds that 576 + * we specify. In appears to access up to the next 2-word 577 + * boundary. We'll just be uber cautious and zero the 578 + * unwritten bytes in the buffer. 579 + */ 580 + if (ctx->partial_size) { 581 + memset(ctx->partial + ctx->partial_size, 0, 582 + VMAC_NHBYTES - ctx->partial_size); 583 + } 584 + mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); 606 585 memcpy(out, &mac, sizeof(vmac_t)); 607 586 memset(&mac, 0, sizeof(vmac_t)); 608 587 memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); 588 + ctx->partial_size = 0; 609 589 return 0; 610 590 } 611 591 ··· 713 673 714 674 MODULE_LICENSE("GPL"); 715 675 MODULE_DESCRIPTION("VMAC hash algorithm"); 716 -
+2
include/crypto/vmac.h
··· 56 56 struct vmac_ctx_t { 57 57 struct crypto_cipher *child; 58 58 struct vmac_ctx __vmac_ctx; 59 + u8 partial[VMAC_NHBYTES]; /* partial block */ 60 + int partial_size; /* size of the partial block */ 59 61 }; 60 62 61 63 #endif /* __CRYPTO_VMAC_H */