Module Name:    src
Committed By:   drochner
Date:           Thu May 26 21:50:03 UTC 2011

Modified Files:
        src/crypto/dist/ipsec-tools/src/libipsec: pfkey_dump.c
        src/crypto/dist/ipsec-tools/src/setkey: token.l
        src/sys/net: pfkeyv2.h
        src/sys/netipsec: xform_esp.c
        src/sys/opencrypto: cryptodev.h cryptosoft.c cryptosoft_xform.c
            files.opencrypto xform.c xform.h
        src/usr.bin/netstat: fast_ipsec.c
Added Files:
        src/sys/opencrypto: gmac.c gmac.h

Log Message:
pull in AES-GCM/GMAC support from OpenBSD
This is still somewhat experimental. Tested between 2 similar boxes
so far. There is much potential for performance improvement. For now,
I've changed the gmac code to accept any data alignment, as the "char *"
pointer suggests. As the code is practically used, 32-bit alignment
can be assumed, at the cost of data copies. I don't know whether
bytewise access or copies are worse performance-wise. For efficient
implementations using SSE2 instructions on x86, even stricter
alignment requirements might arise.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 \
    src/crypto/dist/ipsec-tools/src/libipsec/pfkey_dump.c
cvs rdiff -u -r1.15 -r1.16 src/crypto/dist/ipsec-tools/src/setkey/token.l
cvs rdiff -u -r1.28 -r1.29 src/sys/net/pfkeyv2.h
cvs rdiff -u -r1.37 -r1.38 src/sys/netipsec/xform_esp.c
cvs rdiff -u -r1.23 -r1.24 src/sys/opencrypto/cryptodev.h \
    src/sys/opencrypto/files.opencrypto
cvs rdiff -u -r1.36 -r1.37 src/sys/opencrypto/cryptosoft.c
cvs rdiff -u -r1.22 -r1.23 src/sys/opencrypto/cryptosoft_xform.c
cvs rdiff -u -r0 -r1.1 src/sys/opencrypto/gmac.c src/sys/opencrypto/gmac.h
cvs rdiff -u -r1.27 -r1.28 src/sys/opencrypto/xform.c
cvs rdiff -u -r1.18 -r1.19 src/sys/opencrypto/xform.h
cvs rdiff -u -r1.16 -r1.17 src/usr.bin/netstat/fast_ipsec.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/crypto/dist/ipsec-tools/src/libipsec/pfkey_dump.c
diff -u src/crypto/dist/ipsec-tools/src/libipsec/pfkey_dump.c:1.18 src/crypto/dist/ipsec-tools/src/libipsec/pfkey_dump.c:1.19
--- src/crypto/dist/ipsec-tools/src/libipsec/pfkey_dump.c:1.18	Fri Dec  3 14:32:52 2010
+++ src/crypto/dist/ipsec-tools/src/libipsec/pfkey_dump.c	Thu May 26 21:50:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: pfkey_dump.c,v 1.18 2010/12/03 14:32:52 tteras Exp $	*/
+/*	$NetBSD: pfkey_dump.c,v 1.19 2011/05/26 21:50:02 drochner Exp $	*/
 
 /*	$KAME: pfkey_dump.c,v 1.45 2003/09/08 10:14:56 itojun Exp $	*/
 
@@ -197,6 +197,12 @@
 #ifdef SADB_X_EALG_AESCTR
 	{ SADB_X_EALG_AESCTR, "aes-ctr", },
 #endif
+#ifdef SADB_X_EALG_AESGCM16
+	{ SADB_X_EALG_AESGCM16, "aes-gcm-16", },
+#endif
+#ifdef SADB_X_EALG_AESGMAC
+	{ SADB_X_EALG_AESGMAC, "aes-gmac", },
+#endif
 #ifdef SADB_X_EALG_CAMELLIACBC
 	{ SADB_X_EALG_CAMELLIACBC, "camellia-cbc", },
 #endif

Index: src/crypto/dist/ipsec-tools/src/setkey/token.l
diff -u src/crypto/dist/ipsec-tools/src/setkey/token.l:1.15 src/crypto/dist/ipsec-tools/src/setkey/token.l:1.16
--- src/crypto/dist/ipsec-tools/src/setkey/token.l:1.15	Fri Jun  4 13:06:03 2010
+++ src/crypto/dist/ipsec-tools/src/setkey/token.l	Thu May 26 21:50:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: token.l,v 1.15 2010/06/04 13:06:03 vanhu Exp $	*/
+/*	$NetBSD: token.l,v 1.16 2011/05/26 21:50:02 drochner Exp $	*/
 
 /*	$KAME: token.l,v 1.44 2003/10/21 07:20:58 itojun Exp $	*/
 
@@ -223,6 +223,16 @@
 	yylval.num = SADB_X_EALG_CAMELLIACBC; BEGIN INITIAL; return(ALG_ENC); 
 #endif
 }
+<S_ENCALG>aes-gcm-16	{
+#ifdef SADB_X_EALG_AESGCM16
+	yylval.num = SADB_X_EALG_AESGCM16; BEGIN INITIAL; return(ALG_ENC);
+#endif
+}
+<S_ENCALG>aes-gmac	{
+#ifdef SADB_X_EALG_AESGMAC
+	yylval.num = SADB_X_EALG_AESGMAC; BEGIN INITIAL; return(ALG_ENC);
+#endif
+}
 
 	/* compression algorithms */
 {hyphen}C	{ return(F_COMP); }

Index: src/sys/net/pfkeyv2.h
diff -u src/sys/net/pfkeyv2.h:1.28 src/sys/net/pfkeyv2.h:1.29
--- src/sys/net/pfkeyv2.h:1.28	Thu May  5 17:46:48 2011
+++ src/sys/net/pfkeyv2.h	Thu May 26 21:50:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: pfkeyv2.h,v 1.28 2011/05/05 17:46:48 drochner Exp $	*/
+/*	$NetBSD: pfkeyv2.h,v 1.29 2011/05/26 21:50:02 drochner Exp $	*/
 /*	$KAME: pfkeyv2.h,v 1.36 2003/07/25 09:33:37 itojun Exp $	*/
 
 /*
@@ -351,7 +351,10 @@
 #define SADB_X_AALG_SHA2_384	6
 #define SADB_X_AALG_SHA2_512	7
 #define SADB_X_AALG_RIPEMD160HMAC 8
-#define SADB_X_AALG_AES_XCBC_MAC 9 /* draft-ietf-ipsec-ciph-aes-xcbc-mac-04 */
+#define SADB_X_AALG_AES_XCBC_MAC 9 /* RFC3566 */
+#define SADB_X_AALG_AES128GMAC	11 /* RFC4543 + Errata1821 */
+#define SADB_X_AALG_AES192GMAC	12
+#define SADB_X_AALG_AES256GMAC	13
 /* private allocations should use 249-255 (RFC2407) */
 #define SADB_X_AALG_MD5		249	/* Keyed MD5 */
 #define SADB_X_AALG_SHA		250	/* Keyed SHA */
