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