]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/eli/g_eli_crypto.c
Upgrade to OpenSSH 7.3p1.
[FreeBSD/FreeBSD.git] / sys / geom / eli / g_eli_crypto.c
1 /*-
2  * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
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 cryptoini cri;
63         struct cryptop *crp;
64         struct cryptodesc *crd;
65         uint64_t sid;
66         u_char *p;
67         int error;
68
69         KASSERT(algo != CRYPTO_AES_XTS,
70             ("%s: CRYPTO_AES_XTS unexpected here", __func__));
71
72         bzero(&cri, sizeof(cri));
73         cri.cri_alg = algo;
74         cri.cri_key = __DECONST(void *, key);
75         cri.cri_klen = keysize;
76         error = crypto_newsession(&sid, &cri, CRYPTOCAP_F_SOFTWARE);
77         if (error != 0)
78                 return (error);
79         p = malloc(sizeof(*crp) + sizeof(*crd), M_ELI, M_NOWAIT | M_ZERO);
80         if (p == NULL) {
81                 crypto_freesession(sid);
82                 return (ENOMEM);
83         }
84         crp = (struct cryptop *)p;      p += sizeof(*crp);
85         crd = (struct cryptodesc *)p;   p += sizeof(*crd);
86
87         crd->crd_skip = 0;
88         crd->crd_len = datasize;
89         crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
90         if (enc)
91                 crd->crd_flags |= CRD_F_ENCRYPT;
92         crd->crd_alg = algo;
93         crd->crd_key = __DECONST(void *, key);
94         crd->crd_klen = keysize;
95         bzero(crd->crd_iv, sizeof(crd->crd_iv));
96         crd->crd_next = NULL;
97
98         crp->crp_sid = sid;
99         crp->crp_ilen = datasize;
100         crp->crp_olen = datasize;
101         crp->crp_opaque = NULL;
102         crp->crp_callback = g_eli_crypto_done;
103         crp->crp_buf = (void *)data;
104         crp->crp_flags = CRYPTO_F_CBIFSYNC;
105         crp->crp_desc = crd;
106
107         error = crypto_dispatch(crp);
108         if (error == 0) {
109                 while (crp->crp_opaque == NULL)
110                         tsleep(crp, PRIBIO, "geli", hz / 5);
111                 error = crp->crp_etype;
112         }
113
114         free(crp, M_ELI);
115         crypto_freesession(sid);
116         return (error);
117 }
118 #else   /* !_KERNEL */
119 static int
120 g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
121     const u_char *key, size_t keysize)
122 {
123         EVP_CIPHER_CTX ctx;
124         const EVP_CIPHER *type;
125         u_char iv[keysize];
126         int outsize;
127
128         assert(algo != CRYPTO_AES_XTS);
129
130         switch (algo) {
131         case CRYPTO_NULL_CBC:
132                 type = EVP_enc_null();
133                 break;
134         case CRYPTO_AES_CBC:
135                 switch (keysize) {
136                 case 128:
137                         type = EVP_aes_128_cbc();
138                         break;
139                 case 192:
140                         type = EVP_aes_192_cbc();
141                         break;
142                 case 256:
143                         type = EVP_aes_256_cbc();
144                         break;
145                 default:
146                         return (EINVAL);
147                 }
148                 break;
149         case CRYPTO_BLF_CBC:
150                 type = EVP_bf_cbc();
151                 break;
152 #ifndef OPENSSL_NO_CAMELLIA
153         case CRYPTO_CAMELLIA_CBC:
154                 switch (keysize) {
155                 case 128:
156                         type = EVP_camellia_128_cbc();
157                         break;
158                 case 192:
159                         type = EVP_camellia_192_cbc();
160                         break;
161                 case 256:
162                         type = EVP_camellia_256_cbc();
163                         break;
164                 default:
165                         return (EINVAL);
166                 }
167                 break;
168 #endif
169         case CRYPTO_3DES_CBC:
170                 type = EVP_des_ede3_cbc();
171                 break;
172         default:
173                 return (EINVAL);
174         }
175
176         EVP_CIPHER_CTX_init(&ctx);
177
178         EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc);
179         EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8);
180         EVP_CIPHER_CTX_set_padding(&ctx, 0);
181         bzero(iv, sizeof(iv));
182         EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc);
183
184         if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) {
185                 EVP_CIPHER_CTX_cleanup(&ctx);
186                 return (EINVAL);
187         }
188         assert(outsize == (int)datasize);
189
190         if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) {
191                 EVP_CIPHER_CTX_cleanup(&ctx);
192                 return (EINVAL);
193         }
194         assert(outsize == 0);
195
196         EVP_CIPHER_CTX_cleanup(&ctx);
197         return (0);
198 }
199 #endif  /* !_KERNEL */
200
201 int
202 g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
203     const u_char *key, size_t keysize)
204 {
205
206         /* We prefer AES-CBC for metadata protection. */
207         if (algo == CRYPTO_AES_XTS)
208                 algo = CRYPTO_AES_CBC;
209
210         return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
211 }
212
213 int
214 g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
215     const u_char *key, size_t keysize)
216 {
217
218         /* We prefer AES-CBC for metadata protection. */
219         if (algo == CRYPTO_AES_XTS)
220                 algo = CRYPTO_AES_CBC;
221
222         return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
223 }