@@ -369,9 +372,12 @@
 #define SADB_X_EALG_BLOWFISHCBC	7
 #define SADB_X_EALG_RIJNDAELCBC	12
 #define SADB_X_EALG_AES		12
-#define SADB_X_EALG_AESCTR	13
-/* private allocations - based on RFC4312/IANA assignment */
-#define SADB_X_EALG_CAMELLIACBC	22
+#define SADB_X_EALG_AESCTR	13 /* RFC3686 */
+#define SADB_X_EALG_AESGCM8	18 /* RFC4106 */
+#define SADB_X_EALG_AESGCM12	19
+#define SADB_X_EALG_AESGCM16	20
+#define SADB_X_EALG_CAMELLIACBC	22 /* RFC4312 */
+#define SADB_X_EALG_AESGMAC	23 /* RFC4543 + Errata1821 */
 /* private allocations should use 249-255 (RFC2407) */
 #define SADB_X_EALG_SKIPJACK    250
 

Index: src/sys/netipsec/xform_esp.c
diff -u src/sys/netipsec/xform_esp.c:1.37 src/sys/netipsec/xform_esp.c:1.38
--- src/sys/netipsec/xform_esp.c:1.37	Mon May 23 15:17:25 2011
+++ src/sys/netipsec/xform_esp.c	Thu May 26 21:50:02 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_esp.c,v 1.37 2011/05/23 15:17:25 drochner Exp $	*/
+/*	$NetBSD: xform_esp.c,v 1.38 2011/05/26 21:50:02 drochner Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_esp.c,v 1.2.2.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$OpenBSD: ip_esp.c,v 1.69 2001/06/26 06:18:59 angelos Exp $ */
 
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.37 2011/05/23 15:17:25 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.38 2011/05/26 21:50:02 drochner Exp $");
 
 #include "opt_inet.h"
 #ifdef __FreeBSD__
@@ -132,6 +132,10 @@
 		return &enc_xform_camellia;
 	case SADB_X_EALG_AESCTR:
 		return &enc_xform_aes_ctr;
+	case SADB_X_EALG_AESGCM16:
+		return &enc_xform_aes_gcm;
+	case SADB_X_EALG_AESGMAC:
+		return &enc_xform_aes_gmac;
 	case SADB_EALG_NULL:
 		return &enc_xform_null;
 	}
@@ -219,6 +223,28 @@
 	sav->tdb_xform = xsp;
 	sav->tdb_encalgxform = txform;
 
+	if (sav->alg_enc == SADB_X_EALG_AESGCM16 ||
+	    sav->alg_enc == SADB_X_EALG_AESGMAC) {
+		switch (keylen) {
+		case 20:
+			sav->alg_auth = SADB_X_AALG_AES128GMAC;
+			sav->tdb_authalgxform = &auth_hash_gmac_aes_128;
+			break;
+		case 28:
+			sav->alg_auth = SADB_X_AALG_AES192GMAC;
+			sav->tdb_authalgxform = &auth_hash_gmac_aes_192;
+			break;
+		case 36:
+			sav->alg_auth = SADB_X_AALG_AES256GMAC;
+			sav->tdb_authalgxform = &auth_hash_gmac_aes_256;
+			break;
+		}
+		memset(&cria, 0, sizeof(cria));
+		cria.cri_alg = sav->tdb_authalgxform->type;
+		cria.cri_klen = _KEYBITS(sav->key_enc);
+		cria.cri_key = _KEYBUF(sav->key_enc);
+	}
+
 	/* Initialize crypto session. */
 	memset(&crie, 0, sizeof (crie));
 	crie.cri_alg = sav->tdb_encalgxform->type;
@@ -381,12 +407,21 @@
 
 		/* Authentication descriptor */
 		crda->crd_skip = skip;
-		crda->crd_len = m->m_pkthdr.len - (skip + alen);
+		if (espx && espx->type == CRYPTO_AES_GCM_16)
+			crda->crd_len = hlen - sav->ivlen;
+		else
+			crda->crd_len = m->m_pkthdr.len - (skip + alen);
 		crda->crd_inject = m->m_pkthdr.len - alen;
 
 		crda->crd_alg = esph->type;
-		crda->crd_key = _KEYBUF(sav->key_auth);
-		crda->crd_klen = _KEYBITS(sav->key_auth);
+		if (espx && (espx->type == CRYPTO_AES_GCM_16 ||
+			     espx->type == CRYPTO_AES_GMAC)) {
+			crda->crd_key = _KEYBUF(sav->key_enc);
+			crda->crd_klen = _KEYBITS(sav->key_enc);
+		} else {
+			crda->crd_key = _KEYBUF(sav->key_auth);
+			crda->crd_klen = _KEYBITS(sav->key_auth);
+		}
 
 		/* Copy the authenticator */
 		if (mtag == NULL)
