/src/cryptsetup/lib/tcrypt/tcrypt.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling |
3 | | * |
4 | | * Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved. |
5 | | * Copyright (C) 2012-2024 Milan Broz |
6 | | * |
7 | | * This file is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This file is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this file; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | | */ |
21 | | |
22 | | #include <errno.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | |
27 | | #include "libcryptsetup.h" |
28 | | #include "tcrypt.h" |
29 | | #include "internal.h" |
30 | | |
31 | | /* TCRYPT PBKDF variants */ |
32 | | static const struct { |
33 | | unsigned int legacy:1; |
34 | | unsigned int veracrypt:1; |
35 | | const char *name; |
36 | | const char *hash; |
37 | | unsigned int iterations; |
38 | | uint32_t veracrypt_pim_const; |
39 | | uint32_t veracrypt_pim_mult; |
40 | | } tcrypt_kdf[] = { |
41 | | { 0, 0, "pbkdf2", "ripemd160", 2000, 0, 0 }, |
42 | | { 0, 0, "pbkdf2", "ripemd160", 1000, 0, 0 }, |
43 | | { 0, 0, "pbkdf2", "sha512", 1000, 0, 0 }, |
44 | | { 0, 0, "pbkdf2", "whirlpool", 1000, 0, 0 }, |
45 | | { 1, 0, "pbkdf2", "sha1", 2000, 0, 0 }, |
46 | | { 0, 1, "pbkdf2", "sha512", 500000, 15000, 1000 }, |
47 | | { 0, 1, "pbkdf2", "whirlpool", 500000, 15000, 1000 }, |
48 | | { 0, 1, "pbkdf2", "sha256", 500000, 15000, 1000 }, // VeraCrypt 1.0f |
49 | | { 0, 1, "pbkdf2", "sha256", 200000, 0, 2048 }, // boot only |
50 | | { 0, 1, "pbkdf2", "blake2s-256", 500000, 15000, 1000 }, // VeraCrypt 1.26.2 |
51 | | { 0, 1, "pbkdf2", "blake2s-256", 200000, 0, 2048 }, // boot only |
52 | | { 0, 1, "pbkdf2", "ripemd160", 655331, 15000, 1000 }, |
53 | | { 0, 1, "pbkdf2", "ripemd160", 327661, 0, 2048 }, // boot only |
54 | | { 0, 1, "pbkdf2", "stribog512",500000, 15000, 1000 }, |
55 | | // { 0, 1, "pbkdf2", "stribog512",200000, 0, 2048 }, // boot only |
56 | | { 0, 0, NULL, NULL, 0, 0, 0 } |
57 | | }; |
58 | | |
59 | | struct tcrypt_alg { |
60 | | const char *name; |
61 | | unsigned int key_size; |
62 | | unsigned int iv_size; |
63 | | unsigned int key_offset; |
64 | | unsigned int iv_offset; /* or tweak key offset */ |
65 | | unsigned int key_extra_size; |
66 | | }; |
67 | | |
68 | | struct tcrypt_algs { |
69 | | unsigned int legacy:1; |
70 | | unsigned int chain_count; |
71 | | unsigned int chain_key_size; |
72 | | const char *long_name; |
73 | | const char *mode; |
74 | | struct tcrypt_alg cipher[3]; |
75 | | }; |
76 | | |
77 | | /* TCRYPT cipher variants */ |
78 | | static struct tcrypt_algs tcrypt_cipher[] = { |
79 | | /* XTS mode */ |
80 | | {0,1,64,"aes","xts-plain64", |
81 | | {{"aes", 64,16,0,32,0}}}, |
82 | | {0,1,64,"serpent","xts-plain64", |
83 | | {{"serpent",64,16,0,32,0}}}, |
84 | | {0,1,64,"twofish","xts-plain64", |
85 | | {{"twofish",64,16,0,32,0}}}, |
86 | | {0,2,128,"twofish-aes","xts-plain64", |
87 | | {{"twofish",64,16, 0,64,0}, |
88 | | {"aes", 64,16,32,96,0}}}, |
89 | | {0,3,192,"serpent-twofish-aes","xts-plain64", |
90 | | {{"serpent",64,16, 0, 96,0}, |
91 | | {"twofish",64,16,32,128,0}, |
92 | | {"aes", 64,16,64,160,0}}}, |
93 | | {0,2,128,"aes-serpent","xts-plain64", |
94 | | {{"aes", 64,16, 0,64,0}, |
95 | | {"serpent",64,16,32,96,0}}}, |
96 | | {0,3,192,"aes-twofish-serpent","xts-plain64", |
97 | | {{"aes", 64,16, 0, 96,0}, |
98 | | {"twofish",64,16,32,128,0}, |
99 | | {"serpent",64,16,64,160,0}}}, |
100 | | {0,2,128,"serpent-twofish","xts-plain64", |
101 | | {{"serpent",64,16, 0,64,0}, |
102 | | {"twofish",64,16,32,96,0}}}, |
103 | | {0,1,64,"camellia","xts-plain64", |
104 | | {{"camellia", 64,16,0,32,0}}}, |
105 | | {0,1,64,"kuznyechik","xts-plain64", |
106 | | {{"kuznyechik", 64,16,0,32,0}}}, |
107 | | {0,2,128,"kuznyechik-camellia","xts-plain64", |
108 | | {{"kuznyechik",64,16, 0,64,0}, |
109 | | {"camellia", 64,16,32,96,0}}}, |
110 | | {0,2,128,"twofish-kuznyechik","xts-plain64", |
111 | | {{"twofish", 64,16, 0,64,0}, |
112 | | {"kuznyechik",64,16,32,96,0}}}, |
113 | | {0,2,128,"serpent-camellia","xts-plain64", |
114 | | {{"serpent", 64,16, 0,64,0}, |
115 | | {"camellia", 64,16,32,96,0}}}, |
116 | | {0,2,128,"aes-kuznyechik","xts-plain64", |
117 | | {{"aes", 64,16, 0,64,0}, |
118 | | {"kuznyechik",64,16,32,96,0}}}, |
119 | | {0,3,192,"camellia-serpent-kuznyechik","xts-plain64", |
120 | | {{"camellia", 64,16, 0, 96,0}, |
121 | | {"serpent", 64,16,32,128,0}, |
122 | | {"kuznyechik",64,16,64,160,0}}}, |
123 | | |
124 | | /* LRW mode */ |
125 | | {0,1,48,"aes","lrw-benbi", |
126 | | {{"aes", 48,16,32,0,0}}}, |
127 | | {0,1,48,"serpent","lrw-benbi", |
128 | | {{"serpent",48,16,32,0,0}}}, |
129 | | {0,1,48,"twofish","lrw-benbi", |
130 | | {{"twofish",48,16,32,0,0}}}, |
131 | | {0,2,96,"twofish-aes","lrw-benbi", |
132 | | {{"twofish",48,16,32,0,0}, |
133 | | {"aes", 48,16,64,0,0}}}, |
134 | | {0,3,144,"serpent-twofish-aes","lrw-benbi", |
135 | | {{"serpent",48,16,32,0,0}, |
136 | | {"twofish",48,16,64,0,0}, |
137 | | {"aes", 48,16,96,0,0}}}, |
138 | | {0,2,96,"aes-serpent","lrw-benbi", |
139 | | {{"aes", 48,16,32,0,0}, |
140 | | {"serpent",48,16,64,0,0}}}, |
141 | | {0,3,144,"aes-twofish-serpent","lrw-benbi", |
142 | | {{"aes", 48,16,32,0,0}, |
143 | | {"twofish",48,16,64,0,0}, |
144 | | {"serpent",48,16,96,0,0}}}, |
145 | | {0,2,96,"serpent-twofish", "lrw-benbi", |
146 | | {{"serpent",48,16,32,0,0}, |
147 | | {"twofish",48,16,64,0,0}}}, |
148 | | |
149 | | /* Kernel LRW block size is fixed to 16 bytes for GF(2^128) |
150 | | * thus cannot be used with blowfish where block is 8 bytes. |
151 | | * There also no GF(2^64) support. |
152 | | {1,1,64,"blowfish_le","lrw-benbi", |
153 | | {{"blowfish_le",64,8,32,0,0}}}, |
154 | | {1,2,112,"blowfish_le-aes","lrw-benbi", |
155 | | {{"blowfish_le",64, 8,32,0,0}, |
156 | | {"aes", 48,16,88,0,0}}}, |
157 | | {1,3,160,"serpent-blowfish_le-aes","lrw-benbi", |
158 | | {{"serpent", 48,16, 32,0,0}, |
159 | | {"blowfish_le",64, 8, 64,0,0}, |
160 | | {"aes", 48,16,120,0,0}}},*/ |
161 | | |
162 | | /* |
163 | | * CBC + "outer" CBC (both with whitening) |
164 | | * chain_key_size: alg_keys_bytes + IV_seed_bytes + whitening_bytes |
165 | | */ |
166 | | {1,1,32+16+16,"aes","cbc-tcw", |
167 | | {{"aes", 32,16,32,0,32}}}, |
168 | | {1,1,32+16+16,"serpent","cbc-tcw", |
169 | | {{"serpent",32,16,32,0,32}}}, |
170 | | {1,1,32+16+16,"twofish","cbc-tcw", |
171 | | {{"twofish",32,16,32,0,32}}}, |
172 | | {1,2,64+16+16,"twofish-aes","cbci-tcrypt", |
173 | | {{"twofish",32,16,32,0,0}, |
174 | | {"aes", 32,16,64,0,32}}}, |
175 | | {1,3,96+16+16,"serpent-twofish-aes","cbci-tcrypt", |
176 | | {{"serpent",32,16,32,0,0}, |
177 | | {"twofish",32,16,64,0,0}, |
178 | | {"aes", 32,16,96,0,32}}}, |
179 | | {1,2,64+16+16,"aes-serpent","cbci-tcrypt", |
180 | | {{"aes", 32,16,32,0,0}, |
181 | | {"serpent",32,16,64,0,32}}}, |
182 | | {1,3,96+16+16,"aes-twofish-serpent", "cbci-tcrypt", |
183 | | {{"aes", 32,16,32,0,0}, |
184 | | {"twofish",32,16,64,0,0}, |
185 | | {"serpent",32,16,96,0,32}}}, |
186 | | {1,2,64+16+16,"serpent-twofish", "cbci-tcrypt", |
187 | | {{"serpent",32,16,32,0,0}, |
188 | | {"twofish",32,16,64,0,32}}}, |
189 | | {1,1,16+8+16,"cast5","cbc-tcw", |
190 | | {{"cast5", 16,8,32,0,24}}}, |
191 | | {1,1,24+8+16,"des3_ede","cbc-tcw", |
192 | | {{"des3_ede",24,8,32,0,24}}}, |
193 | | {1,1,56+8+16,"blowfish_le","cbc-tcrypt", |
194 | | {{"blowfish_le",56,8,32,0,24}}}, |
195 | | {1,2,88+16+16,"blowfish_le-aes","cbc-tcrypt", |
196 | | {{"blowfish_le",56, 8,32,0,0}, |
197 | | {"aes", 32,16,88,0,32}}}, |
198 | | {1,3,120+16+16,"serpent-blowfish_le-aes","cbc-tcrypt", |
199 | | {{"serpent", 32,16, 32,0,0}, |
200 | | {"blowfish_le",56, 8, 64,0,0}, |
201 | | {"aes", 32,16,120,0,32}}}, |
202 | | {} |
203 | | }; |
204 | | |
205 | | static int TCRYPT_hdr_from_disk(struct crypt_device *cd, |
206 | | struct tcrypt_phdr *hdr, |
207 | | struct crypt_params_tcrypt *params, |
208 | | int kdf_index, int cipher_index) |
209 | 0 | { |
210 | 0 | uint32_t crc32; |
211 | 0 | size_t size; |
212 | | |
213 | | /* Check CRC32 of header */ |
214 | 0 | size = TCRYPT_HDR_LEN - sizeof(hdr->d.keys) - sizeof(hdr->d.header_crc32); |
215 | 0 | crc32 = crypt_crc32(~0, (unsigned char*)&hdr->d, size) ^ ~0; |
216 | 0 | if (be16_to_cpu(hdr->d.version) > 3 && |
217 | 0 | crc32 != be32_to_cpu(hdr->d.header_crc32)) { |
218 | 0 | log_dbg(cd, "TCRYPT header CRC32 mismatch."); |
219 | 0 | return -EINVAL; |
220 | 0 | } |
221 | | |
222 | | /* Check CRC32 of keys */ |
223 | 0 | crc32 = crypt_crc32(~0, (unsigned char*)hdr->d.keys, sizeof(hdr->d.keys)) ^ ~0; |
224 | 0 | if (crc32 != be32_to_cpu(hdr->d.keys_crc32)) { |
225 | 0 | log_dbg(cd, "TCRYPT keys CRC32 mismatch."); |
226 | 0 | return -EINVAL; |
227 | 0 | } |
228 | | |
229 | | /* Convert header to cpu format */ |
230 | 0 | hdr->d.version = be16_to_cpu(hdr->d.version); |
231 | 0 | hdr->d.version_tc = be16_to_cpu(hdr->d.version_tc); |
232 | |
|
233 | 0 | hdr->d.keys_crc32 = be32_to_cpu(hdr->d.keys_crc32); |
234 | |
|
235 | 0 | hdr->d.hidden_volume_size = be64_to_cpu(hdr->d.hidden_volume_size); |
236 | 0 | hdr->d.volume_size = be64_to_cpu(hdr->d.volume_size); |
237 | |
|
238 | 0 | hdr->d.mk_offset = be64_to_cpu(hdr->d.mk_offset); |
239 | 0 | if (!hdr->d.mk_offset) |
240 | 0 | hdr->d.mk_offset = 512; |
241 | |
|
242 | 0 | hdr->d.mk_size = be64_to_cpu(hdr->d.mk_size); |
243 | |
|
244 | 0 | hdr->d.flags = be32_to_cpu(hdr->d.flags); |
245 | |
|
246 | 0 | hdr->d.sector_size = be32_to_cpu(hdr->d.sector_size); |
247 | 0 | if (!hdr->d.sector_size) |
248 | 0 | hdr->d.sector_size = 512; |
249 | |
|
250 | 0 | hdr->d.header_crc32 = be32_to_cpu(hdr->d.header_crc32); |
251 | | |
252 | | /* Set params */ |
253 | 0 | params->passphrase = NULL; |
254 | 0 | params->passphrase_size = 0; |
255 | 0 | params->hash_name = tcrypt_kdf[kdf_index].hash; |
256 | 0 | params->key_size = tcrypt_cipher[cipher_index].chain_key_size; |
257 | 0 | params->cipher = tcrypt_cipher[cipher_index].long_name; |
258 | 0 | params->mode = tcrypt_cipher[cipher_index].mode; |
259 | |
|
260 | 0 | return 0; |
261 | 0 | } |
262 | | |
263 | | /* |
264 | | * Kernel implements just big-endian version of blowfish, hack it here |
265 | | */ |
266 | | static void TCRYPT_swab_le(char *buf) |
267 | 0 | { |
268 | 0 | uint32_t *l = VOIDP_CAST(uint32_t*)&buf[0]; |
269 | 0 | uint32_t *r = VOIDP_CAST(uint32_t*)&buf[4]; |
270 | 0 | *l = swab32(*l); |
271 | 0 | *r = swab32(*r); |
272 | 0 | } |
273 | | |
274 | | static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg, |
275 | | const char *key, char *buf) |
276 | 0 | { |
277 | 0 | int bs = alg->iv_size; |
278 | 0 | char iv[8], iv_old[8]; |
279 | 0 | struct crypt_cipher *cipher = NULL; |
280 | 0 | int i, j, r; |
281 | |
|
282 | 0 | assert(bs == 8); |
283 | | |
284 | 0 | r = crypt_cipher_init(&cipher, "blowfish", "ecb", |
285 | 0 | &key[alg->key_offset], alg->key_size); |
286 | 0 | if (r < 0) |
287 | 0 | return r; |
288 | | |
289 | 0 | memcpy(iv, &key[alg->iv_offset], alg->iv_size); |
290 | 0 | for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { |
291 | 0 | memcpy(iv_old, &buf[i], bs); |
292 | 0 | TCRYPT_swab_le(&buf[i]); |
293 | 0 | r = crypt_cipher_decrypt(cipher, &buf[i], &buf[i], |
294 | 0 | bs, NULL, 0); |
295 | 0 | TCRYPT_swab_le(&buf[i]); |
296 | 0 | if (r < 0) |
297 | 0 | break; |
298 | 0 | for (j = 0; j < bs; j++) |
299 | 0 | buf[i + j] ^= iv[j]; |
300 | 0 | memcpy(iv, iv_old, bs); |
301 | 0 | } |
302 | |
|
303 | 0 | crypt_cipher_destroy(cipher); |
304 | 0 | crypt_safe_memzero(iv, bs); |
305 | 0 | crypt_safe_memzero(iv_old, bs); |
306 | 0 | return r; |
307 | 0 | } |
308 | | |
309 | | static void TCRYPT_remove_whitening(char *buf, const char *key) |
310 | 0 | { |
311 | 0 | int j; |
312 | |
|
313 | 0 | for (j = 0; j < TCRYPT_HDR_LEN; j++) |
314 | 0 | buf[j] ^= key[j % 8]; |
315 | 0 | } |
316 | | |
317 | | static void TCRYPT_copy_key(struct tcrypt_alg *alg, const char *mode, |
318 | | char *out_key, const char *key) |
319 | 0 | { |
320 | 0 | int ks2; |
321 | 0 | if (!strncmp(mode, "xts", 3)) { |
322 | 0 | ks2 = alg->key_size / 2; |
323 | 0 | crypt_safe_memcpy(out_key, &key[alg->key_offset], ks2); |
324 | 0 | crypt_safe_memcpy(&out_key[ks2], &key[alg->iv_offset], ks2); |
325 | 0 | } else if (!strncmp(mode, "lrw", 3)) { |
326 | 0 | ks2 = alg->key_size - TCRYPT_LRW_IKEY_LEN; |
327 | 0 | crypt_safe_memcpy(out_key, &key[alg->key_offset], ks2); |
328 | 0 | crypt_safe_memcpy(&out_key[ks2], key, TCRYPT_LRW_IKEY_LEN); |
329 | 0 | } else if (!strncmp(mode, "cbc", 3)) { |
330 | 0 | crypt_safe_memcpy(out_key, &key[alg->key_offset], alg->key_size); |
331 | | /* IV + whitening */ |
332 | 0 | crypt_safe_memcpy(&out_key[alg->key_size], &key[alg->iv_offset], |
333 | 0 | alg->key_extra_size); |
334 | 0 | } |
335 | 0 | } |
336 | | |
337 | | static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode, |
338 | | const char *key,struct tcrypt_phdr *hdr) |
339 | 0 | { |
340 | 0 | char backend_key[TCRYPT_HDR_KEY_LEN]; |
341 | 0 | char iv[TCRYPT_HDR_IV_LEN] = {}; |
342 | 0 | char mode_name[MAX_CIPHER_LEN + 1]; |
343 | 0 | struct crypt_cipher *cipher; |
344 | 0 | char *c, *buf = (char*)&hdr->e; |
345 | 0 | int r; |
346 | | |
347 | | /* Remove IV if present */ |
348 | 0 | mode_name[MAX_CIPHER_LEN] = '\0'; |
349 | 0 | strncpy(mode_name, mode, MAX_CIPHER_LEN); |
350 | 0 | c = strchr(mode_name, '-'); |
351 | 0 | if (c) |
352 | 0 | *c = '\0'; |
353 | |
|
354 | 0 | if (!strncmp(mode, "lrw", 3)) |
355 | 0 | iv[alg->iv_size - 1] = 1; |
356 | 0 | else if (!strncmp(mode, "cbc", 3)) { |
357 | 0 | TCRYPT_remove_whitening(buf, &key[8]); |
358 | 0 | if (!strcmp(alg->name, "blowfish_le")) |
359 | 0 | return decrypt_blowfish_le_cbc(alg, key, buf); |
360 | 0 | memcpy(iv, &key[alg->iv_offset], alg->iv_size); |
361 | 0 | } |
362 | | |
363 | 0 | TCRYPT_copy_key(alg, mode, backend_key, key); |
364 | 0 | r = crypt_cipher_init(&cipher, alg->name, mode_name, |
365 | 0 | backend_key, alg->key_size); |
366 | 0 | if (!r) { |
367 | 0 | r = crypt_cipher_decrypt(cipher, buf, buf, TCRYPT_HDR_LEN, |
368 | 0 | iv, alg->iv_size); |
369 | 0 | crypt_cipher_destroy(cipher); |
370 | 0 | } |
371 | |
|
372 | 0 | crypt_safe_memzero(backend_key, sizeof(backend_key)); |
373 | 0 | crypt_safe_memzero(iv, TCRYPT_HDR_IV_LEN); |
374 | 0 | return r; |
375 | 0 | } |
376 | | |
377 | | /* |
378 | | * For chained ciphers and CBC mode we need "outer" decryption. |
379 | | * Backend doesn't provide this, so implement it here directly using ECB. |
380 | | */ |
381 | | static int TCRYPT_decrypt_cbci(struct tcrypt_algs *ciphers, |
382 | | const char *key, struct tcrypt_phdr *hdr) |
383 | 0 | { |
384 | 0 | struct crypt_cipher *cipher[3]; |
385 | 0 | unsigned int bs = ciphers->cipher[0].iv_size; |
386 | 0 | char *buf = (char*)&hdr->e, iv[16], iv_old[16]; |
387 | 0 | unsigned int i, j; |
388 | 0 | int r = -EINVAL; |
389 | |
|
390 | 0 | assert(ciphers->chain_count <= 3); |
391 | 0 | assert(bs <= 16); |
392 | | |
393 | 0 | TCRYPT_remove_whitening(buf, &key[8]); |
394 | |
|
395 | 0 | memcpy(iv, &key[ciphers->cipher[0].iv_offset], bs); |
396 | | |
397 | | /* Initialize all ciphers in chain in ECB mode */ |
398 | 0 | for (j = 0; j < ciphers->chain_count; j++) |
399 | 0 | cipher[j] = NULL; |
400 | 0 | for (j = 0; j < ciphers->chain_count; j++) { |
401 | 0 | r = crypt_cipher_init(&cipher[j], ciphers->cipher[j].name, "ecb", |
402 | 0 | &key[ciphers->cipher[j].key_offset], |
403 | 0 | ciphers->cipher[j].key_size); |
404 | 0 | if (r < 0) |
405 | 0 | goto out; |
406 | 0 | } |
407 | | |
408 | | /* Implements CBC with chained ciphers in loop inside */ |
409 | 0 | for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { |
410 | 0 | memcpy(iv_old, &buf[i], bs); |
411 | 0 | for (j = ciphers->chain_count; j > 0; j--) { |
412 | 0 | r = crypt_cipher_decrypt(cipher[j - 1], &buf[i], &buf[i], |
413 | 0 | bs, NULL, 0); |
414 | 0 | if (r < 0) |
415 | 0 | goto out; |
416 | 0 | } |
417 | 0 | for (j = 0; j < bs; j++) |
418 | 0 | buf[i + j] ^= iv[j]; |
419 | 0 | memcpy(iv, iv_old, bs); |
420 | 0 | } |
421 | 0 | out: |
422 | 0 | for (j = 0; j < ciphers->chain_count; j++) |
423 | 0 | if (cipher[j]) |
424 | 0 | crypt_cipher_destroy(cipher[j]); |
425 | |
|
426 | 0 | crypt_safe_memzero(iv, bs); |
427 | 0 | crypt_safe_memzero(iv_old, bs); |
428 | 0 | return r; |
429 | 0 | } |
430 | | |
431 | | static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, |
432 | | const char *key, struct crypt_params_tcrypt *params) |
433 | 0 | { |
434 | 0 | struct tcrypt_phdr hdr2; |
435 | 0 | int i, j, r = -EINVAL; |
436 | |
|
437 | 0 | for (i = 0; tcrypt_cipher[i].chain_count; i++) { |
438 | 0 | if (params->cipher && !strstr(tcrypt_cipher[i].long_name, params->cipher)) |
439 | 0 | continue; |
440 | 0 | if (!(params->flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_cipher[i].legacy) |
441 | 0 | continue; |
442 | 0 | log_dbg(cd, "TCRYPT: trying cipher %s-%s", |
443 | 0 | tcrypt_cipher[i].long_name, tcrypt_cipher[i].mode); |
444 | |
|
445 | 0 | memcpy(&hdr2.e, &hdr->e, TCRYPT_HDR_LEN); |
446 | |
|
447 | 0 | if (!strncmp(tcrypt_cipher[i].mode, "cbci", 4)) |
448 | 0 | r = TCRYPT_decrypt_cbci(&tcrypt_cipher[i], key, &hdr2); |
449 | 0 | else for (j = tcrypt_cipher[i].chain_count - 1; j >= 0 ; j--) { |
450 | 0 | if (!tcrypt_cipher[i].cipher[j].name) |
451 | 0 | continue; |
452 | 0 | r = TCRYPT_decrypt_hdr_one(&tcrypt_cipher[i].cipher[j], |
453 | 0 | tcrypt_cipher[i].mode, key, &hdr2); |
454 | 0 | if (r < 0) |
455 | 0 | break; |
456 | 0 | } |
457 | |
|
458 | 0 | if (r < 0) { |
459 | 0 | log_dbg(cd, "TCRYPT: returned error %d, skipped.", r); |
460 | 0 | if (r == -ENOTSUP) |
461 | 0 | break; |
462 | 0 | r = -ENOENT; |
463 | 0 | continue; |
464 | 0 | } |
465 | | |
466 | 0 | if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) { |
467 | 0 | log_dbg(cd, "TCRYPT: Signature magic detected."); |
468 | 0 | memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN); |
469 | 0 | r = i; |
470 | 0 | break; |
471 | 0 | } |
472 | 0 | if ((params->flags & CRYPT_TCRYPT_VERA_MODES) && |
473 | 0 | !strncmp(hdr2.d.magic, VCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) { |
474 | 0 | log_dbg(cd, "TCRYPT: Signature magic detected (Veracrypt)."); |
475 | 0 | memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN); |
476 | 0 | r = i; |
477 | 0 | break; |
478 | 0 | } |
479 | 0 | r = -EPERM; |
480 | 0 | } |
481 | |
|
482 | 0 | crypt_safe_memzero(&hdr2, sizeof(hdr2)); |
483 | 0 | return r; |
484 | 0 | } |
485 | | |
486 | | static int TCRYPT_pool_keyfile(struct crypt_device *cd, |
487 | | unsigned char pool[VCRYPT_KEY_POOL_LEN], |
488 | | const char *keyfile, int keyfiles_pool_length) |
489 | 0 | { |
490 | 0 | unsigned char *data; |
491 | 0 | int i, j, fd, data_size, r = -EIO; |
492 | 0 | uint32_t crc; |
493 | |
|
494 | 0 | log_dbg(cd, "TCRYPT: using keyfile %s.", keyfile); |
495 | |
|
496 | 0 | data = malloc(TCRYPT_KEYFILE_LEN); |
497 | 0 | if (!data) |
498 | 0 | return -ENOMEM; |
499 | 0 | memset(data, 0, TCRYPT_KEYFILE_LEN); |
500 | |
|
501 | 0 | fd = open(keyfile, O_RDONLY); |
502 | 0 | if (fd < 0) { |
503 | 0 | log_err(cd, _("Failed to open key file.")); |
504 | 0 | goto out; |
505 | 0 | } |
506 | | |
507 | 0 | data_size = read_buffer(fd, data, TCRYPT_KEYFILE_LEN); |
508 | 0 | close(fd); |
509 | 0 | if (data_size < 0) { |
510 | 0 | log_err(cd, _("Error reading keyfile %s."), keyfile); |
511 | 0 | goto out; |
512 | 0 | } |
513 | | |
514 | 0 | for (i = 0, j = 0, crc = ~0U; i < data_size; i++) { |
515 | 0 | crc = crypt_crc32(crc, &data[i], 1); |
516 | 0 | pool[j++] += (unsigned char)(crc >> 24); |
517 | 0 | pool[j++] += (unsigned char)(crc >> 16); |
518 | 0 | pool[j++] += (unsigned char)(crc >> 8); |
519 | 0 | pool[j++] += (unsigned char)(crc); |
520 | 0 | j %= keyfiles_pool_length; |
521 | 0 | } |
522 | 0 | r = 0; |
523 | 0 | out: |
524 | 0 | crypt_safe_memzero(&crc, sizeof(crc)); |
525 | 0 | crypt_safe_memzero(data, TCRYPT_KEYFILE_LEN); |
526 | 0 | free(data); |
527 | |
|
528 | 0 | return r; |
529 | 0 | } |
530 | | |
531 | | static int TCRYPT_init_hdr(struct crypt_device *cd, |
532 | | struct tcrypt_phdr *hdr, |
533 | | struct crypt_params_tcrypt *params) |
534 | 0 | { |
535 | 0 | unsigned char pwd[VCRYPT_KEY_POOL_LEN] = {}; |
536 | 0 | size_t passphrase_size, max_passphrase_size; |
537 | 0 | char *key; |
538 | 0 | unsigned int i, skipped = 0, iterations; |
539 | 0 | int r = -EPERM, keyfiles_pool_length; |
540 | |
|
541 | 0 | if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN)) |
542 | 0 | return -ENOMEM; |
543 | | |
544 | 0 | if (params->flags & CRYPT_TCRYPT_VERA_MODES && |
545 | 0 | params->passphrase_size > TCRYPT_KEY_POOL_LEN) { |
546 | | /* Really. Keyfile pool length depends on passphrase size in Veracrypt. */ |
547 | 0 | max_passphrase_size = VCRYPT_KEY_POOL_LEN; |
548 | 0 | keyfiles_pool_length = VCRYPT_KEY_POOL_LEN; |
549 | 0 | } else { |
550 | 0 | max_passphrase_size = TCRYPT_KEY_POOL_LEN; |
551 | 0 | keyfiles_pool_length = TCRYPT_KEY_POOL_LEN; |
552 | 0 | } |
553 | |
|
554 | 0 | if (params->keyfiles_count) |
555 | 0 | passphrase_size = max_passphrase_size; |
556 | 0 | else |
557 | 0 | passphrase_size = params->passphrase_size; |
558 | |
|
559 | 0 | if (params->passphrase_size > max_passphrase_size) { |
560 | 0 | log_err(cd, _("Maximum TCRYPT passphrase length (%zu) exceeded."), |
561 | 0 | max_passphrase_size); |
562 | 0 | goto out; |
563 | 0 | } |
564 | | |
565 | | /* Calculate pool content from keyfiles */ |
566 | 0 | for (i = 0; i < params->keyfiles_count; i++) { |
567 | 0 | r = TCRYPT_pool_keyfile(cd, pwd, params->keyfiles[i], keyfiles_pool_length); |
568 | 0 | if (r < 0) |
569 | 0 | goto out; |
570 | 0 | } |
571 | | |
572 | | /* If provided password, combine it with pool */ |
573 | 0 | for (i = 0; i < params->passphrase_size; i++) |
574 | 0 | pwd[i] += params->passphrase[i]; |
575 | |
|
576 | 0 | for (i = 0; tcrypt_kdf[i].name; i++) { |
577 | 0 | if (params->hash_name && !strstr(tcrypt_kdf[i].hash, params->hash_name)) |
578 | 0 | continue; |
579 | 0 | if (!(params->flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_kdf[i].legacy) |
580 | 0 | continue; |
581 | 0 | if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt) |
582 | 0 | continue; |
583 | 0 | if ((params->flags & CRYPT_TCRYPT_VERA_MODES) && params->veracrypt_pim) { |
584 | | /* Do not try TrueCrypt modes if we have PIM value */ |
585 | 0 | if (!tcrypt_kdf[i].veracrypt) |
586 | 0 | continue; |
587 | | /* adjust iterations to given PIM cmdline parameter */ |
588 | 0 | iterations = tcrypt_kdf[i].veracrypt_pim_const + |
589 | 0 | (tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim); |
590 | 0 | } else |
591 | 0 | iterations = tcrypt_kdf[i].iterations; |
592 | | /* Derive header key */ |
593 | 0 | log_dbg(cd, "TCRYPT: trying KDF: %s-%s-%d%s.", |
594 | 0 | tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations, |
595 | 0 | params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : ""); |
596 | 0 | r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash, |
597 | 0 | (char*)pwd, passphrase_size, |
598 | 0 | hdr->salt, TCRYPT_HDR_SALT_LEN, |
599 | 0 | key, TCRYPT_HDR_KEY_LEN, |
600 | 0 | iterations, 0, 0); |
601 | 0 | if (r < 0) { |
602 | 0 | log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."), |
603 | 0 | tcrypt_kdf[i].hash); |
604 | 0 | skipped++; |
605 | 0 | r = -EPERM; |
606 | 0 | continue; |
607 | 0 | } |
608 | | |
609 | | /* Decrypt header */ |
610 | 0 | r = TCRYPT_decrypt_hdr(cd, hdr, key, params); |
611 | 0 | if (r == -ENOENT) { |
612 | 0 | skipped++; |
613 | 0 | r = -EPERM; |
614 | 0 | continue; |
615 | 0 | } |
616 | 0 | if (r != -EPERM) |
617 | 0 | break; |
618 | 0 | } |
619 | |
|
620 | 0 | if ((r < 0 && skipped && skipped == i) || r == -ENOTSUP) { |
621 | 0 | log_err(cd, _("Required kernel crypto interface not available.")); |
622 | 0 | #ifdef ENABLE_AF_ALG |
623 | 0 | log_err(cd, _("Ensure you have algif_skcipher kernel module loaded.")); |
624 | 0 | #endif |
625 | 0 | r = -ENOTSUP; |
626 | 0 | } |
627 | 0 | if (r < 0) |
628 | 0 | goto out; |
629 | | |
630 | 0 | r = TCRYPT_hdr_from_disk(cd, hdr, params, i, r); |
631 | 0 | if (!r) { |
632 | 0 | log_dbg(cd, "TCRYPT: Magic: %s, Header version: %d, req. %d, sector %d" |
633 | 0 | ", mk_offset %" PRIu64 ", hidden_size %" PRIu64 |
634 | 0 | ", volume size %" PRIu64, tcrypt_kdf[i].veracrypt ? |
635 | 0 | VCRYPT_HDR_MAGIC : TCRYPT_HDR_MAGIC, |
636 | 0 | (int)hdr->d.version, (int)hdr->d.version_tc, (int)hdr->d.sector_size, |
637 | 0 | hdr->d.mk_offset, hdr->d.hidden_volume_size, hdr->d.volume_size); |
638 | 0 | log_dbg(cd, "TCRYPT: Header cipher %s-%s, key size %zu", |
639 | 0 | params->cipher, params->mode, params->key_size); |
640 | 0 | } |
641 | 0 | out: |
642 | 0 | crypt_safe_memzero(pwd, TCRYPT_KEY_POOL_LEN); |
643 | 0 | if (key) |
644 | 0 | crypt_safe_memzero(key, TCRYPT_HDR_KEY_LEN); |
645 | 0 | free(key); |
646 | 0 | return r; |
647 | 0 | } |
648 | | |
649 | | int TCRYPT_read_phdr(struct crypt_device *cd, |
650 | | struct tcrypt_phdr *hdr, |
651 | | struct crypt_params_tcrypt *params) |
652 | 0 | { |
653 | 0 | struct device *base_device = NULL, *device = crypt_metadata_device(cd); |
654 | 0 | ssize_t hdr_size = sizeof(struct tcrypt_phdr); |
655 | 0 | char *base_device_path; |
656 | 0 | int devfd, r; |
657 | |
|
658 | 0 | assert(sizeof(struct tcrypt_phdr) == 512); |
659 | | |
660 | 0 | log_dbg(cd, "Reading TCRYPT header of size %zu bytes from device %s.", |
661 | 0 | hdr_size, device_path(device)); |
662 | |
|
663 | 0 | if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER && |
664 | 0 | crypt_dev_is_partition(device_path(device))) { |
665 | 0 | base_device_path = crypt_get_base_device(device_path(device)); |
666 | |
|
667 | 0 | log_dbg(cd, "Reading TCRYPT system header from device %s.", base_device_path ?: "?"); |
668 | 0 | if (!base_device_path) |
669 | 0 | return -EINVAL; |
670 | | |
671 | 0 | r = device_alloc(cd, &base_device, base_device_path); |
672 | 0 | free(base_device_path); |
673 | 0 | if (r < 0) |
674 | 0 | return r; |
675 | 0 | devfd = device_open(cd, base_device, O_RDONLY); |
676 | 0 | } else |
677 | 0 | devfd = device_open(cd, device, O_RDONLY); |
678 | | |
679 | 0 | if (devfd < 0) { |
680 | 0 | device_free(cd, base_device); |
681 | 0 | log_err(cd, _("Cannot open device %s."), device_path(device)); |
682 | 0 | return -EINVAL; |
683 | 0 | } |
684 | | |
685 | 0 | r = -EIO; |
686 | 0 | if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) { |
687 | 0 | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
688 | 0 | device_alignment(device), hdr, hdr_size, |
689 | 0 | TCRYPT_HDR_SYSTEM_OFFSET) == hdr_size) { |
690 | 0 | r = TCRYPT_init_hdr(cd, hdr, params); |
691 | 0 | } |
692 | 0 | } else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) { |
693 | 0 | if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) { |
694 | 0 | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
695 | 0 | device_alignment(device), hdr, hdr_size, |
696 | 0 | TCRYPT_HDR_HIDDEN_OFFSET_BCK) == hdr_size) |
697 | 0 | r = TCRYPT_init_hdr(cd, hdr, params); |
698 | 0 | } else { |
699 | 0 | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
700 | 0 | device_alignment(device), hdr, hdr_size, |
701 | 0 | TCRYPT_HDR_HIDDEN_OFFSET) == hdr_size) |
702 | 0 | r = TCRYPT_init_hdr(cd, hdr, params); |
703 | 0 | if (r && read_lseek_blockwise(devfd, device_block_size(cd, device), |
704 | 0 | device_alignment(device), hdr, hdr_size, |
705 | 0 | TCRYPT_HDR_HIDDEN_OFFSET_OLD) == hdr_size) |
706 | 0 | r = TCRYPT_init_hdr(cd, hdr, params); |
707 | 0 | } |
708 | 0 | } else if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) { |
709 | 0 | if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
710 | 0 | device_alignment(device), hdr, hdr_size, |
711 | 0 | TCRYPT_HDR_OFFSET_BCK) == hdr_size) |
712 | 0 | r = TCRYPT_init_hdr(cd, hdr, params); |
713 | 0 | } else if (read_lseek_blockwise(devfd, device_block_size(cd, device), |
714 | 0 | device_alignment(device), hdr, hdr_size, 0) == hdr_size) |
715 | 0 | r = TCRYPT_init_hdr(cd, hdr, params); |
716 | |
|
717 | 0 | device_free(cd, base_device); |
718 | 0 | if (r < 0) |
719 | 0 | memset(hdr, 0, sizeof (*hdr)); |
720 | 0 | return r; |
721 | 0 | } |
722 | | |
723 | | static struct tcrypt_algs *TCRYPT_get_algs(const char *cipher, const char *mode) |
724 | 0 | { |
725 | 0 | int i; |
726 | |
|
727 | 0 | if (!cipher || !mode) |
728 | 0 | return NULL; |
729 | | |
730 | 0 | for (i = 0; tcrypt_cipher[i].chain_count; i++) |
731 | 0 | if (!strcmp(tcrypt_cipher[i].long_name, cipher) && |
732 | 0 | !strcmp(tcrypt_cipher[i].mode, mode)) |
733 | 0 | return &tcrypt_cipher[i]; |
734 | | |
735 | 0 | return NULL; |
736 | 0 | } |
737 | | |
738 | | int TCRYPT_activate(struct crypt_device *cd, |
739 | | const char *name, |
740 | | struct tcrypt_phdr *hdr, |
741 | | struct crypt_params_tcrypt *params, |
742 | | uint32_t flags) |
743 | 0 | { |
744 | 0 | char dm_name[PATH_MAX], dm_dev_name[PATH_MAX], cipher_spec[MAX_CIPHER_LEN*2+1]; |
745 | 0 | char *part_path; |
746 | 0 | unsigned int i; |
747 | 0 | int r; |
748 | 0 | uint32_t req_flags, dmc_flags; |
749 | 0 | struct tcrypt_algs *algs; |
750 | 0 | enum devcheck device_check; |
751 | 0 | uint64_t offset = crypt_get_data_offset(cd); |
752 | 0 | struct volume_key *vk = NULL; |
753 | 0 | struct device *ptr_dev = crypt_data_device(cd), *device = NULL, *part_device = NULL; |
754 | 0 | struct crypt_dm_active_device dmd = { |
755 | 0 | .flags = flags |
756 | 0 | }; |
757 | |
|
758 | 0 | if (!hdr->d.version) { |
759 | 0 | log_dbg(cd, "TCRYPT: this function is not supported without encrypted header load."); |
760 | 0 | return -ENOTSUP; |
761 | 0 | } |
762 | | |
763 | 0 | if (hdr->d.sector_size % SECTOR_SIZE) { |
764 | 0 | log_err(cd, _("Activation is not supported for %d sector size."), |
765 | 0 | hdr->d.sector_size); |
766 | 0 | return -ENOTSUP; |
767 | 0 | } |
768 | | |
769 | 0 | if (strstr(params->mode, "-tcrypt")) { |
770 | 0 | log_err(cd, _("Kernel does not support activation for this TCRYPT legacy mode.")); |
771 | 0 | return -ENOTSUP; |
772 | 0 | } |
773 | | |
774 | 0 | if (strstr(params->mode, "-tcw")) |
775 | 0 | req_flags = DM_TCW_SUPPORTED; |
776 | 0 | else |
777 | 0 | req_flags = DM_PLAIN64_SUPPORTED; |
778 | |
|
779 | 0 | algs = TCRYPT_get_algs(params->cipher, params->mode); |
780 | 0 | if (!algs) |
781 | 0 | return -EINVAL; |
782 | | |
783 | 0 | if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) |
784 | 0 | dmd.size = 0; |
785 | 0 | else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) |
786 | 0 | dmd.size = hdr->d.hidden_volume_size / SECTOR_SIZE; |
787 | 0 | else |
788 | 0 | dmd.size = hdr->d.volume_size / SECTOR_SIZE; |
789 | |
|
790 | 0 | if (dmd.flags & CRYPT_ACTIVATE_SHARED) |
791 | 0 | device_check = DEV_OK; |
792 | 0 | else |
793 | 0 | device_check = DEV_EXCL; |
794 | |
|
795 | 0 | if ((params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) && |
796 | 0 | !crypt_dev_is_partition(device_path(crypt_data_device(cd)))) { |
797 | 0 | part_path = crypt_get_partition_device(device_path(crypt_data_device(cd)), |
798 | 0 | crypt_get_data_offset(cd), dmd.size); |
799 | 0 | if (part_path) { |
800 | 0 | if (!device_alloc(cd, &part_device, part_path)) { |
801 | 0 | log_verbose(cd, _("Activating TCRYPT system encryption for partition %s."), |
802 | 0 | part_path); |
803 | 0 | ptr_dev = part_device; |
804 | 0 | offset = 0; |
805 | 0 | } |
806 | 0 | free(part_path); |
807 | 0 | } else |
808 | | /* |
809 | | * System encryption use the whole device mapping, there can |
810 | | * be active partitions. |
811 | | */ |
812 | 0 | device_check = DEV_OK; |
813 | 0 | } |
814 | |
|
815 | 0 | r = device_block_adjust(cd, ptr_dev, device_check, |
816 | 0 | offset, &dmd.size, &dmd.flags); |
817 | 0 | if (r) |
818 | 0 | goto out; |
819 | | |
820 | | /* From here, key size for every cipher must be the same */ |
821 | 0 | vk = crypt_alloc_volume_key(algs->cipher[0].key_size + |
822 | 0 | algs->cipher[0].key_extra_size, NULL); |
823 | 0 | if (!vk) { |
824 | 0 | r = -ENOMEM; |
825 | 0 | goto out; |
826 | 0 | } |
827 | | |
828 | 0 | for (i = algs->chain_count; i > 0; i--) { |
829 | 0 | if (i == 1) { |
830 | 0 | dm_name[sizeof(dm_name)-1] = '\0'; |
831 | 0 | strncpy(dm_name, name, sizeof(dm_name)-1); |
832 | 0 | dmd.flags = flags; |
833 | 0 | } else { |
834 | 0 | if (snprintf(dm_name, sizeof(dm_name), "%s_%d", name, i-1) < 0) { |
835 | 0 | r = -EINVAL; |
836 | 0 | break; |
837 | 0 | } |
838 | 0 | dmd.flags = flags | CRYPT_ACTIVATE_PRIVATE; |
839 | 0 | } |
840 | | |
841 | 0 | TCRYPT_copy_key(&algs->cipher[i-1], algs->mode, |
842 | 0 | vk->key, hdr->d.keys); |
843 | |
|
844 | 0 | if (algs->chain_count != i) { |
845 | 0 | if (snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d", dm_get_dir(), name, i) < 0) { |
846 | 0 | r = -EINVAL; |
847 | 0 | break; |
848 | 0 | } |
849 | 0 | r = device_alloc(cd, &device, dm_dev_name); |
850 | 0 | if (r) |
851 | 0 | break; |
852 | 0 | ptr_dev = device; |
853 | 0 | offset = 0; |
854 | 0 | } |
855 | | |
856 | 0 | r = snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", algs->cipher[i-1].name, algs->mode); |
857 | 0 | if (r < 0 || (size_t)r >= sizeof(cipher_spec)) { |
858 | 0 | r = -ENOMEM; |
859 | 0 | break; |
860 | 0 | } |
861 | | |
862 | 0 | r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, ptr_dev, vk, |
863 | 0 | cipher_spec, crypt_get_iv_offset(cd), offset, |
864 | 0 | crypt_get_integrity(cd), |
865 | 0 | crypt_get_integrity_tag_size(cd), |
866 | 0 | crypt_get_sector_size(cd)); |
867 | 0 | if (r) |
868 | 0 | break; |
869 | | |
870 | 0 | log_dbg(cd, "Trying to activate TCRYPT device %s using cipher %s.", |
871 | 0 | dm_name, dmd.segment.u.crypt.cipher); |
872 | 0 | r = dm_create_device(cd, dm_name, CRYPT_TCRYPT, &dmd); |
873 | |
|
874 | 0 | dm_targets_free(cd, &dmd); |
875 | 0 | device_free(cd, device); |
876 | 0 | device = NULL; |
877 | |
|
878 | 0 | if (r) |
879 | 0 | break; |
880 | 0 | } |
881 | |
|
882 | 0 | if (r < 0 && |
883 | 0 | (dm_flags(cd, DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) { |
884 | 0 | log_err(cd, _("Kernel does not support TCRYPT compatible mapping.")); |
885 | 0 | r = -ENOTSUP; |
886 | 0 | } |
887 | |
|
888 | 0 | out: |
889 | 0 | crypt_free_volume_key(vk); |
890 | 0 | device_free(cd, device); |
891 | 0 | device_free(cd, part_device); |
892 | 0 | return r; |
893 | 0 | } |
894 | | |
895 | | static int TCRYPT_remove_one(struct crypt_device *cd, const char *name, |
896 | | const char *base_uuid, int index, uint32_t flags) |
897 | 0 | { |
898 | 0 | struct crypt_dm_active_device dmd; |
899 | 0 | char dm_name[PATH_MAX]; |
900 | 0 | int r; |
901 | |
|
902 | 0 | if (snprintf(dm_name, sizeof(dm_name), "%s_%d", name, index) < 0) |
903 | 0 | return -ENOMEM; |
904 | | |
905 | 0 | r = dm_status_device(cd, dm_name); |
906 | 0 | if (r < 0) |
907 | 0 | return r; |
908 | | |
909 | 0 | r = dm_query_device(cd, dm_name, DM_ACTIVE_UUID, &dmd); |
910 | 0 | if (!r && !strncmp(dmd.uuid, base_uuid, strlen(base_uuid))) |
911 | 0 | r = dm_remove_device(cd, dm_name, flags); |
912 | |
|
913 | 0 | free(CONST_CAST(void*)dmd.uuid); |
914 | 0 | return r; |
915 | 0 | } |
916 | | |
917 | | int TCRYPT_deactivate(struct crypt_device *cd, const char *name, uint32_t flags) |
918 | 0 | { |
919 | 0 | struct crypt_dm_active_device dmd; |
920 | 0 | int r; |
921 | |
|
922 | 0 | r = dm_query_device(cd, name, DM_ACTIVE_UUID, &dmd); |
923 | 0 | if (r < 0) |
924 | 0 | return r; |
925 | 0 | if (!dmd.uuid) |
926 | 0 | return -EINVAL; |
927 | | |
928 | 0 | r = dm_remove_device(cd, name, flags); |
929 | 0 | if (r < 0) |
930 | 0 | goto out; |
931 | | |
932 | 0 | r = TCRYPT_remove_one(cd, name, dmd.uuid, 1, flags); |
933 | 0 | if (r < 0) |
934 | 0 | goto out; |
935 | | |
936 | 0 | r = TCRYPT_remove_one(cd, name, dmd.uuid, 2, flags); |
937 | 0 | out: |
938 | 0 | free(CONST_CAST(void*)dmd.uuid); |
939 | 0 | return (r == -ENODEV) ? 0 : r; |
940 | 0 | } |
941 | | |
942 | | static int TCRYPT_status_one(struct crypt_device *cd, const char *name, |
943 | | const char *base_uuid, int index, |
944 | | size_t *key_size, char *cipher, |
945 | | struct tcrypt_phdr *tcrypt_hdr, |
946 | | struct device **device) |
947 | 0 | { |
948 | 0 | struct crypt_dm_active_device dmd; |
949 | 0 | struct dm_target *tgt = &dmd.segment; |
950 | 0 | char dm_name[PATH_MAX], *c; |
951 | 0 | int r; |
952 | |
|
953 | 0 | if (snprintf(dm_name, sizeof(dm_name), "%s_%d", name, index) < 0) |
954 | 0 | return -ENOMEM; |
955 | | |
956 | 0 | r = dm_status_device(cd, dm_name); |
957 | 0 | if (r < 0) |
958 | 0 | return r; |
959 | | |
960 | 0 | r = dm_query_device(cd, dm_name, DM_ACTIVE_DEVICE | |
961 | 0 | DM_ACTIVE_UUID | |
962 | 0 | DM_ACTIVE_CRYPT_CIPHER | |
963 | 0 | DM_ACTIVE_CRYPT_KEYSIZE, &dmd); |
964 | 0 | if (r < 0) |
965 | 0 | return r; |
966 | 0 | if (!single_segment(&dmd) || tgt->type != DM_CRYPT) { |
967 | 0 | r = -ENOTSUP; |
968 | 0 | goto out; |
969 | 0 | } |
970 | | |
971 | 0 | r = 0; |
972 | |
|
973 | 0 | if (!strncmp(dmd.uuid, base_uuid, strlen(base_uuid))) { |
974 | 0 | if ((c = strchr(tgt->u.crypt.cipher, '-'))) |
975 | 0 | *c = '\0'; |
976 | 0 | strcat(cipher, "-"); |
977 | 0 | strncat(cipher, tgt->u.crypt.cipher, MAX_CIPHER_LEN); |
978 | 0 | *key_size += tgt->u.crypt.vk->keylength; |
979 | 0 | tcrypt_hdr->d.mk_offset = tgt->u.crypt.offset * SECTOR_SIZE; |
980 | 0 | device_free(cd, *device); |
981 | 0 | MOVE_REF(*device, tgt->data_device); |
982 | 0 | } else |
983 | 0 | r = -ENODEV; |
984 | 0 | out: |
985 | 0 | dm_targets_free(cd, &dmd); |
986 | 0 | free(CONST_CAST(void*)dmd.uuid); |
987 | 0 | return r; |
988 | 0 | } |
989 | | |
990 | | int TCRYPT_init_by_name(struct crypt_device *cd, const char *name, |
991 | | const char *uuid, |
992 | | const struct dm_target *tgt, |
993 | | struct device **device, |
994 | | struct crypt_params_tcrypt *tcrypt_params, |
995 | | struct tcrypt_phdr *tcrypt_hdr) |
996 | 0 | { |
997 | 0 | struct tcrypt_algs *algs; |
998 | 0 | char cipher[MAX_CIPHER_LEN * 4], mode[MAX_CIPHER_LEN+1], *tmp; |
999 | 0 | size_t key_size; |
1000 | 0 | int r; |
1001 | |
|
1002 | 0 | memset(tcrypt_params, 0, sizeof(*tcrypt_params)); |
1003 | 0 | memset(tcrypt_hdr, 0, sizeof(*tcrypt_hdr)); |
1004 | 0 | tcrypt_hdr->d.sector_size = SECTOR_SIZE; |
1005 | 0 | tcrypt_hdr->d.mk_offset = tgt->u.crypt.offset * SECTOR_SIZE; |
1006 | |
|
1007 | 0 | strncpy(cipher, tgt->u.crypt.cipher, MAX_CIPHER_LEN); |
1008 | 0 | tmp = strchr(cipher, '-'); |
1009 | 0 | if (!tmp) |
1010 | 0 | return -EINVAL; |
1011 | 0 | *tmp = '\0'; |
1012 | 0 | mode[MAX_CIPHER_LEN] = '\0'; |
1013 | 0 | strncpy(mode, ++tmp, MAX_CIPHER_LEN); |
1014 | |
|
1015 | 0 | key_size = tgt->u.crypt.vk->keylength; |
1016 | 0 | r = TCRYPT_status_one(cd, name, uuid, 1, &key_size, |
1017 | 0 | cipher, tcrypt_hdr, device); |
1018 | 0 | if (!r) |
1019 | 0 | r = TCRYPT_status_one(cd, name, uuid, 2, &key_size, |
1020 | 0 | cipher, tcrypt_hdr, device); |
1021 | |
|
1022 | 0 | if (r < 0 && r != -ENODEV) |
1023 | 0 | return r; |
1024 | | |
1025 | 0 | algs = TCRYPT_get_algs(cipher, mode); |
1026 | 0 | if (!algs || key_size != algs->chain_key_size) |
1027 | 0 | return -EINVAL; |
1028 | | |
1029 | 0 | tcrypt_params->key_size = algs->chain_key_size; |
1030 | 0 | tcrypt_params->cipher = algs->long_name; |
1031 | 0 | tcrypt_params->mode = algs->mode; |
1032 | 0 | return 0; |
1033 | 0 | } |
1034 | | |
1035 | | uint64_t TCRYPT_get_data_offset(struct crypt_device *cd, |
1036 | | struct tcrypt_phdr *hdr, |
1037 | | struct crypt_params_tcrypt *params) |
1038 | 0 | { |
1039 | 0 | uint64_t size; |
1040 | |
|
1041 | 0 | if (!hdr->d.version) { |
1042 | | /* No real header loaded, initialized by active device, use default mk_offset */ |
1043 | 0 | } else if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) { |
1044 | | /* Mapping through whole device, not partition! */ |
1045 | 0 | if (crypt_dev_is_partition(device_path(crypt_data_device(cd)))) |
1046 | 0 | return 0; |
1047 | 0 | } else if (params->mode && !strncmp(params->mode, "xts", 3)) { |
1048 | 0 | if (hdr->d.version < 3) |
1049 | 0 | return 1; |
1050 | | |
1051 | 0 | if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) { |
1052 | 0 | if (hdr->d.version > 3) |
1053 | 0 | return (hdr->d.mk_offset / SECTOR_SIZE); |
1054 | 0 | if (device_size(crypt_metadata_device(cd), &size) < 0) |
1055 | 0 | return 0; |
1056 | 0 | return (size - hdr->d.hidden_volume_size + |
1057 | 0 | (TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / SECTOR_SIZE; |
1058 | 0 | } |
1059 | 0 | } else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) { |
1060 | 0 | if (device_size(crypt_metadata_device(cd), &size) < 0) |
1061 | 0 | return 0; |
1062 | 0 | return (size - hdr->d.hidden_volume_size + |
1063 | 0 | (TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / SECTOR_SIZE; |
1064 | 0 | } |
1065 | | |
1066 | 0 | return hdr->d.mk_offset / SECTOR_SIZE; |
1067 | 0 | } |
1068 | | |
1069 | | uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd, |
1070 | | struct tcrypt_phdr *hdr, |
1071 | | struct crypt_params_tcrypt *params) |
1072 | 0 | { |
1073 | 0 | uint64_t iv_offset, partition_offset; |
1074 | |
|
1075 | 0 | if (params->mode && !strncmp(params->mode, "xts", 3)) |
1076 | 0 | iv_offset = TCRYPT_get_data_offset(cd, hdr, params); |
1077 | 0 | else if (params->mode && !strncmp(params->mode, "lrw", 3)) |
1078 | 0 | iv_offset = 0; |
1079 | 0 | else |
1080 | 0 | iv_offset = hdr->d.mk_offset / SECTOR_SIZE; |
1081 | |
|
1082 | 0 | if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) { |
1083 | 0 | partition_offset = crypt_dev_partition_offset(device_path(crypt_data_device(cd))); |
1084 | | /* FIXME: we need to deal with overflow sooner */ |
1085 | 0 | if (iv_offset > (UINT64_MAX - partition_offset)) |
1086 | 0 | iv_offset = UINT64_MAX; |
1087 | 0 | else |
1088 | 0 | iv_offset += partition_offset; |
1089 | 0 | } |
1090 | |
|
1091 | 0 | return iv_offset; |
1092 | 0 | } |
1093 | | |
1094 | | int TCRYPT_get_volume_key(struct crypt_device *cd, |
1095 | | struct tcrypt_phdr *hdr, |
1096 | | struct crypt_params_tcrypt *params, |
1097 | | struct volume_key **vk) |
1098 | 0 | { |
1099 | 0 | struct tcrypt_algs *algs; |
1100 | 0 | unsigned int i, key_index; |
1101 | |
|
1102 | 0 | if (!hdr->d.version) { |
1103 | 0 | log_err(cd, _("This function is not supported without TCRYPT header load.")); |
1104 | 0 | return -ENOTSUP; |
1105 | 0 | } |
1106 | | |
1107 | 0 | algs = TCRYPT_get_algs(params->cipher, params->mode); |
1108 | 0 | if (!algs) |
1109 | 0 | return -EINVAL; |
1110 | | |
1111 | 0 | *vk = crypt_alloc_volume_key(params->key_size, NULL); |
1112 | 0 | if (!*vk) |
1113 | 0 | return -ENOMEM; |
1114 | | |
1115 | 0 | for (i = 0, key_index = 0; i < algs->chain_count; i++) { |
1116 | 0 | TCRYPT_copy_key(&algs->cipher[i], algs->mode, |
1117 | 0 | &(*vk)->key[key_index], hdr->d.keys); |
1118 | 0 | key_index += algs->cipher[i].key_size; |
1119 | 0 | } |
1120 | |
|
1121 | 0 | return 0; |
1122 | 0 | } |
1123 | | |
1124 | | int TCRYPT_dump(struct crypt_device *cd, |
1125 | | struct tcrypt_phdr *hdr, |
1126 | | struct crypt_params_tcrypt *params) |
1127 | 0 | { |
1128 | 0 | log_std(cd, "%s header information for %s\n", |
1129 | 0 | hdr->d.magic[0] == 'T' ? "TCRYPT" : "VERACRYPT", |
1130 | 0 | device_path(crypt_metadata_device(cd))); |
1131 | 0 | if (hdr->d.version) { |
1132 | 0 | log_std(cd, "Version: \t%d\n", hdr->d.version); |
1133 | 0 | log_std(cd, "Driver req.:\t%x.%x\n", hdr->d.version_tc >> 8, |
1134 | 0 | hdr->d.version_tc & 0xFF); |
1135 | |
|
1136 | 0 | log_std(cd, "Sector size:\t%" PRIu32 "\n", hdr->d.sector_size); |
1137 | 0 | log_std(cd, "MK offset:\t%" PRIu64 "\n", hdr->d.mk_offset); |
1138 | 0 | log_std(cd, "PBKDF2 hash:\t%s\n", params->hash_name); |
1139 | 0 | } |
1140 | 0 | log_std(cd, "Cipher chain:\t%s\n", params->cipher); |
1141 | 0 | log_std(cd, "Cipher mode:\t%s\n", params->mode); |
1142 | 0 | log_std(cd, "MK bits: \t%zu\n", params->key_size * 8); |
1143 | 0 | return 0; |
1144 | 0 | } |