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