xref: /freebsd/sys/crypto/openssl/ossl_aes.c (revision ba3c1f5972d7b90feb6e6da47905ff2757e0fe57)
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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/malloc.h>
33 
34 #include <opencrypto/cryptodev.h>
35 #include <opencrypto/gmac.h>
36 
37 #include <crypto/openssl/ossl.h>
38 #include <crypto/openssl/ossl_aes_gcm.h>
39 #include <crypto/openssl/ossl_cipher.h>
40 
41 #if defined(__amd64__) || defined(__i386__)
42 #include <crypto/openssl/ossl_x86.h>
43 #elif defined (__aarch64__)
44 #include <crypto/openssl/ossl_aarch64.h>
45 #endif
46 
47 static ossl_cipher_process_t ossl_aes_cbc;
48 static ossl_cipher_process_t ossl_aes_gcm;
49 
50 struct ossl_cipher ossl_cipher_aes_cbc = {
51 	.type = CRYPTO_AES_CBC,
52 	.blocksize = AES_BLOCK_LEN,
53 	.ivsize = AES_BLOCK_LEN,
54 
55 	/* Filled during initialization based on CPU caps. */
56 	.set_encrypt_key = NULL,
57 	.set_decrypt_key = NULL,
58 	.process = ossl_aes_cbc
59 };
60 
61 struct ossl_cipher ossl_cipher_aes_gcm = {
62 	.type = CRYPTO_AES_NIST_GCM_16,
63 	.blocksize = 1,
64 	.ivsize = AES_GCM_IV_LEN,
65 
66 	/* Filled during initialization based on CPU caps. */
67 	.set_encrypt_key = NULL,
68 	.set_decrypt_key = NULL,
69 	.process = ossl_aes_gcm,
70 };
71 
72 static int
73 ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp,
74     const struct crypto_session_params *csp)
75 {
76 	struct crypto_buffer_cursor cc_in, cc_out;
77 	unsigned char block[EALG_MAX_BLOCK_LEN];
78 	unsigned char iv[EALG_MAX_BLOCK_LEN];
79 	const unsigned char *in, *inseg;
80 	unsigned char *out, *outseg;
81 	size_t plen, seglen, inlen, outlen;
82 	struct ossl_cipher_context key;
83 	struct ossl_cipher *cipher;
84 	int blocklen, error;
85 	bool encrypt;
86 
87 	cipher = s->cipher;
88 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
89 	plen = crp->crp_payload_length;
90 	blocklen = cipher->blocksize;
91 
92 	if (plen % blocklen)
93 		return (EINVAL);
94 
95 	if (crp->crp_cipher_key != NULL) {
96 		if (encrypt)
97 			error = cipher->set_encrypt_key(crp->crp_cipher_key,
98 			    8 * csp->csp_cipher_klen, &key);
99 		else
100 			error = cipher->set_decrypt_key(crp->crp_cipher_key,
101 			    8 * csp->csp_cipher_klen, &key);
102 		if (error)
103 			return (error);
104 	} else {
105 		if (encrypt)
106 			key = s->enc_ctx;
107 		else
108 			key = s->dec_ctx;
109 	}
110 
111 	crypto_read_iv(crp, iv);
112 
113 	/* Derived from ossl_chacha20.c */
114 	crypto_cursor_init(&cc_in, &crp->crp_buf);
115 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
116 	inseg = crypto_cursor_segment(&cc_in, &inlen);
117 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
118 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
119 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
120 	} else {
121 		cc_out = cc_in;
122 	}
123 	outseg = crypto_cursor_segment(&cc_out, &outlen);
124 
125 	while (plen >= blocklen) {
126 		if (inlen < blocklen) {
127 			crypto_cursor_copydata(&cc_in, blocklen, block);
128 			in = block;
129 			inlen = blocklen;
130 		} else {
131 			in = inseg;
132 		}
133 		if (outlen < blocklen) {
134 			out = block;
135 			outlen = blocklen;
136 		} else {
137 			out = outseg;
138 		}
139 
140 		/* Figure out how many blocks we can encrypt/decrypt at once. */
141 		seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen);
142 
143 		AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt);
144 
145 		if (out == block) {
146 			crypto_cursor_copyback(&cc_out, blocklen, block);
147 			outseg = crypto_cursor_segment(&cc_out, &outlen);
148 		} else {
149 			crypto_cursor_advance(&cc_out, seglen);
150 			outseg += seglen;
151 			outlen -= seglen;
152 		}
153 		if (in == block) {
154 			inseg = crypto_cursor_segment(&cc_in, &inlen);
155 		} else {
156 			crypto_cursor_advance(&cc_in, seglen);
157 			inseg += seglen;
158 			inlen -= seglen;
159 		}
160 		plen -= seglen;
161 	}
162 
163 	explicit_bzero(block, sizeof(block));
164 	explicit_bzero(iv, sizeof(iv));
165 	explicit_bzero(&key, sizeof(key));
166 	return (0);
167 }
168 
169 static int
170 ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp,
171     const struct crypto_session_params *csp)
172 {
173 	struct ossl_cipher_context key;
174 	struct crypto_buffer_cursor cc_in, cc_out;
175 	unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN];
176 	struct ossl_gcm_context *ctx;
177 	const unsigned char *inseg;
178 	unsigned char *outseg;
179 	size_t inlen, outlen, seglen;
180 	int error;
181 	bool encrypt;
182 
183 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
184 
185 	if (crp->crp_cipher_key != NULL) {
186 		if (encrypt)
187 			error = s->cipher->set_encrypt_key(crp->crp_cipher_key,
188 			    8 * csp->csp_cipher_klen, &key);
189 		else
190 			error = s->cipher->set_decrypt_key(crp->crp_cipher_key,
191 			    8 * csp->csp_cipher_klen, &key);
192 		if (error)
193 			return (error);
194 		ctx = (struct ossl_gcm_context *)&key;
195 	} else if (encrypt) {
196 		ctx = (struct ossl_gcm_context *)&s->enc_ctx;
197 	} else {
198 		ctx = (struct ossl_gcm_context *)&s->dec_ctx;
199 	}
200 
201 	crypto_read_iv(crp, iv);
202 	ctx->ops->setiv(ctx, iv, csp->csp_ivlen);
203 
204 	crypto_cursor_init(&cc_in, &crp->crp_buf);
205 	crypto_cursor_advance(&cc_in, crp->crp_aad_start);
206 	for (size_t alen = crp->crp_aad_length; alen > 0; alen -= seglen) {
207 		inseg = crypto_cursor_segment(&cc_in, &inlen);
208 		seglen = MIN(alen, inlen);
209 		if (ctx->ops->aad(ctx, inseg, seglen) != 0)
210 			return (EINVAL);
211 		crypto_cursor_advance(&cc_in, seglen);
212 	}
213 
214 	crypto_cursor_init(&cc_in, &crp->crp_buf);
215 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
216 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
217 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
218 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
219 	} else {
220 		cc_out = cc_in;
221 	}
222 
223 	for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) {
224 		inseg = crypto_cursor_segment(&cc_in, &inlen);
225 		outseg = crypto_cursor_segment(&cc_out, &outlen);
226 		seglen = MIN(plen, MIN(inlen, outlen));
227 
228 		if (encrypt) {
229 			if (ctx->ops->encrypt(ctx, inseg, outseg, seglen) != 0)
230 				return (EINVAL);
231 		} else {
232 			if (ctx->ops->decrypt(ctx, inseg, outseg, seglen) != 0)
233 				return (EINVAL);
234 		}
235 
236 		crypto_cursor_advance(&cc_in, seglen);
237 		crypto_cursor_advance(&cc_out, seglen);
238 	}
239 
240 	error = 0;
241 	if (encrypt) {
242 		ctx->ops->tag(ctx, tag, GMAC_DIGEST_LEN);
243 		crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
244 		    tag);
245 	} else {
246 		crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
247 		    tag);
248 		if (ctx->ops->finish(ctx, tag, GMAC_DIGEST_LEN) != 0)
249 			error = EBADMSG;
250 	}
251 
252 	explicit_bzero(iv, sizeof(iv));
253 	explicit_bzero(tag, sizeof(tag));
254 
255 	return (error);
256 }
257