1 /* $OpenBSD: gmac.c,v 1.3 2011/01/11 15:44:23 deraadt Exp $ */
4 * Copyright (c) 2010 Mike Belopuhov <mike@vantronix.net>
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.
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.
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.
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/endian.h>
29 #include <crypto/rijndael/rijndael.h>
30 #include <opencrypto/gmac.h>
32 void ghash_gfmul(uint32_t *, uint32_t *, uint32_t *);
33 void ghash_update(GHASH_CTX
*, uint8_t *, size_t);
35 /* Computes a block multiplication in the GF(2^128) */
37 ghash_gfmul(uint32_t *X
, uint32_t *Y
, uint32_t *product
)
40 uint32_t z
[4] = { 0, 0, 0, 0};
41 uint8_t *x
= (uint8_t *)X
;
50 for (i
= 0; i
< GMAC_BLOCK_LEN
* 8; i
++) {
52 if (x
[i
>> 3] & (1 << (~i
& 7))) {
57 } /* else: we preserve old values */
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
);
67 product
[0] = htobe32(z
[0]);
68 product
[1] = htobe32(z
[1]);
69 product
[2] = htobe32(z
[2]);
70 product
[3] = htobe32(z
[3]);
74 ghash_update(GHASH_CTX
*ctx
, uint8_t *X
, size_t len
)
76 uint32_t *x
= (uint32_t *)X
;
77 uint32_t *s
= (uint32_t *)ctx
->S
;
78 uint32_t *y
= (uint32_t *)ctx
->Z
;
81 for (i
= 0; i
< len
/ GMAC_BLOCK_LEN
; i
++) {
87 ghash_gfmul((uint32_t *)ctx
->S
, (uint32_t *)ctx
->H
,
94 bcopy(ctx
->S
, ctx
->Z
, GMAC_BLOCK_LEN
);
97 #define AESCTR_NONCESIZE 4
100 AES_GMAC_Init(AES_GMAC_CTX
*ctx
)
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
);
109 AES_GMAC_Setkey(AES_GMAC_CTX
*ctx
, const uint8_t *key
, uint16_t klen
)
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
);
120 AES_GMAC_Reinit(AES_GMAC_CTX
*ctx
, const uint8_t *iv
, uint16_t ivlen
)
122 /* copy out IV to the counter block */
123 bcopy(iv
, ctx
->J
+ AESCTR_NONCESIZE
, ivlen
);
127 AES_GMAC_Update(AES_GMAC_CTX
*ctx
, uint8_t *data
, uint16_t len
)
129 uint32_t blk
[4] = { 0, 0, 0, 0 };
133 plen
= len
% GMAC_BLOCK_LEN
;
134 if (len
>= GMAC_BLOCK_LEN
)
135 ghash_update(&ctx
->ghash
, data
, len
- plen
);
137 bcopy(data
+ (len
- plen
), (uint8_t *)blk
, plen
);
138 ghash_update(&ctx
->ghash
, (uint8_t *)blk
,
146 AES_GMAC_Final(uint8_t digest
[GMAC_DIGEST_LEN
], AES_GMAC_CTX
*ctx
)
148 uint8_t keystream
[GMAC_BLOCK_LEN
];
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
));