1 1.4 riastrad /* $NetBSD: gmac.c,v 1.4 2020/06/29 23:34:48 riastradh Exp $ */ 2 1.1 drochner /* OpenBSD: gmac.c,v 1.3 2011/01/11 15:44:23 deraadt Exp */ 3 1.1 drochner 4 1.1 drochner /* 5 1.1 drochner * Copyright (c) 2010 Mike Belopuhov <mike (at) vantronix.net> 6 1.1 drochner * 7 1.1 drochner * Permission to use, copy, modify, and distribute this software for any 8 1.1 drochner * purpose with or without fee is hereby granted, provided that the above 9 1.1 drochner * copyright notice and this permission notice appear in all copies. 10 1.1 drochner * 11 1.1 drochner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 1.1 drochner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 drochner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 1.1 drochner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 drochner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 drochner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 1.1 drochner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 drochner */ 19 1.1 drochner 20 1.1 drochner /* 21 1.1 drochner * This code implements the Message Authentication part of the 22 1.1 drochner * Galois/Counter Mode (as being described in the RFC 4543) using 23 1.1 drochner * the AES cipher. FIPS SP 800-38D describes the algorithm details. 24 1.1 drochner */ 25 1.1 drochner 26 1.1 drochner #include <sys/param.h> 27 1.1 drochner #include <sys/systm.h> 28 1.1 drochner 29 1.4 riastrad #include <crypto/aes/aes.h> 30 1.4 riastrad 31 1.1 drochner #include <opencrypto/gmac.h> 32 1.1 drochner 33 1.3 drochner void ghash_gfmul(const GMAC_INT *, const GMAC_INT *, GMAC_INT *); 34 1.1 drochner void ghash_update(GHASH_CTX *, const uint8_t *, size_t); 35 1.1 drochner 36 1.1 drochner /* Computes a block multiplication in the GF(2^128) */ 37 1.1 drochner void 38 1.3 drochner ghash_gfmul(const GMAC_INT *X, const GMAC_INT *Y, GMAC_INT *product) 39 1.1 drochner { 40 1.3 drochner GMAC_INT v[GMAC_BLOCK_LEN/GMAC_INTLEN]; 41 1.1 drochner uint32_t mul; 42 1.1 drochner int i; 43 1.1 drochner 44 1.2 drochner memcpy(v, Y, GMAC_BLOCK_LEN); 45 1.2 drochner memset(product, 0, GMAC_BLOCK_LEN); 46 1.1 drochner 47 1.1 drochner for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) { 48 1.1 drochner /* update Z */ 49 1.3 drochner #if GMAC_INTLEN == 8 50 1.3 drochner if (X[i >> 6] & (1ULL << (~i & 63))) { 51 1.3 drochner product[0] ^= v[0]; 52 1.3 drochner product[1] ^= v[1]; 53 1.3 drochner } /* else: we preserve old values */ 54 1.3 drochner #else 55 1.2 drochner if (X[i >> 5] & (1 << (~i & 31))) { 56 1.2 drochner product[0] ^= v[0]; 57 1.2 drochner product[1] ^= v[1]; 58 1.2 drochner product[2] ^= v[2]; 59 1.2 drochner product[3] ^= v[3]; 60 1.1 drochner } /* else: we preserve old values */ 61 1.3 drochner #endif 62 1.1 drochner /* update V */ 63 1.3 drochner #if GMAC_INTLEN == 8 64 1.3 drochner mul = v[1] & 1; 65 1.3 drochner v[1] = (v[0] << 63) | (v[1] >> 1); 66 1.3 drochner v[0] = (v[0] >> 1) ^ (0xe100000000000000ULL * mul); 67 1.3 drochner #else 68 1.1 drochner mul = v[3] & 1; 69 1.1 drochner v[3] = (v[2] << 31) | (v[3] >> 1); 70 1.1 drochner v[2] = (v[1] << 31) | (v[2] >> 1); 71 1.1 drochner v[1] = (v[0] << 31) | (v[1] >> 1); 72 1.1 drochner v[0] = (v[0] >> 1) ^ (0xe1000000 * mul); 73 1.3 drochner #endif 74 1.1 drochner } 75 1.1 drochner } 76 1.1 drochner 77 1.1 drochner void 78 1.1 drochner ghash_update(GHASH_CTX *ctx, const uint8_t *X, size_t len) 79 1.1 drochner { 80 1.3 drochner GMAC_INT x; 81 1.3 drochner GMAC_INT *s = ctx->S; 82 1.3 drochner GMAC_INT *y = ctx->Z; 83 1.3 drochner int i, j, k; 84 1.1 drochner 85 1.1 drochner for (i = 0; i < len / GMAC_BLOCK_LEN; i++) { 86 1.3 drochner for (j = 0; j < GMAC_BLOCK_LEN/GMAC_INTLEN; j++) { 87 1.3 drochner x = 0; 88 1.3 drochner for (k = 0; k < GMAC_INTLEN; k++) { 89 1.3 drochner x <<= 8; 90 1.3 drochner x |= X[k]; 91 1.3 drochner } 92 1.2 drochner s[j] = y[j] ^ x; 93 1.3 drochner X += GMAC_INTLEN; 94 1.2 drochner } 95 1.1 drochner 96 1.2 drochner ghash_gfmul(ctx->H, ctx->S, ctx->S); 97 1.1 drochner 98 1.1 drochner y = s; 99 1.1 drochner } 100 1.1 drochner 101 1.1 drochner memcpy(ctx->Z, ctx->S, GMAC_BLOCK_LEN); 102 1.1 drochner } 103 1.1 drochner 104 1.1 drochner #define AESCTR_NONCESIZE 4 105 1.1 drochner 106 1.1 drochner void 107 1.1 drochner AES_GMAC_Init(AES_GMAC_CTX *ctx) 108 1.1 drochner { 109 1.1 drochner 110 1.1 drochner memset(ctx, 0, sizeof(AES_GMAC_CTX)); 111 1.1 drochner } 112 1.1 drochner 113 1.1 drochner void 114 1.1 drochner AES_GMAC_Setkey(AES_GMAC_CTX *ctx, const uint8_t *key, uint16_t klen) 115 1.1 drochner { 116 1.2 drochner int i; 117 1.2 drochner 118 1.4 riastrad switch (klen) { 119 1.4 riastrad case 16 + AESCTR_NONCESIZE: 120 1.4 riastrad ctx->rounds = aes_setenckey128(&ctx->K, key); 121 1.4 riastrad break; 122 1.4 riastrad case 24 + AESCTR_NONCESIZE: 123 1.4 riastrad ctx->rounds = aes_setenckey192(&ctx->K, key); 124 1.4 riastrad break; 125 1.4 riastrad case 32 + AESCTR_NONCESIZE: 126 1.4 riastrad ctx->rounds = aes_setenckey256(&ctx->K, key); 127 1.4 riastrad break; 128 1.4 riastrad default: 129 1.4 riastrad panic("invalid AES_GMAC_Setkey length in bytes: %u", 130 1.4 riastrad (unsigned)klen); 131 1.4 riastrad } 132 1.1 drochner /* copy out salt to the counter block */ 133 1.1 drochner memcpy(ctx->J, key + klen - AESCTR_NONCESIZE, AESCTR_NONCESIZE); 134 1.1 drochner /* prepare a hash subkey */ 135 1.4 riastrad aes_enc(&ctx->K, (const void *)ctx->ghash.H, (void *)ctx->ghash.H, 136 1.4 riastrad ctx->rounds); 137 1.3 drochner #if GMAC_INTLEN == 8 138 1.3 drochner for (i = 0; i < 2; i++) 139 1.3 drochner ctx->ghash.H[i] = be64toh(ctx->ghash.H[i]); 140 1.3 drochner #else 141 1.2 drochner for (i = 0; i < 4; i++) 142 1.2 drochner ctx->ghash.H[i] = be32toh(ctx->ghash.H[i]); 143 1.3 drochner #endif 144 1.1 drochner } 145 1.1 drochner 146 1.1 drochner void 147 1.1 drochner AES_GMAC_Reinit(AES_GMAC_CTX *ctx, const uint8_t *iv, uint16_t ivlen) 148 1.1 drochner { 149 1.1 drochner /* copy out IV to the counter block */ 150 1.1 drochner memcpy(ctx->J + AESCTR_NONCESIZE, iv, ivlen); 151 1.1 drochner } 152 1.1 drochner 153 1.1 drochner int 154 1.1 drochner AES_GMAC_Update(AES_GMAC_CTX *ctx, const uint8_t *data, uint16_t len) 155 1.1 drochner { 156 1.2 drochner uint8_t blk[16] = { 0 }; 157 1.1 drochner int plen; 158 1.1 drochner 159 1.1 drochner if (len > 0) { 160 1.1 drochner plen = len % GMAC_BLOCK_LEN; 161 1.1 drochner if (len >= GMAC_BLOCK_LEN) 162 1.2 drochner ghash_update(&ctx->ghash, data, len - plen); 163 1.1 drochner if (plen) { 164 1.1 drochner memcpy(blk, data + (len - plen), plen); 165 1.2 drochner ghash_update(&ctx->ghash, blk, GMAC_BLOCK_LEN); 166 1.1 drochner } 167 1.1 drochner } 168 1.1 drochner return (0); 169 1.1 drochner } 170 1.1 drochner 171 1.1 drochner void 172 1.1 drochner AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], AES_GMAC_CTX *ctx) 173 1.1 drochner { 174 1.2 drochner uint8_t keystream[GMAC_BLOCK_LEN], *k, *d; 175 1.1 drochner int i; 176 1.1 drochner 177 1.1 drochner /* do one round of GCTR */ 178 1.1 drochner ctx->J[GMAC_BLOCK_LEN - 1] = 1; 179 1.4 riastrad aes_enc(&ctx->K, ctx->J, keystream, ctx->rounds); 180 1.2 drochner k = keystream; 181 1.2 drochner d = digest; 182 1.3 drochner #if GMAC_INTLEN == 8 183 1.3 drochner for (i = 0; i < GMAC_DIGEST_LEN/8; i++) { 184 1.3 drochner d[0] = (uint8_t)(ctx->ghash.S[i] >> 56) ^ k[0]; 185 1.3 drochner d[1] = (uint8_t)(ctx->ghash.S[i] >> 48) ^ k[1]; 186 1.3 drochner d[2] = (uint8_t)(ctx->ghash.S[i] >> 40) ^ k[2]; 187 1.3 drochner d[3] = (uint8_t)(ctx->ghash.S[i] >> 32) ^ k[3]; 188 1.3 drochner d[4] = (uint8_t)(ctx->ghash.S[i] >> 24) ^ k[4]; 189 1.3 drochner d[5] = (uint8_t)(ctx->ghash.S[i] >> 16) ^ k[5]; 190 1.3 drochner d[6] = (uint8_t)(ctx->ghash.S[i] >> 8) ^ k[6]; 191 1.3 drochner d[7] = (uint8_t)ctx->ghash.S[i] ^ k[7]; 192 1.3 drochner d += 8; 193 1.3 drochner k += 8; 194 1.3 drochner } 195 1.3 drochner #else 196 1.2 drochner for (i = 0; i < GMAC_DIGEST_LEN/4; i++) { 197 1.2 drochner d[0] = (uint8_t)(ctx->ghash.S[i] >> 24) ^ k[0]; 198 1.2 drochner d[1] = (uint8_t)(ctx->ghash.S[i] >> 16) ^ k[1]; 199 1.2 drochner d[2] = (uint8_t)(ctx->ghash.S[i] >> 8) ^ k[2]; 200 1.2 drochner d[3] = (uint8_t)ctx->ghash.S[i] ^ k[3]; 201 1.2 drochner d += 4; 202 1.2 drochner k += 4; 203 1.2 drochner } 204 1.3 drochner #endif 205 1.1 drochner memset(keystream, 0, sizeof(keystream)); 206 1.1 drochner } 207