@@ -418,7 +453,10 @@
 	if (espx) {
 		IPSEC_ASSERT(crde != NULL, ("esp_input: null esp crypto descriptor"));
 		crde->crd_skip = skip + hlen;
-		crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
+		if (espx->type == CRYPTO_AES_GMAC)
+			crde->crd_len = 0;
+		else
+			crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
 		crde->crd_inject = skip + hlen - sav->ivlen;
 
 		crde->crd_alg = espx->type;
@@ -856,7 +894,10 @@
 
 		/* Encryption descriptor. */
 		crde->crd_skip = skip + hlen;
-		crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
+		if (espx->type == CRYPTO_AES_GMAC)
+			crde->crd_len = 0;
+		else
+			crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
 		crde->crd_flags = CRD_F_ENCRYPT;
 		crde->crd_inject = skip + hlen - sav->ivlen;
 
@@ -896,13 +937,22 @@
 	if (esph) {
 		/* Authentication descriptor. */
 		crda->crd_skip = skip;
-		crda->crd_len = m->m_pkthdr.len - (skip + alen);
+		if (espx && espx->type == CRYPTO_AES_GCM_16)
+			crda->crd_len = hlen - sav->ivlen;
+		else
+			crda->crd_len = m->m_pkthdr.len - (skip + alen);
 		crda->crd_inject = m->m_pkthdr.len - alen;
 
 		/* Authentication operation. */
 		crda->crd_alg = esph->type;
-		crda->crd_key = _KEYBUF(sav->key_auth);
-		crda->crd_klen = _KEYBITS(sav->key_auth);
+		if (espx && (espx->type == CRYPTO_AES_GCM_16 ||
+			     espx->type == CRYPTO_AES_GMAC)) {
+			crda->crd_key = _KEYBUF(sav->key_enc);
+			crda->crd_klen = _KEYBITS(sav->key_enc);
+		} else {
+			crda->crd_key = _KEYBUF(sav->key_auth);
+			crda->crd_klen = _KEYBITS(sav->key_auth);
+		}
 	}
 
 	return crypto_dispatch(crp);

Index: src/sys/opencrypto/cryptodev.h
diff -u src/sys/opencrypto/cryptodev.h:1.23 src/sys/opencrypto/cryptodev.h:1.24
--- src/sys/opencrypto/cryptodev.h:1.23	Tue May 24 19:10:09 2011
+++ src/sys/opencrypto/cryptodev.h	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cryptodev.h,v 1.23 2011/05/24 19:10:09 drochner Exp $ */
+/*	$NetBSD: cryptodev.h,v 1.24 2011/05/26 21:50:03 drochner Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.2.2.6 2003/07/02 17:04:50 sam Exp $	*/
 /*	$OpenBSD: cryptodev.h,v 1.33 2002/07/17 23:52:39 art Exp $	*/
 
@@ -140,7 +140,12 @@
 #define CRYPTO_CAMELLIA_CBC	26
 #define CRYPTO_AES_CTR		27
 #define CRYPTO_AES_XCBC_MAC_96	28
-#define CRYPTO_ALGORITHM_MAX	28 /* Keep updated - see below */
+#define CRYPTO_AES_GCM_16	29
+#define CRYPTO_AES_128_GMAC	30
+#define CRYPTO_AES_192_GMAC	31
+#define CRYPTO_AES_256_GMAC	32
+#define CRYPTO_AES_GMAC		33
+#define CRYPTO_ALGORITHM_MAX	33 /* Keep updated - see below */
 
 /* Algorithm flags */
 #define	CRYPTO_ALG_FLAG_SUPPORTED	0x01 /* Algorithm is supported */
Index: src/sys/opencrypto/files.opencrypto
diff -u src/sys/opencrypto/files.opencrypto:1.23 src/sys/opencrypto/files.opencrypto:1.24
--- src/sys/opencrypto/files.opencrypto:1.23	Tue May 24 19:10:11 2011
+++ src/sys/opencrypto/files.opencrypto	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-#	$NetBSD: files.opencrypto,v 1.23 2011/05/24 19:10:11 drochner Exp $
+#	$NetBSD: files.opencrypto,v 1.24 2011/05/26 21:50:03 drochner Exp $
 #
 #
 
@@ -19,6 +19,7 @@
 file	opencrypto/cryptosoft.c		swcrypto
 file	opencrypto/deflate.c		swcrypto	# wrapper around zlib
 file	opencrypto/aesxcbcmac.c		swcrypto
+file	opencrypto/gmac.c		swcrypto
 
 # Pseudo-device for userspace access to opencrypto
 # (and thus crypto hardware accelerators).

Index: src/sys/opencrypto/cryptosoft.c
diff -u src/sys/opencrypto/cryptosoft.c:1.36 src/sys/opencrypto/cryptosoft.c:1.37
--- src/sys/opencrypto/cryptosoft.c:1.36	Tue May 24 19:10:10 2011
+++ src/sys/opencrypto/cryptosoft.c	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cryptosoft.c,v 1.36 2011/05/24 19:10:10 drochner Exp $ */
+/*	$NetBSD: cryptosoft.c,v 1.37 2011/05/26 21:50:03 drochner Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/cryptosoft.c,v 1.2.2.1 2002/11/21 23:34:23 sam Exp $	*/
 /*	$OpenBSD: cryptosoft.c,v 1.35 2002/04/26 08:43:50 deraadt Exp $	*/
 
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cryptosoft.c,v 1.36 2011/05/24 19:10:10 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cryptosoft.c,v 1.37 2011/05/26 21:50:03 drochner Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -48,6 +48,7 @@
 	SHA384_CTX sha384ctx;
 	SHA512_CTX sha512ctx;
 	aesxcbc_ctx aesxcbcctx;
+	AES_GMAC_CTX aesgmacctx;
 };
 
 struct swcr_data **swcr_sessions = NULL;
@@ -63,6 +64,7 @@
 
 static	int swcr_encdec(struct cryptodesc *, const struct swcr_data *, void *, int);
 static	int swcr_compdec(struct cryptodesc *, const struct swcr_data *, void *, int, int *);
+static	int swcr_combined(struct cryptop *, int);
 static	int swcr_process(void *, struct cryptop *, int);
 static	int swcr_newsession(void *, u_int32_t *, struct cryptoini *);
 static	int swcr_freesession(void *, u_int64_t);
