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