1 /* $OpenBSD: gmac.c,v 1.3 2011/01/11 15:44:23 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Mike Belopuhov <mike@vantronix.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * This code implements the Message Authentication part of the 21 * Galois/Counter Mode (as being described in the RFC 4543) using 22 * the AES cipher. FIPS SP 800-38D describes the algorithm details. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 28 #include <crypto/rijndael.h> 29 #include <crypto/gmac.h> 30 31 void ghash_gfmul(uint32_t *, uint32_t *, uint32_t *); 32 void ghash_update(GHASH_CTX *, uint8_t *, size_t); 33 34 /* Computes a block multiplication in the GF(2^128) */ 35 void 36 ghash_gfmul(uint32_t *X, uint32_t *Y, uint32_t *product) 37 { 38 uint32_t v[4]; 39 uint32_t z[4] = { 0, 0, 0, 0}; 40 uint8_t *x = (uint8_t *)X; 41 uint32_t mul; 42 int i; 43 44 v[0] = betoh32(Y[0]); 45 v[1] = betoh32(Y[1]); 46 v[2] = betoh32(Y[2]); 47 v[3] = betoh32(Y[3]); 48 49 for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) { 50 /* update Z */ 51 if (x[i >> 3] & (1 << (~i & 7))) { 52 z[0] ^= v[0]; 53 z[1] ^= v[1]; 54 z[2] ^= v[2]; 55 z[3] ^= v[3]; 56 } /* else: we preserve old values */ 57 58 /* update V */ 59 mul = v[3] & 1; 60 v[3] = (v[2] << 31) | (v[3] >> 1); 61 v[2] = (v[1] << 31) | (v[2] >> 1); 62 v[1] = (v[0] << 31) | (v[1] >> 1); 63 v[0] = (v[0] >> 1) ^ (0xe1000000 * mul); 64 } 65 66 product[0] = htobe32(z[0]); 67 product[1] = htobe32(z[1]); 68 product[2] = htobe32(z[2]); 69 product[3] = htobe32(z[3]); 70 } 71 72 void 73 ghash_update(GHASH_CTX *ctx, uint8_t *X, size_t len) 74 { 75 uint32_t *x = (uint32_t *)X; 76 uint32_t *s = (uint32_t *)ctx->S; 77 uint32_t *y = (uint32_t *)ctx->Z; 78 int i; 79 80 for (i = 0; i < len / GMAC_BLOCK_LEN; i++) { 81 s[0] = y[0] ^ x[0]; 82 s[1] = y[1] ^ x[1]; 83 s[2] = y[2] ^ x[2]; 84 s[3] = y[3] ^ x[3]; 85 86 ghash_gfmul((uint32_t *)ctx->S, (uint32_t *)ctx->H, 87 (uint32_t *)ctx->S); 88 89 y = s; 90 x += 4; 91 } 92 93 bcopy(ctx->S, ctx->Z, GMAC_BLOCK_LEN); 94 } 95 96 #define AESCTR_NONCESIZE 4 97 98 void 99 AES_GMAC_Init(AES_GMAC_CTX *ctx) 100 { 101 bzero(ctx->ghash.H, GMAC_BLOCK_LEN); 102 bzero(ctx->ghash.S, GMAC_BLOCK_LEN); 103 bzero(ctx->ghash.Z, GMAC_BLOCK_LEN); 104 bzero(ctx->J, GMAC_BLOCK_LEN); 105 } 106 107 void 108 AES_GMAC_Setkey(AES_GMAC_CTX *ctx, const uint8_t *key, uint16_t klen) 109 { 110 ctx->rounds = rijndaelKeySetupEnc(ctx->K, (u_char *)key, 111 (klen - AESCTR_NONCESIZE) * 8); 112 /* copy out salt to the counter block */ 113 bcopy(key + klen - AESCTR_NONCESIZE, ctx->J, AESCTR_NONCESIZE); 114 /* prepare a hash subkey */ 115 rijndaelEncrypt(ctx->K, ctx->rounds, ctx->ghash.H, ctx->ghash.H); 116 } 117 118 void 119 AES_GMAC_Reinit(AES_GMAC_CTX *ctx, const uint8_t *iv, uint16_t ivlen) 120 { 121 /* copy out IV to the counter block */ 122 bcopy(iv, ctx->J + AESCTR_NONCESIZE, ivlen); 123 } 124 125 int 126 AES_GMAC_Update(AES_GMAC_CTX *ctx, const uint8_t *data, uint16_t len) 127 { 128 uint32_t blk[4] = { 0, 0, 0, 0 }; 129 int plen; 130 131 if (len > 0) { 132 plen = len % GMAC_BLOCK_LEN; 133 if (len >= GMAC_BLOCK_LEN) 134 ghash_update(&ctx->ghash, (uint8_t *)data, len - plen); 135 if (plen) { 136 bcopy((uint8_t *)data + (len - plen), (uint8_t *)blk, 137 plen); 138 ghash_update(&ctx->ghash, (uint8_t *)blk, 139 GMAC_BLOCK_LEN); 140 } 141 } 142 return (0); 143 } 144 145 void 146 AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], AES_GMAC_CTX *ctx) 147 { 148 uint8_t keystream[GMAC_BLOCK_LEN]; 149 int i; 150 151 /* do one round of GCTR */ 152 ctx->J[GMAC_BLOCK_LEN - 1] = 1; 153 rijndaelEncrypt(ctx->K, ctx->rounds, ctx->J, keystream); 154 for (i = 0; i < GMAC_DIGEST_LEN; i++) 155 digest[i] = ctx->ghash.S[i] ^ keystream[i]; 156 explicit_bzero(keystream, sizeof(keystream)); 157 } 158