/src/util-linux/libblkid/src/superblocks/cs_fvault2.c
Line | Count | Source |
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 | 8 | { |
58 | 8 | uint32_t seed = le32_to_cpu(sb->checksum.seed); |
59 | 8 | uint32_t crc = le32_to_cpu(sb->checksum.value); |
60 | 8 | unsigned char *buf = (unsigned char *)sb + sizeof(sb->checksum); |
61 | 8 | size_t buf_size = sizeof(*sb) - sizeof(sb->checksum); |
62 | | |
63 | 8 | return blkid_probe_verify_csum(pr, crc32c(seed, buf, buf_size), crc); |
64 | 8 | } |
65 | | |
66 | | static int probe_cs_fvault2(blkid_probe pr, const struct blkid_idmag *mag) |
67 | 1.40k | { |
68 | 1.40k | const struct cs_fvault2_sb *sb; |
69 | | |
70 | 1.40k | sb = blkid_probe_get_sb(pr, mag, struct cs_fvault2_sb); |
71 | 1.40k | if (!sb) |
72 | 0 | return errno ? -errno : BLKID_PROBE_NONE; |
73 | | |
74 | | /* Apple Core storage Physical Volume Header; only type 1 checksum is supported */ |
75 | 1.40k | if (le16_to_cpu(sb->version) != 1 || |
76 | 226 | le32_to_cpu(sb->checksum_algo) != 1) |
77 | 1.39k | return BLKID_PROBE_NONE; |
78 | | |
79 | 8 | if (!cs_fvault2_verify_csum(pr, sb)) |
80 | 8 | return BLKID_PROBE_NONE; |
81 | | |
82 | | /* We support only block type 0x10 as it should be used for FileVault2 */ |
83 | 0 | if (le16_to_cpu(sb->block_type) != 0x10 || |
84 | 0 | le32_to_cpu(sb->key_data_size) != 16 || |
85 | 0 | le32_to_cpu(sb->cipher) != 2 /* AES-XTS */) |
86 | 0 | return BLKID_PROBE_NONE; |
87 | | |
88 | 0 | blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(sb->version)); |
89 | 0 | blkid_probe_set_uuid(pr, sb->ph_vol_uuid); |
90 | |
|
91 | 0 | return BLKID_PROBE_OK; |
92 | 0 | } |
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 | | }; |