1 /*
2 * Copyright (C) 2022 Milan Broz <gmazyland@gmail.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7
8 #include "superblocks.h"
9 #include "crc32c.h"
10
11 /*
12 * For header details, see:
13 * https://github.com/libyal/libfvde/blob/main/documentation/FileVault%20Drive%20Encryption%20(FVDE).asciidoc
14 * https://is.muni.cz/auth/th/p0aok/thesis.pdf
15 */
16
17 /* Apple Core Storage magic bytes */
18 #define CS_MAGIC "CS"
19
20 struct crc32_checksum {
21 uint32_t value;
22 uint32_t seed;
23 } __attribute__((packed));
24
25 /*
26 * The superblock structure describes "physical volume"; Core Storage
27 * then uses another abstractions above, similar to LVM.
28 * After activation through dm-crypt, filesystem (usually HFS+) is on top.
29 * The filesystem block size and used data size cannot be directly derived from
30 * this superblock structure without parsing other metadata blocks.
31 */
32
33 struct cs_fvault2_sb {
34 struct crc32_checksum checksum;
35 uint16_t version;
36 uint16_t block_type;
37 uint8_t unknown1[52];
38 uint64_t ph_vol_size;
39 uint8_t unknown2[16];
40 uint16_t magic;
41 uint32_t checksum_algo;
42 uint8_t unknown3[2];
43 uint32_t block_size;
44 uint32_t metadata_size;
45 uint64_t disklbl_blkoff;
46 uint64_t other_md_blkoffs[3];
47 uint8_t unknown4[32];
48 uint32_t key_data_size;
49 uint32_t cipher;
50 uint8_t key_data[16];
51 uint8_t unknown5[112];
52 uint8_t ph_vol_uuid[16];
53 uint8_t unknown6[192];
54 } __attribute__((packed));
55
56 static int cs_fvault2_verify_csum(blkid_probe pr, const struct cs_fvault2_sb *sb)
57 {
58 uint32_t seed = le32_to_cpu(sb->checksum.seed);
59 uint32_t crc = le32_to_cpu(sb->checksum.value);
60 unsigned char *buf = (unsigned char *)sb + sizeof(sb->checksum);
61 size_t buf_size = sizeof(*sb) - sizeof(sb->checksum);
62
63 return blkid_probe_verify_csum(pr, crc32c(seed, buf, buf_size), crc);
64 }
65
66 static int probe_cs_fvault2(blkid_probe pr, const struct blkid_idmag *mag)
67 {
68 struct cs_fvault2_sb *sb;
69
70 sb = blkid_probe_get_sb(pr, mag, struct cs_fvault2_sb);
71 if (!sb)
72 return errno ? -errno : BLKID_PROBE_NONE;
73
74 /* Apple Core storage Physical Volume Header; only type 1 checksum is supported */
75 if (le16_to_cpu(sb->version) != 1 ||
76 le32_to_cpu(sb->checksum_algo) != 1)
77 return BLKID_PROBE_NONE;
78
79 if (!cs_fvault2_verify_csum(pr, sb))
80 return BLKID_PROBE_NONE;
81
82 /* We support only block type 0x10 as it should be used for FileVault2 */
83 if (le16_to_cpu(sb->block_type) != 0x10 ||
84 le32_to_cpu(sb->key_data_size) != 16 ||
85 le32_to_cpu(sb->cipher) != 2 /* AES-XTS */)
86 return BLKID_PROBE_NONE;
87
88 blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(sb->version));
89 blkid_probe_set_uuid(pr, sb->ph_vol_uuid);
90
91 return BLKID_PROBE_OK;
92 }
93
94 const struct blkid_idinfo cs_fvault2_idinfo =
95 {
96 .name = "cs_fvault2",
97 .usage = BLKID_USAGE_CRYPTO,
98 .probefunc = probe_cs_fvault2,
99 .magics =
100 {
101 { .magic = CS_MAGIC, .len = 2, .sboff = 88 },
102 { NULL }
103 }
104 };