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