1275732Sjmg/*-
2275732Sjmg * Copyright (c) 2014 The FreeBSD Foundation
3275732Sjmg * All rights reserved.
4275732Sjmg *
5275732Sjmg * This software was developed by John-Mark Gurney under
6275732Sjmg * the sponsorship of the FreeBSD Foundation and
7275732Sjmg * Rubicon Communications, LLC (Netgate).
8275732Sjmg * Redistribution and use in source and binary forms, with or without
9275732Sjmg * modification, are permitted provided that the following conditions
10275732Sjmg * are met:
11275732Sjmg * 1.  Redistributions of source code must retain the above copyright
12275732Sjmg *     notice, this list of conditions and the following disclaimer.
13275732Sjmg * 2.  Redistributions in binary form must reproduce the above copyright
14275732Sjmg *     notice, this list of conditions and the following disclaimer in the
15275732Sjmg *     documentation and/or other materials provided with the distribution.
16275732Sjmg *
17275732Sjmg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18275732Sjmg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19275732Sjmg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20275732Sjmg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21275732Sjmg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22275732Sjmg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23275732Sjmg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24275732Sjmg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25275732Sjmg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26275732Sjmg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27275732Sjmg * SUCH DAMAGE.
28275732Sjmg *
29275732Sjmg *	$FreeBSD$
30275732Sjmg *
31275732Sjmg */
32275732Sjmg
33275732Sjmg#include <sys/types.h>
34275732Sjmg#include <sys/systm.h>
35275732Sjmg#include <opencrypto/gfmult.h>
36275732Sjmg#include <opencrypto/gmac.h>
37275732Sjmg
38275732Sjmgvoid
39275732SjmgAES_GMAC_Init(struct aes_gmac_ctx *agc)
40275732Sjmg{
41275732Sjmg
42275732Sjmg	bzero(agc, sizeof *agc);
43275732Sjmg}
44275732Sjmg
45275732Sjmgvoid
46275732SjmgAES_GMAC_Setkey(struct aes_gmac_ctx *agc, const uint8_t *key, uint16_t klen)
47275732Sjmg{
48275732Sjmg	const uint8_t zeros[GMAC_BLOCK_LEN] = {};
49275732Sjmg	struct gf128 h;
50275732Sjmg	uint8_t hbuf[GMAC_BLOCK_LEN];
51275732Sjmg
52275732Sjmg	agc->rounds = rijndaelKeySetupEnc(agc->keysched, key, klen * 8);
53275732Sjmg
54275732Sjmg	rijndaelEncrypt(agc->keysched, agc->rounds, zeros, hbuf);
55275732Sjmg
56275732Sjmg	h = gf128_read(hbuf);
57275732Sjmg	gf128_genmultable4(h, &agc->ghashtbl);
58275732Sjmg
59275732Sjmg	explicit_bzero(&h, sizeof h);
60275732Sjmg	explicit_bzero(hbuf, sizeof hbuf);
61275732Sjmg}
62275732Sjmg
63275732Sjmgvoid
64275732SjmgAES_GMAC_Reinit(struct aes_gmac_ctx *agc, const uint8_t *iv, uint16_t ivlen)
65275732Sjmg{
66275732Sjmg
67275732Sjmg	KASSERT(ivlen <= sizeof agc->counter, ("passed ivlen too large!"));
68275732Sjmg	bcopy(iv, agc->counter, ivlen);
69275732Sjmg}
70275732Sjmg
71275732Sjmgint
72275732SjmgAES_GMAC_Update(struct aes_gmac_ctx *agc, const uint8_t *data, uint16_t len)
73275732Sjmg{
74275732Sjmg	struct gf128 v;
75275732Sjmg	uint8_t buf[GMAC_BLOCK_LEN] = {};
76275732Sjmg	int i;
77275732Sjmg
78275732Sjmg	v = agc->hash;
79275732Sjmg
80275732Sjmg	while (len > 0) {
81275732Sjmg		if (len >= 4*GMAC_BLOCK_LEN) {
82275732Sjmg			i = 4*GMAC_BLOCK_LEN;
83275732Sjmg			v = gf128_mul4b(v, data, &agc->ghashtbl);
84275732Sjmg		} else if (len >= GMAC_BLOCK_LEN) {
85275732Sjmg			i = GMAC_BLOCK_LEN;
86275732Sjmg			v = gf128_add(v, gf128_read(data));
87275732Sjmg			v = gf128_mul(v, &agc->ghashtbl.tbls[0]);
88275732Sjmg		} else {
89275732Sjmg			i = len;
90275732Sjmg			bcopy(data, buf, i);
91275732Sjmg			v = gf128_add(v, gf128_read(&buf[0]));
92275732Sjmg			v = gf128_mul(v, &agc->ghashtbl.tbls[0]);
93275732Sjmg			explicit_bzero(buf, sizeof buf);
94275732Sjmg		}
95275732Sjmg		len -= i;
96275732Sjmg		data += i;
97275732Sjmg	}
98275732Sjmg
99275732Sjmg	agc->hash = v;
100275732Sjmg	explicit_bzero(&v, sizeof v);
101275732Sjmg
102275732Sjmg	return (0);
103275732Sjmg}
104275732Sjmg
105275732Sjmgvoid
106275732SjmgAES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], struct aes_gmac_ctx *agc)
107275732Sjmg{
108275732Sjmg	uint8_t enccntr[GMAC_BLOCK_LEN];
109275732Sjmg	struct gf128 a;
110275732Sjmg
111275732Sjmg	/* XXX - zero additional bytes? */
112275732Sjmg	agc->counter[GMAC_BLOCK_LEN - 1] = 1;
113275732Sjmg
114275732Sjmg	rijndaelEncrypt(agc->keysched, agc->rounds, agc->counter, enccntr);
115275732Sjmg	a = gf128_add(agc->hash, gf128_read(enccntr));
116275732Sjmg	gf128_write(a, digest);
117275732Sjmg
118275732Sjmg	explicit_bzero(enccntr, sizeof enccntr);
119275732Sjmg}
120