xref: /freebsd/sys/crypto/openssl/ossl_aes.c (revision c5405d1c850765d04f74067ebb71f57e9a26b8ea)
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_cipher_context key;
171 	struct crypto_buffer_cursor cc_in, cc_out;
172 	unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN];
173 	struct ossl_gcm_context *ctx;
174 	const unsigned char *inseg;
175 	unsigned char *outseg;
176 	size_t inlen, outlen, seglen;
177 	int error;
178 	bool encrypt;
179 
180 	encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
181 
182 	if (crp->crp_cipher_key != NULL) {
183 		if (encrypt)
184 			error = s->cipher->set_encrypt_key(crp->crp_cipher_key,
185 			    8 * csp->csp_cipher_klen, &key);
186 		else
187 			error = s->cipher->set_decrypt_key(crp->crp_cipher_key,
188 			    8 * csp->csp_cipher_klen, &key);
189 		if (error)
190 			return (error);
191 		ctx = (struct ossl_gcm_context *)&key;
192 	} else if (encrypt) {
193 		ctx = (struct ossl_gcm_context *)&s->enc_ctx;
194 	} else {
195 		ctx = (struct ossl_gcm_context *)&s->dec_ctx;
196 	}
197 
198 	crypto_read_iv(crp, iv);
199 	ctx->ops->setiv(ctx, iv, csp->csp_ivlen);
200 
201 	crypto_cursor_init(&cc_in, &crp->crp_buf);
202 	crypto_cursor_advance(&cc_in, crp->crp_aad_start);
203 	for (size_t alen = crp->crp_aad_length; alen > 0; alen -= seglen) {
204 		inseg = crypto_cursor_segment(&cc_in, &inlen);
205 		seglen = MIN(alen, inlen);
206 		if (ctx->ops->aad(ctx, inseg, seglen) != 0)
207 			return (EINVAL);
208 		crypto_cursor_advance(&cc_in, seglen);
209 	}
210 
211 	crypto_cursor_init(&cc_in, &crp->crp_buf);
212 	crypto_cursor_advance(&cc_in, crp->crp_payload_start);
213 	if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
214 		crypto_cursor_init(&cc_out, &crp->crp_obuf);
215 		crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
216 	} else {
217 		cc_out = cc_in;
218 	}
219 
220 	for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) {
221 		inseg = crypto_cursor_segment(&cc_in, &inlen);
222 		outseg = crypto_cursor_segment(&cc_out, &outlen);
223 		seglen = MIN(plen, MIN(inlen, outlen));
224 
225 		if (encrypt) {
226 			if (ctx->ops->encrypt(ctx, inseg, outseg, seglen) != 0)
227 				return (EINVAL);
228 		} else {
229 			if (ctx->ops->decrypt(ctx, inseg, outseg, seglen) != 0)
230 				return (EINVAL);
231 		}
232 
233 		crypto_cursor_advance(&cc_in, seglen);
234 		crypto_cursor_advance(&cc_out, seglen);
235 	}
236 
237 	error = 0;
238 	if (encrypt) {
239 		ctx->ops->tag(ctx, tag, GMAC_DIGEST_LEN);
240 		crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
241 		    tag);
242 	} else {
243 		crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
244 		    tag);
245 		if (ctx->ops->finish(ctx, tag, GMAC_DIGEST_LEN) != 0)
246 			error = EBADMSG;
247 	}
248 
249 	explicit_bzero(iv, sizeof(iv));
250 	explicit_bzero(tag, sizeof(tag));
251 
252 	return (error);
253 }
254