xref: /freebsd/sys/geom/eli/g_eli_crypto.c (revision 51e235148a4becba94e824a44bd69687644a7f56)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * All rights reserved.
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 AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #ifdef _KERNEL
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #else
36 #include <stdint.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <assert.h>
41 #include <openssl/evp.h>
42 #define	_OpenSSL_
43 #endif
44 #include <geom/eli/g_eli.h>
45 
46 #ifdef _KERNEL
47 MALLOC_DECLARE(M_ELI);
48 
49 static int
50 g_eli_crypto_done(struct cryptop *crp)
51 {
52 
53 	crp->crp_opaque = (void *)crp;
54 	wakeup(crp);
55 	return (0);
56 }
57 
58 static int
59 g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
60     const u_char *key, size_t keysize)
61 {
62 	struct crypto_session_params csp;
63 	struct cryptop *crp;
64 	crypto_session_t sid;
65 	int error;
66 
67 	KASSERT(algo != CRYPTO_AES_XTS,
68 	    ("%s: CRYPTO_AES_XTS unexpected here", __func__));
69 
70 	memset(&csp, 0, sizeof(csp));
71 	csp.csp_mode = CSP_MODE_CIPHER;
72 	csp.csp_cipher_alg = algo;
73 	csp.csp_ivlen = g_eli_ivlen(algo);
74 	csp.csp_cipher_key = key;
75 	csp.csp_cipher_klen = keysize / 8;
76 	error = crypto_newsession(&sid, &csp, CRYPTOCAP_F_SOFTWARE);
77 	if (error != 0)
78 		return (error);
79 	crp = crypto_getreq(sid, M_NOWAIT);
80 	if (crp == NULL) {
81 		crypto_freesession(sid);
82 		return (ENOMEM);
83 	}
84 
85 	crp->crp_payload_start = 0;
86 	crp->crp_payload_length = datasize;
87 	crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_IV_SEPARATE;
88 	crp->crp_op = enc ? CRYPTO_OP_ENCRYPT : CRYPTO_OP_DECRYPT;
89 	memset(crp->crp_iv, 0, sizeof(crp->crp_iv));
90 
91 	crp->crp_opaque = NULL;
92 	crp->crp_callback = g_eli_crypto_done;
93 	crypto_use_buf(crp, data, datasize);
94 
95 	error = crypto_dispatch(crp);
96 	if (error == 0) {
97 		while (crp->crp_opaque == NULL)
98 			tsleep(crp, PRIBIO, "geli", hz / 5);
99 		error = crp->crp_etype;
100 	}
101 
102 	crypto_freereq(crp);
103 	crypto_freesession(sid);
104 	return (error);
105 }
106 #else	/* !_KERNEL */
107 static int
108 g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
109     const u_char *key, size_t keysize)
110 {
111 	EVP_CIPHER_CTX *ctx;
112 	const EVP_CIPHER *type;
113 	u_char iv[G_ELI_IVKEYLEN];
114 	int outsize;
115 
116 	assert(algo != CRYPTO_AES_XTS);
117 
118 	switch (algo) {
119 	case CRYPTO_NULL_CBC:
120 		type = EVP_enc_null();
121 		break;
122 	case CRYPTO_AES_CBC:
123 		switch (keysize) {
124 		case 128:
125 			type = EVP_aes_128_cbc();
126 			break;
127 		case 192:
128 			type = EVP_aes_192_cbc();
129 			break;
130 		case 256:
131 			type = EVP_aes_256_cbc();
132 			break;
133 		default:
134 			return (EINVAL);
135 		}
136 		break;
137 #ifndef OPENSSL_NO_CAMELLIA
138 	case CRYPTO_CAMELLIA_CBC:
139 		switch (keysize) {
140 		case 128:
141 			type = EVP_camellia_128_cbc();
142 			break;
143 		case 192:
144 			type = EVP_camellia_192_cbc();
145 			break;
146 		case 256:
147 			type = EVP_camellia_256_cbc();
148 			break;
149 		default:
150 			return (EINVAL);
151 		}
152 		break;
153 #endif
154 	default:
155 		return (EINVAL);
156 	}
157 
158 	ctx = EVP_CIPHER_CTX_new();
159 	if (ctx == NULL)
160 		return (ENOMEM);
161 
162 	EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, enc);
163 	EVP_CIPHER_CTX_set_key_length(ctx, keysize / 8);
164 	EVP_CIPHER_CTX_set_padding(ctx, 0);
165 	bzero(iv, sizeof(iv));
166 	EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc);
167 
168 	if (EVP_CipherUpdate(ctx, data, &outsize, data, datasize) == 0) {
169 		EVP_CIPHER_CTX_free(ctx);
170 		return (EINVAL);
171 	}
172 	assert(outsize == (int)datasize);
173 
174 	if (EVP_CipherFinal_ex(ctx, data + outsize, &outsize) == 0) {
175 		EVP_CIPHER_CTX_free(ctx);
176 		return (EINVAL);
177 	}
178 	assert(outsize == 0);
179 
180 	EVP_CIPHER_CTX_free(ctx);
181 	return (0);
182 }
183 #endif	/* !_KERNEL */
184 
185 int
186 g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
187     const u_char *key, size_t keysize)
188 {
189 
190 	/* We prefer AES-CBC for metadata protection. */
191 	if (algo == CRYPTO_AES_XTS)
192 		algo = CRYPTO_AES_CBC;
193 
194 	return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
195 }
196 
197 int
198 g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
199     const u_char *key, size_t keysize)
200 {
201 
202 	/* We prefer AES-CBC for metadata protection. */
203 	if (algo == CRYPTO_AES_XTS)
204 		algo = CRYPTO_AES_CBC;
205 
206 	return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
207 }
208