@@ -562,6 +564,143 @@
 }
 
 /*
+ * Apply a combined encryption-authentication transformation
+ */
+static int
+swcr_combined(struct cryptop *crp, int outtype)
+{
+	uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))];
+	u_char *blk = (u_char *)blkbuf;
+	u_char aalg[AALG_MAX_RESULT_LEN];
+	u_char iv[EALG_MAX_BLOCK_LEN];
+	union authctx ctx;
+	struct cryptodesc *crd, *crda = NULL, *crde = NULL;
+	struct swcr_data *sw, *swa, *swe = NULL;
+	const struct swcr_auth_hash *axf = NULL;
+	const struct swcr_enc_xform *exf = NULL;
+	void *buf = (void *)crp->crp_buf;
+	uint32_t *blkp;
+	int i, blksz = 0, ivlen = 0, len;
+
+	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
+		for (sw = swcr_sessions[crp->crp_sid & 0xffffffff];
+		     sw && sw->sw_alg != crd->crd_alg;
+		     sw = sw->sw_next)
+			;
+		if (sw == NULL)
+			return (EINVAL);
+
+		switch (sw->sw_alg) {
+		case CRYPTO_AES_GCM_16:
+		case CRYPTO_AES_GMAC:
+			swe = sw;
+			crde = crd;
+			exf = swe->sw_exf;
+			ivlen = exf->enc_xform->ivsize;
+			break;
+		case CRYPTO_AES_128_GMAC:
+		case CRYPTO_AES_192_GMAC:
+		case CRYPTO_AES_256_GMAC:
+			swa = sw;
+			crda = crd;
+			axf = swa->sw_axf;
+			if (swa->sw_ictx == 0)
+				return (EINVAL);
+			memcpy(&ctx, swa->sw_ictx, axf->ctxsize);
+			blksz = axf->auth_hash->blocksize;
+			break;
+		default:
+			return (EINVAL);
+		}
+	}
+	if (crde == NULL || crda == NULL)
+		return (EINVAL);
+	if (outtype == CRYPTO_BUF_CONTIG)
+		return (EINVAL);
+
+	/* Initialize the IV */
+	if (crde->crd_flags & CRD_F_ENCRYPT) {
+		/* IV explicitly provided ? */
+		if (crde->crd_flags & CRD_F_IV_EXPLICIT) {
+			memcpy(iv, crde->crd_iv, ivlen);
+			if (exf->reinit)
+				exf->reinit(swe->sw_kschedule, iv, 0);
+		} else if (exf->reinit)
+			exf->reinit(swe->sw_kschedule, 0, iv);
+		else
+			arc4randbytes(iv, ivlen);
+
+		/* Do we need to write the IV */
+		if (!(crde->crd_flags & CRD_F_IV_PRESENT))
+			COPYBACK(outtype, buf, crde->crd_inject, ivlen, iv);
+
+	} else {	/* Decryption */
+			/* IV explicitly provided ? */
+		if (crde->crd_flags & CRD_F_IV_EXPLICIT)
+			memcpy(iv, crde->crd_iv, ivlen);
+		else {
+			/* Get IV off buf */
+			COPYDATA(outtype, buf, crde->crd_inject, ivlen, iv);
+		}
+		if (exf->reinit)
+			exf->reinit(swe->sw_kschedule, iv, 0);
+	}
+
+	/* Supply MAC with IV */
+	if (axf->Reinit)
+		axf->Reinit(&ctx, iv, ivlen);
+
+	/* Supply MAC with AAD */
+	for (i = 0; i < crda->crd_len; i += blksz) {
+		len = MIN(crda->crd_len - i, blksz);
+		COPYDATA(outtype, buf, crda->crd_skip + i, len, blk);
+		axf->Update(&ctx, blk, len);
+	}
+
+	/* Do encryption/decryption with MAC */
+	for (i = 0; i < crde->crd_len; i += blksz) {
+		len = MIN(crde->crd_len - i, blksz);
+		if (len < blksz)
+			memset(blk, 0, blksz);
+		COPYDATA(outtype, buf, crde->crd_skip + i, len, blk);
+		if (crde->crd_flags & CRD_F_ENCRYPT) {
+			exf->encrypt(swe->sw_kschedule, blk);
+			axf->Update(&ctx, blk, len);
+		} else {
+			axf->Update(&ctx, blk, len);
+			exf->decrypt(swe->sw_kschedule, blk);
+		}
+		COPYBACK(outtype, buf, crde->crd_skip + i, len, blk);
+	}
+
+	/* Do any required special finalization */
+	switch (crda->crd_alg) {
+		case CRYPTO_AES_128_GMAC:
+		case CRYPTO_AES_192_GMAC:
+		case CRYPTO_AES_256_GMAC:
+			/* length block */
+			memset(blk, 0, blksz);
+			blkp = (uint32_t *)blk + 1;
+			*blkp = htobe32(crda->crd_len * 8);
+			blkp = (uint32_t *)blk + 3;
+			*blkp = htobe32(crde->crd_len * 8);
+			axf->Update(&ctx, blk, blksz);
+			break;
+	}
+
+	/* Finalize MAC */
+	axf->Final(aalg, &ctx);
+
+	/* Inject the authentication data */
+	if (outtype == CRYPTO_BUF_MBUF)
+		COPYBACK(outtype, buf, crda->crd_inject, axf->auth_hash->authsize, aalg);
+	else
+		memcpy(crp->crp_mac, aalg, axf->auth_hash->authsize);
+
+	return (0);
+}
+
+/*
  * Apply a compression/decompression algorithm
  */
 static int
@@ -710,6 +849,9 @@
 		case CRYPTO_AES_CTR:
 			txf = &swcr_enc_xform_aes_ctr;
 			goto enccommon;
+		case CRYPTO_AES_GCM_16:
+			txf = &swcr_enc_xform_aes_gcm;
+			goto enccommon;
 		case CRYPTO_NULL_CBC:
 			txf = &swcr_enc_xform_null;
 			goto enccommon;
@@ -723,6 +865,11 @@
 			(*swd)->sw_exf = txf;
 			break;
 
+		case CRYPTO_AES_GMAC:
+			txf = &swcr_enc_xform_aes_gmac;
+			(*swd)->sw_exf = txf;
+			break;
+
 		case CRYPTO_MD5_HMAC:
 			axf = &swcr_auth_hash_hmac_md5;
 			goto authcommon;
@@ -842,6 +989,16 @@
 
 		case CRYPTO_AES_XCBC_MAC_96:
 			axf = &swcr_auth_hash_aes_xcbc_mac;
