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