diff options
Diffstat (limited to 'libblkid/src/superblocks/bitlocker.c')
-rw-r--r-- | libblkid/src/superblocks/bitlocker.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/libblkid/src/superblocks/bitlocker.c b/libblkid/src/superblocks/bitlocker.c new file mode 100644 index 0000000..111edf3 --- /dev/null +++ b/libblkid/src/superblocks/bitlocker.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2018 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +#define BDE_HDR_SIZE 512 +#define BDE_HDR_OFFSET 0 + +struct bde_header_win7 { +/* 0 */ unsigned char boot_entry_point[3]; +/* 3 */ unsigned char fs_signature[8]; +/* 11 */ unsigned char __dummy1[67 - 11]; +/* 67 */ uint32_t volume_serial; /* NTFS uses 64bit serial number */ +/* 71 */ unsigned char volume_label[11]; /* "NO NAME\x20\x20\x20\x20" only */ +/* 82 */ unsigned char __dummy2[160 - 82]; +/* 160 */ unsigned char guid[16]; /* BitLocker specific GUID */ +/* 176 */ uint64_t fve_metadata_offset; +} __attribute__((packed)); + + +struct bde_header_togo { +/* 0 */ unsigned char boot_entry_point[3]; +/* 3 */ unsigned char fs_signature[8]; +/* 11 */ unsigned char __dummy[424 - 11]; +/* 424 */ unsigned char guid[16]; +/* 440 */ uint64_t fve_metadata_offset; +} __attribute__((packed)); + + +struct bde_fve_metadata { +/* 0 */ unsigned char signature[8]; +/* 8 */ uint16_t size; +/* 10 */ uint16_t version; +}; + +enum { + BDE_VERSION_VISTA = 0, + BDE_VERSION_WIN7, + BDE_VERSION_TOGO +}; + +#define BDE_MAGIC_VISTA "\xeb\x52\x90-FVE-FS-" +#define BDE_MAGIC_WIN7 "\xeb\x58\x90-FVE-FS-" +#define BDE_MAGIC_TOGO "\xeb\x58\x90MSWIN4.1" + +#define BDE_MAGIC_FVE "-FVE-FS-" + +static int get_bitlocker_type(const unsigned char *buf) +{ + size_t i; + static const char *map[] = { + [BDE_VERSION_VISTA] = BDE_MAGIC_VISTA, + [BDE_VERSION_WIN7] = BDE_MAGIC_WIN7, + [BDE_VERSION_TOGO] = BDE_MAGIC_TOGO + }; + + for (i = 0; i < ARRAY_SIZE(map); i++) { + if (memcmp(buf, map[i], 11) == 0) + return (int) i; + } + + return -1; +} + +/* Returns: < 0 error, 1 nothing, 0 success + */ +static int get_bitlocker_headers(blkid_probe pr, + int *type, + const unsigned char **buf_hdr, + const unsigned char **buf_fve) +{ + + const unsigned char *buf; + const struct bde_fve_metadata *fve; + uint64_t off = 0; + int kind; + + if (buf_hdr) + *buf_hdr = NULL; + if (buf_fve) + *buf_fve = NULL; + if (type) + *type = -1; + + buf = blkid_probe_get_buffer(pr, BDE_HDR_OFFSET, BDE_HDR_SIZE); + if (!buf) + return errno ? -errno : 1; + + kind = get_bitlocker_type(buf); + + /* Check BitLocker header */ + switch (kind) { + case BDE_VERSION_WIN7: + off = le64_to_cpu(((const struct bde_header_win7 *) buf)->fve_metadata_offset); + break; + case BDE_VERSION_TOGO: + off = le64_to_cpu(((const struct bde_header_togo *) buf)->fve_metadata_offset); + break; + case BDE_VERSION_VISTA: + goto done; + default: + goto nothing; + } + + if (!off) + goto nothing; + if (buf_hdr) + *buf_hdr = buf; + + /* Check Bitlocker FVE metadata header */ + buf = blkid_probe_get_buffer(pr, off, sizeof(struct bde_fve_metadata)); + if (!buf) + return errno ? -errno : 1; + + fve = (const struct bde_fve_metadata *) buf; + if (memcmp(fve->signature, BDE_MAGIC_FVE, sizeof(fve->signature)) != 0) + goto nothing; + if (buf_fve) + *buf_fve = buf; +done: + if (type) + *type = kind; + return 0; +nothing: + return 1; +} + +/* + * This is used by vFAT and NTFS prober to avoid collisions with bitlocker. + */ +int blkid_probe_is_bitlocker(blkid_probe pr) +{ + return get_bitlocker_headers(pr, NULL, NULL, NULL) == 0; +} + +static int probe_bitlocker(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + const unsigned char *buf_fve = NULL; + const unsigned char *buf_hdr = NULL; + int rc, kind; + + rc = get_bitlocker_headers(pr, &kind, &buf_hdr, &buf_fve); + if (rc) + return rc; + + if (kind == BDE_VERSION_WIN7) { + const struct bde_header_win7 *hdr = (const struct bde_header_win7 *) buf_hdr; + + /* Unfortunately, it seems volume_serial is always zero */ + blkid_probe_sprintf_uuid(pr, + (const unsigned char *) &hdr->volume_serial, + sizeof(hdr->volume_serial), + "%016d", le32_to_cpu(hdr->volume_serial)); + } + + if (buf_fve) { + const struct bde_fve_metadata *fve = (const struct bde_fve_metadata *) buf_fve; + + blkid_probe_sprintf_version(pr, "%d", fve->version); + } + return 0; +} + +/* See header details: + * https://github.com/libyal/libbde/blob/master/documentation/BitLocker%20Drive%20Encryption%20(BDE)%20format.asciidoc + */ +const struct blkid_idinfo bitlocker_idinfo = +{ + .name = "BitLocker", + .usage = BLKID_USAGE_CRYPTO, + .probefunc = probe_bitlocker, + .magics = + { + { .magic = BDE_MAGIC_VISTA, .len = 11 }, + { .magic = BDE_MAGIC_WIN7, .len = 11 }, + { .magic = BDE_MAGIC_TOGO, .len = 11 }, + { NULL } + } +}; |