xref: /freebsd/sys/geom/eli/g_eli_crypto.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1c58794deSPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
30c58794deSPawel Jakub Dawidek #ifdef _KERNEL
31c58794deSPawel Jakub Dawidek #include <sys/systm.h>
32c58794deSPawel Jakub Dawidek #include <sys/kernel.h>
33c58794deSPawel Jakub Dawidek #include <sys/malloc.h>
34c58794deSPawel Jakub Dawidek #else
35c58794deSPawel Jakub Dawidek #include <stdint.h>
36c58794deSPawel Jakub Dawidek #include <string.h>
37c58794deSPawel Jakub Dawidek #include <strings.h>
38c58794deSPawel Jakub Dawidek #include <errno.h>
39c58794deSPawel Jakub Dawidek #include <assert.h>
40c58794deSPawel Jakub Dawidek #include <openssl/evp.h>
41c58794deSPawel Jakub Dawidek #define	_OpenSSL_
42c58794deSPawel Jakub Dawidek #endif
43c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
44c58794deSPawel Jakub Dawidek 
45c58794deSPawel Jakub Dawidek #ifdef _KERNEL
46c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
47c58794deSPawel Jakub Dawidek 
48c58794deSPawel Jakub Dawidek static int
g_eli_crypto_done(struct cryptop * crp)49c58794deSPawel Jakub Dawidek g_eli_crypto_done(struct cryptop *crp)
50c58794deSPawel Jakub Dawidek {
51c58794deSPawel Jakub Dawidek 
52c58794deSPawel Jakub Dawidek 	crp->crp_opaque = (void *)crp;
53c58794deSPawel Jakub Dawidek 	wakeup(crp);
54c58794deSPawel Jakub Dawidek 	return (0);
55c58794deSPawel Jakub Dawidek }
56c58794deSPawel Jakub Dawidek 
57c58794deSPawel Jakub Dawidek static int
g_eli_crypto_cipher(u_int algo,int enc,u_char * data,size_t datasize,const u_char * key,size_t keysize)58c58794deSPawel Jakub Dawidek g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
59c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
60c58794deSPawel Jakub Dawidek {
61c0341432SJohn Baldwin 	struct crypto_session_params csp;
62c58794deSPawel Jakub Dawidek 	struct cryptop *crp;
631df7f415SConrad Meyer 	crypto_session_t sid;
64c58794deSPawel Jakub Dawidek 	int error;
65c58794deSPawel Jakub Dawidek 
669a5a1d1eSPawel Jakub Dawidek 	KASSERT(algo != CRYPTO_AES_XTS,
679a5a1d1eSPawel Jakub Dawidek 	    ("%s: CRYPTO_AES_XTS unexpected here", __func__));
689a5a1d1eSPawel Jakub Dawidek 
69c0341432SJohn Baldwin 	memset(&csp, 0, sizeof(csp));
70c0341432SJohn Baldwin 	csp.csp_mode = CSP_MODE_CIPHER;
71c0341432SJohn Baldwin 	csp.csp_cipher_alg = algo;
72c0341432SJohn Baldwin 	csp.csp_ivlen = g_eli_ivlen(algo);
73c0341432SJohn Baldwin 	csp.csp_cipher_key = key;
74c0341432SJohn Baldwin 	csp.csp_cipher_klen = keysize / 8;
75c0341432SJohn Baldwin 	error = crypto_newsession(&sid, &csp, CRYPTOCAP_F_SOFTWARE);
76c58794deSPawel Jakub Dawidek 	if (error != 0)
77c58794deSPawel Jakub Dawidek 		return (error);
78c0341432SJohn Baldwin 	crp = crypto_getreq(sid, M_NOWAIT);
79c0341432SJohn Baldwin 	if (crp == NULL) {
80c58794deSPawel Jakub Dawidek 		crypto_freesession(sid);
81c58794deSPawel Jakub Dawidek 		return (ENOMEM);
82c58794deSPawel Jakub Dawidek 	}
83c58794deSPawel Jakub Dawidek 
84c0341432SJohn Baldwin 	crp->crp_payload_start = 0;
85c0341432SJohn Baldwin 	crp->crp_payload_length = datasize;
86c0341432SJohn Baldwin 	crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_IV_SEPARATE;
87c0341432SJohn Baldwin 	crp->crp_op = enc ? CRYPTO_OP_ENCRYPT : CRYPTO_OP_DECRYPT;
88c0341432SJohn Baldwin 	memset(crp->crp_iv, 0, sizeof(crp->crp_iv));
89c58794deSPawel Jakub Dawidek 
90c58794deSPawel Jakub Dawidek 	crp->crp_opaque = NULL;
91c58794deSPawel Jakub Dawidek 	crp->crp_callback = g_eli_crypto_done;
929c0e3d3aSJohn Baldwin 	crypto_use_buf(crp, data, datasize);
93c58794deSPawel Jakub Dawidek 
94c58794deSPawel Jakub Dawidek 	error = crypto_dispatch(crp);
95c58794deSPawel Jakub Dawidek 	if (error == 0) {
96c58794deSPawel Jakub Dawidek 		while (crp->crp_opaque == NULL)
97c58794deSPawel Jakub Dawidek 			tsleep(crp, PRIBIO, "geli", hz / 5);
98c58794deSPawel Jakub Dawidek 		error = crp->crp_etype;
99c58794deSPawel Jakub Dawidek 	}
100c58794deSPawel Jakub Dawidek 
101c0341432SJohn Baldwin 	crypto_freereq(crp);
102c58794deSPawel Jakub Dawidek 	crypto_freesession(sid);
103c58794deSPawel Jakub Dawidek 	return (error);
104c58794deSPawel Jakub Dawidek }
105c58794deSPawel Jakub Dawidek #else	/* !_KERNEL */
106c58794deSPawel Jakub Dawidek static int
g_eli_crypto_cipher(u_int algo,int enc,u_char * data,size_t datasize,const u_char * key,size_t keysize)107c58794deSPawel Jakub Dawidek g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
108c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
109c58794deSPawel Jakub Dawidek {
1109c40dcbeSJung-uk Kim 	EVP_CIPHER_CTX *ctx;
111c58794deSPawel Jakub Dawidek 	const EVP_CIPHER *type;
112d61effd3SJohn Baldwin 	u_char iv[G_ELI_IVKEYLEN];
113c58794deSPawel Jakub Dawidek 	int outsize;
114c58794deSPawel Jakub Dawidek 
1159a5a1d1eSPawel Jakub Dawidek 	assert(algo != CRYPTO_AES_XTS);
1169a5a1d1eSPawel Jakub Dawidek 
117c58794deSPawel Jakub Dawidek 	switch (algo) {
118c58794deSPawel Jakub Dawidek 	case CRYPTO_NULL_CBC:
119c58794deSPawel Jakub Dawidek 		type = EVP_enc_null();
120c58794deSPawel Jakub Dawidek 		break;
121c58794deSPawel Jakub Dawidek 	case CRYPTO_AES_CBC:
122c58794deSPawel Jakub Dawidek 		switch (keysize) {
123c58794deSPawel Jakub Dawidek 		case 128:
124c58794deSPawel Jakub Dawidek 			type = EVP_aes_128_cbc();
125c58794deSPawel Jakub Dawidek 			break;
126c58794deSPawel Jakub Dawidek 		case 192:
127c58794deSPawel Jakub Dawidek 			type = EVP_aes_192_cbc();
128c58794deSPawel Jakub Dawidek 			break;
129c58794deSPawel Jakub Dawidek 		case 256:
130c58794deSPawel Jakub Dawidek 			type = EVP_aes_256_cbc();
131c58794deSPawel Jakub Dawidek 			break;
132c58794deSPawel Jakub Dawidek 		default:
133c58794deSPawel Jakub Dawidek 			return (EINVAL);
134c58794deSPawel Jakub Dawidek 		}
135c58794deSPawel Jakub Dawidek 		break;
13618b0b6d1SJohn Birrell #ifndef OPENSSL_NO_CAMELLIA
137864cba96SPawel Jakub Dawidek 	case CRYPTO_CAMELLIA_CBC:
138864cba96SPawel Jakub Dawidek 		switch (keysize) {
139864cba96SPawel Jakub Dawidek 		case 128:
140864cba96SPawel Jakub Dawidek 			type = EVP_camellia_128_cbc();
141864cba96SPawel Jakub Dawidek 			break;
142864cba96SPawel Jakub Dawidek 		case 192:
143864cba96SPawel Jakub Dawidek 			type = EVP_camellia_192_cbc();
144864cba96SPawel Jakub Dawidek 			break;
145864cba96SPawel Jakub Dawidek 		case 256:
146864cba96SPawel Jakub Dawidek 			type = EVP_camellia_256_cbc();
147864cba96SPawel Jakub Dawidek 			break;
148864cba96SPawel Jakub Dawidek 		default:
149864cba96SPawel Jakub Dawidek 			return (EINVAL);
150864cba96SPawel Jakub Dawidek 		}
151864cba96SPawel Jakub Dawidek 		break;
15218b0b6d1SJohn Birrell #endif
153c58794deSPawel Jakub Dawidek 	default:
154c58794deSPawel Jakub Dawidek 		return (EINVAL);
155c58794deSPawel Jakub Dawidek 	}
156c58794deSPawel Jakub Dawidek 
1579c40dcbeSJung-uk Kim 	ctx = EVP_CIPHER_CTX_new();
1589c40dcbeSJung-uk Kim 	if (ctx == NULL)
1599c40dcbeSJung-uk Kim 		return (ENOMEM);
160c58794deSPawel Jakub Dawidek 
1619c40dcbeSJung-uk Kim 	EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, enc);
1629c40dcbeSJung-uk Kim 	EVP_CIPHER_CTX_set_key_length(ctx, keysize / 8);
1639c40dcbeSJung-uk Kim 	EVP_CIPHER_CTX_set_padding(ctx, 0);
164c58794deSPawel Jakub Dawidek 	bzero(iv, sizeof(iv));
1659c40dcbeSJung-uk Kim 	EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc);
166c58794deSPawel Jakub Dawidek 
1679c40dcbeSJung-uk Kim 	if (EVP_CipherUpdate(ctx, data, &outsize, data, datasize) == 0) {
1689c40dcbeSJung-uk Kim 		EVP_CIPHER_CTX_free(ctx);
169c58794deSPawel Jakub Dawidek 		return (EINVAL);
170c58794deSPawel Jakub Dawidek 	}
171c58794deSPawel Jakub Dawidek 	assert(outsize == (int)datasize);
172c58794deSPawel Jakub Dawidek 
1739c40dcbeSJung-uk Kim 	if (EVP_CipherFinal_ex(ctx, data + outsize, &outsize) == 0) {
1749c40dcbeSJung-uk Kim 		EVP_CIPHER_CTX_free(ctx);
175c58794deSPawel Jakub Dawidek 		return (EINVAL);
176c58794deSPawel Jakub Dawidek 	}
177c58794deSPawel Jakub Dawidek 	assert(outsize == 0);
178c58794deSPawel Jakub Dawidek 
1799c40dcbeSJung-uk Kim 	EVP_CIPHER_CTX_free(ctx);
180c58794deSPawel Jakub Dawidek 	return (0);
181c58794deSPawel Jakub Dawidek }
182c58794deSPawel Jakub Dawidek #endif	/* !_KERNEL */
183c58794deSPawel Jakub Dawidek 
184c58794deSPawel Jakub Dawidek int
g_eli_crypto_encrypt(u_int algo,u_char * data,size_t datasize,const u_char * key,size_t keysize)185c58794deSPawel Jakub Dawidek g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
186c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
187c58794deSPawel Jakub Dawidek {
188c58794deSPawel Jakub Dawidek 
1899a5a1d1eSPawel Jakub Dawidek 	/* We prefer AES-CBC for metadata protection. */
1909a5a1d1eSPawel Jakub Dawidek 	if (algo == CRYPTO_AES_XTS)
1919a5a1d1eSPawel Jakub Dawidek 		algo = CRYPTO_AES_CBC;
1929a5a1d1eSPawel Jakub Dawidek 
193c58794deSPawel Jakub Dawidek 	return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
194c58794deSPawel Jakub Dawidek }
195c58794deSPawel Jakub Dawidek 
196c58794deSPawel Jakub Dawidek int
g_eli_crypto_decrypt(u_int algo,u_char * data,size_t datasize,const u_char * key,size_t keysize)197c58794deSPawel Jakub Dawidek g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
198c58794deSPawel Jakub Dawidek     const u_char *key, size_t keysize)
199c58794deSPawel Jakub Dawidek {
200c58794deSPawel Jakub Dawidek 
2019a5a1d1eSPawel Jakub Dawidek 	/* We prefer AES-CBC for metadata protection. */
2029a5a1d1eSPawel Jakub Dawidek 	if (algo == CRYPTO_AES_XTS)
2039a5a1d1eSPawel Jakub Dawidek 		algo = CRYPTO_AES_CBC;
2049a5a1d1eSPawel Jakub Dawidek 
205c58794deSPawel Jakub Dawidek 	return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
206c58794deSPawel Jakub Dawidek }
207