+			goto auth4common;
+		case CRYPTO_AES_128_GMAC:
+			axf = &swcr_auth_hash_gmac_aes_128;
+			goto auth4common;
+		case CRYPTO_AES_192_GMAC:
+			axf = &swcr_auth_hash_gmac_aes_192;
+			goto auth4common;
+		case CRYPTO_AES_256_GMAC:
+			axf = &swcr_auth_hash_gmac_aes_256;
+		auth4common:
 			(*swd)->sw_ictx = malloc(axf->ctxsize,
 			    M_CRYPTO_DATA, M_NOWAIT);
 			if ((*swd)->sw_ictx == NULL) {
@@ -912,6 +1069,7 @@
 		case CRYPTO_RIJNDAEL128_CBC:
 		case CRYPTO_CAMELLIA_CBC:
 		case CRYPTO_AES_CTR:
+		case CRYPTO_AES_GCM_16:
 		case CRYPTO_NULL_CBC:
 			txf = swd->sw_exf;
 
@@ -919,6 +1077,9 @@
 				txf->zerokey(&(swd->sw_kschedule));
 			break;
 
+		case CRYPTO_AES_GMAC:
+			break;
+
 		case CRYPTO_MD5_HMAC:
 		case CRYPTO_MD5_HMAC_96:
 		case CRYPTO_SHA1_HMAC:
@@ -958,6 +1119,9 @@
 		case CRYPTO_MD5:
 		case CRYPTO_SHA1:
 		case CRYPTO_AES_XCBC_MAC_96:
+		case CRYPTO_AES_128_GMAC:
+		case CRYPTO_AES_192_GMAC:
+		case CRYPTO_AES_256_GMAC:
 			axf = swd->sw_axf;
 
 			if (swd->sw_ictx)
@@ -1069,6 +1233,14 @@
 				goto done;
 			break;
 
+		case CRYPTO_AES_GCM_16:
+		case CRYPTO_AES_GMAC:
+		case CRYPTO_AES_128_GMAC:
+		case CRYPTO_AES_192_GMAC:
+		case CRYPTO_AES_256_GMAC:
+			crp->crp_etype = swcr_combined(crp, type);
+			goto done;
+
 		case CRYPTO_DEFLATE_COMP:
 		case CRYPTO_DEFLATE_COMP_NOGROW:
 		case CRYPTO_GZIP_COMP:
@@ -1111,6 +1283,8 @@
 	REGISTER(CRYPTO_SKIPJACK_CBC);
 	REGISTER(CRYPTO_CAMELLIA_CBC);
 	REGISTER(CRYPTO_AES_CTR);
+	REGISTER(CRYPTO_AES_GCM_16);
+	REGISTER(CRYPTO_AES_GMAC);
 	REGISTER(CRYPTO_NULL_CBC);
 	REGISTER(CRYPTO_MD5_HMAC);
 	REGISTER(CRYPTO_MD5_HMAC_96);
@@ -1127,6 +1301,9 @@
 	REGISTER(CRYPTO_MD5);
 	REGISTER(CRYPTO_SHA1);
 	REGISTER(CRYPTO_AES_XCBC_MAC_96);
+	REGISTER(CRYPTO_AES_128_GMAC);
+	REGISTER(CRYPTO_AES_192_GMAC);
+	REGISTER(CRYPTO_AES_256_GMAC);
 	REGISTER(CRYPTO_RIJNDAEL128_CBC);
 	REGISTER(CRYPTO_DEFLATE_COMP);
 	REGISTER(CRYPTO_DEFLATE_COMP_NOGROW);

Index: src/sys/opencrypto/cryptosoft_xform.c
diff -u src/sys/opencrypto/cryptosoft_xform.c:1.22 src/sys/opencrypto/cryptosoft_xform.c:1.23
--- src/sys/opencrypto/cryptosoft_xform.c:1.22	Tue May 24 19:10:11 2011
+++ src/sys/opencrypto/cryptosoft_xform.c	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: cryptosoft_xform.c,v 1.22 2011/05/24 19:10:11 drochner Exp $ */
+/*	$NetBSD: cryptosoft_xform.c,v 1.23 2011/05/26 21:50:03 drochner Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/xform.c,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $	*/
 /*	$OpenBSD: xform.c,v 1.19 2002/08/16 22:47:25 dhartmei Exp $	*/
 
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: cryptosoft_xform.c,v 1.22 2011/05/24 19:10:11 drochner Exp $");
+__KERNEL_RCSID(1, "$NetBSD: cryptosoft_xform.c,v 1.23 2011/05/26 21:50:03 drochner Exp $");
 
 #include <crypto/blowfish/blowfish.h>
 #include <crypto/cast128/cast128.h>
@@ -56,12 +56,14 @@
 #include <sys/sha1.h>
 #include <sys/sha2.h>
 #include <opencrypto/aesxcbcmac.h>
+#include <opencrypto/gmac.h>
 
 struct swcr_auth_hash {
 	const struct auth_hash *auth_hash;
 	int ctxsize;
 	void (*Init)(void *);
 	void (*Setkey)(void *, const uint8_t *, uint16_t);
+	void (*Reinit)(void *, const uint8_t *, uint16_t);
 	int  (*Update)(void *, const uint8_t *, uint16_t);
 	void (*Final)(uint8_t *, void *);
 };
@@ -118,6 +120,7 @@
 static  void cml_zerokey(u_int8_t **);
 static  void aes_ctr_zerokey(u_int8_t **);
 static  void aes_ctr_reinit(void *, const u_int8_t *, u_int8_t *);
+static  void aes_gcm_reinit(void *, const u_int8_t *, u_int8_t *);
 
 static	void null_init(void *);
 static	int null_update(void *, const u_int8_t *, u_int16_t);
@@ -215,6 +218,24 @@
 	aes_ctr_reinit
 };
 
