xref: /freebsd/sys/crypto/openssl/ossl_aes.c (revision 525fe93dc7487a1e63a90f6a2b956abc601963c1)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 Stormshield.
5  * Copyright (c) 2021 Semihalf.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/malloc.h>
30 
31 #include <opencrypto/cryptodev.h>
32 #include <opencrypto/gmac.h>
33 
34 #include <crypto/openssl/ossl.h>
35 #include <crypto/openssl/ossl_aes_gcm.h>
36 #include <crypto/openssl/ossl_cipher.h>
37 
38 #if defined(__amd64__) || defined(__i386__)
39 #include <crypto/openssl/ossl_x86.h>
40 #elif defined (__aarch64__)
41 #include <crypto/openssl/ossl_aarch64.h>
42 #endif
43 
44 static ossl_cipher_process_t ossl_aes_cbc;
45 static ossl_cipher_process_t ossl_aes_gcm;
46 
47 struct ossl_cipher ossl_cipher_aes_cbc = {
48 	.type = CRYPTO_AES_CBC,
49 	.blocksize = AES_BLOCK_LEN,
50 	.ivsize = AES_BLOCK_LEN,
51 
52 	/* Filled during initialization based on CPU caps. */
53 	.set_encrypt_key = NULL,
54 	.set_decrypt_key = NULL,
55 	.process = ossl_aes_cbc
56 };
57 
58 struct ossl_cipher ossl_cipher_aes_gcm = {
59 	.type = CRYPTO_AES_NIST_GCM_16,
60 	.blocksize = 1,
61 	.ivsize = AES_GCM_IV_LEN,
62 
63 	/* Filled during initialization based on CPU caps. */
64 	.set_encrypt_key = NULL,
65 	.set_decrypt_key = NULL,
66 	.process = ossl_aes_gcm,
67 };
68 
69 static int
70 ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp,
71     const struct crypto_session_params *csp)
72 {
73 	struct crypto_buffer_cursor cc_in, cc_out;
74 	unsigned char block[EALG_MAX_BLOCK_LEN];
75 	unsigned char iv[EALG_MAX_BLOCK_LEN];
76 	const unsigned char *in, *inseg;
77 	unsigned char *out, *outseg;
78 	size_t plen, seglen, inlen, outlen;
79 	struct ossl_cipher_context key;
80 	struct ossl_cipher *cipher;
81 	int blocklen, error;
82 	bool encrypt;
83 
84 	cipher = s->cipher;
85 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
86 	plen = crp->crp_payload_length;
87 	blocklen = cipher->blocksize;
88 
89 	if (plen % blocklen)
90 		return (EINVAL);
91 
92 	if (crp->crp_cipher_key != NULL) {
93 		if (encrypt)
94 			error = cipher->set_encrypt_key(crp->crp_cipher_key,
95 			    8 * csp->csp_cipher_klen, &key);
96 		else
97 			error = cipher->set_decrypt_key(crp->crp_cipher_key,
98 			    8 * csp->csp_cipher_klen, &key);
99 		if (error)
100 			return (error);
101 	} else {
102 		if (encrypt)
103 			key = s->enc_ctx;
104 		else
105 			key = s->dec_ctx;
106 	}
107 
108 	crypto_read_iv(crp, iv);
109 
110 	/* Derived from ossl_chacha20.c */
111 	crypto_cursor_init(&cc_in, &crp->crp_buf);
112 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
113 	inseg = crypto_cursor_segment(&cc_in, &inlen);
114 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
115 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
116 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
117 	} else {
118 		cc_out = cc_in;
119 	}
120 	outseg = crypto_cursor_segment(&cc_out, &outlen);
121 
122 	while (plen >= blocklen) {
123 		if (inlen < blocklen) {
124 			crypto_cursor_copydata(&cc_in, blocklen, block);
125 			in = block;
126 			inlen = blocklen;
127 		} else {
128 			in = inseg;
129 		}
130 		if (outlen < blocklen) {
131 			out = block;
132 			outlen = blocklen;
133 		} else {
134 			out = outseg;
135 		}
136 
137 		/* Figure out how many blocks we can encrypt/decrypt at once. */
138 		seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen);
139 
140 		AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt);
141 
142 		if (out == block) {
143 			crypto_cursor_copyback(&cc_out, blocklen, block);
144 			outseg = crypto_cursor_segment(&cc_out, &outlen);
145 		} else {
146 			crypto_cursor_advance(&cc_out, seglen);
147 			outseg += seglen;
148 			outlen -= seglen;
149 		}
150 		if (in == block) {
151 			inseg = crypto_cursor_segment(&cc_in, &inlen);
152 		} else {
153 			crypto_cursor_advance(&cc_in, seglen);
154 			inseg += seglen;
155 			inlen -= seglen;
156 		}
157 		plen -= seglen;
158 	}
159 
160 	explicit_bzero(block, sizeof(block));
161 	explicit_bzero(iv, sizeof(iv));
162 	explicit_bzero(&key, sizeof(key));
163 	return (0);
164 }
165 
166 static int
167 ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp,
168     const struct crypto_session_params *csp)
169 {
170 	struct ossl_gcm_context ctx;
171 	struct crypto_buffer_cursor cc_in, cc_out;
172 	unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN];
173 	const unsigned char *inseg;
174 	unsigned char *outseg;
175 	size_t inlen, outlen, seglen;
176 	int error;
177 	bool encrypt;
178 
179 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
180 
181 	if (crp->crp_cipher_key != NULL) {
182 		if (encrypt)
183 			error = s->cipher->set_encrypt_key(crp->crp_cipher_key,
184 			    8 * csp->csp_cipher_klen,
185 			    (struct ossl_cipher_context *)&ctx);
186 		else
187 			error = s->cipher->set_decrypt_key(crp->crp_cipher_key,
188 			    8 * csp->csp_cipher_klen,
189 			    (struct ossl_cipher_context *)&ctx);
190 		if (error)
191 			return (error);
192 	} else if (encrypt) {
193 		memcpy(&ctx, &s->enc_ctx, sizeof(struct ossl_gcm_context));
194 	} else {
195 		memcpy(&ctx, &s->dec_ctx, sizeof(struct ossl_gcm_context));
196 	}
197 
198 	crypto_read_iv(crp, iv);
199 	ctx.ops->setiv(&ctx, iv, csp->csp_ivlen);
200 
201 	if (crp->crp_aad != NULL) {
202 		if (ctx.ops->aad(&ctx, crp->crp_aad, crp->crp_aad_length) != 0)
203 			return (EINVAL);
204 	} else {
205 		crypto_cursor_init(&cc_in, &crp->crp_buf);
206 		crypto_cursor_advance(&cc_in, crp->crp_aad_start);
207 		for (size_t alen = crp->crp_aad_length; alen > 0;
208 		    alen -= seglen) {
209 			inseg = crypto_cursor_segment(&cc_in, &inlen);
210 			seglen = MIN(alen, inlen);
211 			if (ctx.ops->aad(&ctx, inseg, seglen) != 0)
212 				return (EINVAL);
213 			crypto_cursor_advance(&cc_in, seglen);
214 		}
215 	}
216 
217 	crypto_cursor_init(&cc_in, &crp->crp_buf);
218 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
219 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
220 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
221 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
222 	} else {
223 		cc_out = cc_in;
224 	}
225 
226 	for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) {
227 		inseg = crypto_cursor_segment(&cc_in, &inlen);
228 		outseg = crypto_cursor_segment(&cc_out, &outlen);
229 		seglen = MIN(plen, MIN(inlen, outlen));
230 
231 		if (encrypt) {
232 			if (ctx.ops->encrypt(&ctx, inseg, outseg, seglen) != 0)
233 				return (EINVAL);
234 		} else {
235 			if (ctx.ops->decrypt(&ctx, inseg, outseg, seglen) != 0)
236 				return (EINVAL);
237 		}
238 
239 		crypto_cursor_advance(&cc_in, seglen);
240 		crypto_cursor_advance(&cc_out, seglen);
241 	}
242 
243 	error = 0;
244 	if (encrypt) {
245 		ctx.ops->tag(&ctx, tag, GMAC_DIGEST_LEN);
246 		crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
247 		    tag);
248 	} else {
249 		crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
250 		    tag);
251 		if (ctx.ops->finish(&ctx, tag, GMAC_DIGEST_LEN) != 0)
252 			error = EBADMSG;
253 	}
254 
255 	explicit_bzero(iv, sizeof(iv));
256 	explicit_bzero(tag, sizeof(tag));
257 	explicit_bzero(&ctx, sizeof(ctx));
258 
259 	return (error);
260 }
261