xref: /netbsd-src/sys/opencrypto/gmac.c (revision 8835ffd08237019b1c2cfd70d4eab20f517cd01d)
1*8835ffd0Sriastradh /* $NetBSD: gmac.c,v 1.4 2020/06/29 23:34:48 riastradh Exp $ */
20a8dabdaSdrochner /* OpenBSD: gmac.c,v 1.3 2011/01/11 15:44:23 deraadt Exp */
30a8dabdaSdrochner 
40a8dabdaSdrochner /*
50a8dabdaSdrochner  * Copyright (c) 2010 Mike Belopuhov <mike@vantronix.net>
60a8dabdaSdrochner  *
70a8dabdaSdrochner  * Permission to use, copy, modify, and distribute this software for any
80a8dabdaSdrochner  * purpose with or without fee is hereby granted, provided that the above
90a8dabdaSdrochner  * copyright notice and this permission notice appear in all copies.
100a8dabdaSdrochner  *
110a8dabdaSdrochner  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
120a8dabdaSdrochner  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
130a8dabdaSdrochner  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
140a8dabdaSdrochner  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
150a8dabdaSdrochner  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
160a8dabdaSdrochner  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
170a8dabdaSdrochner  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
180a8dabdaSdrochner  */
190a8dabdaSdrochner 
200a8dabdaSdrochner /*
210a8dabdaSdrochner  * This code implements the Message Authentication part of the
220a8dabdaSdrochner  * Galois/Counter Mode (as being described in the RFC 4543) using
230a8dabdaSdrochner  * the AES cipher.  FIPS SP 800-38D describes the algorithm details.
240a8dabdaSdrochner  */
250a8dabdaSdrochner 
260a8dabdaSdrochner #include <sys/param.h>
270a8dabdaSdrochner #include <sys/systm.h>
280a8dabdaSdrochner 
29*8835ffd0Sriastradh #include <crypto/aes/aes.h>
30*8835ffd0Sriastradh 
310a8dabdaSdrochner #include <opencrypto/gmac.h>
320a8dabdaSdrochner 
33b8b7a5e3Sdrochner void	ghash_gfmul(const GMAC_INT *, const GMAC_INT *, GMAC_INT *);
340a8dabdaSdrochner void	ghash_update(GHASH_CTX *, const uint8_t *, size_t);
350a8dabdaSdrochner 
360a8dabdaSdrochner /* Computes a block multiplication in the GF(2^128) */
370a8dabdaSdrochner void
ghash_gfmul(const GMAC_INT * X,const GMAC_INT * Y,GMAC_INT * product)38b8b7a5e3Sdrochner ghash_gfmul(const GMAC_INT *X, const GMAC_INT *Y, GMAC_INT *product)
390a8dabdaSdrochner {
40b8b7a5e3Sdrochner 	GMAC_INT	v[GMAC_BLOCK_LEN/GMAC_INTLEN];
410a8dabdaSdrochner 	uint32_t	mul;
420a8dabdaSdrochner 	int		i;
430a8dabdaSdrochner 
442706a22aSdrochner 	memcpy(v, Y, GMAC_BLOCK_LEN);
452706a22aSdrochner 	memset(product, 0, GMAC_BLOCK_LEN);
460a8dabdaSdrochner 
470a8dabdaSdrochner 	for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) {
480a8dabdaSdrochner 		/* update Z */
49b8b7a5e3Sdrochner #if GMAC_INTLEN == 8
50b8b7a5e3Sdrochner 		if (X[i >> 6] & (1ULL << (~i & 63))) {
51b8b7a5e3Sdrochner 			product[0] ^= v[0];
52b8b7a5e3Sdrochner 			product[1] ^= v[1];
53b8b7a5e3Sdrochner 		} /* else: we preserve old values */
54b8b7a5e3Sdrochner #else
552706a22aSdrochner 		if (X[i >> 5] & (1 << (~i & 31))) {
562706a22aSdrochner 			product[0] ^= v[0];
572706a22aSdrochner 			product[1] ^= v[1];
582706a22aSdrochner 			product[2] ^= v[2];
592706a22aSdrochner 			product[3] ^= v[3];
600a8dabdaSdrochner 		} /* else: we preserve old values */
61b8b7a5e3Sdrochner #endif
620a8dabdaSdrochner 		/* update V */
63b8b7a5e3Sdrochner #if GMAC_INTLEN == 8
64b8b7a5e3Sdrochner 		mul = v[1] & 1;
65b8b7a5e3Sdrochner 		v[1] = (v[0] << 63) | (v[1] >> 1);
66b8b7a5e3Sdrochner 		v[0] = (v[0] >> 1) ^ (0xe100000000000000ULL * mul);
67b8b7a5e3Sdrochner #else
680a8dabdaSdrochner 		mul = v[3] & 1;
690a8dabdaSdrochner 		v[3] = (v[2] << 31) | (v[3] >> 1);
700a8dabdaSdrochner 		v[2] = (v[1] << 31) | (v[2] >> 1);
710a8dabdaSdrochner 		v[1] = (v[0] << 31) | (v[1] >> 1);
720a8dabdaSdrochner 		v[0] = (v[0] >> 1) ^ (0xe1000000 * mul);
73b8b7a5e3Sdrochner #endif
740a8dabdaSdrochner 	}
750a8dabdaSdrochner }
760a8dabdaSdrochner 
770a8dabdaSdrochner void
ghash_update(GHASH_CTX * ctx,const uint8_t * X,size_t len)780a8dabdaSdrochner ghash_update(GHASH_CTX *ctx, const uint8_t *X, size_t len)
790a8dabdaSdrochner {
80b8b7a5e3Sdrochner 	GMAC_INT x;
81b8b7a5e3Sdrochner 	GMAC_INT *s = ctx->S;
82b8b7a5e3Sdrochner 	GMAC_INT *y = ctx->Z;
83b8b7a5e3Sdrochner 	int i, j, k;
840a8dabdaSdrochner 
850a8dabdaSdrochner 	for (i = 0; i < len / GMAC_BLOCK_LEN; i++) {
86b8b7a5e3Sdrochner 		for (j = 0; j < GMAC_BLOCK_LEN/GMAC_INTLEN; j++) {
87b8b7a5e3Sdrochner 			x = 0;
88b8b7a5e3Sdrochner 			for (k = 0; k < GMAC_INTLEN; k++) {
89b8b7a5e3Sdrochner 				x <<= 8;
90b8b7a5e3Sdrochner 				x |= X[k];
91b8b7a5e3Sdrochner 			}
922706a22aSdrochner 			s[j] = y[j] ^ x;
93b8b7a5e3Sdrochner 			X += GMAC_INTLEN;
942706a22aSdrochner 		}
950a8dabdaSdrochner 
962706a22aSdrochner 		ghash_gfmul(ctx->H, ctx->S, ctx->S);
970a8dabdaSdrochner 
980a8dabdaSdrochner 		y = s;
990a8dabdaSdrochner 	}
1000a8dabdaSdrochner 
1010a8dabdaSdrochner 	memcpy(ctx->Z, ctx->S, GMAC_BLOCK_LEN);
1020a8dabdaSdrochner }
1030a8dabdaSdrochner 
1040a8dabdaSdrochner #define AESCTR_NONCESIZE	4
1050a8dabdaSdrochner 
1060a8dabdaSdrochner void
AES_GMAC_Init(AES_GMAC_CTX * ctx)1070a8dabdaSdrochner AES_GMAC_Init(AES_GMAC_CTX *ctx)
1080a8dabdaSdrochner {
1090a8dabdaSdrochner 
1100a8dabdaSdrochner 	memset(ctx, 0, sizeof(AES_GMAC_CTX));
1110a8dabdaSdrochner }
1120a8dabdaSdrochner 
1130a8dabdaSdrochner void
AES_GMAC_Setkey(AES_GMAC_CTX * ctx,const uint8_t * key,uint16_t klen)1140a8dabdaSdrochner AES_GMAC_Setkey(AES_GMAC_CTX *ctx, const uint8_t *key, uint16_t klen)
1150a8dabdaSdrochner {
1162706a22aSdrochner 	int i;
1172706a22aSdrochner 
118*8835ffd0Sriastradh 	switch (klen) {
119*8835ffd0Sriastradh 	case 16 + AESCTR_NONCESIZE:
120*8835ffd0Sriastradh 		ctx->rounds = aes_setenckey128(&ctx->K, key);
121*8835ffd0Sriastradh 		break;
122*8835ffd0Sriastradh 	case 24 + AESCTR_NONCESIZE:
123*8835ffd0Sriastradh 		ctx->rounds = aes_setenckey192(&ctx->K, key);
124*8835ffd0Sriastradh 		break;
125*8835ffd0Sriastradh 	case 32 + AESCTR_NONCESIZE:
126*8835ffd0Sriastradh 		ctx->rounds = aes_setenckey256(&ctx->K, key);
127*8835ffd0Sriastradh 		break;
128*8835ffd0Sriastradh 	default:
129*8835ffd0Sriastradh 		panic("invalid AES_GMAC_Setkey length in bytes: %u",
130*8835ffd0Sriastradh 		    (unsigned)klen);
131*8835ffd0Sriastradh 	}
1320a8dabdaSdrochner 	/* copy out salt to the counter block */
1330a8dabdaSdrochner 	memcpy(ctx->J, key + klen - AESCTR_NONCESIZE, AESCTR_NONCESIZE);
1340a8dabdaSdrochner 	/* prepare a hash subkey */
135*8835ffd0Sriastradh 	aes_enc(&ctx->K, (const void *)ctx->ghash.H, (void *)ctx->ghash.H,
136*8835ffd0Sriastradh 	    ctx->rounds);
137b8b7a5e3Sdrochner #if GMAC_INTLEN == 8
138b8b7a5e3Sdrochner 	for (i = 0; i < 2; i++)
139b8b7a5e3Sdrochner 		ctx->ghash.H[i] = be64toh(ctx->ghash.H[i]);
140b8b7a5e3Sdrochner #else
1412706a22aSdrochner 	for (i = 0; i < 4; i++)
1422706a22aSdrochner 		ctx->ghash.H[i] = be32toh(ctx->ghash.H[i]);
143b8b7a5e3Sdrochner #endif
1440a8dabdaSdrochner }
1450a8dabdaSdrochner 
1460a8dabdaSdrochner void
AES_GMAC_Reinit(AES_GMAC_CTX * ctx,const uint8_t * iv,uint16_t ivlen)1470a8dabdaSdrochner AES_GMAC_Reinit(AES_GMAC_CTX *ctx, const uint8_t *iv, uint16_t ivlen)
1480a8dabdaSdrochner {
1490a8dabdaSdrochner 	/* copy out IV to the counter block */
1500a8dabdaSdrochner 	memcpy(ctx->J + AESCTR_NONCESIZE, iv, ivlen);
1510a8dabdaSdrochner }
1520a8dabdaSdrochner 
1530a8dabdaSdrochner int
AES_GMAC_Update(AES_GMAC_CTX * ctx,const uint8_t * data,uint16_t len)1540a8dabdaSdrochner AES_GMAC_Update(AES_GMAC_CTX *ctx, const uint8_t *data, uint16_t len)
1550a8dabdaSdrochner {
1562706a22aSdrochner 	uint8_t		blk[16] = { 0 };
1570a8dabdaSdrochner 	int		plen;
1580a8dabdaSdrochner 
1590a8dabdaSdrochner 	if (len > 0) {
1600a8dabdaSdrochner 		plen = len % GMAC_BLOCK_LEN;
1610a8dabdaSdrochner 		if (len >= GMAC_BLOCK_LEN)
1622706a22aSdrochner 			ghash_update(&ctx->ghash, data, len - plen);
1630a8dabdaSdrochner 		if (plen) {
1640a8dabdaSdrochner 			memcpy(blk, data + (len - plen), plen);
1652706a22aSdrochner 			ghash_update(&ctx->ghash, blk, GMAC_BLOCK_LEN);
1660a8dabdaSdrochner 		}
1670a8dabdaSdrochner 	}
1680a8dabdaSdrochner 	return (0);
1690a8dabdaSdrochner }
1700a8dabdaSdrochner 
1710a8dabdaSdrochner void
AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN],AES_GMAC_CTX * ctx)1720a8dabdaSdrochner AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], AES_GMAC_CTX *ctx)
1730a8dabdaSdrochner {
1742706a22aSdrochner 	uint8_t		keystream[GMAC_BLOCK_LEN], *k, *d;
1750a8dabdaSdrochner 	int		i;
1760a8dabdaSdrochner 
1770a8dabdaSdrochner 	/* do one round of GCTR */
1780a8dabdaSdrochner 	ctx->J[GMAC_BLOCK_LEN - 1] = 1;
179*8835ffd0Sriastradh 	aes_enc(&ctx->K, ctx->J, keystream, ctx->rounds);
1802706a22aSdrochner 	k = keystream;
1812706a22aSdrochner 	d = digest;
182b8b7a5e3Sdrochner #if GMAC_INTLEN == 8
183b8b7a5e3Sdrochner 	for (i = 0; i < GMAC_DIGEST_LEN/8; i++) {
184b8b7a5e3Sdrochner 		d[0] = (uint8_t)(ctx->ghash.S[i] >> 56) ^ k[0];
185b8b7a5e3Sdrochner 		d[1] = (uint8_t)(ctx->ghash.S[i] >> 48) ^ k[1];
186b8b7a5e3Sdrochner 		d[2] = (uint8_t)(ctx->ghash.S[i] >> 40) ^ k[2];
187b8b7a5e3Sdrochner 		d[3] = (uint8_t)(ctx->ghash.S[i] >> 32) ^ k[3];
188b8b7a5e3Sdrochner 		d[4] = (uint8_t)(ctx->ghash.S[i] >> 24) ^ k[4];
189b8b7a5e3Sdrochner 		d[5] = (uint8_t)(ctx->ghash.S[i] >> 16) ^ k[5];
190b8b7a5e3Sdrochner 		d[6] = (uint8_t)(ctx->ghash.S[i] >> 8) ^ k[6];
191b8b7a5e3Sdrochner 		d[7] = (uint8_t)ctx->ghash.S[i] ^ k[7];
192b8b7a5e3Sdrochner 		d += 8;
193b8b7a5e3Sdrochner 		k += 8;
194b8b7a5e3Sdrochner 	}
195b8b7a5e3Sdrochner #else
1962706a22aSdrochner 	for (i = 0; i < GMAC_DIGEST_LEN/4; i++) {
1972706a22aSdrochner 		d[0] = (uint8_t)(ctx->ghash.S[i] >> 24) ^ k[0];
1982706a22aSdrochner 		d[1] = (uint8_t)(ctx->ghash.S[i] >> 16) ^ k[1];
1992706a22aSdrochner 		d[2] = (uint8_t)(ctx->ghash.S[i] >> 8) ^ k[2];
2002706a22aSdrochner 		d[3] = (uint8_t)ctx->ghash.S[i] ^ k[3];
2012706a22aSdrochner 		d += 4;
2022706a22aSdrochner 		k += 4;
2032706a22aSdrochner 	}
204b8b7a5e3Sdrochner #endif
2050a8dabdaSdrochner 	memset(keystream, 0, sizeof(keystream));
2060a8dabdaSdrochner }
207