xref: /freebsd/sys/crypto/openssl/ossl_aes.c (revision 5c0dac0b7a012f326edab06ad85aee5ad68ff120)
1197ff4c3SKornel Duleba /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3197ff4c3SKornel Duleba  *
4197ff4c3SKornel Duleba  * Copyright (c) 2021 Stormshield.
5197ff4c3SKornel Duleba  * Copyright (c) 2021 Semihalf.
6197ff4c3SKornel Duleba  *
7197ff4c3SKornel Duleba  * Redistribution and use in source and binary forms, with or without
8197ff4c3SKornel Duleba  * modification, are permitted provided that the following conditions
9197ff4c3SKornel Duleba  * are met:
10197ff4c3SKornel Duleba  * 1. Redistributions of source code must retain the above copyright
11197ff4c3SKornel Duleba  *    notice, this list of conditions and the following disclaimer.
12197ff4c3SKornel Duleba  * 2. Redistributions in binary form must reproduce the above copyright
13197ff4c3SKornel Duleba  *    notice, this list of conditions and the following disclaimer in the
14197ff4c3SKornel Duleba  *    documentation and/or other materials provided with the distribution.
15197ff4c3SKornel Duleba  *
16197ff4c3SKornel Duleba  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17197ff4c3SKornel Duleba  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18197ff4c3SKornel Duleba  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19197ff4c3SKornel Duleba  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20197ff4c3SKornel Duleba  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21197ff4c3SKornel Duleba  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22197ff4c3SKornel Duleba  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23197ff4c3SKornel Duleba  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24197ff4c3SKornel Duleba  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25197ff4c3SKornel Duleba  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26197ff4c3SKornel Duleba  */
27197ff4c3SKornel Duleba 
28197ff4c3SKornel Duleba #include <sys/param.h>
29197ff4c3SKornel Duleba #include <sys/malloc.h>
30197ff4c3SKornel Duleba 
31197ff4c3SKornel Duleba #include <opencrypto/cryptodev.h>
329a3444d9SMark Johnston #include <opencrypto/gmac.h>
33197ff4c3SKornel Duleba 
34197ff4c3SKornel Duleba #include <crypto/openssl/ossl.h>
359a3444d9SMark Johnston #include <crypto/openssl/ossl_aes_gcm.h>
36197ff4c3SKornel Duleba #include <crypto/openssl/ossl_cipher.h>
37197ff4c3SKornel Duleba 
38197ff4c3SKornel Duleba #if defined(__amd64__) || defined(__i386__)
39197ff4c3SKornel Duleba #include <crypto/openssl/ossl_x86.h>
40197ff4c3SKornel Duleba #elif defined (__aarch64__)
41197ff4c3SKornel Duleba #include <crypto/openssl/ossl_aarch64.h>
42197ff4c3SKornel Duleba #endif
43197ff4c3SKornel Duleba 
44197ff4c3SKornel Duleba static ossl_cipher_process_t ossl_aes_cbc;
459a3444d9SMark Johnston static ossl_cipher_process_t ossl_aes_gcm;
46197ff4c3SKornel Duleba 
47197ff4c3SKornel Duleba struct ossl_cipher ossl_cipher_aes_cbc = {
48197ff4c3SKornel Duleba 	.type = CRYPTO_AES_CBC,
49197ff4c3SKornel Duleba 	.blocksize = AES_BLOCK_LEN,
50197ff4c3SKornel Duleba 	.ivsize = AES_BLOCK_LEN,
51197ff4c3SKornel Duleba 
52197ff4c3SKornel Duleba 	/* Filled during initialization based on CPU caps. */
53197ff4c3SKornel Duleba 	.set_encrypt_key = NULL,
54197ff4c3SKornel Duleba 	.set_decrypt_key = NULL,
55197ff4c3SKornel Duleba 	.process = ossl_aes_cbc
56197ff4c3SKornel Duleba };
57197ff4c3SKornel Duleba 
589a3444d9SMark Johnston struct ossl_cipher ossl_cipher_aes_gcm = {
599a3444d9SMark Johnston 	.type = CRYPTO_AES_NIST_GCM_16,
609a3444d9SMark Johnston 	.blocksize = 1,
619a3444d9SMark Johnston 	.ivsize = AES_GCM_IV_LEN,
629a3444d9SMark Johnston 
639a3444d9SMark Johnston 	/* Filled during initialization based on CPU caps. */
649a3444d9SMark Johnston 	.set_encrypt_key = NULL,
659a3444d9SMark Johnston 	.set_decrypt_key = NULL,
669a3444d9SMark Johnston 	.process = ossl_aes_gcm,
679a3444d9SMark Johnston };
689a3444d9SMark Johnston 
69197ff4c3SKornel Duleba static int
70197ff4c3SKornel Duleba ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp,
71197ff4c3SKornel Duleba     const struct crypto_session_params *csp)
72197ff4c3SKornel Duleba {
73197ff4c3SKornel Duleba 	struct crypto_buffer_cursor cc_in, cc_out;
74197ff4c3SKornel Duleba 	unsigned char block[EALG_MAX_BLOCK_LEN];
75197ff4c3SKornel Duleba 	unsigned char iv[EALG_MAX_BLOCK_LEN];
76197ff4c3SKornel Duleba 	const unsigned char *in, *inseg;
77197ff4c3SKornel Duleba 	unsigned char *out, *outseg;
78197ff4c3SKornel Duleba 	size_t plen, seglen, inlen, outlen;
79197ff4c3SKornel Duleba 	struct ossl_cipher_context key;
80197ff4c3SKornel Duleba 	struct ossl_cipher *cipher;
81197ff4c3SKornel Duleba 	int blocklen, error;
82197ff4c3SKornel Duleba 	bool encrypt;
83197ff4c3SKornel Duleba 
84197ff4c3SKornel Duleba 	cipher = s->cipher;
85197ff4c3SKornel Duleba 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
86197ff4c3SKornel Duleba 	plen = crp->crp_payload_length;
87197ff4c3SKornel Duleba 	blocklen = cipher->blocksize;
88197ff4c3SKornel Duleba 
89197ff4c3SKornel Duleba 	if (plen % blocklen)
90197ff4c3SKornel Duleba 		return (EINVAL);
91197ff4c3SKornel Duleba 
92197ff4c3SKornel Duleba 	if (crp->crp_cipher_key != NULL) {
93197ff4c3SKornel Duleba 		if (encrypt)
94197ff4c3SKornel Duleba 			error = cipher->set_encrypt_key(crp->crp_cipher_key,
95197ff4c3SKornel Duleba 			    8 * csp->csp_cipher_klen, &key);
96197ff4c3SKornel Duleba 		else
97197ff4c3SKornel Duleba 			error = cipher->set_decrypt_key(crp->crp_cipher_key,
98197ff4c3SKornel Duleba 			    8 * csp->csp_cipher_klen, &key);
99197ff4c3SKornel Duleba 		if (error)
100197ff4c3SKornel Duleba 			return (error);
101197ff4c3SKornel Duleba 	} else {
102197ff4c3SKornel Duleba 		if (encrypt)
103197ff4c3SKornel Duleba 			key = s->enc_ctx;
104197ff4c3SKornel Duleba 		else
105197ff4c3SKornel Duleba 			key = s->dec_ctx;
106197ff4c3SKornel Duleba 	}
107197ff4c3SKornel Duleba 
108197ff4c3SKornel Duleba 	crypto_read_iv(crp, iv);
109197ff4c3SKornel Duleba 
110197ff4c3SKornel Duleba 	/* Derived from ossl_chacha20.c */
111197ff4c3SKornel Duleba 	crypto_cursor_init(&cc_in, &crp->crp_buf);
112197ff4c3SKornel Duleba 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
113197ff4c3SKornel Duleba 	inseg = crypto_cursor_segment(&cc_in, &inlen);
114197ff4c3SKornel Duleba 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
115197ff4c3SKornel Duleba 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
116197ff4c3SKornel Duleba 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
117197ff4c3SKornel Duleba 	} else {
118197ff4c3SKornel Duleba 		cc_out = cc_in;
119197ff4c3SKornel Duleba 	}
120197ff4c3SKornel Duleba 	outseg = crypto_cursor_segment(&cc_out, &outlen);
121197ff4c3SKornel Duleba 
122197ff4c3SKornel Duleba 	while (plen >= blocklen) {
123197ff4c3SKornel Duleba 		if (inlen < blocklen) {
124197ff4c3SKornel Duleba 			crypto_cursor_copydata(&cc_in, blocklen, block);
125197ff4c3SKornel Duleba 			in = block;
126197ff4c3SKornel Duleba 			inlen = blocklen;
127197ff4c3SKornel Duleba 		} else {
128197ff4c3SKornel Duleba 			in = inseg;
129197ff4c3SKornel Duleba 		}
130197ff4c3SKornel Duleba 		if (outlen < blocklen) {
131197ff4c3SKornel Duleba 			out = block;
132197ff4c3SKornel Duleba 			outlen = blocklen;
133197ff4c3SKornel Duleba 		} else {
134197ff4c3SKornel Duleba 			out = outseg;
135197ff4c3SKornel Duleba 		}
136197ff4c3SKornel Duleba 
137197ff4c3SKornel Duleba 		/* Figure out how many blocks we can encrypt/decrypt at once. */
138197ff4c3SKornel Duleba 		seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen);
139197ff4c3SKornel Duleba 
140197ff4c3SKornel Duleba 		AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt);
141197ff4c3SKornel Duleba 
142197ff4c3SKornel Duleba 		if (out == block) {
143197ff4c3SKornel Duleba 			crypto_cursor_copyback(&cc_out, blocklen, block);
144197ff4c3SKornel Duleba 			outseg = crypto_cursor_segment(&cc_out, &outlen);
145197ff4c3SKornel Duleba 		} else {
146197ff4c3SKornel Duleba 			crypto_cursor_advance(&cc_out, seglen);
147197ff4c3SKornel Duleba 			outseg += seglen;
148197ff4c3SKornel Duleba 			outlen -= seglen;
149197ff4c3SKornel Duleba 		}
150197ff4c3SKornel Duleba 		if (in == block) {
151197ff4c3SKornel Duleba 			inseg = crypto_cursor_segment(&cc_in, &inlen);
152197ff4c3SKornel Duleba 		} else {
153197ff4c3SKornel Duleba 			crypto_cursor_advance(&cc_in, seglen);
154197ff4c3SKornel Duleba 			inseg += seglen;
155197ff4c3SKornel Duleba 			inlen -= seglen;
156197ff4c3SKornel Duleba 		}
157197ff4c3SKornel Duleba 		plen -= seglen;
158197ff4c3SKornel Duleba 	}
159197ff4c3SKornel Duleba 
160197ff4c3SKornel Duleba 	explicit_bzero(block, sizeof(block));
161197ff4c3SKornel Duleba 	explicit_bzero(iv, sizeof(iv));
162197ff4c3SKornel Duleba 	explicit_bzero(&key, sizeof(key));
163197ff4c3SKornel Duleba 	return (0);
164197ff4c3SKornel Duleba }
1659a3444d9SMark Johnston 
1669a3444d9SMark Johnston static int
1679a3444d9SMark Johnston ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp,
1689a3444d9SMark Johnston     const struct crypto_session_params *csp)
1699a3444d9SMark Johnston {
170*5c0dac0bSMark Johnston 	struct ossl_gcm_context ctx;
1719a3444d9SMark Johnston 	struct crypto_buffer_cursor cc_in, cc_out;
1729a3444d9SMark Johnston 	unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN];
1739a3444d9SMark Johnston 	const unsigned char *inseg;
1749a3444d9SMark Johnston 	unsigned char *outseg;
1759a3444d9SMark Johnston 	size_t inlen, outlen, seglen;
1769a3444d9SMark Johnston 	int error;
1779a3444d9SMark Johnston 	bool encrypt;
1789a3444d9SMark Johnston 
1799a3444d9SMark Johnston 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
1809a3444d9SMark Johnston 
1819a3444d9SMark Johnston 	if (crp->crp_cipher_key != NULL) {
1829a3444d9SMark Johnston 		if (encrypt)
1839a3444d9SMark Johnston 			error = s->cipher->set_encrypt_key(crp->crp_cipher_key,
184*5c0dac0bSMark Johnston 			    8 * csp->csp_cipher_klen,
185*5c0dac0bSMark Johnston 			    (struct ossl_cipher_context *)&ctx);
1869a3444d9SMark Johnston 		else
1879a3444d9SMark Johnston 			error = s->cipher->set_decrypt_key(crp->crp_cipher_key,
188*5c0dac0bSMark Johnston 			    8 * csp->csp_cipher_klen,
189*5c0dac0bSMark Johnston 			    (struct ossl_cipher_context *)&ctx);
1909a3444d9SMark Johnston 		if (error)
1919a3444d9SMark Johnston 			return (error);
1929a3444d9SMark Johnston 	} else if (encrypt) {
193*5c0dac0bSMark Johnston 		memcpy(&ctx, &s->enc_ctx, sizeof(struct ossl_gcm_context));
1949a3444d9SMark Johnston 	} else {
195*5c0dac0bSMark Johnston 		memcpy(&ctx, &s->dec_ctx, sizeof(struct ossl_gcm_context));
1969a3444d9SMark Johnston 	}
1979a3444d9SMark Johnston 
1989a3444d9SMark Johnston 	crypto_read_iv(crp, iv);
199*5c0dac0bSMark Johnston 	ctx.ops->setiv(&ctx, iv, csp->csp_ivlen);
2009a3444d9SMark Johnston 
20187826c87SMark Johnston 	if (crp->crp_aad != NULL) {
202*5c0dac0bSMark Johnston 		if (ctx.ops->aad(&ctx, crp->crp_aad, crp->crp_aad_length) != 0)
20387826c87SMark Johnston 			return (EINVAL);
20487826c87SMark Johnston 	} else {
2059a3444d9SMark Johnston 		crypto_cursor_init(&cc_in, &crp->crp_buf);
2069a3444d9SMark Johnston 		crypto_cursor_advance(&cc_in, crp->crp_aad_start);
20787826c87SMark Johnston 		for (size_t alen = crp->crp_aad_length; alen > 0;
20887826c87SMark Johnston 		    alen -= seglen) {
2099a3444d9SMark Johnston 			inseg = crypto_cursor_segment(&cc_in, &inlen);
2109a3444d9SMark Johnston 			seglen = MIN(alen, inlen);
211*5c0dac0bSMark Johnston 			if (ctx.ops->aad(&ctx, inseg, seglen) != 0)
2129a3444d9SMark Johnston 				return (EINVAL);
2139a3444d9SMark Johnston 			crypto_cursor_advance(&cc_in, seglen);
2149a3444d9SMark Johnston 		}
21587826c87SMark Johnston 	}
2169a3444d9SMark Johnston 
2179a3444d9SMark Johnston 	crypto_cursor_init(&cc_in, &crp->crp_buf);
2189a3444d9SMark Johnston 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
2199a3444d9SMark Johnston 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
2209a3444d9SMark Johnston 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
2219a3444d9SMark Johnston 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
2229a3444d9SMark Johnston 	} else {
2239a3444d9SMark Johnston 		cc_out = cc_in;
2249a3444d9SMark Johnston 	}
2259a3444d9SMark Johnston 
2269a3444d9SMark Johnston 	for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) {
2279a3444d9SMark Johnston 		inseg = crypto_cursor_segment(&cc_in, &inlen);
2289a3444d9SMark Johnston 		outseg = crypto_cursor_segment(&cc_out, &outlen);
2299a3444d9SMark Johnston 		seglen = MIN(plen, MIN(inlen, outlen));
2309a3444d9SMark Johnston 
2319a3444d9SMark Johnston 		if (encrypt) {
232*5c0dac0bSMark Johnston 			if (ctx.ops->encrypt(&ctx, inseg, outseg, seglen) != 0)
2339a3444d9SMark Johnston 				return (EINVAL);
2349a3444d9SMark Johnston 		} else {
235*5c0dac0bSMark Johnston 			if (ctx.ops->decrypt(&ctx, inseg, outseg, seglen) != 0)
2369a3444d9SMark Johnston 				return (EINVAL);
2379a3444d9SMark Johnston 		}
2389a3444d9SMark Johnston 
2399a3444d9SMark Johnston 		crypto_cursor_advance(&cc_in, seglen);
2409a3444d9SMark Johnston 		crypto_cursor_advance(&cc_out, seglen);
2419a3444d9SMark Johnston 	}
2429a3444d9SMark Johnston 
2439a3444d9SMark Johnston 	error = 0;
2449a3444d9SMark Johnston 	if (encrypt) {
245*5c0dac0bSMark Johnston 		ctx.ops->tag(&ctx, tag, GMAC_DIGEST_LEN);
2469a3444d9SMark Johnston 		crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
2479a3444d9SMark Johnston 		    tag);
2489a3444d9SMark Johnston 	} else {
2499a3444d9SMark Johnston 		crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
2509a3444d9SMark Johnston 		    tag);
251*5c0dac0bSMark Johnston 		if (ctx.ops->finish(&ctx, tag, GMAC_DIGEST_LEN) != 0)
2529a3444d9SMark Johnston 			error = EBADMSG;
2539a3444d9SMark Johnston 	}
2549a3444d9SMark Johnston 
2559a3444d9SMark Johnston 	explicit_bzero(iv, sizeof(iv));
2569a3444d9SMark Johnston 	explicit_bzero(tag, sizeof(tag));
257*5c0dac0bSMark Johnston 	explicit_bzero(&ctx, sizeof(ctx));
2589a3444d9SMark Johnston 
2599a3444d9SMark Johnston 	return (error);
2609a3444d9SMark Johnston }
261