xref: /freebsd/sys/geom/eli/g_eli_crypto.c (revision 1df7f41560f3772da6b3023344f0c12aedf1119b)
1c58794deSPawel Jakub Dawidek /*-
23728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33728855aSPedro F. Giffuni  *
49839c97bSPawel Jakub Dawidek  * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5c58794deSPawel Jakub Dawidek  * All rights reserved.
6c58794deSPawel Jakub Dawidek  *
7c58794deSPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
8c58794deSPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
9c58794deSPawel Jakub Dawidek  * are met:
10c58794deSPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
11c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
12c58794deSPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
13c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
14c58794deSPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
15c58794deSPawel Jakub Dawidek  *
16c58794deSPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17c58794deSPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c58794deSPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c58794deSPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20c58794deSPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c58794deSPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c58794deSPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c58794deSPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c58794deSPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c58794deSPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c58794deSPawel Jakub Dawidek  * SUCH DAMAGE.
27c58794deSPawel Jakub Dawidek  */
28c58794deSPawel Jakub Dawidek 
29c58794deSPawel Jakub Dawidek #include <sys/cdefs.h>
30c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$");
31c58794deSPawel Jakub Dawidek 
32c58794deSPawel Jakub Dawidek #include <sys/param.h>
33c58794deSPawel Jakub Dawidek #ifdef _KERNEL
34c58794deSPawel Jakub Dawidek #include <sys/systm.h>
35c58794deSPawel Jakub Dawidek #include <sys/kernel.h>
36c58794deSPawel Jakub Dawidek #include <sys/malloc.h>
37c58794deSPawel Jakub Dawidek #else
38c58794deSPawel Jakub Dawidek #include <stdint.h>
39c58794deSPawel Jakub Dawidek #include <string.h>
40c58794deSPawel Jakub Dawidek #include <strings.h>
41c58794deSPawel Jakub Dawidek #include <errno.h>
42c58794deSPawel Jakub Dawidek #include <assert.h>
43c58794deSPawel Jakub Dawidek #include <openssl/evp.h>
44c58794deSPawel Jakub Dawidek #define	_OpenSSL_
45c58794deSPawel Jakub Dawidek #endif
46c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
47c58794deSPawel Jakub Dawidek 
48c58794deSPawel Jakub Dawidek #ifdef _KERNEL
49c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
50c58794deSPawel Jakub Dawidek 
51c58794deSPawel Jakub Dawidek static int
52c58794deSPawel Jakub Dawidek g_eli_crypto_done(struct cryptop *crp)
53c58794deSPawel Jakub Dawidek {
54c58794deSPawel Jakub Dawidek 
55c58794deSPawel Jakub Dawidek 	crp->crp_opaque = (void *)crp;
56c58794deSPawel Jakub Dawidek 	wakeup(crp);
57c58794deSPawel Jakub Dawidek 	return (0);
58c58794deSPawel Jakub Dawidek }
59c58794deSPawel Jakub Dawidek 
60c58794deSPawel Jakub Dawidek static int
61c58794deSPawel Jakub Dawidek g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
62c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
63c58794deSPawel Jakub Dawidek {
64c58794deSPawel Jakub Dawidek 	struct cryptoini cri;
65c58794deSPawel Jakub Dawidek 	struct cryptop *crp;
66c58794deSPawel Jakub Dawidek 	struct cryptodesc *crd;
67*1df7f415SConrad Meyer 	crypto_session_t sid;
68c58794deSPawel Jakub Dawidek 	u_char *p;
69c58794deSPawel Jakub Dawidek 	int error;
70c58794deSPawel Jakub Dawidek 
719a5a1d1eSPawel Jakub Dawidek 	KASSERT(algo != CRYPTO_AES_XTS,
729a5a1d1eSPawel Jakub Dawidek 	    ("%s: CRYPTO_AES_XTS unexpected here", __func__));
739a5a1d1eSPawel Jakub Dawidek 
74c58794deSPawel Jakub Dawidek 	bzero(&cri, sizeof(cri));
75c58794deSPawel Jakub Dawidek 	cri.cri_alg = algo;
76c58794deSPawel Jakub Dawidek 	cri.cri_key = __DECONST(void *, key);
77c58794deSPawel Jakub Dawidek 	cri.cri_klen = keysize;
786810ad6fSSam Leffler 	error = crypto_newsession(&sid, &cri, CRYPTOCAP_F_SOFTWARE);
79c58794deSPawel Jakub Dawidek 	if (error != 0)
80c58794deSPawel Jakub Dawidek 		return (error);
8189fac384SJohn-Mark Gurney 	p = malloc(sizeof(*crp) + sizeof(*crd), M_ELI, M_NOWAIT | M_ZERO);
82c58794deSPawel Jakub Dawidek 	if (p == NULL) {
83c58794deSPawel Jakub Dawidek 		crypto_freesession(sid);
84c58794deSPawel Jakub Dawidek 		return (ENOMEM);
85c58794deSPawel Jakub Dawidek 	}
86c58794deSPawel Jakub Dawidek 	crp = (struct cryptop *)p;	p += sizeof(*crp);
87c58794deSPawel Jakub Dawidek 	crd = (struct cryptodesc *)p;	p += sizeof(*crd);
88c58794deSPawel Jakub Dawidek 
89c58794deSPawel Jakub Dawidek 	crd->crd_skip = 0;
90c58794deSPawel Jakub Dawidek 	crd->crd_len = datasize;
915af2ae28SPawel Jakub Dawidek 	crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
92c58794deSPawel Jakub Dawidek 	if (enc)
93c58794deSPawel Jakub Dawidek 		crd->crd_flags |= CRD_F_ENCRYPT;
94c58794deSPawel Jakub Dawidek 	crd->crd_alg = algo;
95c58794deSPawel Jakub Dawidek 	crd->crd_key = __DECONST(void *, key);
96c58794deSPawel Jakub Dawidek 	crd->crd_klen = keysize;
97c58794deSPawel Jakub Dawidek 	bzero(crd->crd_iv, sizeof(crd->crd_iv));
98c58794deSPawel Jakub Dawidek 	crd->crd_next = NULL;
99c58794deSPawel Jakub Dawidek 
100c58794deSPawel Jakub Dawidek 	crp->crp_sid = sid;
101c58794deSPawel Jakub Dawidek 	crp->crp_ilen = datasize;
102c58794deSPawel Jakub Dawidek 	crp->crp_olen = datasize;
103c58794deSPawel Jakub Dawidek 	crp->crp_opaque = NULL;
104c58794deSPawel Jakub Dawidek 	crp->crp_callback = g_eli_crypto_done;
10589fac384SJohn-Mark Gurney 	crp->crp_buf = (void *)data;
10608fca7a5SJohn-Mark Gurney 	crp->crp_flags = CRYPTO_F_CBIFSYNC;
107c58794deSPawel Jakub Dawidek 	crp->crp_desc = crd;
108c58794deSPawel Jakub Dawidek 
109c58794deSPawel Jakub Dawidek 	error = crypto_dispatch(crp);
110c58794deSPawel Jakub Dawidek 	if (error == 0) {
111c58794deSPawel Jakub Dawidek 		while (crp->crp_opaque == NULL)
112c58794deSPawel Jakub Dawidek 			tsleep(crp, PRIBIO, "geli", hz / 5);
113c58794deSPawel Jakub Dawidek 		error = crp->crp_etype;
114c58794deSPawel Jakub Dawidek 	}
115c58794deSPawel Jakub Dawidek 
116c58794deSPawel Jakub Dawidek 	free(crp, M_ELI);
117c58794deSPawel Jakub Dawidek 	crypto_freesession(sid);
118c58794deSPawel Jakub Dawidek 	return (error);
119c58794deSPawel Jakub Dawidek }
120c58794deSPawel Jakub Dawidek #else	/* !_KERNEL */
121c58794deSPawel Jakub Dawidek static int
122c58794deSPawel Jakub Dawidek g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
123c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
124c58794deSPawel Jakub Dawidek {
125c58794deSPawel Jakub Dawidek 	EVP_CIPHER_CTX ctx;
126c58794deSPawel Jakub Dawidek 	const EVP_CIPHER *type;
127c58794deSPawel Jakub Dawidek 	u_char iv[keysize];
128c58794deSPawel Jakub Dawidek 	int outsize;
129c58794deSPawel Jakub Dawidek 
1309a5a1d1eSPawel Jakub Dawidek 	assert(algo != CRYPTO_AES_XTS);
1319a5a1d1eSPawel Jakub Dawidek 
132c58794deSPawel Jakub Dawidek 	switch (algo) {
133c58794deSPawel Jakub Dawidek 	case CRYPTO_NULL_CBC:
134c58794deSPawel Jakub Dawidek 		type = EVP_enc_null();
135c58794deSPawel Jakub Dawidek 		break;
136c58794deSPawel Jakub Dawidek 	case CRYPTO_AES_CBC:
137c58794deSPawel Jakub Dawidek 		switch (keysize) {
138c58794deSPawel Jakub Dawidek 		case 128:
139c58794deSPawel Jakub Dawidek 			type = EVP_aes_128_cbc();
140c58794deSPawel Jakub Dawidek 			break;
141c58794deSPawel Jakub Dawidek 		case 192:
142c58794deSPawel Jakub Dawidek 			type = EVP_aes_192_cbc();
143c58794deSPawel Jakub Dawidek 			break;
144c58794deSPawel Jakub Dawidek 		case 256:
145c58794deSPawel Jakub Dawidek 			type = EVP_aes_256_cbc();
146c58794deSPawel Jakub Dawidek 			break;
147c58794deSPawel Jakub Dawidek 		default:
148c58794deSPawel Jakub Dawidek 			return (EINVAL);
149c58794deSPawel Jakub Dawidek 		}
150c58794deSPawel Jakub Dawidek 		break;
151c58794deSPawel Jakub Dawidek 	case CRYPTO_BLF_CBC:
152c58794deSPawel Jakub Dawidek 		type = EVP_bf_cbc();
153c58794deSPawel Jakub Dawidek 		break;
15418b0b6d1SJohn Birrell #ifndef OPENSSL_NO_CAMELLIA
155864cba96SPawel Jakub Dawidek 	case CRYPTO_CAMELLIA_CBC:
156864cba96SPawel Jakub Dawidek 		switch (keysize) {
157864cba96SPawel Jakub Dawidek 		case 128:
158864cba96SPawel Jakub Dawidek 			type = EVP_camellia_128_cbc();
159864cba96SPawel Jakub Dawidek 			break;
160864cba96SPawel Jakub Dawidek 		case 192:
161864cba96SPawel Jakub Dawidek 			type = EVP_camellia_192_cbc();
162864cba96SPawel Jakub Dawidek 			break;
163864cba96SPawel Jakub Dawidek 		case 256:
164864cba96SPawel Jakub Dawidek 			type = EVP_camellia_256_cbc();
165864cba96SPawel Jakub Dawidek 			break;
166864cba96SPawel Jakub Dawidek 		default:
167864cba96SPawel Jakub Dawidek 			return (EINVAL);
168864cba96SPawel Jakub Dawidek 		}
169864cba96SPawel Jakub Dawidek 		break;
17018b0b6d1SJohn Birrell #endif
171c58794deSPawel Jakub Dawidek 	case CRYPTO_3DES_CBC:
172c58794deSPawel Jakub Dawidek 		type = EVP_des_ede3_cbc();
173c58794deSPawel Jakub Dawidek 		break;
174c58794deSPawel Jakub Dawidek 	default:
175c58794deSPawel Jakub Dawidek 		return (EINVAL);
176c58794deSPawel Jakub Dawidek 	}
177c58794deSPawel Jakub Dawidek 
178c58794deSPawel Jakub Dawidek 	EVP_CIPHER_CTX_init(&ctx);
179c58794deSPawel Jakub Dawidek 
180c58794deSPawel Jakub Dawidek 	EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc);
181c58794deSPawel Jakub Dawidek 	EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8);
182c58794deSPawel Jakub Dawidek 	EVP_CIPHER_CTX_set_padding(&ctx, 0);
183c58794deSPawel Jakub Dawidek 	bzero(iv, sizeof(iv));
184c58794deSPawel Jakub Dawidek 	EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc);
185c58794deSPawel Jakub Dawidek 
186c58794deSPawel Jakub Dawidek 	if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) {
187c58794deSPawel Jakub Dawidek 		EVP_CIPHER_CTX_cleanup(&ctx);
188c58794deSPawel Jakub Dawidek 		return (EINVAL);
189c58794deSPawel Jakub Dawidek 	}
190c58794deSPawel Jakub Dawidek 	assert(outsize == (int)datasize);
191c58794deSPawel Jakub Dawidek 
192c58794deSPawel Jakub Dawidek 	if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) {
193c58794deSPawel Jakub Dawidek 		EVP_CIPHER_CTX_cleanup(&ctx);
194c58794deSPawel Jakub Dawidek 		return (EINVAL);
195c58794deSPawel Jakub Dawidek 	}
196c58794deSPawel Jakub Dawidek 	assert(outsize == 0);
197c58794deSPawel Jakub Dawidek 
198c58794deSPawel Jakub Dawidek 	EVP_CIPHER_CTX_cleanup(&ctx);
199c58794deSPawel Jakub Dawidek 	return (0);
200c58794deSPawel Jakub Dawidek }
201c58794deSPawel Jakub Dawidek #endif	/* !_KERNEL */
202c58794deSPawel Jakub Dawidek 
203c58794deSPawel Jakub Dawidek int
204c58794deSPawel Jakub Dawidek g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
205c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
206c58794deSPawel Jakub Dawidek {
207c58794deSPawel Jakub Dawidek 
2089a5a1d1eSPawel Jakub Dawidek 	/* We prefer AES-CBC for metadata protection. */
2099a5a1d1eSPawel Jakub Dawidek 	if (algo == CRYPTO_AES_XTS)
2109a5a1d1eSPawel Jakub Dawidek 		algo = CRYPTO_AES_CBC;
2119a5a1d1eSPawel Jakub Dawidek 
212c58794deSPawel Jakub Dawidek 	return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
213c58794deSPawel Jakub Dawidek }
214c58794deSPawel Jakub Dawidek 
215c58794deSPawel Jakub Dawidek int
216c58794deSPawel Jakub Dawidek g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
217c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
218c58794deSPawel Jakub Dawidek {
219c58794deSPawel Jakub Dawidek 
2209a5a1d1eSPawel Jakub Dawidek 	/* We prefer AES-CBC for metadata protection. */
2219a5a1d1eSPawel Jakub Dawidek 	if (algo == CRYPTO_AES_XTS)
2229a5a1d1eSPawel Jakub Dawidek 		algo = CRYPTO_AES_CBC;
2239a5a1d1eSPawel Jakub Dawidek 
224c58794deSPawel Jakub Dawidek 	return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
225c58794deSPawel Jakub Dawidek }
226