+static const struct swcr_enc_xform swcr_enc_xform_aes_gcm = {
+	&enc_xform_aes_gcm,
+	aes_ctr_crypt,
+	aes_ctr_crypt,
+	aes_ctr_setkey,
+	aes_ctr_zerokey,
+	aes_gcm_reinit
+};
+
+static const struct swcr_enc_xform swcr_enc_xform_aes_gmac = {
+	&enc_xform_aes_gmac,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
 static const struct swcr_enc_xform swcr_enc_xform_camellia = {
 	&enc_xform_camellia,
 	cml_encrypt,
@@ -227,80 +248,80 @@
 /* Authentication instances */
 static const struct swcr_auth_hash swcr_auth_hash_null = {
 	&auth_hash_null, sizeof(int), /* NB: context isn't used */
-	null_init, NULL, null_update, null_final
+	null_init, NULL, NULL, null_update, null_final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_md5 = {
 	&auth_hash_hmac_md5, sizeof(MD5_CTX),
-	(void (*) (void *)) MD5Init, NULL, MD5Update_int,
+	(void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int,
 	(void (*) (u_int8_t *, void *)) MD5Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_sha1 = {
 	&auth_hash_hmac_sha1, sizeof(SHA1_CTX),
-	SHA1Init_int, NULL, SHA1Update_int, SHA1Final_int
+	SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_ripemd_160 = {
 	&auth_hash_hmac_ripemd_160, sizeof(RMD160_CTX),
-	(void (*)(void *)) RMD160Init, NULL, RMD160Update_int,
+	(void (*)(void *)) RMD160Init, NULL, NULL, RMD160Update_int,
 	(void (*)(u_int8_t *, void *)) RMD160Final
 };
 static const struct swcr_auth_hash swcr_auth_hash_hmac_md5_96 = {
 	&auth_hash_hmac_md5_96, sizeof(MD5_CTX),
-	(void (*) (void *)) MD5Init, NULL, MD5Update_int,
+	(void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int,
 	(void (*) (u_int8_t *, void *)) MD5Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_sha1_96 = {
 	&auth_hash_hmac_sha1_96, sizeof(SHA1_CTX),
-	SHA1Init_int, NULL, SHA1Update_int, SHA1Final_int
+	SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_ripemd_160_96 = {
 	&auth_hash_hmac_ripemd_160_96, sizeof(RMD160_CTX),
-	(void (*)(void *)) RMD160Init, NULL, RMD160Update_int,
+	(void (*)(void *)) RMD160Init, NULL, NULL, RMD160Update_int,
 	(void (*)(u_int8_t *, void *)) RMD160Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_key_md5 = {
 	&auth_hash_key_md5, sizeof(MD5_CTX),
-	(void (*)(void *)) MD5Init, NULL, MD5Update_int,
+	(void (*)(void *)) MD5Init, NULL, NULL, MD5Update_int,
 	(void (*)(u_int8_t *, void *)) MD5Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_key_sha1 = {
 	&auth_hash_key_sha1, sizeof(SHA1_CTX),
-	SHA1Init_int, NULL, SHA1Update_int, SHA1Final_int
+	SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_md5 = {
 	&auth_hash_md5, sizeof(MD5_CTX),
-	(void (*) (void *)) MD5Init, NULL, MD5Update_int,
+	(void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int,
 	(void (*) (u_int8_t *, void *)) MD5Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_sha1 = {
 	&auth_hash_sha1, sizeof(SHA1_CTX),
-	(void (*)(void *)) SHA1Init, NULL, SHA1Update_int,
+	(void (*)(void *)) SHA1Init, NULL, NULL, SHA1Update_int,
 	(void (*)(u_int8_t *, void *)) SHA1Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_sha2_256 = {
 	&auth_hash_hmac_sha2_256, sizeof(SHA256_CTX),
-	(void (*)(void *)) SHA256_Init, NULL, SHA256Update_int,
+	(void (*)(void *)) SHA256_Init, NULL, NULL, SHA256Update_int,
 	(void (*)(u_int8_t *, void *)) SHA256_Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_sha2_384 = {
 	&auth_hash_hmac_sha2_384, sizeof(SHA384_CTX),
-	(void (*)(void *)) SHA384_Init, NULL, SHA384Update_int,
+	(void (*)(void *)) SHA384_Init, NULL, NULL, SHA384Update_int,
 	(void (*)(u_int8_t *, void *)) SHA384_Final
 };
 
 static const struct swcr_auth_hash swcr_auth_hash_hmac_sha2_512 = {
 	&auth_hash_hmac_sha2_512, sizeof(SHA512_CTX),
-	(void (*)(void *)) SHA512_Init, NULL, SHA512Update_int,
+	(void (*)(void *)) SHA512_Init, NULL, NULL, SHA512Update_int,
 	(void (*)(u_int8_t *, void *)) SHA512_Final
 };
 
@@ -308,7 +329,34 @@
 	&auth_hash_aes_xcbc_mac_96, sizeof(aesxcbc_ctx),
 	null_init,
 	(void (*)(void *, const u_int8_t *, u_int16_t))aes_xcbc_mac_init,
-	aes_xcbc_mac_loop, aes_xcbc_mac_result
+	NULL, aes_xcbc_mac_loop, aes_xcbc_mac_result
+};
+
+static const struct swcr_auth_hash swcr_auth_hash_gmac_aes_128 = {
+	&auth_hash_gmac_aes_128, sizeof(AES_GMAC_CTX),
+	(void (*)(void *))AES_GMAC_Init,
+	(void (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Setkey,
+	(void (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Reinit,
+	(int (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Update,
+	(void (*)(u_int8_t *, void *))AES_GMAC_Final
+};
+
+static const struct swcr_auth_hash swcr_auth_hash_gmac_aes_192 = {
+	&auth_hash_gmac_aes_192, sizeof(AES_GMAC_CTX),
+	(void (*)(void *))AES_GMAC_Init,
+	(void (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Setkey,
+	(void (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Reinit,
+	(int (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Update,
+	(void (*)(u_int8_t *, void *))AES_GMAC_Final
+};
+
+static const struct swcr_auth_hash swcr_auth_hash_gmac_aes_256 = {
+	&auth_hash_gmac_aes_256, sizeof(AES_GMAC_CTX),
+	(void (*)(void *))AES_GMAC_Init,
+	(void (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Setkey,
+	(void (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Reinit,
+	(int (*)(void *, const u_int8_t *, u_int16_t))AES_GMAC_Update,
+	(void (*)(u_int8_t *, void *))AES_GMAC_Final
 };
 
 /* Compression instance */
@@ -723,6 +771,23 @@
 	memset(ctx->ac_block + AESCTR_NONCESIZE + AESCTR_IVSIZE, 0, 4);
 }
 
+void
+aes_gcm_reinit(void *key, const u_int8_t *iv, u_int8_t *ivout)
+{
+	struct aes_ctr_ctx *ctx = key;
+
+	if (!iv) {
+		ctx->ivgenctx.lastiv++;
+		iv = (const u_int8_t *)&ctx->ivgenctx.lastiv;
+	}
+	if (ivout)
+		memcpy(ivout, iv, AESCTR_IVSIZE);
+	memcpy(ctx->ac_block + AESCTR_NONCESIZE, iv, AESCTR_IVSIZE);
+	/* reset counter */
+	memset(ctx->ac_block + AESCTR_NONCESIZE + AESCTR_IVSIZE, 0, 4);
+	ctx->ac_block[AESCTR_BLOCKSIZE - 1] = 1; /* GCM starts with 1 */
+}
+
 /*
  * And now for auth.
  */

Index: src/sys/opencrypto/xform.c
diff -u src/sys/opencrypto/xform.c:1.27 src/sys/opencrypto/xform.c:1.28
--- src/sys/opencrypto/xform.c:1.27	Tue May 24 19:10:11 2011
+++ src/sys/opencrypto/xform.c	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform.c,v 1.27 2011/05/24 19:10:11 drochner Exp $ */
+/*	$NetBSD: xform.c,v 1.28 2011/05/26 21:50:03 drochner Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/xform.c,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $	*/
 /*	$OpenBSD: xform.c,v 1.19 2002/08/16 22:47:25 dhartmei Exp $	*/
 
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform.c,v 1.27 2011/05/24 19:10:11 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform.c,v 1.28 2011/05/26 21:50:03 drochner Exp $");
 
 #include <sys/param.h>
 #include <sys/malloc.h>
@@ -140,6 +140,16 @@
 	16, 8, 16+4, 32+4
 };
 
+const struct enc_xform enc_xform_aes_gcm = {
+	CRYPTO_AES_GCM_16, "AES-GCM",
+	4 /* ??? */, 8, 16+4, 32+4
+};
+
+const struct enc_xform enc_xform_aes_gmac = {
+	CRYPTO_AES_GMAC, "AES-GMAC",
+	4 /* ??? */, 8, 16+4, 32+4
+};
+
 /* Authentication instances */
 const struct auth_hash auth_hash_null = {
 	CRYPTO_NULL_HMAC, "NULL-HMAC",
@@ -216,6 +226,21 @@
 	16, 16, 12, 0
 };
 
+const struct auth_hash auth_hash_gmac_aes_128 = {
+	CRYPTO_AES_128_GMAC, "GMAC-AES-128",
+	16+4, 16, 16, 16 /* ??? */
+};
+
+const struct auth_hash auth_hash_gmac_aes_192 = {
+	CRYPTO_AES_192_GMAC, "GMAC-AES-192",
+	24+4, 16, 16, 16 /* ??? */
+};
+
+const struct auth_hash auth_hash_gmac_aes_256 = {
+	CRYPTO_AES_256_GMAC, "GMAC-AES-256",
+	32+4, 16, 16, 16 /* ??? */
+};
+
 /* Compression instance */
 const struct comp_algo comp_algo_deflate = {
 	CRYPTO_DEFLATE_COMP, "Deflate",

Index: src/sys/opencrypto/xform.h
diff -u src/sys/opencrypto/xform.h:1.18 src/sys/opencrypto/xform.h:1.19
--- src/sys/opencrypto/xform.h:1.18	Tue May 24 19:10:12 2011
+++ src/sys/opencrypto/xform.h	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform.h,v 1.18 2011/05/24 19:10:12 drochner Exp $ */
+/*	$NetBSD: xform.h,v 1.19 2011/05/26 21:50:03 drochner Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/xform.h,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $	*/
 /*	$OpenBSD: xform.h,v 1.10 2002/04/22 23:10:09 deraadt Exp $	*/
 
@@ -65,6 +65,8 @@
 extern const struct enc_xform enc_xform_arc4;
 extern const struct enc_xform enc_xform_camellia;
 extern const struct enc_xform enc_xform_aes_ctr;
+extern const struct enc_xform enc_xform_aes_gcm;
+extern const struct enc_xform enc_xform_aes_gmac;
 
 extern const struct auth_hash auth_hash_null;
 extern const struct auth_hash auth_hash_md5;
@@ -81,6 +83,9 @@
 extern const struct auth_hash auth_hash_hmac_sha2_384;
 extern const struct auth_hash auth_hash_hmac_sha2_512;
 extern const struct auth_hash auth_hash_aes_xcbc_mac_96;
+extern const struct auth_hash auth_hash_gmac_aes_128;
+extern const struct auth_hash auth_hash_gmac_aes_192;
+extern const struct auth_hash auth_hash_gmac_aes_256;
 
 extern const struct comp_algo comp_algo_deflate;
 extern const struct comp_algo comp_algo_deflate_nogrow;

Index: src/usr.bin/netstat/fast_ipsec.c
diff -u src/usr.bin/netstat/fast_ipsec.c:1.16 src/usr.bin/netstat/fast_ipsec.c:1.17
--- src/usr.bin/netstat/fast_ipsec.c:1.16	Tue May 24 19:10:12 2011
+++ src/usr.bin/netstat/fast_ipsec.c	Thu May 26 21:50:03 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: fast_ipsec.c,v 1.16 2011/05/24 19:10:12 drochner Exp $ */
+/*	$NetBSD: fast_ipsec.c,v 1.17 2011/05/26 21:50:03 drochner Exp $ */
 /* 	$FreeBSD: src/tools/tools/crypto/ipsecstats.c,v 1.1.4.1 2003/06/03 00:13:13 sam Exp $ */
 
 /*-
@@ -33,7 +33,7 @@
 #include <sys/cdefs.h>
 #ifndef lint
 #ifdef __NetBSD__
-__RCSID("$NetBSD: fast_ipsec.c,v 1.16 2011/05/24 19:10:12 drochner Exp $");
+__RCSID("$NetBSD: fast_ipsec.c,v 1.17 2011/05/26 21:50:03 drochner Exp $");
 #endif
 #endif /* not lint*/
 
@@ -118,6 +118,9 @@
 	{ SADB_X_AALG_SHA2_384,	"hmac-sha2-384", },
 	{ SADB_X_AALG_SHA2_512,	"hmac-sha2-512", },
 	{ SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", },
+	{ SADB_X_AALG_AES128GMAC, "aes-128-gmac", },
+	{ SADB_X_AALG_AES192GMAC, "aes-192-gmac", },
+	{ SADB_X_AALG_AES256GMAC, "aes-256-gmac", },
 };
 static const struct alg espalgs[] = {
 	{ SADB_EALG_NONE,	"none", },
@@ -129,6 +132,8 @@
 	{ SADB_X_EALG_RIJNDAELCBC, "aes-cbc", },
 	{ SADB_X_EALG_CAMELLIACBC, "camellia-cbc", },
 	{ SADB_X_EALG_AESCTR,	"aes-ctr", },
+	{ SADB_X_EALG_AESGCM16,	"aes-gcm-16", },
+	{ SADB_X_EALG_AESGMAC, "aes-gmac", },
 };
 static const struct alg ipcompalgs[] = {
 	{ SADB_X_CALG_NONE,	"none", },

Added files:

Index: src/sys/opencrypto/gmac.c
diff -u /dev/null src/sys/opencrypto/gmac.c:1.1
--- /dev/null	Thu May 26 21:50:03 2011
+++ src/sys/opencrypto/gmac.c	Thu May 26 21:50:03 2011
@@ -0,0 +1,153 @@
+/* $NetBSD: gmac.c,v 1.1 2011/05/26 21:50:03 drochner Exp $ */
+/* OpenBSD: gmac.c,v 1.3 2011/01/11 15:44:23 deraadt Exp */
+
+/*
+ * Copyright (c) 2010 Mike Belopuhov <m...@vantronix.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This code implements the Message Authentication part of the
+ * Galois/Counter Mode (as being described in the RFC 4543) using
+ * the AES cipher.  FIPS SP 800-38D describes the algorithm details.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <crypto/rijndael/rijndael.h>
+#include <opencrypto/gmac.h>
+
+void	ghash_gfmul(const uint32_t *, const uint32_t *, uint32_t *);
+void	ghash_update(GHASH_CTX *, const uint8_t *, size_t);
+
+/* Computes a block multiplication in the GF(2^128) */
+void
+ghash_gfmul(const uint32_t *X, const uint32_t *Y, uint32_t *product)
+{
+	uint32_t	v[4];
+	uint32_t	z[4] = { 0, 0, 0, 0};
+	const uint8_t	*x = (const uint8_t *)X;
+	uint32_t	mul;
+	int		i;
+
+	v[0] = be32toh(Y[0]);
+	v[1] = be32toh(Y[1]);
+	v[2] = be32toh(Y[2]);
+	v[3] = be32toh(Y[3]);
+
+	for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) {
+		/* update Z */
+		if (x[i >> 3] & (1 << (~i & 7))) {
+			z[0] ^= v[0];
+			z[1] ^= v[1];
+			z[2] ^= v[2];
+			z[3] ^= v[3];
+		} /* else: we preserve old values */
+
+		/* update V */
+		mul = v[3] & 1;
+		v[3] = (v[2] << 31) | (v[3] >> 1);
+		v[2] = (v[1] << 31) | (v[2] >> 1);
+		v[1] = (v[0] << 31) | (v[1] >> 1);
+		v[0] = (v[0] >> 1) ^ (0xe1000000 * mul);
+	}
+
+	product[0] = htobe32(z[0]);
+	product[1] = htobe32(z[1]);
+	product[2] = htobe32(z[2]);
+	product[3] = htobe32(z[3]);
+}
+
+void
+ghash_update(GHASH_CTX *ctx, const uint8_t *X, size_t len)
+{
+	uint8_t *s = (uint8_t *)ctx->S;
+	uint8_t *y = (uint8_t *)ctx->Z;
+	int i, j;
+
+	for (i = 0; i < len / GMAC_BLOCK_LEN; i++) {
+		for (j = 0; j < GMAC_BLOCK_LEN; j++)
+			s[j] = y[j] ^ X[j];
+
+		ghash_gfmul(ctx->S, ctx->H, ctx->S);
+
+		y = s;
+		X += GMAC_BLOCK_LEN;
+	}
+
+	memcpy(ctx->Z, ctx->S, GMAC_BLOCK_LEN);
+}
+
+#define AESCTR_NONCESIZE	4
+
+void
+AES_GMAC_Init(AES_GMAC_CTX *ctx)
+{
+
+	memset(ctx, 0, sizeof(AES_GMAC_CTX));
+}
+
+void
+AES_GMAC_Setkey(AES_GMAC_CTX *ctx, const uint8_t *key, uint16_t klen)
+{
+	ctx->rounds = rijndaelKeySetupEnc(ctx->K, (const u_char *)key,
+	    (klen - AESCTR_NONCESIZE) * 8);
+	/* copy out salt to the counter block */
+	memcpy(ctx->J, key + klen - AESCTR_NONCESIZE, AESCTR_NONCESIZE);
+	/* prepare a hash subkey */
+	rijndaelEncrypt(ctx->K, ctx->rounds, (void *)ctx->ghash.H,
+			(void *)ctx->ghash.H);
+}
+
+void
+AES_GMAC_Reinit(AES_GMAC_CTX *ctx, const uint8_t *iv, uint16_t ivlen)
+{
+	/* copy out IV to the counter block */
+	memcpy(ctx->J + AESCTR_NONCESIZE, iv, ivlen);
+}
+
+int
+AES_GMAC_Update(AES_GMAC_CTX *ctx, const uint8_t *data, uint16_t len)
+{
+	uint32_t	blk[4] = { 0, 0, 0, 0 };
+	int		plen;
+
+	if (len > 0) {
+		plen = len % GMAC_BLOCK_LEN;
+		if (len >= GMAC_BLOCK_LEN)
+			ghash_update(&ctx->ghash, (const uint8_t *)data,
+				     len - plen);
+		if (plen) {
+			memcpy(blk, data + (len - plen), plen);
+			ghash_update(&ctx->ghash, (uint8_t *)blk,
+			    GMAC_BLOCK_LEN);
+		}
+	}
+	return (0);
+}
+
+void
+AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], AES_GMAC_CTX *ctx)
+{
+	uint8_t		keystream[GMAC_BLOCK_LEN];
+	int		i;
+
+	/* do one round of GCTR */
+	ctx->J[GMAC_BLOCK_LEN - 1] = 1;
+	rijndaelEncrypt(ctx->K, ctx->rounds, ctx->J, keystream);
+	for (i = 0; i < GMAC_DIGEST_LEN; i++)
+		digest[i] = ((uint8_t *)ctx->ghash.S)[i] ^ keystream[i];
+	memset(keystream, 0, sizeof(keystream));
+}
Index: src/sys/opencrypto/gmac.h
diff -u /dev/null src/sys/opencrypto/gmac.h:1.1
--- /dev/null	Thu May 26 21:50:03 2011
+++ src/sys/opencrypto/gmac.h	Thu May 26 21:50:03 2011
@@ -0,0 +1,51 @@
+/* $NetBSD: gmac.h,v 1.1 2011/05/26 21:50:03 drochner Exp $ */
+/* OpenBSD: gmac.h,v 1.1 2010/09/22 11:54:23 mikeb Exp */
+
+/*
+ * Copyright (c) 2010 Mike Belopuhov <m...@vantronix.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GMAC_H_
+#define _GMAC_H_
+
+#include <crypto/rijndael/rijndael.h>
+
+#define GMAC_BLOCK_LEN		16
+#define GMAC_DIGEST_LEN		16
+
+typedef struct _GHASH_CTX {
+	uint32_t	H[GMAC_BLOCK_LEN/4];		/* hash subkey */
+	uint32_t	S[GMAC_BLOCK_LEN/4];		/* state */
+	uint32_t	Z[GMAC_BLOCK_LEN/4];		/* initial state */
+} GHASH_CTX;
+
+typedef struct _AES_GMAC_CTX {
+	GHASH_CTX	ghash;
+	uint32_t	K[4*(RIJNDAEL_MAXNR + 1)];
+	uint8_t		J[GMAC_BLOCK_LEN];		/* counter block */
+	int		rounds;
+} AES_GMAC_CTX;
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void	AES_GMAC_Init(AES_GMAC_CTX *);
+void	AES_GMAC_Setkey(AES_GMAC_CTX *, const uint8_t *, uint16_t);
+void	AES_GMAC_Reinit(AES_GMAC_CTX *, const uint8_t *, uint16_t);
+int	AES_GMAC_Update(AES_GMAC_CTX *, const uint8_t *, uint16_t);
+void	AES_GMAC_Final(uint8_t [GMAC_DIGEST_LEN], AES_GMAC_CTX *);
+__END_DECLS
+
+#endif /* _GMAC_H_ */

Reply via email to