(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
cs_fvault2.c
       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  };