xref: /freebsd/sys/crypto/openssl/amd64/ossl_aes_gcm.c (revision 9a3444d91c706dda65040138acbdb8c932213960)
1*9a3444d9SMark Johnston /*
2*9a3444d9SMark Johnston  * Copyright 2010-2022 The OpenSSL Project Authors. All Rights Reserved.
3*9a3444d9SMark Johnston  * Copyright (c) 2021, Intel Corporation. All Rights Reserved.
4*9a3444d9SMark Johnston  *
5*9a3444d9SMark Johnston  * Licensed under the Apache License 2.0 (the "License").  You may not use
6*9a3444d9SMark Johnston  * this file except in compliance with the License.  You can obtain a copy
7*9a3444d9SMark Johnston  * in the file LICENSE in the source distribution or at
8*9a3444d9SMark Johnston  * https://www.openssl.org/source/license.html
9*9a3444d9SMark Johnston  */
10*9a3444d9SMark Johnston 
11*9a3444d9SMark Johnston /*
12*9a3444d9SMark Johnston  * This file contains a AES-GCM wrapper implementation from OpenSSL 3.1,
13*9a3444d9SMark Johnston  * targeting amd64 VAES extensions.  This was ported from
14*9a3444d9SMark Johnston  * cipher_aes_gcm_hw_vaes_avx512.inc.
15*9a3444d9SMark Johnston  */
16*9a3444d9SMark Johnston 
17*9a3444d9SMark Johnston #include <sys/endian.h>
18*9a3444d9SMark Johnston #include <sys/systm.h>
19*9a3444d9SMark Johnston 
20*9a3444d9SMark Johnston #include <crypto/openssl/ossl.h>
21*9a3444d9SMark Johnston #include <crypto/openssl/ossl_aes_gcm.h>
22*9a3444d9SMark Johnston #include <crypto/openssl/ossl_cipher.h>
23*9a3444d9SMark Johnston 
24*9a3444d9SMark Johnston #include <opencrypto/cryptodev.h>
25*9a3444d9SMark Johnston 
26*9a3444d9SMark Johnston _Static_assert(
27*9a3444d9SMark Johnston     sizeof(struct ossl_gcm_context) <= sizeof(struct ossl_cipher_context),
28*9a3444d9SMark Johnston     "ossl_gcm_context too large");
29*9a3444d9SMark Johnston 
30*9a3444d9SMark Johnston void aesni_set_encrypt_key(const void *key, int bits, void *ctx);
31*9a3444d9SMark Johnston 
32*9a3444d9SMark Johnston static void
33*9a3444d9SMark Johnston gcm_init(struct ossl_gcm_context *ctx, const void *key, size_t keylen)
34*9a3444d9SMark Johnston {
35*9a3444d9SMark Johnston 	KASSERT(keylen == 128 || keylen == 192 || keylen == 256,
36*9a3444d9SMark Johnston 	    ("%s: invalid key length %zu", __func__, keylen));
37*9a3444d9SMark Johnston 
38*9a3444d9SMark Johnston 	memset(&ctx->gcm, 0, sizeof(ctx->gcm));
39*9a3444d9SMark Johnston 	memset(&ctx->aes_ks, 0, sizeof(ctx->aes_ks));
40*9a3444d9SMark Johnston 	aesni_set_encrypt_key(key, keylen, &ctx->aes_ks);
41*9a3444d9SMark Johnston 	ctx->ops->init(ctx, key, keylen);
42*9a3444d9SMark Johnston }
43*9a3444d9SMark Johnston 
44*9a3444d9SMark Johnston static void
45*9a3444d9SMark Johnston gcm_tag(struct ossl_gcm_context *ctx, unsigned char *tag, size_t len)
46*9a3444d9SMark Johnston {
47*9a3444d9SMark Johnston 	(void)ctx->ops->finish(ctx, NULL, 0);
48*9a3444d9SMark Johnston 	memcpy(tag, ctx->gcm.Xi.c, len);
49*9a3444d9SMark Johnston }
50*9a3444d9SMark Johnston 
51*9a3444d9SMark Johnston void ossl_gcm_gmult_avx512(uint64_t Xi[2], void *gcm128ctx);
52*9a3444d9SMark Johnston void ossl_aes_gcm_init_avx512(const void *ks, void *gcm128ctx);
53*9a3444d9SMark Johnston void ossl_aes_gcm_setiv_avx512(const void *ks, void *gcm128ctx,
54*9a3444d9SMark Johnston     const unsigned char *iv, size_t ivlen);
55*9a3444d9SMark Johnston void ossl_aes_gcm_update_aad_avx512(void *gcm128ctx, const unsigned char *aad,
56*9a3444d9SMark Johnston     size_t len);
57*9a3444d9SMark Johnston void ossl_aes_gcm_encrypt_avx512(const void *ks, void *gcm128ctx,
58*9a3444d9SMark Johnston     unsigned int *pblocklen, const unsigned char *in, size_t len,
59*9a3444d9SMark Johnston     unsigned char *out);
60*9a3444d9SMark Johnston void ossl_aes_gcm_decrypt_avx512(const void *ks, void *gcm128ctx,
61*9a3444d9SMark Johnston     unsigned int *pblocklen, const unsigned char *in, size_t len,
62*9a3444d9SMark Johnston     unsigned char *out);
63*9a3444d9SMark Johnston void ossl_aes_gcm_finalize_avx512(void *gcm128ctx, unsigned int pblocklen);
64*9a3444d9SMark Johnston 
65*9a3444d9SMark Johnston static void
66*9a3444d9SMark Johnston gcm_init_avx512(struct ossl_gcm_context *ctx, const void *key, size_t keylen)
67*9a3444d9SMark Johnston {
68*9a3444d9SMark Johnston 	ossl_aes_gcm_init_avx512(&ctx->aes_ks, &ctx->gcm);
69*9a3444d9SMark Johnston }
70*9a3444d9SMark Johnston 
71*9a3444d9SMark Johnston static void
72*9a3444d9SMark Johnston gcm_setiv_avx512(struct ossl_gcm_context *ctx, const unsigned char *iv,
73*9a3444d9SMark Johnston     size_t len)
74*9a3444d9SMark Johnston {
75*9a3444d9SMark Johnston 	KASSERT(len == AES_GCM_IV_LEN,
76*9a3444d9SMark Johnston 	    ("%s: invalid IV length %zu", __func__, len));
77*9a3444d9SMark Johnston 
78*9a3444d9SMark Johnston 	ctx->gcm.Yi.u[0] = 0;		/* Current counter */
79*9a3444d9SMark Johnston 	ctx->gcm.Yi.u[1] = 0;
80*9a3444d9SMark Johnston 	ctx->gcm.Xi.u[0] = 0;		/* AAD hash */
81*9a3444d9SMark Johnston 	ctx->gcm.Xi.u[1] = 0;
82*9a3444d9SMark Johnston 	ctx->gcm.len.u[0] = 0;		/* AAD length */
83*9a3444d9SMark Johnston 	ctx->gcm.len.u[1] = 0;		/* Message length */
84*9a3444d9SMark Johnston 	ctx->gcm.ares = 0;
85*9a3444d9SMark Johnston 	ctx->gcm.mres = 0;
86*9a3444d9SMark Johnston 
87*9a3444d9SMark Johnston 	ossl_aes_gcm_setiv_avx512(&ctx->aes_ks, ctx, iv, len);
88*9a3444d9SMark Johnston }
89*9a3444d9SMark Johnston 
90*9a3444d9SMark Johnston static int
91*9a3444d9SMark Johnston gcm_aad_avx512(struct ossl_gcm_context *ctx, const unsigned char *aad,
92*9a3444d9SMark Johnston     size_t len)
93*9a3444d9SMark Johnston {
94*9a3444d9SMark Johnston 	uint64_t alen = ctx->gcm.len.u[0];
95*9a3444d9SMark Johnston 	size_t lenblks;
96*9a3444d9SMark Johnston 	unsigned int ares;
97*9a3444d9SMark Johnston 
98*9a3444d9SMark Johnston 	/* Bad sequence: call of AAD update after message processing */
99*9a3444d9SMark Johnston 	if (ctx->gcm.len.u[1])
100*9a3444d9SMark Johnston 		return -2;
101*9a3444d9SMark Johnston 
102*9a3444d9SMark Johnston 	alen += len;
103*9a3444d9SMark Johnston 	/* AAD is limited by 2^64 bits, thus 2^61 bytes */
104*9a3444d9SMark Johnston 	if (alen > (1ull << 61) || (sizeof(len) == 8 && alen < len))
105*9a3444d9SMark Johnston 		return -1;
106*9a3444d9SMark Johnston 	ctx->gcm.len.u[0] = alen;
107*9a3444d9SMark Johnston 
108*9a3444d9SMark Johnston 	ares = ctx->gcm.ares;
109*9a3444d9SMark Johnston 	/* Partial AAD block left from previous AAD update calls */
110*9a3444d9SMark Johnston 	if (ares > 0) {
111*9a3444d9SMark Johnston 		/*
112*9a3444d9SMark Johnston 		 * Fill partial block buffer till full block
113*9a3444d9SMark Johnston 		 * (note, the hash is stored reflected)
114*9a3444d9SMark Johnston 		 */
115*9a3444d9SMark Johnston 		while (ares > 0 && len > 0) {
116*9a3444d9SMark Johnston 			ctx->gcm.Xi.c[15 - ares] ^= *(aad++);
117*9a3444d9SMark Johnston 			--len;
118*9a3444d9SMark Johnston 			ares = (ares + 1) % AES_BLOCK_LEN;
119*9a3444d9SMark Johnston 		}
120*9a3444d9SMark Johnston 		/* Full block gathered */
121*9a3444d9SMark Johnston 		if (ares == 0) {
122*9a3444d9SMark Johnston 			ossl_gcm_gmult_avx512(ctx->gcm.Xi.u, ctx);
123*9a3444d9SMark Johnston 		} else { /* no more AAD */
124*9a3444d9SMark Johnston 			ctx->gcm.ares = ares;
125*9a3444d9SMark Johnston 			return 0;
126*9a3444d9SMark Johnston 		}
127*9a3444d9SMark Johnston 	}
128*9a3444d9SMark Johnston 
129*9a3444d9SMark Johnston 	/* Bulk AAD processing */
130*9a3444d9SMark Johnston 	lenblks = len & ((size_t)(-AES_BLOCK_LEN));
131*9a3444d9SMark Johnston 	if (lenblks > 0) {
132*9a3444d9SMark Johnston 		ossl_aes_gcm_update_aad_avx512(ctx, aad, lenblks);
133*9a3444d9SMark Johnston 		aad += lenblks;
134*9a3444d9SMark Johnston 		len -= lenblks;
135*9a3444d9SMark Johnston 	}
136*9a3444d9SMark Johnston 
137*9a3444d9SMark Johnston 	/* Add remaining AAD to the hash (note, the hash is stored reflected) */
138*9a3444d9SMark Johnston 	if (len > 0) {
139*9a3444d9SMark Johnston 		ares = (unsigned int)len;
140*9a3444d9SMark Johnston 		for (size_t i = 0; i < len; ++i)
141*9a3444d9SMark Johnston 			ctx->gcm.Xi.c[15 - i] ^= aad[i];
142*9a3444d9SMark Johnston 	}
143*9a3444d9SMark Johnston 
144*9a3444d9SMark Johnston 	ctx->gcm.ares = ares;
145*9a3444d9SMark Johnston 
146*9a3444d9SMark Johnston 	return 0;
147*9a3444d9SMark Johnston }
148*9a3444d9SMark Johnston 
149*9a3444d9SMark Johnston static int
150*9a3444d9SMark Johnston _gcm_encrypt_avx512(struct ossl_gcm_context *ctx, const unsigned char *in,
151*9a3444d9SMark Johnston     unsigned char *out, size_t len, bool encrypt)
152*9a3444d9SMark Johnston {
153*9a3444d9SMark Johnston 	uint64_t mlen = ctx->gcm.len.u[1];
154*9a3444d9SMark Johnston 
155*9a3444d9SMark Johnston 	mlen += len;
156*9a3444d9SMark Johnston 	if (mlen > ((1ull << 36) - 32) || (sizeof(len) == 8 && mlen < len))
157*9a3444d9SMark Johnston 		return -1;
158*9a3444d9SMark Johnston 
159*9a3444d9SMark Johnston 	ctx->gcm.len.u[1] = mlen;
160*9a3444d9SMark Johnston 
161*9a3444d9SMark Johnston 	/* Finalize GHASH(AAD) if AAD partial blocks left unprocessed */
162*9a3444d9SMark Johnston 	if (ctx->gcm.ares > 0) {
163*9a3444d9SMark Johnston 		ossl_gcm_gmult_avx512(ctx->gcm.Xi.u, ctx);
164*9a3444d9SMark Johnston 		ctx->gcm.ares = 0;
165*9a3444d9SMark Johnston 	}
166*9a3444d9SMark Johnston 
167*9a3444d9SMark Johnston 	if (encrypt) {
168*9a3444d9SMark Johnston 		ossl_aes_gcm_encrypt_avx512(&ctx->aes_ks, ctx, &ctx->gcm.mres,
169*9a3444d9SMark Johnston 		    in, len, out);
170*9a3444d9SMark Johnston 	} else {
171*9a3444d9SMark Johnston 		ossl_aes_gcm_decrypt_avx512(&ctx->aes_ks, ctx, &ctx->gcm.mres,
172*9a3444d9SMark Johnston 		    in, len, out);
173*9a3444d9SMark Johnston 	}
174*9a3444d9SMark Johnston 
175*9a3444d9SMark Johnston 	return 0;
176*9a3444d9SMark Johnston }
177*9a3444d9SMark Johnston 
178*9a3444d9SMark Johnston static int
179*9a3444d9SMark Johnston gcm_encrypt_avx512(struct ossl_gcm_context *ctx, const unsigned char *in,
180*9a3444d9SMark Johnston     unsigned char *out, size_t len)
181*9a3444d9SMark Johnston {
182*9a3444d9SMark Johnston 	return _gcm_encrypt_avx512(ctx, in, out, len, true);
183*9a3444d9SMark Johnston }
184*9a3444d9SMark Johnston 
185*9a3444d9SMark Johnston static int
186*9a3444d9SMark Johnston gcm_decrypt_avx512(struct ossl_gcm_context *ctx, const unsigned char *in,
187*9a3444d9SMark Johnston     unsigned char *out, size_t len)
188*9a3444d9SMark Johnston {
189*9a3444d9SMark Johnston 	return _gcm_encrypt_avx512(ctx, in, out, len, false);
190*9a3444d9SMark Johnston }
191*9a3444d9SMark Johnston 
192*9a3444d9SMark Johnston static int
193*9a3444d9SMark Johnston gcm_finish_avx512(struct ossl_gcm_context *ctx, const unsigned char *tag,
194*9a3444d9SMark Johnston     size_t len)
195*9a3444d9SMark Johnston {
196*9a3444d9SMark Johnston 	unsigned int *res = &ctx->gcm.mres;
197*9a3444d9SMark Johnston 
198*9a3444d9SMark Johnston 	/* Finalize AAD processing */
199*9a3444d9SMark Johnston 	if (ctx->gcm.ares > 0)
200*9a3444d9SMark Johnston 		res = &ctx->gcm.ares;
201*9a3444d9SMark Johnston 
202*9a3444d9SMark Johnston 	ossl_aes_gcm_finalize_avx512(ctx, *res);
203*9a3444d9SMark Johnston 
204*9a3444d9SMark Johnston 	ctx->gcm.ares = ctx->gcm.mres = 0;
205*9a3444d9SMark Johnston 
206*9a3444d9SMark Johnston 	if (tag != NULL)
207*9a3444d9SMark Johnston 		return timingsafe_bcmp(ctx->gcm.Xi.c, tag, len);
208*9a3444d9SMark Johnston 	return 0;
209*9a3444d9SMark Johnston }
210*9a3444d9SMark Johnston 
211*9a3444d9SMark Johnston static const struct ossl_aes_gcm_ops gcm_ops_avx512 = {
212*9a3444d9SMark Johnston 	.init = gcm_init_avx512,
213*9a3444d9SMark Johnston 	.setiv = gcm_setiv_avx512,
214*9a3444d9SMark Johnston 	.aad = gcm_aad_avx512,
215*9a3444d9SMark Johnston 	.encrypt = gcm_encrypt_avx512,
216*9a3444d9SMark Johnston 	.decrypt = gcm_decrypt_avx512,
217*9a3444d9SMark Johnston 	.finish = gcm_finish_avx512,
218*9a3444d9SMark Johnston 	.tag = gcm_tag,
219*9a3444d9SMark Johnston };
220*9a3444d9SMark Johnston 
221*9a3444d9SMark Johnston int ossl_aes_gcm_setkey_avx512(const unsigned char *key, int klen, void *_ctx);
222*9a3444d9SMark Johnston 
223*9a3444d9SMark Johnston int
224*9a3444d9SMark Johnston ossl_aes_gcm_setkey_avx512(const unsigned char *key, int klen,
225*9a3444d9SMark Johnston     void *_ctx)
226*9a3444d9SMark Johnston {
227*9a3444d9SMark Johnston 	struct ossl_gcm_context *ctx;
228*9a3444d9SMark Johnston 
229*9a3444d9SMark Johnston 	ctx = _ctx;
230*9a3444d9SMark Johnston 	ctx->ops = &gcm_ops_avx512;
231*9a3444d9SMark Johnston 	gcm_init(ctx, key, klen);
232*9a3444d9SMark Johnston 	return (0);
233*9a3444d9SMark Johnston }
234