Hi community,
The following VMAC(AES) patch, ported from http://fastcrypto.org/vmac,
is used to support S3 memory integrity verification for Intel(R) Trusted
Execution Technology (for more about Intel(R) TXT patches, see
http://lkml.org/lkml/2009/6/22/578), since the VMAC algorithm is very
fast to MAC the memory during S3 sleep, compared with other MAC algorithms.
We request your feedback and suggestions.
Thanks.
Shane
Signed-off-by: Shane Wang <shane.wang@xxxxxxxxx>
Signed-off-by: Joseph Cihula <joseph.cihula@xxxxxxxxx>
diff -r 973795c2770b crypto/Kconfig
--- a/crypto/Kconfig Mon Jul 13 20:57:01 2009 -0700
+++ b/crypto/Kconfig Thu Jul 16 02:56:25 2009 -0700
@@ -261,6 +261,18 @@ config CRYPTO_XCBC
http://www.ietf.org/rfc/rfc3566.txt
http://csrc.nist.gov/encryption/modes/proposedmodes/
xcbc-mac/xcbc-mac-spec.pdf
+
+config CRYPTO_VMAC
+ tristate "VMAC support"
+ depends on EXPERIMENTAL
+ select CRYPTO_HASH
+ select CRYPTO_MANAGER
+ help
+ VMAC is a message authentication algorithm designed for
+ very high speed on 64-bit architectures.
+
+ See also:
+ <http://fastcrypto.org/vmac>
comment "Digest"
diff -r 973795c2770b crypto/Makefile
--- a/crypto/Makefile Mon Jul 13 20:57:01 2009 -0700
+++ b/crypto/Makefile Thu Jul 16 02:56:25 2009 -0700
@@ -33,6 +33,7 @@ cryptomgr-objs := algboss.o testmgr.o
obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
+obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
obj-$(CONFIG_CRYPTO_MD4) += md4.o
diff -r 973795c2770b crypto/tcrypt.c
--- a/crypto/tcrypt.c Mon Jul 13 20:57:01 2009 -0700
+++ b/crypto/tcrypt.c Thu Jul 16 02:56:25 2009 -0700
@@ -700,6 +700,9 @@ static void do_test(int m)
case 108:
tcrypt_test("hmac(rmd160)");
break;
+ case 109:
+ tcrypt_test("vmac(aes)");
+ break;
case 200:
test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
diff -r 973795c2770b crypto/testmgr.c
--- a/crypto/testmgr.c Mon Jul 13 20:57:01 2009 -0700
+++ b/crypto/testmgr.c Thu Jul 16 02:56:25 2009 -0700
@@ -1968,6 +1968,15 @@ static const struct alg_test_desc alg_te
}
}
}, {
+ .alg = "vmac(aes)",
+ .test = alg_test_hash,
+ .suite = {
+ .hash = {
+ .vecs = aes_vmac128_tv_template,
+ .count = VMAC_AES_TEST_VECTORS
+ }
+ }
+ }, {
.alg = "wp256",
.test = alg_test_hash,
.suite = {
diff -r 973795c2770b crypto/testmgr.h
--- a/crypto/testmgr.h Mon Jul 13 20:57:01 2009 -0700
+++ b/crypto/testmgr.h Thu Jul 16 02:56:25 2009 -0700
@@ -1639,6 +1639,22 @@ static struct hash_testvec aes_xcbc128_t
.np = 2,
.ksize = 16,
}
+};
+
+#define VMAC_AES_TEST_VECTORS 1
+static char vmac_string[128] = {'\x01', '\x01', '\x01', '\x01',
+ '\x02', '\x03', '\x02', '\x02',
+ '\x02', '\x04', '\x01', '\x07',
+ '\x04', '\x01', '\x04', '\x03',};
+static struct hash_testvec aes_vmac128_tv_template[] = {
+ {
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .plaintext = vmac_string,
+ .digest = "\xcb\xd7\x8a\xfd\xb7\x33\x79\xe7",
+ .psize = 128,
+ .ksize = 16,
+ },
};
/*
diff -r 973795c2770b crypto/vmac.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/vmac.c Thu Jul 16 02:56:25 2009 -0700
@@ -0,0 +1,682 @@
+/*
+ * Modified to interface to the Linux kernel
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+/*
--------------------------------------------------------------------------
+ * VMAC and VHASH Implementation by Ted Krovetz (tdk@xxxxxxx) and Wei Dai.
+ * This implementation is herby placed in the public domain.
+ * The authors offers no warranty. Use at your own risk.
+ * Please send bug reports to the authors.
+ * Last modified: 17 APR 08, 1700 PDT
+ *
----------------------------------------------------------------------- */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/vmac.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/vmac.h>
+
+/*
+ * Enable code tuned for 64-bit registers; otherwise tuned for 32-bit
+ */
+#ifndef VMAC_ARCH_64
+#define VMAC_ARCH_64 (__x86_64__ || __ppc64__ || _M_X64)
+#endif
+
+/*
+ * Native word reads. Update (or define via compiler) if incorrect
+ */
+#ifndef VMAC_ARCH_BIG_ENDIAN /* Assume big-endian unless on the list */
+#define VMAC_ARCH_BIG_ENDIAN \
+ (!(__x86_64__ || __i386__ || _M_IX86 || \
+ _M_X64 || __ARMEL__ || __MIPSEL__))
+#endif
+
+/*
+ * Constants and masks
+ */
+#define UINT64_C(x) x##ULL
+const uint64_t p64 = UINT64_C(0xfffffffffffffeff); /* 2^64 - 257
prime */
+const uint64_t m62 = UINT64_C(0x3fffffffffffffff); /* 62-bit mask
*/
+const uint64_t m63 = UINT64_C(0x7fffffffffffffff); /* 63-bit mask
*/
+const uint64_t m64 = UINT64_C(0xffffffffffffffff); /* 64-bit mask
*/
+const uint64_t mpoly = UINT64_C(0x1fffffff1fffffff); /* Poly key mask
*/
+
+
+#if (VMAC_ARCH_BIG_ENDIAN)
+#define get64BE(ptr) (*(uint64_t *)(ptr))
+#define get64LE(ptr) GET_REVERSED_64(ptr)
+#define INDEX_HIGH 0
+#define INDEX_LOW 1
+#else /* assume little-endian */
+#define get64BE(ptr) GET_REVERSED_64(ptr)
+#define get64LE(ptr) (*(uint64_t *)(ptr))
+#define INDEX_HIGH 1
+#define INDEX_LOW 0
+#endif
+
+
+/*
+ * For highest performance the L1 NH and L2 polynomial hashes should be
+ * carefully implemented to take advantage of one's target architechture.
+ * Here these two hash functions are defined multiple time; once for
+ * 64-bit architectures, once for 32-bit SSE2 architectures, and once
+ * for the rest (32-bit) architectures.
+ * For each, nh_16 *must* be defined (works on multiples of 16 bytes).
+ * Optionally, nh_vmac_nhbytes can be defined (for multiples of
+ * VMAC_NHBYTES), and nh_16_2 and nh_vmac_nhbytes_2 (versions that do two
+ * NH computations at once).
+ */
+
+#if VMAC_ARCH_64
+
+#define nh_16(mp, kp, nw, rh, rl) \
+{ int i; uint64_t th, tl; \
+ rh = rl = 0; \
+ for (i = 0; i < nw; i+= 2) { \
+ MUL64(th,tl,get64LE((mp)+i )+(kp)[i ], \
+ get64LE((mp)+i+1)+(kp)[i+1]); \
+ ADD128(rh,rl,th,tl); \
+ } \
+}
+
+#define nh_16_2(mp, kp, nw, rh, rl, rh1, rl1) \
+{ int i; uint64_t th, tl; \
+ rh1 = rl1 = rh = rl = 0; \
+ for (i = 0; i < nw; i+= 2) { \
+ MUL64(th,tl,get64LE((mp)+i )+(kp)[i ], \
+ get64LE((mp)+i+1)+(kp)[i+1]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i )+(kp)[i+2], \
+ get64LE((mp)+i+1)+(kp)[i+3]); \
+ ADD128(rh1,rl1,th,tl); \
+ } \
+}
+
+#if (VMAC_NHBYTES >= 64) /* These versions do 64-bytes of message at a
time */
+#define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \
+{ int i; uint64_t th, tl; \
+ rh = rl = 0; \
+ for (i = 0; i < nw; i+= 8) { \
+ MUL64(th,tl,get64LE((mp)+i )+(kp)[i ], \
+ get64LE((mp)+i+1)+(kp)[i+1]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+2)+(kp)[i+2], \
+ get64LE((mp)+i+3)+(kp)[i+3]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+4)+(kp)[i+4], \
+ get64LE((mp)+i+5)+(kp)[i+5]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+6)+(kp)[i+6], \
+ get64LE((mp)+i+7)+(kp)[i+7]); \
+ ADD128(rh,rl,th,tl); \
+ } \
+}
+
+#define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh1, rl1) \
+{ int i; uint64_t th, tl; \
+ rh1 = rl1 = rh = rl = 0; \
+ for (i = 0; i < nw; i+= 8) { \
+ MUL64(th,tl,get64LE((mp)+i )+(kp)[i ], \
+ get64LE((mp)+i+1)+(kp)[i+1]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i )+(kp)[i+2], \
+ get64LE((mp)+i+1)+(kp)[i+3]); \
+ ADD128(rh1,rl1,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+2)+(kp)[i+2], \
+ get64LE((mp)+i+3)+(kp)[i+3]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+2)+(kp)[i+4], \
+ get64LE((mp)+i+3)+(kp)[i+5]); \
+ ADD128(rh1,rl1,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+4)+(kp)[i+4], \
+ get64LE((mp)+i+5)+(kp)[i+5]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+4)+(kp)[i+6], \
+ get64LE((mp)+i+5)+(kp)[i+7]); \
+ ADD128(rh1,rl1,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+6)+(kp)[i+6], \
+ get64LE((mp)+i+7)+(kp)[i+7]); \
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64LE((mp)+i+6)+(kp)[i+8], \
+ get64LE((mp)+i+7)+(kp)[i+9]); \
+ ADD128(rh1,rl1,th,tl); \
+ } \
+}
+#endif
+
+#define poly_step(ah, al, kh, kl, mh, ml) \
+{ uint64_t t1h, t1l, t2h, t2l, t3h, t3l, z=0; \
+ /* compute ab*cd, put bd into result registers */ \
+ PMUL64(t3h,t3l,al,kh); \
+ PMUL64(t2h,t2l,ah,kl); \
+ PMUL64(t1h,t1l,ah,2*kh); \
+ PMUL64(ah,al,al,kl); \
+ /* add 2 * ac to result */ \
+ ADD128(ah,al,t1h,t1l); \
+ /* add together ad + bc */ \
+ ADD128(t2h,t2l,t3h,t3l); \
+ /* now (ah,al), (t2l,2*t2h) need summing */ \
+ /* first add the high registers, carrying into t2h */ \
+ ADD128(t2h,ah,z,t2l); \
+ /* double t2h and add top bit of ah */ \
+ t2h = 2 * t2h + (ah >> 63); \
+ ah &= m63; \
+ /* now add the low registers */ \
+ ADD128(ah,al,mh,ml); \
+ ADD128(ah,al,z,t2h); \
+}
+
+#else /* not VMAC_ARCH_64 */
+
+#ifndef nh_16
+#define nh_16(mp, kp, nw, rh, rl) \
+{ uint64_t t1,t2,m1,m2,t; \
+ int i; \
+ rh = rl = t = 0; \
+ for (i = 0; i < nw; i+=2) { \
+ t1 = get64LE(mp+i) + kp[i]; \
+ t2 = get64LE(mp+i+1) + kp[i+1]; \
+ m2 = MUL32(t1 >> 32, t2); \
+ m1 = MUL32(t1, t2 >> 32); \
+ ADD128(rh,rl,MUL32(t1 >> 32,t2 >> 32),MUL32(t1,t2)); \
+ rh += (uint64_t)(uint32_t)(m1 >> 32) \
+ + (uint32_t)(m2 >> 32); \
+ t += (uint64_t)(uint32_t)m1 + (uint32_t)m2; \
+ } \
+ ADD128(rh,rl,(t >> 32),(t << 32)); \
+}
+#endif
+
+static void poly_step_func(uint64_t *ahi, uint64_t *alo,
+ const uint64_t *kh, const uint64_t *kl,
+ const uint64_t *mh, const uint64_t *ml)
+{
+#define a0 *(((uint32_t*)alo)+INDEX_LOW)
+#define a1 *(((uint32_t*)alo)+INDEX_HIGH)
+#define a2 *(((uint32_t*)ahi)+INDEX_LOW)
+#define a3 *(((uint32_t*)ahi)+INDEX_HIGH)
+#define k0 *(((uint32_t*)kl)+INDEX_LOW)
+#define k1 *(((uint32_t*)kl)+INDEX_HIGH)
+#define k2 *(((uint32_t*)kh)+INDEX_LOW)
+#define k3 *(((uint32_t*)kh)+INDEX_HIGH)
+
+ uint64_t p, q, t;
+ uint32_t t2;
+
+ p = MUL32(a3, k3);
+ p += p;
+ p += *(uint64_t *)mh;
+ p += MUL32(a0, k2);
+ p += MUL32(a1, k1);
+ p += MUL32(a2, k0);
+ t = (uint32_t)(p);
+ p >>= 32;
+ p += MUL32(a0, k3);
+ p += MUL32(a1, k2);
+ p += MUL32(a2, k1);
+ p += MUL32(a3, k0);
+ t |= ((uint64_t)((uint32_t)p & 0x7fffffff)) << 32;
+ p >>= 31;
+ p += (uint64_t)(((uint32_t*)ml)[INDEX_LOW]);
+ p += MUL32(a0, k0);
+ q = MUL32(a1, k3);
+ q += MUL32(a2, k2);
+ q += MUL32(a3, k1);
+ q += q;
+ p += q;
+ t2 = (uint32_t)(p);
+ p >>= 32;
+ p += (uint64_t)(((uint32_t*)ml)[INDEX_HIGH]);
+ p += MUL32(a0, k1);
+ p += MUL32(a1, k0);
+ q = MUL32(a2, k3);
+ q += MUL32(a3, k2);
+ q += q;
+ p += q;
+ *(uint64_t *)(alo) = (p << 32) | t2;
+ p >>= 32;
+ *(uint64_t *)(ahi) = p + t;
+
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef k0
+#undef k1
+#undef k2
+#undef k3
+}
+
+#define poly_step(ah, al, kh, kl, mh, ml) \
+ poly_step_func(&(ah), &(al), &(kh), &(kl), &(mh), &(ml))
+
+#endif /* end of specialized NH and poly definitions */
+
+/* At least nh_16 is defined. Defined others as needed here */
+#ifndef nh_16_2
+#define nh_16_2(mp, kp, nw, rh, rl, rh2, rl2) \
+ nh_16(mp, kp, nw, rh, rl); \
+ nh_16(mp, ((kp)+2), nw, rh2, rl2);
+#endif
+#ifndef nh_vmac_nhbytes
+#define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \
+ nh_16(mp, kp, nw, rh, rl)
+#endif
+#ifndef nh_vmac_nhbytes_2
+#define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh2, rl2) \
+ nh_vmac_nhbytes(mp, kp, nw, rh, rl); \
+ nh_vmac_nhbytes(mp, ((kp)+2), nw, rh2, rl2);
+#endif
+
+static void vhash_abort(struct vmac_ctx *ctx)
+{
+ ctx->polytmp[0] = ctx->polykey[0] ;
+ ctx->polytmp[1] = ctx->polykey[1] ;
+ ctx->first_block_processed = 0;
+}
+
+static uint64_t l3hash( uint64_t p1, uint64_t p2,
+ uint64_t k1, uint64_t k2, uint64_t len)
+{
+ uint64_t rh, rl, t, z=0;
+
+ /* fully reduce (p1,p2)+(len,0) mod p127 */
+ t = p1 >> 63;
+ p1 &= m63;
+ ADD128(p1, p2, len, t);
+ /* At this point, (p1,p2) is at most 2^127+(len<<64) */
+ t = (p1 > m63) + ((p1 == m63) && (p2 == m64));
+ ADD128(p1, p2, z, t);
+ p1 &= m63;
+
+ /* compute (p1,p2)/(2^64-2^32) and (p1,p2)%(2^64-2^32) */
+ t = p1 + (p2 >> 32);
+ t += (t >> 32);
+ t += (uint32_t)t > 0xfffffffeu;
+ p1 += (t >> 32);
+ p2 += (p1 << 32);
+
+ /* compute (p1+k1)%p64 and (p2+k2)%p64 */
+ p1 += k1;
+ p1 += (0 - (p1 < k1)) & 257;
+ p2 += k2;
+ p2 += (0 - (p2 < k2)) & 257;
+
+ /* compute (p1+k1)*(p2+k2)%p64 */
+ MUL64(rh, rl, p1, p2);
+ t = rh >> 56;
+ ADD128(t, rl, z, rh);
+ rh <<= 8;
+ ADD128(t, rl, z, rh);
+ t += t << 8;
+ rl += t;
+ rl += (0 - (rl < t)) & 257;
+ rl += (0 - (rl > p64-1)) & 257;
+ return rl;
+}
+
+static void vhash_update(unsigned char *m,
+ unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */
+ struct vmac_ctx *ctx)
+{
+ uint64_t rh, rl, *mptr;
+ const uint64_t *kptr = (uint64_t *)ctx->nhkey;
+ int i;
+ uint64_t ch, cl;
+ uint64_t pkh = ctx->polykey[0];
+ uint64_t pkl = ctx->polykey[1];
+
+ mptr = (uint64_t *)m;
+ i = mbytes / VMAC_NHBYTES; /* Must be non-zero */
+
+ ch = ctx->polytmp[0];
+ cl = ctx->polytmp[1];
+
+ if ( ! ctx->first_block_processed) {
+ ctx->first_block_processed = 1;
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl);
+ rh &= m62;
+ ADD128(ch,cl,rh,rl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ i--;
+ }
+
+ while (i--) {
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl);
+ rh &= m62;
+ poly_step(ch,cl,pkh,pkl,rh,rl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ }
+
+ ctx->polytmp[0] = ch;
+ ctx->polytmp[1] = cl;
+}
+
+static uint64_t vhash(unsigned char m[], unsigned int mbytes,
+ uint64_t *tagl, struct vmac_ctx *ctx)
+{
+ uint64_t rh, rl, *mptr;
+ const uint64_t *kptr = (uint64_t *)ctx->nhkey;
+ int i, remaining;
+ uint64_t ch, cl;
+ uint64_t pkh = ctx->polykey[0];
+ uint64_t pkl = ctx->polykey[1];
+
+ mptr = (uint64_t *)m;
+ i = mbytes / VMAC_NHBYTES;
+ remaining = mbytes % VMAC_NHBYTES;
+
+ if (ctx->first_block_processed) {
+ ch = ctx->polytmp[0];
+ cl = ctx->polytmp[1];
+ }
+ else if (i) {
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,ch,cl);
+ ch &= m62;
+ ADD128(ch,cl,pkh,pkl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ i--;
+ }
+ else if (remaining) {
+ nh_16(mptr,kptr,2*((remaining+15)/16),ch,cl);
+ ch &= m62;
+ ADD128(ch,cl,pkh,pkl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ goto do_l3;
+ }
+ else {/* Empty String */
+ ch = pkh; cl = pkl;
+ goto do_l3;
+ }
+
+ while (i--) {
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl);
+ rh &= m62;
+ poly_step(ch,cl,pkh,pkl,rh,rl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ }
+ if (remaining) {
+ nh_16(mptr,kptr,2*((remaining+15)/16),rh,rl);
+ rh &= m62;
+ poly_step(ch,cl,pkh,pkl,rh,rl);
+ }
+
+do_l3:
+ vhash_abort(ctx);
+ remaining *= 8;
+ return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1],remaining);
+}
+
+static uint64_t vmac( unsigned char m[], unsigned int mbytes,
+ unsigned char n[16], uint64_t *tagl,
+ vmac_ctx_t *ctx)
+{
+ uint64_t *in_n, *out_p;
+ uint64_t p, h;
+ int i;
+
+ in_n = ctx->__vmac_ctx.cached_nonce;
+ out_p = ctx->__vmac_ctx.cached_aes;
+
+ i = n[15] & 1;
+ if ( (*(uint64_t *)(n+8) != in_n[1]) ||
+ (*(uint64_t *)(n ) != in_n[0])) {
+
+ in_n[0] = *(uint64_t *)(n );
+ in_n[1] = *(uint64_t *)(n+8);
+ ((unsigned char *)in_n)[15] &= 0xFE;
+ crypto_cipher_encrypt_one(ctx->child,
+ (unsigned char *)out_p, (unsigned char *)in_n);
+
+ ((unsigned char *)in_n)[15] |= (unsigned char)(1-i);
+ }
+ p = get64BE(out_p + i);
+ h = vhash(m, mbytes, (uint64_t *)0, &ctx->__vmac_ctx);
+ return p + h;
+}
+
+static int vmac_set_key(unsigned char user_key[], vmac_ctx_t *ctx)
+{
+ uint64_t in[2] = {0}, out[2];
+ unsigned i;
+ int err = 0;
+
+ if ((err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN)))
+ return err;
+
+ /* Fill nh key */
+ ((unsigned char *)in)[0] = 0x80;
+ for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i+=2) {
+ crypto_cipher_encrypt_one(ctx->child,
+ (unsigned char *)out, (unsigned char *)in);
+ ctx->__vmac_ctx.nhkey[i ] = get64BE(out);
+ ctx->__vmac_ctx.nhkey[i+1] = get64BE(out+1);
+ ((unsigned char *)in)[15] += 1;
+ }
+
+ /* Fill poly key */
+ ((unsigned char *)in)[0] = 0xC0;
+ in[1] = 0;
+ for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i+=2) {
+ crypto_cipher_encrypt_one(ctx->child,
+ (unsigned char *)out, (unsigned char *)in);
+ ctx->__vmac_ctx.polytmp[i ] =
+ ctx->__vmac_ctx.polykey[i ] = get64BE(out) & mpoly;
+ ctx->__vmac_ctx.polytmp[i+1] =
+ ctx->__vmac_ctx.polykey[i+1] = get64BE(out+1) & mpoly;
+ ((unsigned char *)in)[15] += 1;
+ }
+
+ /* Fill ip key */
+ ((unsigned char *)in)[0] = 0xE0;
+ in[1] = 0;
+ for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i+=2) {
+ do {
+ crypto_cipher_encrypt_one(ctx->child,
+ (unsigned char *)out, (unsigned char *)in);
+ ctx->__vmac_ctx.l3key[i ] = get64BE(out);
+ ctx->__vmac_ctx.l3key[i+1] = get64BE(out+1);
+ ((unsigned char *)in)[15] += 1;
+ } while (ctx->__vmac_ctx.l3key[i] >= p64
+ || ctx->__vmac_ctx.l3key[i+1] >= p64);
+ }
+
+ /* Invalidate nonce/aes cache and reset other elements */
+ ctx->__vmac_ctx.cached_nonce[0] = (uint64_t)-1; /* Ensure illegal nonce */
+ ctx->__vmac_ctx.cached_nonce[1] = (uint64_t)0; /* Ensure illegal nonce */
+ ctx->__vmac_ctx.first_block_processed = 0;
+
+ return err;
+}
+
+static int vmac_setkey(struct crypto_hash *parent,
+ const u8 *key, unsigned int keylen)
+{
+ vmac_ctx_t *ctx = crypto_hash_ctx(parent);
+
+ if (keylen != VMAC_KEY_LEN) {
+ crypto_hash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ return vmac_set_key((u8 *)key, ctx);
+}
+
+static int vmac_init(struct hash_desc *desc)
+{
+ vmac_ctx_t *ctx = crypto_hash_ctx(desc->tfm);
+
+ memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx));
+ return 0;
+}
+
+static int vmac_update2(struct hash_desc *desc,
+ struct scatterlist *sg, unsigned int nbytes)
+{
+ vmac_ctx_t *ctx = crypto_hash_ctx(desc->tfm);
+
+ for (;;) {
+ struct page *pg = sg_page(sg);
+ unsigned int offset = sg->offset;
+ unsigned int slen = sg->length;
+ char *data;
+
+ if (unlikely(slen > nbytes))
+ slen = nbytes;
+
+ nbytes -= slen;
+ data = crypto_kmap(pg, 0) + offset;
+ vhash_update((u8 *)data, slen, &ctx->__vmac_ctx);
+ crypto_kunmap(data, 0);
+ crypto_yield(desc->flags);
+
+ if (!nbytes)
+ break;
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ return 0;
+}
+
+static int vmac_update(struct hash_desc *desc,
+ struct scatterlist *sg, unsigned int nbytes)
+{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+
+ return vmac_update2(desc, sg, nbytes);
+}
+
+static int vmac_final(struct hash_desc *desc, u8 *out)
+{
+ vmac_ctx_t *ctx = crypto_hash_ctx(desc->tfm);
+ vmac_t mac;
+ u8 nonce[16] = {};
+
+ mac = vmac(NULL, 0, nonce, NULL, ctx);
+ memcpy(out, &mac, sizeof(vmac_t));
+ memset(&mac, 0, sizeof(vmac_t));
+ memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx));
+ return 0;
+}
+
+static int vmac_digest(struct hash_desc *desc,
+ struct scatterlist *sg, unsigned int nbytes, u8 *out)
+{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+
+ vmac_init(desc);
+ vmac_update2(desc, sg, nbytes);
+ return vmac_final(desc, out);
+}
+
+static int vmac_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_cipher *cipher;
+ struct crypto_instance *inst = (void *)tfm->__crt_alg;
+ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+ vmac_ctx_t *ctx = crypto_hash_ctx(__crypto_hash_cast(tfm));
+
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ ctx->child = cipher;
+ return 0;
+}
+
+static void vmac_exit_tfm(struct crypto_tfm *tfm)
+{
+ vmac_ctx_t *ctx = crypto_hash_ctx(__crypto_hash_cast(tfm));
+ crypto_free_cipher(ctx->child);
+}
+
+static void vmac_free(struct crypto_instance *inst)
+{
+ crypto_drop_spawn(crypto_instance_ctx(inst));
+ kfree(inst);
+}
+
+static struct crypto_instance *vmac_alloc(struct rtattr **tb)
+{
+ struct crypto_instance *inst;
+ struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+ if (err)
+ return ERR_PTR(err);
+
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
+ if (IS_ERR(alg))
+ return ERR_CAST(alg);
+
+ inst = crypto_alloc_instance("vmac", alg);
+ if (IS_ERR(inst))
+ goto out_put_alg;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
+ inst->alg.cra_priority = alg->cra_priority;
+ inst->alg.cra_blocksize = alg->cra_blocksize;
+ inst->alg.cra_alignmask = alg->cra_alignmask;
+ inst->alg.cra_type = &crypto_hash_type;
+
+ inst->alg.cra_hash.digestsize = sizeof(vmac_t);
+ inst->alg.cra_ctxsize = sizeof(vmac_ctx_t);
+ inst->alg.cra_init = vmac_init_tfm;
+ inst->alg.cra_exit = vmac_exit_tfm;
+
+ inst->alg.cra_hash.init = vmac_init;
+ inst->alg.cra_hash.update = vmac_update;
+ inst->alg.cra_hash.final = vmac_final;
+ inst->alg.cra_hash.digest = vmac_digest;
+ inst->alg.cra_hash.setkey = vmac_setkey;
+
+out_put_alg:
+ crypto_mod_put(alg);
+ return inst;
+}
+
+static struct crypto_template vmac_tmpl = {
+ .name = "vmac",
+ .alloc = vmac_alloc,
+ .free = vmac_free,
+ .module = THIS_MODULE,
+};
+
+static int __init vmac_module_init(void)
+{
+ return crypto_register_template(&vmac_tmpl);
+}
+
+static void __exit vmac_module_exit(void)
+{
+ crypto_unregister_template(&vmac_tmpl);
+}
+
+module_init(vmac_module_init);
+module_exit(vmac_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VMAC hash algorithm");
+
diff -r 973795c2770b include/crypto/internal/vmac.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/crypto/internal/vmac.h Thu Jul 16 02:56:25 2009 -0700
@@ -0,0 +1,186 @@
+/*
+ * Modified to interface to the Linux kernel
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+/*
--------------------------------------------------------------------------
+ * VMAC and VHASH Implementation by Ted Krovetz (tdk@xxxxxxx) and Wei Dai.
+ * This implementation is herby placed in the public domain.
+ * The authors offers no warranty. Use at your own risk.
+ * Please send bug reports to the authors.
+ * Last modified: 17 APR 08, 1700 PDT
+ *
----------------------------------------------------------------------- */
+
+#ifndef _CRYPTO_INTERNAL_VMAC_H
+#define _CRYPTO_INTERNAL_VMAC_H
+
+/*
+ * The following routines are used in this implementation. They are
+ * written via macros to simulate zero-overhead call-by-reference.
+ * All have default implemantations for when they are not defined in an
+ * architecture-specific manner.
+ *
+ * MUL64: 64x64->128-bit multiplication
+ * PMUL64: assumes top bits cleared on inputs
+ * ADD128: 128x128->128-bit addition
+ * GET_REVERSED_64: load and byte-reverse 64-bit word
+ */
+
+/* x86_64 or amd64 */
+#if (__GNUC__ && (__x86_64__ || __amd64__))
+
+#define ADD128(rh,rl,ih,il) \
+ asm ("addq %3, %1 \n\t" \
+ "adcq %2, %0" \
+ : "+r"(rh),"+r"(rl) \
+ : "r"(ih),"r"(il) : "cc");
+
+#define MUL64(rh,rl,i1,i2) \
+ asm ("mulq %3" : "=a"(rl), "=d"(rh) : "a"(i1), "r"(i2) : "cc")
+
+#define PMUL64 MUL64
+
+#define GET_REVERSED_64(p) \
+ ({uint64_t x; \
+ asm ("bswapq %0" : "=r" (x) : "0"(*(uint64_t *)(p))); x;})
+/* i386 */
+#elif (__GNUC__ && __i386__)
+
+#define GET_REVERSED_64(p) \
+ ({ uint64_t x; \
+ uint32_t *tp = (uint32_t *)(p); \
+ asm ( "bswap %%edx\n\t" \
+ "bswap %%eax" \
+ : "=A"(x) \
+ : "a"(tp[1]), "d"(tp[0])); \
+ x; })
+/* ppc64 */
+#elif (__GNUC__ && __ppc64__)
+
+#define ADD128(rh,rl,ih,il)\
+ asm volatile ( "addc %1, %1, %3 \n\t" \
+ "adde %0, %0, %2" \
+ : "+r"(rh),"+r"(rl) \
+ : "r"(ih),"r"(il));
+
+#define MUL64(rh,rl,i1,i2) \
+{ \
+ uint64_t _i1 = (i1), _i2 = (i2); \
+ rl = _i1 * _i2; \
+ asm volatile ( "mulhdu %0, %1, %2" \
+ : "=r" (rh) \
+ : "r" (_i1), "r" (_i2)); \
+}
+
+#define PMUL64 MUL64
+
+#define GET_REVERSED_64(p) \
+ ({ uint32_t hi, lo, *_p = (uint32_t *)(p); \
+ asm volatile (" lwbrx %0, %1, %2" \
+ : "=r"(lo) \
+ : "b%"(0), "r"(_p) ); \
+ asm volatile (" lwbrx %0, %1, %2" \
+ : "=r"(hi) \
+ : "b%"(4), "r"(_p) ); \
+ ((uint64_t)hi << 32) | (uint64_t)lo; } )
+
+/* ppc */
+#elif (__GNUC__ && (__ppc__ || __PPC__))
+
+#define GET_REVERSED_64(p)\
+ ({ uint32_t hi, lo, *_p = (uint32_t *)(p); \
+ asm volatile (" lwbrx %0, %1, %2" \
+ : "=r"(lo) \
+ : "b%"(0), "r"(_p) ); \
+ asm volatile (" lwbrx %0, %1, %2" \
+ : "=r"(hi) \
+ : "b%"(4), "r"(_p) ); \
+ ((uint64_t)hi << 32) | (uint64_t)lo; } )
+
+/* armel or arm */
+#elif (__GNUC__ && (__ARMEL__ || __ARM__))
+
+#define bswap32(v) \
+ ({ uint32_t tmp,out; \
+ asm volatile ( "eor %1, %2, %2, ror #16\n" \
+ "bic %1, %1, #0x00ff0000\n" \
+ "mov %0, %2, ror #8\n" \
+ "eor %0, %0, %1, lsr #8" \
+ : "=r" (out), "=&r" (tmp) \
+ : "r" (v)); \
+ out; } )
+#endif
+
+/*
+ * Default implementations, if not defined above
+ */
+
+#ifndef ADD128
+#define ADD128(rh,rl,ih,il) \
+ { uint64_t _il = (il); \
+ (rl) += (_il); \
+ if ((rl) < (_il)) (rh)++; \
+ (rh) += (ih); \
+ }
+#endif
+
+#ifndef MUL32
+#define MUL32(i1,i2) ((uint64_t)(uint32_t)(i1)*(uint32_t)(i2))
+#endif
+
+#ifndef PMUL64 /* rh may not be same as i1 or i2 */
+#define PMUL64(rh,rl,i1,i2) /* Assumes m doesn't overflow */ \
+ { uint64_t _i1 = (i1), _i2 = (i2); \
+ uint64_t m = MUL32(_i1,_i2>>32) + MUL32(_i1>>32,_i2); \
+ rh = MUL32(_i1>>32,_i2>>32); \
+ rl = MUL32(_i1,_i2); \
+ ADD128(rh,rl,(m >> 32),(m << 32)); \
+ }
+#endif
+
+#ifndef MUL64
+#define MUL64(rh,rl,i1,i2) \
+ { uint64_t _i1 = (i1), _i2 = (i2); \
+ uint64_t m1= MUL32(_i1,_i2>>32); \
+ uint64_t m2= MUL32(_i1>>32,_i2); \
+ rh = MUL32(_i1>>32,_i2>>32); \
+ rl = MUL32(_i1,_i2); \
+ ADD128(rh,rl,(m1 >> 32),(m1 << 32)); \
+ ADD128(rh,rl,(m2 >> 32),(m2 << 32)); \
+ }
+#endif
+
+#ifndef GET_REVERSED_64
+#ifndef bswap64
+#ifndef bswap32
+#define bswap32(x) \
+ ({ uint32_t bsx = (x); \
+ ((((bsx) & 0xff000000u) >> 24) \
+ | (((bsx) & 0x00ff0000u) >> 8) \
+ | (((bsx) & 0x0000ff00u) << 8) \
+ | (((bsx) & 0x000000ffu) << 24)); })
+#endif
+#define bswap64(x)\
+ ({ union { uint64_t ll; uint32_t l[2]; } w, r; \
+ w.ll = (x); \
+ r.l[0] = bswap32 (w.l[1]); \
+ r.l[1] = bswap32 (w.l[0]); \
+ r.ll; })
+#endif
+#define GET_REVERSED_64(p) bswap64(*(uint64_t *)(p))
+#endif
+
+#endif /* _CRYPTO_INTERNAL_VMAC_H */
diff -r 973795c2770b include/crypto/vmac.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/crypto/vmac.h Thu Jul 16 02:56:25 2009 -0700
@@ -0,0 +1,61 @@
+/*
+ * Modified to interface to the Linux kernel
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __CRYPTO_VMAC_H
+#define __CRYPTO_VMAC_H
+
+/*
--------------------------------------------------------------------------
+ * VMAC and VHASH Implementation by Ted Krovetz (tdk@xxxxxxx) and Wei Dai.
+ * This implementation is herby placed in the public domain.
+ * The authors offers no warranty. Use at your own risk.
+ * Please send bug reports to the authors.
+ * Last modified: 17 APR 08, 1700 PDT
+ *
----------------------------------------------------------------------- */
+
+/*
+ * User definable settings.
+ */
+#define VMAC_TAG_LEN 64
+#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */
+#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8)
+#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/
+
+/*
+ * This implementation uses uint32_t and uint64_t as names for unsigned 32-
+ * and 64-bit integer types. These are defined in C99 stdint.h. The
+ * following may need adaptation if you are not running a C99 or
+ * Microsoft C environment.
+ */
+struct vmac_ctx {
+ uint64_t nhkey [(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)];
+ uint64_t polykey[2*VMAC_TAG_LEN/64];
+ uint64_t l3key [2*VMAC_TAG_LEN/64];
+ uint64_t polytmp[2*VMAC_TAG_LEN/64];
+ uint64_t cached_nonce[2];
+ uint64_t cached_aes[2];
+ int first_block_processed;
+};
+
+typedef uint64_t vmac_t;
+
+typedef struct {
+ struct crypto_cipher *child;
+ struct vmac_ctx __vmac_ctx;
+} vmac_ctx_t;
+
+#endif /* __CRYPTO_VMAC_H */
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html