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