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 #include <sys/endian.h> 28 29 #include <crypto/rijndael/rijndael.h> 30 #include <opencrypto/gmac.h> 31 32 void ghash_gfmul(uint32_t *, uint32_t *, uint32_t *); 33 void ghash_update(GHASH_CTX *, uint8_t *, size_t); 34 35 /* Computes a block multiplication in the GF(2^128) */ 36 void 37 ghash_gfmul(uint32_t *X, uint32_t *Y, uint32_t *product) 38 { 39 uint32_t v[4]; 40 uint32_t z[4] = { 0, 0, 0, 0}; 41 uint8_t *x = (uint8_t *)X; 42 uint32_t mul; 43 int i; 44 45 v[0] = be32toh(Y[0]); 46 v[1] = be32toh(Y[1]); 47 v[2] = be32toh(Y[2]); 48 v[3] = be32toh(Y[3]); 49 50 for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) { 51 /* update Z */ 52 if (x[i >> 3] & (1 << (~i & 7))) { 53 z[0] ^= v[0]; 54 z[1] ^= v[1]; 55 z[2] ^= v[2]; 56 z[3] ^= v[3]; 57 } /* else: we preserve old values */ 58 59 /* update V */ 60 mul = v[3] & 1; 61 v[3] = (v[2] << 31) | (v[3] >> 1); 62 v[2] = (v[1] << 31) | (v[2] >> 1); 63 v[1] = (v[0] << 31) | (v[1] >> 1); 64 v[0] = (v[0] >> 1) ^ (0xe1000000 * mul); 65 } 66 67 product[0] = htobe32(z[0]); 68 product[1] = htobe32(z[1]); 69 product[2] = htobe32(z[2]); 70 product[3] = htobe32(z[3]); 71 } 72 73 void 74 ghash_update(GHASH_CTX *ctx, uint8_t *X, size_t len) 75 { 76 uint32_t *x = (uint32_t *)X; 77 uint32_t *s = (uint32_t *)ctx->S; 78 uint32_t *y = (uint32_t *)ctx->Z; 79 int i; 80 81 for (i = 0; i < len / GMAC_BLOCK_LEN; i++) { 82 s[0] = y[0] ^ x[0]; 83 s[1] = y[1] ^ x[1]; 84 s[2] = y[2] ^ x[2]; 85 s[3] = y[3] ^ x[3]; 86 87 ghash_gfmul((uint32_t *)ctx->S, (uint32_t *)ctx->H, 88 (uint32_t *)ctx->S); 89 90 y = s; 91 x += 4; 92 } 93 94 bcopy(ctx->S, ctx->Z, GMAC_BLOCK_LEN); 95 } 96 97 #define AESCTR_NONCESIZE 4 98 99 void 100 AES_GMAC_Init(AES_GMAC_CTX *ctx) 101 { 102 bzero(ctx->ghash.H, GMAC_BLOCK_LEN); 103 bzero(ctx->ghash.S, GMAC_BLOCK_LEN); 104 bzero(ctx->ghash.Z, GMAC_BLOCK_LEN); 105 bzero(ctx->J, GMAC_BLOCK_LEN); 106 } 107 108 void 109 AES_GMAC_Setkey(AES_GMAC_CTX *ctx, const uint8_t *key, uint16_t klen) 110 { 111 ctx->rounds = rijndaelKeySetupEnc(ctx->K, __DECONST(u_char *, key), 112 (klen - AESCTR_NONCESIZE) * 8); 113 /* copy out salt to the counter block */ 114 bcopy(key + klen - AESCTR_NONCESIZE, ctx->J, AESCTR_NONCESIZE); 115 /* prepare a hash subkey */ 116 rijndaelEncrypt(ctx->K, ctx->rounds, ctx->ghash.H, ctx->ghash.H); 117 } 118 119 void 120 AES_GMAC_Reinit(AES_GMAC_CTX *ctx, const uint8_t *iv, uint16_t ivlen) 121 { 122 /* copy out IV to the counter block */ 123 bcopy(iv, ctx->J + AESCTR_NONCESIZE, ivlen); 124 } 125 126 int 127 AES_GMAC_Update(AES_GMAC_CTX *ctx, uint8_t *data, uint16_t len) 128 { 129 uint32_t blk[4] = { 0, 0, 0, 0 }; 130 int plen; 131 132 if (len > 0) { 133 plen = len % GMAC_BLOCK_LEN; 134 if (len >= GMAC_BLOCK_LEN) 135 ghash_update(&ctx->ghash, data, len - plen); 136 if (plen) { 137 bcopy(data + (len - plen), (uint8_t *)blk, 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 bzero(keystream, sizeof(keystream)); 157 } 158 159