]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
crypto: vmac - Make VMAC work when blocks aren't aligned
authorSalman Qazi <sqazi@google.com>
Fri, 5 Oct 2012 21:24:14 +0000 (14:24 -0700)
committerHerbert Xu <herbert@gondor.apana.org.au>
Mon, 15 Oct 2012 14:33:20 +0000 (22:33 +0800)
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>
crypto/testmgr.h
crypto/vmac.c
include/crypto/vmac.h

index 76d7f6cc82f554f8be2846b393846218f5c9a587..f8365e913de97cf939d80fb14b61e3e968c99154 100644 (file)
@@ -1707,7 +1707,7 @@ static struct hash_testvec aes_xcbc128_tv_template[] = {
        }
 };
 
-#define VMAC_AES_TEST_VECTORS  8
+#define VMAC_AES_TEST_VECTORS  11
 static char vmac_string1[128] = {'\x01', '\x01', '\x01', '\x01',
                                '\x02', '\x03', '\x02', '\x02',
                                '\x02', '\x04', '\x01', '\x07',
@@ -1723,6 +1723,19 @@ static char vmac_string3[128] = {'a', 'b', 'c', 'a', 'b', 'c',
                                'a', 'b', 'c', 'a', 'b', 'c',
                                };
 
+static char vmac_string4[17] = {'b', 'c', 'e', 'f',
+                               'i', 'j', 'l', 'm',
+                               'o', 'p', 'r', 's',
+                               't', 'u', 'w', 'x', 'z'};
+
+static char vmac_string5[127] = {'r', 'm', 'b', 't', 'c',
+                                'o', 'l', 'k', ']', '%',
+                                '9', '2', '7', '!', 'A'};
+
+static char vmac_string6[129] = {'p', 't', '*', '7', 'l',
+                                'i', '!', '#', 'w', '0',
+                                'z', '/', '4', 'A', 'n'};
+
 static struct hash_testvec aes_vmac128_tv_template[] = {
        {
                .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
@@ -1776,6 +1789,24 @@ static struct hash_testvec aes_vmac128_tv_template[] = {
                .digest = "\x8b\x32\x8f\xe1\xed\x8f\xfa\xd4",
                .psize  = 128,
                .ksize  = 16,
+       }, {
+               .key = "a09b5cd!f#07K\x00\x00\x00",
+               .plaintext = vmac_string4,
+               .digest = "\xab\xa5\x0f\xea\x42\x4e\xa1\x5f",
+               .psize = sizeof(vmac_string4),
+               .ksize = 16,
+       }, {
+               .key = "a09b5cd!f#07K\x00\x00\x00",
+               .plaintext = vmac_string5,
+               .digest = "\x25\x31\x98\xbc\x1d\xe8\x67\x60",
+               .psize = sizeof(vmac_string5),
+               .ksize = 16,
+       }, {
+               .key = "a09b5cd!f#07K\x00\x00\x00",
+               .plaintext = vmac_string6,
+               .digest = "\xc4\xae\x9b\x47\x95\x65\xeb\x41",
+               .psize = sizeof(vmac_string6),
+               .ksize = 16,
        },
 };
 
index f2338ca983686c5aea9f57d1ad733097bd6a1455..2eb11a30c29cee93203a1b90a990cc4463368440 100644 (file)
@@ -375,6 +375,11 @@ static void vhash_update(const unsigned char *m,
        u64 pkh = ctx->polykey[0];
        u64 pkl = ctx->polykey[1];
 
+       if (!mbytes)
+               return;
+
+       BUG_ON(mbytes % VMAC_NHBYTES);
+
        mptr = (u64 *)m;
        i = mbytes / VMAC_NHBYTES;  /* Must be non-zero */
 
@@ -454,7 +459,7 @@ do_l3:
 }
 
 static u64 vmac(unsigned char m[], unsigned int mbytes,
-                       unsigned char n[16], u64 *tagl,
+                       const unsigned char n[16], u64 *tagl,
                        struct vmac_ctx_t *ctx)
 {
        u64 *in_n, *out_p;
@@ -559,8 +564,33 @@ static int vmac_update(struct shash_desc *pdesc, const u8 *p,
 {
        struct crypto_shash *parent = pdesc->tfm;
        struct vmac_ctx_t *ctx = crypto_shash_ctx(parent);
+       int expand;
+       int min;
+
+       expand = VMAC_NHBYTES - ctx->partial_size > 0 ?
+                       VMAC_NHBYTES - ctx->partial_size : 0;
+
+       min = len < expand ? len : expand;
+
+       memcpy(ctx->partial + ctx->partial_size, p, min);
+       ctx->partial_size += min;
+
+       if (len < expand)
+               return 0;
 
-       vhash_update(p, len, &ctx->__vmac_ctx);
+       vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx);
+       ctx->partial_size = 0;
+
+       len -= expand;
+       p += expand;
+
+       if (len % VMAC_NHBYTES) {
+               memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES),
+                       len % VMAC_NHBYTES);
+               ctx->partial_size = len % VMAC_NHBYTES;
+       }
+
+       vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx);
 
        return 0;
 }
@@ -572,10 +602,20 @@ static int vmac_final(struct shash_desc *pdesc, u8 *out)
        vmac_t mac;
        u8 nonce[16] = {};
 
-       mac = vmac(NULL, 0, nonce, NULL, ctx);
+       /* vmac() ends up accessing outside the array bounds that
+        * we specify.  In appears to access up to the next 2-word
+        * boundary.  We'll just be uber cautious and zero the
+        * unwritten bytes in the buffer.
+        */
+       if (ctx->partial_size) {
+               memset(ctx->partial + ctx->partial_size, 0,
+                       VMAC_NHBYTES - ctx->partial_size);
+       }
+       mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx);
        memcpy(out, &mac, sizeof(vmac_t));
        memset(&mac, 0, sizeof(vmac_t));
        memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx));
+       ctx->partial_size = 0;
        return 0;
 }
 
@@ -673,4 +713,3 @@ module_exit(vmac_module_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("VMAC hash algorithm");
-
index c4467c55df1e56a1cf22cf70a82dac467db1c711..6b700c7b2fe1cba3cd054a200eac450ac4bde7be 100644 (file)
@@ -56,6 +56,8 @@ typedef u64 vmac_t;
 struct vmac_ctx_t {
        struct crypto_cipher *child;
        struct vmac_ctx __vmac_ctx;
+       u8 partial[VMAC_NHBYTES];       /* partial block */
+       int partial_size;               /* size of the partial block */
 };
 
 #endif /* __CRYPTO_VMAC_H */