Merge branch 'vendor/OPENPAM'
[dragonfly.git] / lib / libtcplay / crypto.c
1 /*
2  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
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  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <inttypes.h>
32
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <stdio.h>
38
39 #include "crc32.h"
40 #include "tcplay.h"
41
42 int
43 tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain,
44     unsigned char *key)
45 {
46         int total_key_bytes, used_key_bytes;
47         struct tc_cipher_chain *dummy_chain;
48
49         /*
50          * We need to determine the total key bytes as the key locations
51          * depend on it.
52          */
53         total_key_bytes = 0;
54         for (dummy_chain = cipher_chain;
55             dummy_chain != NULL;
56             dummy_chain = dummy_chain->next) {
57                 total_key_bytes += dummy_chain->cipher->klen;
58         }
59
60         /*
61          * Now we need to get prepare the keys, as the keys are in
62          * forward order with respect to the cipher cascade, but
63          * the actual decryption is in reverse cipher cascade order.
64          */
65         used_key_bytes = 0;
66         for (dummy_chain = cipher_chain;
67             dummy_chain != NULL;
68             dummy_chain = dummy_chain->next) {
69                 dummy_chain->key = alloc_safe_mem(dummy_chain->cipher->klen);
70                 if (dummy_chain->key == NULL) {
71                         tc_log(1, "tc_decrypt: Could not allocate key "
72                             "memory\n");
73                         return ENOMEM;
74                 }
75
76                 /* XXX: here we assume XTS operation! */
77                 memcpy(dummy_chain->key,
78                     key + used_key_bytes/2,
79                     dummy_chain->cipher->klen/2);
80                 memcpy(dummy_chain->key + dummy_chain->cipher->klen/2,
81                     key + (total_key_bytes/2) + used_key_bytes/2,
82                     dummy_chain->cipher->klen/2);
83
84                 /* Remember how many key bytes we've seen */
85                 used_key_bytes += dummy_chain->cipher->klen;
86         }
87
88         return 0;
89 }
90
91 int
92 tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain)
93 {
94         for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) {
95                 if (cipher_chain->key != NULL) {
96                         free_safe_mem(cipher_chain->key);
97                         cipher_chain->key = NULL;
98                 }
99         }
100
101         return 0;
102 }
103
104 int
105 tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
106     unsigned char *iv,
107     unsigned char *in, int in_len, unsigned char *out)
108 {
109         struct tc_cipher_chain *chain_start;
110         int err;
111
112         chain_start = cipher_chain;
113
114         if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
115                 return err;
116
117 #ifdef DEBUG
118         printf("tc_encrypt: starting chain\n");
119 #endif
120
121         /*
122          * Now process the actual decryption, in forward cascade order.
123          */
124         for (;
125             cipher_chain != NULL;
126             cipher_chain = cipher_chain->next) {
127 #ifdef DEBUG
128                 printf("tc_encrypt: Currently using cipher %s\n",
129                     cipher_chain->cipher->name);
130 #endif
131
132                 err = syscrypt(cipher_chain->cipher, cipher_chain->key,
133                     cipher_chain->cipher->klen, iv, in, out, in_len, 1);
134
135                 /* Deallocate this key, since we won't need it anymore */
136                 free_safe_mem(cipher_chain->key);
137                 cipher_chain->key = NULL;
138
139                 if (err != 0) {
140                         tc_cipher_chain_free_keys(chain_start);
141                         return err;
142                 }
143
144                 /* Set next input buffer as current output buffer */
145                 in = out;
146         }
147
148         tc_cipher_chain_free_keys(chain_start);
149
150         return 0;
151 }
152
153 int
154 tc_decrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
155     unsigned char *iv,
156     unsigned char *in, int in_len, unsigned char *out)
157 {
158         struct tc_cipher_chain *chain_start;
159         int err;
160
161         chain_start = cipher_chain;
162
163         if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
164                 return err;
165
166 #ifdef DEBUG
167         printf("tc_decrypt: starting chain!\n");
168 #endif
169
170         /*
171          * Now process the actual decryption, in reverse cascade order; so
172          * first find the last element in the chain.
173          */
174         for (; cipher_chain->next != NULL; cipher_chain = cipher_chain->next)
175                 ;
176         for (;
177             cipher_chain != NULL;
178             cipher_chain = cipher_chain->prev) {
179 #ifdef DEBUG
180                 printf("tc_decrypt: Currently using cipher %s\n",
181                     cipher_chain->cipher->name);
182 #endif
183
184                 err = syscrypt(cipher_chain->cipher, cipher_chain->key,
185                     cipher_chain->cipher->klen, iv, in, out, in_len, 0);
186
187                 /* Deallocate this key, since we won't need it anymore */
188                 free_safe_mem(cipher_chain->key);
189                 cipher_chain->key = NULL;
190
191                 if (err != 0) {
192                         tc_cipher_chain_free_keys(chain_start);
193                         return err;
194                 }
195
196                 /* Set next input buffer as current output buffer */
197                 in = out;
198         }
199
200         tc_cipher_chain_free_keys(chain_start);
201
202         return 0;
203 }
204
205 int
206 apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[],
207     int nkeyfiles)
208 {
209         int pl, k;
210         unsigned char *kpool;
211         unsigned char *kdata;
212         int kpool_idx;
213         size_t i, kdata_sz;
214         uint32_t crc;
215
216         if (pass_memsz < MAX_PASSSZ) {
217                 tc_log(1, "Not enough memory for password manipluation\n");
218                 return ENOMEM;
219         }
220
221         pl = strlen((char *)pass);
222         memset(pass+pl, 0, MAX_PASSSZ-pl);
223
224         if ((kpool = alloc_safe_mem(KPOOL_SZ)) == NULL) {
225                 tc_log(1, "Error allocating memory for keyfile pool\n");
226                 return ENOMEM;
227         }
228
229         memset(kpool, 0, KPOOL_SZ);
230
231         for (k = 0; k < nkeyfiles; k++) {
232 #ifdef DEBUG
233                 printf("Loading keyfile %s into kpool\n", keyfiles[k]);
234 #endif
235                 kpool_idx = 0;
236                 crc = ~0U;
237                 kdata_sz = MAX_KFILE_SZ;
238
239                 if ((kdata = read_to_safe_mem(keyfiles[k], 0, &kdata_sz)) == NULL) {
240                         tc_log(1, "Error reading keyfile %s content\n",
241                             keyfiles[k]);
242                         free_safe_mem(kpool);
243                         return EIO;
244                 }
245
246                 for (i = 0; i < kdata_sz; i++) {
247                         crc = crc32_intermediate(crc, kdata[i]);
248
249                         kpool[kpool_idx++] += (unsigned char)(crc >> 24);
250                         kpool[kpool_idx++] += (unsigned char)(crc >> 16);
251                         kpool[kpool_idx++] += (unsigned char)(crc >> 8);
252                         kpool[kpool_idx++] += (unsigned char)(crc);
253
254                         /* Wrap around */
255                         if (kpool_idx == KPOOL_SZ)
256                                 kpool_idx = 0;
257                 }
258
259                 free_safe_mem(kdata);
260         }
261
262 #ifdef DEBUG
263         printf("Applying kpool to passphrase\n");
264 #endif
265         /* Apply keyfile pool to passphrase */
266         for (i = 0; i < KPOOL_SZ; i++)
267                 pass[i] += kpool[i];
268
269         free_safe_mem(kpool);
270
271         return 0;
272 }