xref: /freebsd/sys/crypto/openssl/ossl_aes.c (revision 3465f14dac7dc4efaf1f8b4e10c2a00b2db7c513)
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>
4244f8e1e8SMark Johnston #elif defined (__arm__)
4344f8e1e8SMark Johnston #include <crypto/openssl/ossl_arm.h>
44*3465f14dSShawn Anastasio #elif defined (__powerpc64__)
45*3465f14dSShawn Anastasio #include <crypto/openssl/ossl_ppc.h>
46*3465f14dSShawn Anastasio #else
47*3465f14dSShawn Anastasio #error "Unsupported architecture!"
48197ff4c3SKornel Duleba #endif
49197ff4c3SKornel Duleba 
50197ff4c3SKornel Duleba static ossl_cipher_process_t ossl_aes_cbc;
519a3444d9SMark Johnston static ossl_cipher_process_t ossl_aes_gcm;
52197ff4c3SKornel Duleba 
53197ff4c3SKornel Duleba struct ossl_cipher ossl_cipher_aes_cbc = {
54197ff4c3SKornel Duleba 	.type = CRYPTO_AES_CBC,
55197ff4c3SKornel Duleba 	.blocksize = AES_BLOCK_LEN,
56197ff4c3SKornel Duleba 	.ivsize = AES_BLOCK_LEN,
57197ff4c3SKornel Duleba 
58197ff4c3SKornel Duleba 	/* Filled during initialization based on CPU caps. */
59197ff4c3SKornel Duleba 	.set_encrypt_key = NULL,
60197ff4c3SKornel Duleba 	.set_decrypt_key = NULL,
61197ff4c3SKornel Duleba 	.process = ossl_aes_cbc
62197ff4c3SKornel Duleba };
63197ff4c3SKornel Duleba 
649a3444d9SMark Johnston struct ossl_cipher ossl_cipher_aes_gcm = {
659a3444d9SMark Johnston 	.type = CRYPTO_AES_NIST_GCM_16,
669a3444d9SMark Johnston 	.blocksize = 1,
679a3444d9SMark Johnston 	.ivsize = AES_GCM_IV_LEN,
689a3444d9SMark Johnston 
699a3444d9SMark Johnston 	/* Filled during initialization based on CPU caps. */
709a3444d9SMark Johnston 	.set_encrypt_key = NULL,
719a3444d9SMark Johnston 	.set_decrypt_key = NULL,
729a3444d9SMark Johnston 	.process = ossl_aes_gcm,
739a3444d9SMark Johnston };
749a3444d9SMark Johnston 
75197ff4c3SKornel Duleba static int
ossl_aes_cbc(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)76197ff4c3SKornel Duleba ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp,
77197ff4c3SKornel Duleba     const struct crypto_session_params *csp)
78197ff4c3SKornel Duleba {
79197ff4c3SKornel Duleba 	struct crypto_buffer_cursor cc_in, cc_out;
80197ff4c3SKornel Duleba 	unsigned char block[EALG_MAX_BLOCK_LEN];
81197ff4c3SKornel Duleba 	unsigned char iv[EALG_MAX_BLOCK_LEN];
82197ff4c3SKornel Duleba 	const unsigned char *in, *inseg;
83197ff4c3SKornel Duleba 	unsigned char *out, *outseg;
84197ff4c3SKornel Duleba 	size_t plen, seglen, inlen, outlen;
85197ff4c3SKornel Duleba 	struct ossl_cipher_context key;
86197ff4c3SKornel Duleba 	struct ossl_cipher *cipher;
87197ff4c3SKornel Duleba 	int blocklen, error;
88197ff4c3SKornel Duleba 	bool encrypt;
89197ff4c3SKornel Duleba 
90197ff4c3SKornel Duleba 	cipher = s->cipher;
91197ff4c3SKornel Duleba 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
92197ff4c3SKornel Duleba 	plen = crp->crp_payload_length;
93197ff4c3SKornel Duleba 	blocklen = cipher->blocksize;
94197ff4c3SKornel Duleba 
95197ff4c3SKornel Duleba 	if (plen % blocklen)
96197ff4c3SKornel Duleba 		return (EINVAL);
97197ff4c3SKornel Duleba 
98197ff4c3SKornel Duleba 	if (crp->crp_cipher_key != NULL) {
99197ff4c3SKornel Duleba 		if (encrypt)
100197ff4c3SKornel Duleba 			error = cipher->set_encrypt_key(crp->crp_cipher_key,
101197ff4c3SKornel Duleba 			    8 * csp->csp_cipher_klen, &key);
102197ff4c3SKornel Duleba 		else
103197ff4c3SKornel Duleba 			error = cipher->set_decrypt_key(crp->crp_cipher_key,
104197ff4c3SKornel Duleba 			    8 * csp->csp_cipher_klen, &key);
105197ff4c3SKornel Duleba 		if (error)
106197ff4c3SKornel Duleba 			return (error);
107197ff4c3SKornel Duleba 	} else {
108197ff4c3SKornel Duleba 		if (encrypt)
109197ff4c3SKornel Duleba 			key = s->enc_ctx;
110197ff4c3SKornel Duleba 		else
111197ff4c3SKornel Duleba 			key = s->dec_ctx;
112197ff4c3SKornel Duleba 	}
113197ff4c3SKornel Duleba 
114197ff4c3SKornel Duleba 	crypto_read_iv(crp, iv);
115197ff4c3SKornel Duleba 
116197ff4c3SKornel Duleba 	/* Derived from ossl_chacha20.c */
117197ff4c3SKornel Duleba 	crypto_cursor_init(&cc_in, &crp->crp_buf);
118197ff4c3SKornel Duleba 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
119197ff4c3SKornel Duleba 	inseg = crypto_cursor_segment(&cc_in, &inlen);
120197ff4c3SKornel Duleba 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
121197ff4c3SKornel Duleba 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
122197ff4c3SKornel Duleba 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
123197ff4c3SKornel Duleba 	} else {
124197ff4c3SKornel Duleba 		cc_out = cc_in;
125197ff4c3SKornel Duleba 	}
126197ff4c3SKornel Duleba 	outseg = crypto_cursor_segment(&cc_out, &outlen);
127197ff4c3SKornel Duleba 
128197ff4c3SKornel Duleba 	while (plen >= blocklen) {
129197ff4c3SKornel Duleba 		if (inlen < blocklen) {
130197ff4c3SKornel Duleba 			crypto_cursor_copydata(&cc_in, blocklen, block);
131197ff4c3SKornel Duleba 			in = block;
132197ff4c3SKornel Duleba 			inlen = blocklen;
133197ff4c3SKornel Duleba 		} else {
134197ff4c3SKornel Duleba 			in = inseg;
135197ff4c3SKornel Duleba 		}
136197ff4c3SKornel Duleba 		if (outlen < blocklen) {
137197ff4c3SKornel Duleba 			out = block;
138197ff4c3SKornel Duleba 			outlen = blocklen;
139197ff4c3SKornel Duleba 		} else {
140197ff4c3SKornel Duleba 			out = outseg;
141197ff4c3SKornel Duleba 		}
142197ff4c3SKornel Duleba 
143197ff4c3SKornel Duleba 		/* Figure out how many blocks we can encrypt/decrypt at once. */
144197ff4c3SKornel Duleba 		seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen);
145197ff4c3SKornel Duleba 
146197ff4c3SKornel Duleba 		AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt);
147197ff4c3SKornel Duleba 
148197ff4c3SKornel Duleba 		if (out == block) {
149197ff4c3SKornel Duleba 			crypto_cursor_copyback(&cc_out, blocklen, block);
150197ff4c3SKornel Duleba 			outseg = crypto_cursor_segment(&cc_out, &outlen);
151197ff4c3SKornel Duleba 		} else {
152197ff4c3SKornel Duleba 			crypto_cursor_advance(&cc_out, seglen);
153197ff4c3SKornel Duleba 			outseg += seglen;
154197ff4c3SKornel Duleba 			outlen -= seglen;
155197ff4c3SKornel Duleba 		}
156197ff4c3SKornel Duleba 		if (in == block) {
157197ff4c3SKornel Duleba 			inseg = crypto_cursor_segment(&cc_in, &inlen);
158197ff4c3SKornel Duleba 		} else {
159197ff4c3SKornel Duleba 			crypto_cursor_advance(&cc_in, seglen);
160197ff4c3SKornel Duleba 			inseg += seglen;
161197ff4c3SKornel Duleba 			inlen -= seglen;
162197ff4c3SKornel Duleba 		}
163197ff4c3SKornel Duleba 		plen -= seglen;
164197ff4c3SKornel Duleba 	}
165197ff4c3SKornel Duleba 
166197ff4c3SKornel Duleba 	explicit_bzero(block, sizeof(block));
167197ff4c3SKornel Duleba 	explicit_bzero(iv, sizeof(iv));
168197ff4c3SKornel Duleba 	explicit_bzero(&key, sizeof(key));
169197ff4c3SKornel Duleba 	return (0);
170197ff4c3SKornel Duleba }
1719a3444d9SMark Johnston 
1729a3444d9SMark Johnston static int
ossl_aes_gcm(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)1739a3444d9SMark Johnston ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp,
1749a3444d9SMark Johnston     const struct crypto_session_params *csp)
1759a3444d9SMark Johnston {
1765c0dac0bSMark Johnston 	struct ossl_gcm_context ctx;
1779a3444d9SMark Johnston 	struct crypto_buffer_cursor cc_in, cc_out;
1789a3444d9SMark Johnston 	unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN];
1799a3444d9SMark Johnston 	const unsigned char *inseg;
1809a3444d9SMark Johnston 	unsigned char *outseg;
1819a3444d9SMark Johnston 	size_t inlen, outlen, seglen;
1829a3444d9SMark Johnston 	int error;
1839a3444d9SMark Johnston 	bool encrypt;
1849a3444d9SMark Johnston 
1859a3444d9SMark Johnston 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
1869a3444d9SMark Johnston 
1879a3444d9SMark Johnston 	if (crp->crp_cipher_key != NULL) {
1889a3444d9SMark Johnston 		if (encrypt)
1899a3444d9SMark Johnston 			error = s->cipher->set_encrypt_key(crp->crp_cipher_key,
1905c0dac0bSMark Johnston 			    8 * csp->csp_cipher_klen,
1915c0dac0bSMark Johnston 			    (struct ossl_cipher_context *)&ctx);
1929a3444d9SMark Johnston 		else
1939a3444d9SMark Johnston 			error = s->cipher->set_decrypt_key(crp->crp_cipher_key,
1945c0dac0bSMark Johnston 			    8 * csp->csp_cipher_klen,
1955c0dac0bSMark Johnston 			    (struct ossl_cipher_context *)&ctx);
1969a3444d9SMark Johnston 		if (error)
1979a3444d9SMark Johnston 			return (error);
1989a3444d9SMark Johnston 	} else if (encrypt) {
1995c0dac0bSMark Johnston 		memcpy(&ctx, &s->enc_ctx, sizeof(struct ossl_gcm_context));
2009a3444d9SMark Johnston 	} else {
2015c0dac0bSMark Johnston 		memcpy(&ctx, &s->dec_ctx, sizeof(struct ossl_gcm_context));
2029a3444d9SMark Johnston 	}
2039a3444d9SMark Johnston 
2049a3444d9SMark Johnston 	crypto_read_iv(crp, iv);
2055c0dac0bSMark Johnston 	ctx.ops->setiv(&ctx, iv, csp->csp_ivlen);
2069a3444d9SMark Johnston 
20787826c87SMark Johnston 	if (crp->crp_aad != NULL) {
2085c0dac0bSMark Johnston 		if (ctx.ops->aad(&ctx, crp->crp_aad, crp->crp_aad_length) != 0)
20987826c87SMark Johnston 			return (EINVAL);
21087826c87SMark Johnston 	} else {
2119a3444d9SMark Johnston 		crypto_cursor_init(&cc_in, &crp->crp_buf);
2129a3444d9SMark Johnston 		crypto_cursor_advance(&cc_in, crp->crp_aad_start);
21387826c87SMark Johnston 		for (size_t alen = crp->crp_aad_length; alen > 0;
21487826c87SMark Johnston 		    alen -= seglen) {
2159a3444d9SMark Johnston 			inseg = crypto_cursor_segment(&cc_in, &inlen);
2169a3444d9SMark Johnston 			seglen = MIN(alen, inlen);
2175c0dac0bSMark Johnston 			if (ctx.ops->aad(&ctx, inseg, seglen) != 0)
2189a3444d9SMark Johnston 				return (EINVAL);
2199a3444d9SMark Johnston 			crypto_cursor_advance(&cc_in, seglen);
2209a3444d9SMark Johnston 		}
22187826c87SMark Johnston 	}
2229a3444d9SMark Johnston 
2239a3444d9SMark Johnston 	crypto_cursor_init(&cc_in, &crp->crp_buf);
2249a3444d9SMark Johnston 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
2259a3444d9SMark Johnston 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
2269a3444d9SMark Johnston 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
2279a3444d9SMark Johnston 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
2289a3444d9SMark Johnston 	} else {
2299a3444d9SMark Johnston 		cc_out = cc_in;
2309a3444d9SMark Johnston 	}
2319a3444d9SMark Johnston 
2329a3444d9SMark Johnston 	for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) {
2339a3444d9SMark Johnston 		inseg = crypto_cursor_segment(&cc_in, &inlen);
2349a3444d9SMark Johnston 		outseg = crypto_cursor_segment(&cc_out, &outlen);
2359a3444d9SMark Johnston 		seglen = MIN(plen, MIN(inlen, outlen));
2369a3444d9SMark Johnston 
2379a3444d9SMark Johnston 		if (encrypt) {
2385c0dac0bSMark Johnston 			if (ctx.ops->encrypt(&ctx, inseg, outseg, seglen) != 0)
2399a3444d9SMark Johnston 				return (EINVAL);
2409a3444d9SMark Johnston 		} else {
2415c0dac0bSMark Johnston 			if (ctx.ops->decrypt(&ctx, inseg, outseg, seglen) != 0)
2429a3444d9SMark Johnston 				return (EINVAL);
2439a3444d9SMark Johnston 		}
2449a3444d9SMark Johnston 
2459a3444d9SMark Johnston 		crypto_cursor_advance(&cc_in, seglen);
2469a3444d9SMark Johnston 		crypto_cursor_advance(&cc_out, seglen);
2479a3444d9SMark Johnston 	}
2489a3444d9SMark Johnston 
2499a3444d9SMark Johnston 	error = 0;
2509a3444d9SMark Johnston 	if (encrypt) {
2515c0dac0bSMark Johnston 		ctx.ops->tag(&ctx, tag, GMAC_DIGEST_LEN);
2529a3444d9SMark Johnston 		crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
2539a3444d9SMark Johnston 		    tag);
2549a3444d9SMark Johnston 	} else {
2559a3444d9SMark Johnston 		crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
2569a3444d9SMark Johnston 		    tag);
2575c0dac0bSMark Johnston 		if (ctx.ops->finish(&ctx, tag, GMAC_DIGEST_LEN) != 0)
2589a3444d9SMark Johnston 			error = EBADMSG;
2599a3444d9SMark Johnston 	}
2609a3444d9SMark Johnston 
2619a3444d9SMark Johnston 	explicit_bzero(iv, sizeof(iv));
2629a3444d9SMark Johnston 	explicit_bzero(tag, sizeof(tag));
2635c0dac0bSMark Johnston 	explicit_bzero(&ctx, sizeof(ctx));
2649a3444d9SMark Johnston 
2659a3444d9SMark Johnston 	return (error);
2669a3444d9SMark Johnston }
267