Big changes

Remove disk_op_data global variable in the library
Extract file & fuse outputs in two standalone binaries
Provide global stub functions for dislocker library
Add FIXMEs & TODOs everywhere...
This commit is contained in:
Aorimn
2014-08-15 22:01:31 +02:00
parent 000484f882
commit 052d7ca8a0
20 changed files with 1432 additions and 1375 deletions
+24 -30
View File
@@ -27,10 +27,11 @@ CFLAGS = $(WFLAGS) $(DEFINES) $(INC) $(CHARDEN)
override LDFLAGS += $(LIB) $(LHARDEN)
LIBNAME = lib$(PROGNAME).so
BINS = dislocker dislocker-metadata dislocker-bek
SUFFIXES = fuse file metadata bek
BINS = $(foreach suf, $(SUFFIXES), $(BIN)-$(suf))
BINS_OBJECTS = $(foreach bin, $(BINS), $(bin).o)
SOURCES = common.c config.c sectors.c \
SOURCES = dislocker.c common.c config.c sectors.c \
xstd/xstdio.c xstd/xstdlib.c \
metadata/datums.c metadata/metadata.c metadata/vmk.c \
metadata/fvek.c metadata/extended_info.c \
@@ -55,8 +56,6 @@ MAN_NUMBER = 1
MAN_PATH = $(DESTDIR)/share/man/man$(MAN_NUMBER)/
MAN_ROOT = ../man/
FUSE_ROOT := outputs/fuse/fuse
FILE_ROOT := outputs/file/file
@@ -85,41 +84,25 @@ endif
export
.PHONY : all libs static $(BIN) file fuse common clean
.PHONY : all libs $(BIN) $(SUFFIXES) install uninstall clean travis-install valgrind snapshot release
.c.o :
$(CC) $(CFLAGS) -c -o $@ $<
all : fuse
all : $(BIN)
libs: $(OBJECTS)
$(CC) -shared $(CFLAGS) -o $(LIBNAME) $(OBJECTS)
# Default rules for final binaries
touch :
touch $(BIN).c
$(BIN) : touch libs $(BINS_OBJECTS)
for prog in $(BINS); do \
$(CC) $(CFLAGS) -o $${prog} $${prog}.o $(LDFLAGS); \
done
static : touch libs
$(CC) -static $(CFLAGS) -o $(BIN)-static $(OBJECTS) $(LDFLAGS) -lz -ldl
$(BIN) : libs $(SUFFIXES)
# Build the binary for the file output
file: CFLAGS += -D__RUN_FILE
file: SOURCES += $(FILE_ROOT).c
file: $(FILE_ROOT).o
file: $(BIN)
file: libs $(BIN)-file
# Build the binary for the fuse output
fuse: CFLAGS += -D__RUN_FUSE -DFUSE_USE_VERSION=26
fuse: SOURCES += $(FUSE_ROOT).c
fuse: CFLAGS += -DFUSE_USE_VERSION=26
# Don't link with the same library on MacOSX
ifeq ($(OS), Darwin)
@@ -128,17 +111,28 @@ else
fuse: LDFLAGS += -lfuse
endif # Darwin
fuse: $(FUSE_ROOT).o
fuse: libs $(BIN)-fuse
# Build the binary for getting metadata only
metadata: libs $(BIN)-metadata
# Build the binary for getting bek information only
bek: libs $(BIN)-bek
fuse: $(BIN)
# Check if the installed binary is present, make it if it isn't
check-install:
@[ -e $(BIN) ] && echo "Found $(BIN) binary, installing it" || make clean fuse
@if [ -e $(BIN)-fuse ] ; then \
echo "Found $(BIN) binary, installing it"; \
else \
make clean all; \
fi
install: check-install
install: all
install -pm755 $(BINS) $(BINARIES_PATH)
cd $(BINARIES_PATH) && ln $(BIN)-fuse $(BIN) && cd -
install -pm755 $(LIBNAME) $(LIBRARY_PATH)
if [ "$(OS)" = "Darwin" ]; then \
cp $(MAN_ROOT)$(BIN)_osx_man $(MAN_ROOT)$(BIN).$(MAN_NUMBER); \
@@ -162,7 +156,7 @@ uninstall: clean
clean:
rm -rf -- $(OBJECTS) $(FILE_ROOT).o $(FUSE_ROOT).o *~ *.swp $(BINS) $(BINS_OBJECTS) $(LIBNAME)
rm -rf -- $(OBJECTS) *~ *.swp $(BINS) $(BINS_OBJECTS) $(LIBNAME)
travis-install:
if [ "$$TRAVIS_OS_NAME" = "linux" ]; then \
+3 -2
View File
@@ -54,7 +54,7 @@ PROGNAME " by " AUTHOR ", v"VERSION " (compiled for " __OS "/" __ARCH ")\n"
" decrypt volume using the recovery password method\n"
" -q, --quiet do NOT display anything\n"
" -r, --readonly do not allow to write on the BitLocker volume\n"
" -s, --stateok do not check the volume's state, assume it's ok to mount it"
" -s, --stateok do not check the volume's state, assume it's ok to mount it\n"
" -u, --user-password decrypt volume using the user password method\n"
" -v, --verbosity increase verbosity (CRITICAL errors are displayed by default)\n"
" -V, --volume VOLUME volume to get metadata and keys from\n"
@@ -92,7 +92,7 @@ static void hide_opt(char* opt)
* @param argv Arguments given to the program
* @return Return the number of arguments which are still waiting to be studied
*/
int parse_args(dis_config_t* cfg, int argc, char** argv)
int parse_args(dis_config_t* cfg, int argc, char** argv) // TODO change into dis_parge_args()
{
/** See man getopt_long(3) */
extern int optind;
@@ -269,6 +269,7 @@ void print_args(dis_config_t* cfg)
xprintf(L_DEBUG, " Verbosity: %d\n", cfg->verbosity);
xprintf(L_DEBUG, " Trying to decrypt '%s'\n", cfg->volume_path);
// FIXME decryption_mean is a bitfield
switch(cfg->decryption_mean)
{
case USE_CLEAR_KEY:
+1 -1
View File
@@ -88,7 +88,7 @@ typedef struct _dis_cfg {
* By default, dislocker will check for unstable state that may corrupt data
* if mounted using fuse
*/
char check_state;
char dont_check_state;
} dis_config_t;
+3 -2
View File
@@ -74,18 +74,19 @@ int main (int argc, char **argv)
{
xprintf(L_CRITICAL, "Filename must be provided\n");
usage(argv[0]);
return EXIT_FAILURE;
}
if(( fd = open(filename, O_RDONLY) ) < 0)
{
xprintf(L_CRITICAL, "Failed to open file %s\n", filename);
exit(1);
return EXIT_FAILURE;
}
if(!get_bek_dataset(fd, &bek_dataset))
{
xprintf(L_CRITICAL, "Unable to get the dataset from the BEK file\n");
exit(1);
return EXIT_FAILURE;
}
close(fd);
@@ -21,28 +21,22 @@
* USA.
*/
/* This define is for the O_LARGEFILE definition */
#define _GNU_SOURCE
#include "encommon.h"
#include "dislocker.h"
#include "encryption/decrypt.h"
#include "sectors.h"
#include "metadata/metadata.h"
#include "file.h"
#ifdef __DARWIN
#if defined(__DARWIN) || defined(__FREEBSD)
# define O_LARGEFILE 0
#endif /* __DARWIN */
#endif /* __DARWIN || __FREEBSD */
/** Data used globally for operation on disk (encryption/decryption) */
extern dis_iodata_t disk_op_data;
/* Number of sectors we're reading at a time */
#define NB_READ_SECTOR 16
int file_main(char* ntfs_file)
int file_main(char* ntfs_file, dis_context_t* dis_ctx)
{
// Check parameter
if(!ntfs_file)
@@ -51,11 +45,18 @@ int file_main(char* ntfs_file)
return EXIT_FAILURE;
}
if(!dis_ctx)
{
xprintf(L_ERROR, "Error, no context given. Abort.\n");
return EXIT_FAILURE;
}
uint8_t* buffer = xmalloc((size_t)(NB_READ_SECTOR * disk_op_data.sector_size));
dis_iodata_t io_data = dis_ctx->io_data;
size_t buf_size = (size_t)(NB_READ_SECTOR * io_data.sector_size);
uint8_t* buffer = xmalloc(buf_size);
mode_t mode = S_IRUSR|S_IWUSR;
if(disk_op_data.cfg->is_ro & READ_ONLY)
if(dis_ctx->cfg.is_ro & READ_ONLY)
mode = S_IRUSR;
int fd_ntfs = xopen2(ntfs_file, O_CREAT|O_RDWR|O_LARGEFILE, mode);
@@ -64,30 +65,24 @@ int file_main(char* ntfs_file)
off_t offset = 0;
long long int percent = 0;
xprintf(L_INFO, "File size: %llu bytes\n", disk_op_data.volume_size);
xprintf(L_INFO, "File size: %llu bytes\n", io_data.volume_size);
/* Read all sectors and decrypt them if necessary */
xprintf(L_INFO, "\rDecrypting... 0%%");
fflush(stdout);
off_t decrypting_size = (off_t)disk_op_data.volume_size;
off_t decrypting_size = (off_t)io_data.volume_size;
while(offset < decrypting_size)
{
/* Read and decrypt an entire region of the disk */
disk_op_data.decrypt_region(
disk_op_data.volume_fd,
NB_READ_SECTOR,
disk_op_data.sector_size,
offset,
buffer
);
dislock(dis_ctx, buffer, offset, buf_size);
offset += NB_READ_SECTOR * disk_op_data.sector_size;
offset += (off_t) buf_size;
/* Now copy the required amount of data to the user file */
xwrite(fd_ntfs, buffer, (size_t)(NB_READ_SECTOR * disk_op_data.sector_size));
xwrite(fd_ntfs, buffer, buf_size);
/* Screen update */
if(percent != (offset*100)/decrypting_size)
@@ -105,3 +100,57 @@ int file_main(char* ntfs_file)
return EXIT_SUCCESS;
}
/**
* Main function ran initially
*/
int main(int argc, char** argv)
{
// Check parameters number
if(argc < 2)
{
usage();
exit(EXIT_FAILURE);
}
int param_idx = 0;
int ret = 0;
dis_context_t dis_ctx;
memset(&dis_ctx, 0, sizeof(dis_context_t));
/* Get command line options */
param_idx = parse_args(&dis_ctx.cfg, argc, argv);
/* Check that we have the file where to put NTFS data */
if(param_idx >= argc || param_idx <= 0)
{
fprintf(stderr, "Error, no file given. Abort.\n");
return EXIT_FAILURE;
}
/* Initialize dislocker */
if(dis_initialize(&dis_ctx) == EXIT_FAILURE)
{
xprintf(L_CRITICAL, "Can't initialize dislocker. Abort.\n");
return EXIT_FAILURE;
}
/*
* Create a NTFS file which could be mounted using `mount -o loop...`
*/
char* ntfs_file = argv[param_idx];
xprintf(L_INFO, "Putting NTFS data into '%s'...\n", ntfs_file);
/* Run the decryption */
ret = file_main(ntfs_file, &dis_ctx);
dis_destroy(&dis_ctx);
return ret;
}
+267
View File
@@ -0,0 +1,267 @@
/* -*- coding: utf-8 -*- */
/* -*- mode: c -*- */
/*
* Dislocker -- enables to read/write on BitLocker encrypted partitions under
* Linux
* Copyright (C) 2012-2013 Romain Coltel, Hervé Schauer Consultants
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include "dislocker.h"
#ifdef __DARWIN
# include <osxfuse/fuse.h>
#else
# include <fuse.h>
#endif /* __DARWIN */
/** NTFS virtual partition's name */
#define NTFS_FILENAME "/dislocker-file"
#include "common.h"
#include "encommon.h"
#include "dislocker.h"
#include "metadata/metadata.h"
/**
* Data used globally for operation on disk (encryption/decryption) and in the
* dislocker library.
*/
dis_context_t dis_ctx;
/**
* Stubs used for FUSE operations.
*/
static int fs_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
if(!path || !stbuf)
return -EINVAL;
memset(stbuf, 0, sizeof(struct stat));
if(strcmp(path, "/") == 0)
{
stbuf->st_mode = S_IFDIR | 0555;
stbuf->st_nlink = 2;
}
else if(strcmp(path, NTFS_FILENAME) == 0)
{
mode_t m = (dis_ctx.cfg.is_ro & READ_ONLY) ? 0444 : 0666;
stbuf->st_mode = S_IFREG | m;
stbuf->st_nlink = 1;
stbuf->st_size = (off_t)dis_ctx.io_data.volume_size;
}
else
res = -ENOENT;
return res;
}
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
/* Both variables aren't used here */
(void) offset;
(void) fi;
if(!path || !buf || !filler)
return -EINVAL;
if(strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, NTFS_FILENAME + 1, NULL, 0);
return 0;
}
static int fs_open(const char *path, struct fuse_file_info *fi)
{
if(!path || !fi)
return -EINVAL;
if(strcmp(path, NTFS_FILENAME) != 0)
return -ENOENT;
if(dis_ctx.cfg.is_ro & READ_ONLY)
{
if((fi->flags & 3) != O_RDONLY)
return -EACCES;
}
else
{
/* Authorize read/write, readonly and writeonly operations */
if((fi->flags & 3) != O_RDWR &&
(fi->flags & 3) != O_RDONLY &&
(fi->flags & 3) != O_WRONLY)
return -EACCES;
}
return 0;
}
static int fs_read(
const char *path,
char *buf,
size_t size,
off_t offset,
__attribute__ ((unused)) struct fuse_file_info *fi)
{
if(!path || !buf)
return -EINVAL;
/*
* Perform basic checks
*/
if(strcmp(path, NTFS_FILENAME) != 0)
{
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
return -ENOENT;
}
return dislock(&dis_ctx, (uint8_t*) buf, offset, size);
}
static int fs_write(
const char *path,
const char *buf,
size_t size,
off_t offset,
__attribute__ ((unused)) struct fuse_file_info *fi)
{
// Check parameters
if(!path || !buf)
return -EINVAL;
if(strcmp(path, NTFS_FILENAME) != 0)
{
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
return -ENOENT;
}
return enlock(&dis_ctx, (uint8_t*) buf, offset, size);
}
/* Structure used by the FUSE driver */
struct fuse_operations fs_oper = {
.getattr = fs_getattr,
.readdir = fs_readdir,
.open = fs_open,
.read = fs_read,
.write = fs_write,
};
/**
* Main function ran initially
*/
int main(int argc, char** argv)
{
// Check parameters number
if(argc < 2)
{
usage();
exit(EXIT_FAILURE);
}
int param_idx = 0;
int ret = EXIT_SUCCESS;
memset(&dis_ctx, 0, sizeof(dis_context_t));
/* Get command line options */
param_idx = parse_args(&dis_ctx.cfg, argc, argv);
/* Check we got enough arguments for at least one more, the mount point */
if(param_idx >= argc || param_idx <= 0)
{
xprintf(L_CRITICAL, "Error, no mount point given. Abort.\n");
return EXIT_FAILURE;
}
/* Initialize dislocker */
if(dis_initialize(&dis_ctx) == EXIT_FAILURE)
{
xprintf(L_CRITICAL, "Can't initialize dislocker. Abort.\n");
return EXIT_FAILURE;
}
/*
* Create the parameters table needed for FUSE and run it
* This is as we're running argv[0] followed by ARGS (see usage())
*/
/* Compute the new argc given to FUSE */
size_t new_argc = (size_t)(argc - param_idx + 1);
xprintf(L_DEBUG, "New value for argc: %d\n", new_argc);
char** new_argv = xmalloc(new_argc * sizeof(char*));
/* Get argv[0] */
size_t lg = strlen(argv[0]) + 1;
*new_argv = xmalloc(lg);
memcpy(*new_argv, argv[0], lg);
/* Get all of the parameters from param_idx till the end */
size_t loop = 0;
for(loop = 1; loop < new_argc; ++loop)
{
lg = strlen(argv[(size_t)param_idx + loop - 1]) + 1;
*(new_argv + loop) = xmalloc(lg);
memcpy(*(new_argv + loop), argv[(size_t)param_idx + loop - 1], lg);
}
xprintf(L_INFO, "Running FUSE with these arguments: \n");
for(loop = 0; loop < new_argc; ++loop)
xprintf(L_INFO, " `--> '%s'\n", *(new_argv + loop));
/* Run FUSE */
ret = fuse_main((int)new_argc, new_argv, &fs_oper, NULL);
/* Free FUSE params */
for(loop = 0; loop < new_argc; ++loop)
xfree(new_argv[loop]);
xfree(new_argv);
/* Destroy dislocker structures */
dis_destroy(&dis_ctx);
return ret;
}
+31 -76
View File
@@ -27,9 +27,9 @@
#define _GNU_SOURCE
#include <getopt.h>
#include <locale.h>
#include "dislocker.h"
#include "common.h"
#include "config.h"
@@ -57,21 +57,13 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
int ret = EXIT_SUCCESS;
int optchar = 0;
char *volume_path = NULL;
int fd = 0;
volume_header_t volume_header;
void* bl_metadata = NULL;
bitlocker_dataset_t* dataset = NULL;
datum_vmk_t* vmk_clear_key_datum = NULL;
dis_config_t cfg;
memset(&cfg, 0, sizeof(cfg));
off_t offset = 0;
while((optchar = getopt(argc, argv, "o:V:h")) != -1)
{
@@ -81,7 +73,7 @@ int main(int argc, char **argv)
usage();
return EXIT_SUCCESS;
case 'o':
cfg.offset = (off_t) strtoll(optarg, NULL, 10);
offset = (off_t) strtoll(optarg, NULL, 10);
break;
case 'V':
volume_path = strdup(optarg);
@@ -94,102 +86,65 @@ int main(int argc, char **argv)
}
}
xstdio_init(L_INFO, NULL);
if(!volume_path)
{
usage();
exit(EXIT_FAILURE);
}
// Open the volume as a normal file
fd = xopen(volume_path, O_RDONLY|O_LARGEFILE);
dis_context_t dis_ctx;
memset(&dis_ctx, 0, sizeof(dis_context_t));
/*
* Initialize dislocker's configuration
*/
dis_ctx.cfg.volume_path = volume_path;
dis_ctx.cfg.verbosity = L_INFO;
dis_ctx.cfg.offset = offset;
/* To print UTF-32 strings */
setlocale(LC_ALL, "");
/* We don't want to give decryption mean, we only want the metadata */
dis_ctx.stop_at = AFTER_BITLOCKER_INFORMATION_CHECK;
// Initialize structures
memset(&volume_header, 0, sizeof(volume_header_t));
// Getting volume infos
if(!get_volume_header(&volume_header, fd, cfg.offset))
/* Initialize dislocker */
if(dis_initialize(&dis_ctx) == EXIT_FAILURE)
{
xprintf(L_ERROR, "Error during reading the volume: not enough byte read.\n");
ret = EXIT_FAILURE;
goto error;
xprintf(L_CRITICAL, "Can't initialize dislocker. Abort.\n");
return EXIT_FAILURE;
}
// Printing them
print_volume_header(L_INFO, &volume_header);
// Checking the volume signature
if(memcmp(BITLOCKER_SIGNATURE, volume_header.signature,
BITLOCKER_SIGNATURE_SIZE) != 0)
{
xprintf(L_CRITICAL,
"The signature of the volume (%.8s) doesn't match the "
"BitLocker's one (-FVE-FS-). Abort.\n",
volume_header.signature);
ret = EXIT_FAILURE;
goto error;
}
// Getting BitLocker metadata and validate them
if(!get_metadata_check_validations(&volume_header, fd, &bl_metadata, &cfg))
{
xprintf(L_CRITICAL, "A problem occured during the retrieving of metadata. Abort.\n");
ret = EXIT_FAILURE;
goto error;
}
if(cfg.force_block == 0 || !bl_metadata)
{
xprintf(L_CRITICAL, "Can't find a valid set of metadata on the disk. Abort.\n");
ret = EXIT_FAILURE;
goto error;
}
// Printing BitLocker metadata
print_bl_metadata(L_INFO, bl_metadata);
// Printing volume header
print_volume_header(L_INFO, dis_ctx.io_data.volume_header);
xprintf(L_INFO, "\n");
// Printing BitLocker metadata
print_bl_metadata(L_INFO, dis_ctx.io_data.metadata);
xprintf(L_INFO, "\n");
// Now we're looking at the data
print_data(L_INFO, bl_metadata);
// Now we're looking at the data themselves
print_data(L_INFO, dis_ctx.io_data.metadata);
// Get the metadata's dataset
if(!get_dataset(bl_metadata, &dataset))
if(!get_dataset(dis_ctx.io_data.metadata, &dataset))
{
xprintf(L_CRITICAL, "Can't find a valid dataset. Abort.\n");
ret = EXIT_FAILURE;
goto error;
dis_destroy(&dis_ctx);
return EXIT_FAILURE;
}
// Search for a clear key
if(has_clear_key(dataset, &vmk_clear_key_datum))
{
xprintf(L_INFO, "\n===== There's a clear key here!\n===== Take a look at it:\n");
xprintf(L_INFO, "=======[ There's a clear key here ]========\n");
print_one_datum(L_INFO, (void*)vmk_clear_key_datum);
xprintf(L_INFO, "============[ Clear key end ]============\n");
xprintf(L_INFO, "=============[ Clear key end ]=============\n");
}
else
xprintf(L_INFO, "No clear key found.\n");
error:
// Do some cleaning stuff
if(volume_path)
xfree(volume_path);
dis_destroy(&dis_ctx);
if(bl_metadata)
xfree(bl_metadata);
xclose(fd);
xstdio_end();
return ret;
return EXIT_SUCCESS;
}
+726 -385
View File
File diff suppressed because it is too large Load Diff
+87 -5
View File
@@ -23,14 +23,96 @@
#ifndef DISLOCKER_MAIN_H
#define DISLOCKER_MAIN_H
#include <stdint.h>
#if defined(__RUN_FUSE)
# include "outputs/fuse/fuse.h"
#elif defined(__RUN_FILE)
# include "outputs/file/file.h"
#endif
#include "config.h"
#include "encommon.h"
/**
* dis_initialize() function does a lot of things. So, in order to provide
* flexibility, place some kind of breakpoint after majors steps.
*/
typedef enum {
COMPLETE_EVERYTHING = 0,
AFTER_OPEN_VOLUME,
AFTER_VOLUME_HEADER,
AFTER_VOLUME_CHECK,
AFTER_BITLOCKER_INFORMATION,
AFTER_BITLOCKER_INFORMATION_CHECK,
AFTER_VMK,
AFTER_FVEK,
BEFORE_DECRYPTION_CHECKING,
} dis_stopat_e;
/**
* Main structure to pass to dislocker functions. These keeps various
* information in it.
*/
typedef struct _dis_ctx {
dis_config_t cfg;
dis_iodata_t io_data;
dis_stopat_e stop_at;
} dis_context_t;
/**
* Public prototypes
*/
/**
* Initialize dislocker. As stated above, the initialisation process may be
* stopped at any major step in order to retrieve different information. Note
* that you have to provide an already allocated dis_ctx with an already filled
* dis_ctx->cfg with parameters for dislocker to initialize correctly.
* This function malloc(3)s structures, see dis_destroy() below for free(3)ing
* it.
* dislock() & enlock() function may not be called before executing this
* function.
*
* @param dis_ctx The dislocker context needed for all operations. As stated
* above, this parameter has to be pre-allocated. Furthermore, the dis_ctx->cfg
* structure has to be filled with parameters to properly initialize dislocker.
*/
int dis_initialize(dis_context_t* dis_ctx);
/**
* Once dis_initialize() has been called, this function is able to decrypt the
* BitLocker-encrypted volume.
*
* @param dis_ctx The same parameter passed to dis_initialize.
* @param offset The offset from where to start decrypting.
* @param buffer The buffer to put decrypted data to.
* @param size The size of a region to decrypt.
*/
int dislock(dis_context_t* dis_ctx, uint8_t* buffer, off_t offset, size_t size);
/**
* Once dis_initialize() has been called, this function is able to encrypt data
* to the BitLocker-encrypted volume.
*
* @param dis_ctx The same parameter passed to dis_initialize.
* @param offset The offset where to put the data.
* @param buffer The buffer from where to take data to encrypt.
* @param size The size of a region to decrypt.
*/
int enlock(dis_context_t* dis_ctx, uint8_t* buffer, off_t offset, size_t size);
/**
* Destroy dislocker structures. This is important to call this function after
* dislocker is not needed -- if dis_initialize() has been called -- in order
* for dislocker to free(3) the used memory.
* dislock() & enlock() functions may not be called anymore after executing this
* function.
*/
int dis_destroy(dis_context_t* dis_ctx);
#endif /* DISLOCKER_MAIN_H */
+29 -7
View File
@@ -26,6 +26,7 @@
#include "common.h"
#include "config.h"
#include "metadata/vmk.h"
#include "metadata/metadata.h"
#include "metadata/extended_info.h"
@@ -59,6 +60,15 @@ typedef struct _data {
/* Volume metadata */
bitlocker_header_t* metadata;
/* The volume header, 512 bytes */
volume_header_t* volume_header;
/* The VMK */
datum_key_t* vmk;
/* The FVEK */
datum_key_t* fvek;
/*
* Virtualized regions are presented as zeroes when queried from the NTFS
* layer. In these virtualized regions, we find the 3 BitLocker metadata
@@ -88,17 +98,29 @@ typedef struct _data {
int volume_fd;
/* Contexts used to encrypt or decrypt */
contexts_t* ctx;
/* Configuration parameters */
dis_config_t* cfg;
contexts_t* enc_ctx;
/* Function to decrypt a region of the volume */
int(*decrypt_region)(int fd, size_t nb_read_sector, uint16_t sector_size, off_t sector_start, uint8_t* output);
int(*decrypt_region)(
struct _data* io_data,
size_t nb_read_sector,
uint16_t sector_size,
off_t sector_start,
uint8_t* output
);
/* Function to encrypt a region of the volume */
int(*encrypt_region)(int fd, size_t nb_write_sector, uint16_t sector_size, off_t sector_start, uint8_t* input);
int(*encrypt_region)(
struct _data* io_data,
size_t nb_write_sector,
uint16_t sector_size,
off_t sector_start,
uint8_t* input
);
/* FUSE uses threads. We need to protect our "lseek/read" and "lseek/write" sequences */
/*
* FUSE uses threads. We need to protect our "lseek/read" and "lseek/write"
* sequences
*/
pthread_mutex_t mutex_lseek_rw;
} dis_iodata_t;
+2 -2
View File
@@ -402,11 +402,11 @@ int decrypt_sector(dis_iodata_t* global_data, uint8_t* sector, off_t sector_addr
{
case AES_128_DIFFUSER:
case AES_256_DIFFUSER:
decrypt_with_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
decrypt_with_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
break;
case AES_128_NO_DIFFUSER:
case AES_256_NO_DIFFUSER:
decrypt_without_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
decrypt_without_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
break;
}
+2 -2
View File
@@ -57,11 +57,11 @@ int encrypt_sector(dis_iodata_t* global_data, uint8_t* sector, off_t sector_addr
{
case AES_128_DIFFUSER:
case AES_256_DIFFUSER:
encrypt_with_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
encrypt_with_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
break;
case AES_128_NO_DIFFUSER:
case AES_256_NO_DIFFUSER:
encrypt_without_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
encrypt_without_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
break;
}
-38
View File
@@ -1,38 +0,0 @@
/* -*- coding: utf-8 -*- */
/* -*- mode: c -*- */
/*
* Dislocker -- enables to read/write on BitLocker encrypted partitions under
* Linux
* Copyright (C) 2012-2013 Romain Coltel, Hervé Schauer Consultants
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#ifndef FILE_H
#define FILE_H
#define NB_READ_SECTOR 16
/*
* Only function others can use
*/
int file_main(char* ntfs_file);
#endif /* FILE_H */
-500
View File
@@ -1,500 +0,0 @@
/* -*- coding: utf-8 -*- */
/* -*- mode: c -*- */
/*
* Dislocker -- enables to read/write on BitLocker encrypted partitions under
* Linux
* Copyright (C) 2012-2013 Romain Coltel, Hervé Schauer Consultants
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
/*
* Special thanks to Nitin Kumar and Vipin Kumar for helping me building this
* file
*/
#include "common.h"
#include "encommon.h"
#include "dislocker.h"
#include "encryption/decrypt.h"
#include "sectors.h"
#include "metadata/metadata.h"
#include "fuse.h"
/** Data used globally for operation on disk (encryption/decryption) */
extern dis_iodata_t disk_op_data;
static int fs_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
if(!path || !stbuf)
return -EINVAL;
memset(stbuf, 0, sizeof(struct stat));
if(strcmp(path, "/") == 0)
{
stbuf->st_mode = S_IFDIR | 0555;
stbuf->st_nlink = 2;
}
else if(strcmp(path, NTFS_FILENAME) == 0)
{
mode_t m = disk_op_data.cfg->is_ro ? 0444 : 0666;
stbuf->st_mode = S_IFREG | m;
stbuf->st_nlink = 1;
stbuf->st_size = (off_t)disk_op_data.volume_size;
}
else
res = -ENOENT;
return res;
}
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
/* Both variables aren't used here */
(void) offset;
(void) fi;
if(!path || !buf || !filler)
return -EINVAL;
if(strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, NTFS_FILENAME + 1, NULL, 0);
return 0;
}
static int fs_open(const char *path, struct fuse_file_info *fi)
{
if(!path || !fi)
return -EINVAL;
if(strcmp(path, NTFS_FILENAME) != 0)
return -ENOENT;
if(disk_op_data.cfg->is_ro & READ_ONLY)
{
if((fi->flags & 3) != O_RDONLY)
return -EACCES;
}
else
{
/* Authorize read/write, readonly and writeonly operations */
if((fi->flags & 3) != O_RDWR &&
(fi->flags & 3) != O_RDONLY &&
(fi->flags & 3) != O_WRONLY)
return -EACCES;
}
return 0;
}
static int fs_read(const char *path, char *buf, size_t size,
off_t offset, UNUSED struct fuse_file_info *fi)
{
if(!path || !buf)
return -EINVAL;
uint8_t* buffer = NULL;
size_t sector_count;
off_t sector_start;
size_t sector_to_add = 0;
/*
* Perform basic checks
*/
if(strcmp(path, NTFS_FILENAME) != 0)
{
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
return -ENOENT;
}
if(size == 0)
{
xprintf(L_DEBUG, "Received a request with a null size\n");
return 0;
}
if(offset < 0)
{
xprintf(L_ERROR, "Offset under 0: %#" F_OFF_T "\n", offset);
return -EFAULT;
}
if(offset >= (off_t)disk_op_data.volume_size)
{
xprintf(L_ERROR, "Offset (%#" F_OFF_T ") exceeds volume's size (%#"
F_OFF_T ")\n",
offset, (off_t)disk_op_data.volume_size);
return -EFAULT;
}
/*
* The offset may not be at a sector limit, so we need to decrypt the entire
* sector where it starts. Idem for the end.
*
*
* Example:
* Sector number: 1 2 3 4 5 6 7...
* Data, continuous sectors: |___|___|___|___|___|___|__...
* The data the user want: |__________|
*
* The user don't want all of the data from sectors 2 and 5, but as the data
* are encrypted sector by sector, we have to decrypt them even though we
* won't give him the beginning of the sector 2 and the end of the sector 5.
*
*
*
* Logic to do this is below :
* - count the number of full sectors
* - decode all sectors
* - select and copy the data to user and deallocate all buffers
*/
/* Do not add sectors if we're at the edge of one already */
if((offset % disk_op_data.sector_size) != 0)
sector_to_add += 1;
if(((offset + (off_t)size) % disk_op_data.sector_size) != 0)
sector_to_add += 1;
sector_count = ( size / disk_op_data.sector_size ) + sector_to_add;
sector_start = offset / disk_op_data.sector_size;
xprintf(L_DEBUG,
"--------------------{ Fuse reading }-----------------------\n");
xprintf(L_DEBUG, " Offset and size needed: %#" F_OFF_T
" and %#" F_SIZE_T "\n", offset, size);
xprintf(L_DEBUG, " Start sector number: %#" F_OFF_T
" || Number of sectors: %#" F_SIZE_T "\n",
sector_start, sector_count);
/*
* NOTE: DO NOT use xmalloc() here, we don't want to mess everything up!
* In general, do not use xfunctions() but xprintf() here.
*/
size_t to_allocate = size + sector_to_add*(size_t)disk_op_data.sector_size;
xprintf(L_DEBUG, " Trying to allocate %#" F_SIZE_T " bytes\n",to_allocate);
buffer = malloc(to_allocate);
/* If buffer could not be allocated, return an error */
if(!buffer)
{
xprintf(L_ERROR, "Cannot allocate buffer for reading, abort.\n");
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
if(errno < 0)
return errno;
else
return -ENOMEM;
}
if(!disk_op_data.decrypt_region(
disk_op_data.volume_fd,
sector_count,
disk_op_data.sector_size,
sector_start * disk_op_data.sector_size,
buffer
))
{
free(buffer);
xprintf(L_ERROR, "Cannot decrypt sectors, abort.\n");
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
return -EIO;
}
/* Now copy the required amount of data to the user buffer */
memcpy(buf, buffer + (offset % disk_op_data.sector_size), size);
free(buffer);
xprintf(L_DEBUG, " Outsize which will be returned: %d\n", (int)size);
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
return (int)size;
}
static int fs_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
// Check parameters
if(!path || !buf)
return -EINVAL;
uint8_t* buffer = NULL;
int ret = 0;
size_t sector_count;
off_t sector_start;
size_t sector_to_add = 0;
/* Perform basic checks */
if(disk_op_data.cfg->is_ro & READ_ONLY)
{
xprintf(L_DEBUG, "Only decrypting (-r or --read-only option passed)\n");
return -EACCES;
}
if(strcmp(path, NTFS_FILENAME) != 0)
{
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
return -ENOENT;
}
if(size == 0)
{
xprintf(L_DEBUG, "Received a request with a null size\n");
return 0;
}
if(offset < 0)
{
xprintf(L_ERROR, "Offset under 0: %#" F_OFF_T "\n", offset);
return -EFAULT;
}
if(offset >= (off_t)disk_op_data.volume_size)
{
xprintf(L_ERROR, "Offset (%#" F_OFF_T ") exceeds volume's size (%#"
F_OFF_T ")\n",
offset, (off_t)disk_op_data.volume_size);
return -EFAULT;
}
if((size_t)offset + size >= (size_t)disk_op_data.volume_size)
{
size_t nsize = (size_t)disk_op_data.volume_size
- (size_t)offset;
xprintf(L_WARNING, "Size modified as exceeding volume's end (offset=%#"
F_SIZE_T " + size=%#" F_SIZE_T " >= volume_size=%#"
F_SIZE_T ") ; new size: %#" F_SIZE_T "\n",
(size_t)offset, size, (size_t)disk_op_data.volume_size, nsize);
size = nsize;
}
/*
* Don't authorize to write on metadata, NTFS firsts sectors and on another
* area we shouldn't write to (don't know its signification yet).
*/
off_t metadata_offset = 0;
off_t metadata_size = 0;
size_t virt_loop = 0;
for(virt_loop = 0; virt_loop < disk_op_data.nb_virt_region; virt_loop++)
{
metadata_size = (off_t)disk_op_data.virt_region[virt_loop].size;
if(metadata_size == 0)
continue;
metadata_offset = (off_t)disk_op_data.virt_region[virt_loop].addr;
if(offset >= metadata_offset &&
offset <= metadata_offset + metadata_size)
{
xprintf(L_INFO, "Denying write request on the metadata (1:%#"
F_OFF_T ")\n", offset);
return -EFAULT;
}
if(offset < metadata_offset &&
offset + (off_t)size >= metadata_offset)
{
xprintf(L_INFO, "Denying write request on the metadata (2:%#"
F_OFF_T "+ %#" F_SIZE_T ")\n", offset, size);
return -EFAULT;
}
}
/*
* For BitLocker 7's volume, redirect writes to firsts sectors to the backed
* up ones
*/
if(disk_op_data.metadata->version == V_SEVEN &&
offset < disk_op_data.virtualized_size)
{
xprintf(L_DEBUG, " Entering virtualized area\n");
if(offset + (off_t)size <= disk_op_data.virtualized_size)
{
/*
* If all the request is within the virtualized area, just change
* the offset
*/
offset = offset + (off_t)disk_op_data.metadata->boot_sectors_backup;
xprintf(L_DEBUG, " `-> Just redirecting to %#"F_OFF_T"\n", offset);
}
else
{
/*
* But if the buffer is within the virtualized area and overflow it,
* split the request in two:
* - One for the virtualized area completely (which will be handled
* by "recursing" and entering the case above)
* - One for the rest by changing the offset to the end of the
* virtualized area and the size to the rest to be dec/encrypted
*/
xprintf(L_DEBUG, " `-> Splitting the request in two, recursing\n");
size_t nsize = (size_t)(disk_op_data.virtualized_size - offset);
ret = fs_write(path, buf, nsize, offset, fi);
if(ret < 0)
return ret;
offset = disk_op_data.virtualized_size;
size -= nsize;
buf += nsize;
}
}
/*
* As in the read function, the offset may not be at a sector limit, so we
* need to decrypt the entire sector where it starts till the entire sector
* where it ends, then push the changes into the sectors at correct offset
* and finally encrypt all of these sectors and write them back to the disk.
*
*
* Example:
* Sector number: 1 2 3 4 5 6 7...
* Data, continuous sectors: |___|___|___|___|___|___|__...
* Where the user want to write: |__________|
*
* The user don't want to write everywhere, just from the middle of sector 2
* till a part of sector 5. But we're writing sectors by sectors to be able
* to encrypt using AES. So we'll need entire sectors 2 to 5 included.
*
*
*
* Logic to do this is below :
* - read and decrypt all sectors completely (2 to 5 in the example above)
* - replace some data by the user's one
* - encrypt and write the read sectors
*/
/* Do not add sectors if we're at the edge of one already */
if((offset % disk_op_data.sector_size) != 0)
sector_to_add += 1;
if(((offset + (off_t)size) % disk_op_data.sector_size) != 0)
sector_to_add += 1;
sector_count = ( size / disk_op_data.sector_size ) + sector_to_add;
sector_start = offset / disk_op_data.sector_size;
xprintf(L_DEBUG,
"--------------------{ Fuse writing }-----------------------\n");
xprintf(L_DEBUG, " Offset and size requested: %#" F_OFF_T " and %#"
F_SIZE_T "\n", offset, size);
xprintf(L_DEBUG, " Start sector number: %#" F_OFF_T
" || Number of sectors: %#" F_SIZE_T "\n",
sector_start, sector_count);
/*
* NOTE: DO NOT use xmalloc() here, we don't want to mess everything up!
* In general, do not use xfunctions() but xprintf() here.
*/
buffer = malloc(size + sector_to_add * (size_t)disk_op_data.sector_size);
/* If buffer could not be allocated */
if(!buffer)
{
xprintf(L_ERROR, "Cannot allocate buffer for writing, abort.\n");
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
return -ENOMEM;
}
if(!disk_op_data.decrypt_region(
disk_op_data.volume_fd,
sector_count,
disk_op_data.sector_size,
sector_start * disk_op_data.sector_size,
buffer
))
{
free(buffer);
xprintf(L_ERROR, "Cannot decrypt sectors, abort.\n");
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
return -EIO;
}
/* Now copy the user's buffer to the received data */
memcpy(buffer + (offset % disk_op_data.sector_size), buf, size);
/* Finally, encrypt the buffer and write it to the disk */
if(!disk_op_data.encrypt_region(
disk_op_data.volume_fd,
sector_count,
disk_op_data.sector_size,
sector_start * disk_op_data.sector_size,
buffer
))
{
free(buffer);
xprintf(L_ERROR, "Cannot encrypt sectors, abort.\n");
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
return -EIO;
}
free(buffer);
/* Note that ret is zero when no recursion occurs */
int outsize = (int)size + ret;
xprintf(L_DEBUG, " Outsize which will be returned: %d\n", outsize);
xprintf(L_DEBUG,
"-----------------------------------------------------------\n");
return outsize;
}
struct fuse_operations fs_oper = {
.getattr = fs_getattr,
.readdir = fs_readdir,
.open = fs_open,
.read = fs_read,
.write = fs_write,
};
-43
View File
@@ -1,43 +0,0 @@
/* -*- coding: utf-8 -*- */
/* -*- mode: c -*- */
/*
* Dislocker -- enables to read/write on BitLocker encrypted partitions under
* Linux
* Copyright (C) 2012-2013 Romain Coltel, Hervé Schauer Consultants
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#ifndef FUSE_H
#define FUSE_H
#ifdef __DARWIN
# include <osxfuse/fuse.h>
#else
# include <fuse.h>
#endif /* __DARWIN */
/** NTFS virtual partition's name */
#define NTFS_FILENAME "/dislocker-file"
#endif /* FUSE_H */
-99
View File
@@ -1,99 +0,0 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#if defined(__DARWIN) || defined(__FREEBSD)
# include <osxfuse/fuse.h>
#else
# include <fuse.h>
#endif /* __DARWIN || __FREEBSD */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if(strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
}
else if(strcmp(path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = (off_t)strlen(hello_str);
}
else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if(strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if(strcmp(path, hello_path) != 0)
return -ENOENT;
if((fi->flags & 3) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0)
return -ENOENT;
len = strlen(hello_str);
if (offset < (off_t)len) {
if ((size_t)offset + size > len)
size = len - (size_t)offset;
memcpy(buf, hello_str + offset, size);
} else
size = 0;
return (int)size;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper, NULL);
}
+58 -74
View File
@@ -30,9 +30,7 @@
/**
* Getting the real volume size is proving to be quite difficult.
*/
static uint64_t get_volume_size(volume_header_t* volume_header,
bitlocker_header_t* metadata,
int fd_volume);
static uint64_t get_volume_size(dis_iodata_t* io_data);
@@ -122,40 +120,26 @@ int init_keys(bitlocker_dataset_t* dataset, datum_key_t* fvek_datum,
/**
* Prepare a structure which hold data used for decryption/encryption
*
* @param metadata The BitLocker metadata block
* @param ctx Contexts used to encrypt/decrypt data
* @param cfg Invoked configuration
* @param volume_header First-sector data
* @param offset Where the real volume begins
* @param fd_volume The volume's file descriptor
* @param dis_ctx The dislocker context used everywhere.
* @return TRUE if result can be trusted, FALSE otherwise
*/
int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
dis_config_t* cfg, volume_header_t* volume_header,
off_t offset, int fd_volume)
int prepare_crypt(dis_context_t* dis_ctx)
{
size_t loop = 0;
uint16_t sector_size = volume_header->sector_size;
uint8_t sectors_per_cluster = volume_header->sectors_per_cluster;
dis_iodata_t* io_data = &dis_ctx->io_data;
bitlocker_header_t* metadata = io_data->metadata;
uint16_t sector_size = io_data->volume_header->sector_size;
uint8_t sectors_per_cluster = io_data->volume_header->sectors_per_cluster;
uint32_t cluster_size = 0;
uint64_t metafiles_size = 0;
/** @see dislocker.c */
extern dis_iodata_t disk_op_data;
io_data->xinfo = NULL;
io_data->sector_size = sector_size;
io_data->part_off = dis_ctx->cfg.offset;
io_data->decrypt_region = read_decrypt_sectors;
io_data->encrypt_region = encrypt_write_sectors;
memset(&disk_op_data, 0, sizeof(dis_iodata_t));
disk_op_data.metadata = metadata;
disk_op_data.xinfo = NULL;
disk_op_data.sector_size = sector_size;
disk_op_data.part_off = offset;
disk_op_data.ctx = ctx;
disk_op_data.cfg = cfg;
disk_op_data.volume_fd = fd_volume;
disk_op_data.decrypt_region = read_decrypt_sectors;
disk_op_data.encrypt_region = encrypt_write_sectors;
if(pthread_mutex_init(&disk_op_data.mutex_lseek_rw, NULL) != 0)
if(pthread_mutex_init(&io_data->mutex_lseek_rw, NULL) != 0)
{
xprintf(L_ERROR, "Can't initialize mutex: %s\n", strerror(errno));
return FALSE;
@@ -165,16 +149,18 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
* We need to grab the volume's size from the first sector, so we can
* announce it on a getattr call
*/
disk_op_data.volume_size = get_volume_size(volume_header, metadata,
fd_volume);
if(disk_op_data.volume_size == 0)
io_data->volume_size = get_volume_size(io_data);
if(io_data->volume_size == 0)
{
xprintf(L_ERROR, "Can't initialize the volume's size\n");
return FALSE;
}
xprintf(L_INFO, "Found volume's size: 0x%1$" F_U64_T " (%1$llu) bytes\n",
disk_op_data.volume_size);
xprintf(
L_INFO,
"Found volume's size: 0x%1$" F_U64_T " (%1$llu) bytes\n",
io_data->volume_size
);
/*
* Alignment isn't the same for W$ Vista (size-of-a-cluster aligned on
@@ -197,11 +183,11 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
* Initialize region to report as filled with zeroes, if asked from the NTFS
* layer. This is to mimic BitLocker's behaviour.
*/
disk_op_data.nb_virt_region = 3;
for(loop = 0; loop < disk_op_data.nb_virt_region; loop++)
io_data->nb_virt_region = 3;
for(loop = 0; loop < io_data->nb_virt_region; loop++)
{
disk_op_data.virt_region[loop].addr = metadata->offset_bl_header[loop];
disk_op_data.virt_region[loop].size = metafiles_size;
io_data->virt_region[loop].addr = metadata->offset_bl_header[loop];
io_data->virt_region[loop].size = metafiles_size;
}
if(metadata->version == V_VISTA)
@@ -221,38 +207,46 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
DATUM_VIRTUALIZATION_INFO, NULL, (void**)&datum))
{
char* type_str = datumtypestr(DATUM_VIRTUALIZATION_INFO);
xprintf(L_ERROR, "Error looking for the VIRTUALIZATION datum type"
" %hd (%s). Internal failure, abort.\n",
DATUM_VIRTUALIZATION_INFO, type_str);
xprintf(
L_ERROR,
"Error looking for the VIRTUALIZATION datum type"
" %hd (%s). Internal failure, abort.\n",
DATUM_VIRTUALIZATION_INFO,
type_str
);
xfree(type_str);
datum = NULL;
return FALSE;
}
disk_op_data.nb_virt_region++;
disk_op_data.virt_region[3].addr = metadata->boot_sectors_backup;
disk_op_data.virt_region[3].size = datum->nb_bytes;
disk_op_data.virtualized_size = (off_t)datum->nb_bytes;
io_data->nb_virt_region++;
io_data->virt_region[3].addr = metadata->boot_sectors_backup;
io_data->virt_region[3].size = datum->nb_bytes;
io_data->virtualized_size = (off_t)datum->nb_bytes;
xprintf(L_DEBUG, "Virtualized info size: %#" F_OFF_T "\n",
disk_op_data.virtualized_size);
xprintf(
L_DEBUG,
"Virtualized info size: %#" F_OFF_T "\n",
io_data->virtualized_size
);
/* Extended info is new to Windows 8 */
// TODO add check on datum_types_prop's size against datum->header.datum_type
size_t win7_size = datum_types_prop[datum->header.datum_type].size_header;
size_t actual_size = ((size_t)datum->header.datum_size) & 0xffff;
if(actual_size > win7_size)
{
disk_op_data.xinfo = &datum->xinfo;
io_data->xinfo = &datum->xinfo;
xprintf(L_DEBUG, "Got extended info\n");
}
/* Another area to report as filled with zeroes, new to W8 as well */
if(metadata->curr_state == SWITCHING_ENCRYPTION)
{
disk_op_data.nb_virt_region++;
disk_op_data.virt_region[4].addr = metadata->encrypted_volume_size;
disk_op_data.virt_region[4].size = metadata->unknown_size;
io_data->nb_virt_region++;
io_data->virt_region[4].addr = metadata->encrypted_volume_size;
io_data->virt_region[4].size = metadata->unknown_size;
}
}
else
@@ -262,17 +256,6 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
return FALSE;
}
/*
* Check we can safely run without leaking information or breaking metadata
*/
extern guid_t INFORMATION_OFFSET_GUID;
if(!check_match_guid(volume_header->guid, INFORMATION_OFFSET_GUID))
{
xprintf(L_ERROR, "Unsupported volume GUID.\n");
return FALSE;
}
return TRUE;
}
@@ -310,31 +293,32 @@ static uint64_t get_volume_size_from_mbr(volume_header_t* volume_header)
/**
* Compute the real volume's size.
*
* @param volume_header First-sector data
* @param metadata The BitLocker metadata block
* @param fd The volume's file descriptor
* @param io_data The structure holding major information for accessing the
* volume
* @return The volume size or 0 if it can't be determined
*/
static uint64_t get_volume_size(volume_header_t* volume_header,
bitlocker_header_t* metadata,
int fd_volume)
static uint64_t get_volume_size(dis_iodata_t* io_data)
{
uint64_t volume_size = 0;
volume_size = get_volume_size_from_mbr(volume_header);
volume_size = get_volume_size_from_mbr(io_data->volume_header);
if(!volume_size && metadata->version == V_SEVEN)
if(!volume_size && io_data->metadata->version == V_SEVEN)
{
/*
* For version V_SEVEN, volumes can be partially encrypted.
* Therefore, try to get the real size from the NTFS data
*/
uint8_t* input = xmalloc(volume_header->sector_size);
memset(input, 0, volume_header->sector_size);
uint8_t* input = xmalloc(io_data->volume_header->sector_size);
memset(input, 0, io_data->volume_header->sector_size);
if(!read_decrypt_sectors(fd_volume, 1, volume_header->sector_size, 0,
input))
if(!read_decrypt_sectors(
io_data,
1,
io_data->volume_header->sector_size,
0,
input))
{
xprintf(L_ERROR,
"Unable to read the NTFS header to get the volume's size\n");
+2 -3
View File
@@ -26,6 +26,7 @@
#include <stdint.h>
#include "dislocker.h"
#include "config.h"
#include "encommon.h"
#include "metadata/datums.h"
@@ -42,9 +43,7 @@ int init_keys(bitlocker_dataset_t* dataset, datum_key_t* fvek, contexts_t* ctx);
* Function used to prepare a structure which hold data used for
* decryption/encryption
*/
int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
dis_config_t* cfg, volume_header_t* volume_header,
off_t offset, int fd_volume);
int prepare_crypt(dis_context_t* dis_ctx);
#endif /* PREPARE_H */
+104 -78
View File
@@ -31,19 +31,25 @@
#include "sectors.h"
/** Data used globally for operation on disk (encryption/decryption) */
dis_iodata_t disk_op_data;
/** Prototype of functions used internally */
static void* thread_decrypt(void* args);
static void* thread_encrypt(void* args);
static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
off_t sector_address, uint8_t *output);
static void fix_read_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
uint8_t *output);
static void fix_write_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
uint8_t *output);
static void fix_read_sector_seven(
dis_iodata_t* io_data,
off_t sector_address,
uint8_t *output
);
static void fix_read_sector_vista(
dis_iodata_t* io_data,
uint8_t* input,
uint8_t *output
);
static void fix_write_sector_vista(
dis_iodata_t* io_data,
uint8_t* input,
uint8_t *output
);
@@ -52,7 +58,7 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
* Read and decrypt one or more sectors
* @warning The sector_start has to be correctly aligned
*
* @param fd The file descriptor to the volume
* @param io_data The data structure containing volume's information
* @param nb_read_sector The number of sectors to read
* @param sector_size The size of one sector
* @param sector_start The offset of the first sector to read; See the warning
@@ -60,8 +66,12 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
* @param output The output buffer where to put decrypted data
* @return TRUE if result can be trusted, FALSE otherwise
*/
int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
off_t sector_start, uint8_t* output)
int read_decrypt_sectors(
dis_iodata_t* io_data,
size_t nb_read_sector,
uint16_t sector_size,
off_t sector_start,
uint8_t* output)
{
// Check parameters
if(!output)
@@ -77,7 +87,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
/* Be sure to lock for lseek/read */
if(pthread_mutex_lock(&disk_op_data.mutex_lseek_rw) != 0)
if(pthread_mutex_lock(&io_data->mutex_lseek_rw) != 0)
{
free(input);
xprintf(L_ERROR, "Can't lock rw mutex: %s\n", strerror(errno));
@@ -86,8 +96,8 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
/* Go where we need to read data */
off_t off = sector_start + disk_op_data.part_off;
if(lseek(fd, off, SEEK_SET) < 0)
off_t off = sector_start + io_data->part_off;
if(lseek(io_data->volume_fd, off, SEEK_SET) < 0)
{
free(input);
xprintf(L_ERROR, "Unable to lseek to %#" F_OFF_T "\n", off);
@@ -95,7 +105,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
}
/* Read the sectors we need */
ssize_t read_size = read(fd, input, size);
ssize_t read_size = read(io_data->volume_fd, input, size);
if(read_size <= 0)
{
@@ -106,7 +116,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
}
/* Unlock the previously locked mutex */
if(pthread_mutex_unlock(&disk_op_data.mutex_lseek_rw) != 0)
if(pthread_mutex_unlock(&io_data->mutex_lseek_rw) != 0)
{
free(input);
xprintf(L_ERROR, "Can't unlock rw mutex: %s\n", strerror(errno));
@@ -140,6 +150,8 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
args[loop].modulo = NB_THREAD;
args[loop].modulo_result = loop;
args[loop].io_data = io_data;
pthread_create( &thread[loop], NULL,
thread_decrypt, (void*) &args[loop] );
}
@@ -160,6 +172,8 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
arg.modulo = 0;
arg.modulo_result = 42;
args.io_data = io_data;
thread_decrypt(&arg);
}
#endif
@@ -175,7 +189,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
* Encrypt and write one or more sectors
* @warning The sector_start has to be correctly aligned
*
* @param fd The file descriptor to the volume
* @param io_data The data structure containing volume's information
* @param nb_write_sector The number of sectors to write
* @param sector_size The size of one sector
* @param sector_start The offset of the first sector to write; See the warning
@@ -183,8 +197,12 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
* @param output The input buffer which has to be encrypted and written
* @return TRUE if result can be trusted, FALSE otherwise
*/
int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
off_t sector_start, uint8_t* input)
int encrypt_write_sectors(
dis_iodata_t* io_data,
size_t nb_write_sector,
uint16_t sector_size,
off_t sector_start,
uint8_t* input)
{
// Check parameter
if(!input)
@@ -213,6 +231,8 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
args[loop].modulo = NB_THREAD;
args[loop].modulo_result = loop;
args[loop].io_data = io_data;
pthread_create( &thread[loop], NULL,
thread_encrypt, (void*) &args[loop] );
}
@@ -233,12 +253,14 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
arg.modulo = 0;
arg.modulo_result = 42;
args.io_data = io_data;
thread_encrypt(&arg);
}
#endif
/* Be sure to lock for lseek/write */
if(pthread_mutex_lock(&disk_op_data.mutex_lseek_rw) != 0)
if(pthread_mutex_lock(&io_data->mutex_lseek_rw) != 0)
{
free(output);
xprintf(L_ERROR, "Can't lock rw mutex: %s\n", strerror(errno));
@@ -246,8 +268,8 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
}
/* Go where we need to write data */
off_t off = sector_start + disk_op_data.part_off;
if(lseek(fd, off, SEEK_SET) < 0)
off_t off = sector_start + io_data->part_off;
if(lseek(io_data->volume_fd, off, SEEK_SET) < 0)
{
free(output);
xprintf(L_ERROR, "Unable to lseek to %#" F_OFF_T "\n", off);
@@ -255,13 +277,17 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
}
/* Write the sectors we want */
ssize_t write_size = write(fd, output, nb_write_sector * sector_size);
ssize_t write_size = write(
io_data->volume_fd,
output,
nb_write_sector * sector_size
);
/* Unlock the previously locked mutex */
if(pthread_mutex_unlock(&disk_op_data.mutex_lseek_rw) != 0)
if(pthread_mutex_unlock(&io_data->mutex_lseek_rw) != 0)
{
free(output);
xprintf(L_ERROR, "Can't unlock rw mutex: %s\n", strerror(errno));
free(output);
return FALSE;
}
@@ -283,7 +309,8 @@ static void* thread_decrypt(void* params)
if(!params)
return NULL;
thread_arg_t* args = (thread_arg_t*)params;
thread_arg_t* args = (thread_arg_t*)params;
dis_iodata_t* io_data = args->io_data;
off_t loop = 0;
off_t offset = args->sector_start;
@@ -293,7 +320,7 @@ static void* thread_decrypt(void* params)
size_t virt_loop = 0;
off_t metadata_offset = 0;
uint16_t version = disk_op_data.metadata->version;
uint16_t version = io_data->metadata->version;
off_t size = 0;
@@ -325,13 +352,13 @@ static void* thread_decrypt(void* params)
off_t sector_offset = args->sector_start / args->sector_size + loop;
/* Check for zero out areas */
for(virt_loop = 0; virt_loop < disk_op_data.nb_virt_region; virt_loop++)
for(virt_loop = 0; virt_loop < io_data->nb_virt_region; virt_loop++)
{
size = (off_t)disk_op_data.virt_region[virt_loop].size;
size = (off_t)io_data->virt_region[virt_loop].size;
if(size == 0)
continue;
metadata_offset = (off_t)disk_op_data.virt_region[virt_loop].addr;
metadata_offset = (off_t)io_data->virt_region[virt_loop].addr;
if(offset >= metadata_offset &&
offset <= metadata_offset + size)
{
@@ -348,20 +375,20 @@ static void* thread_decrypt(void* params)
/* Check for sectors fixing and non-encrypted sectors */
if(version == V_SEVEN &&
(uint64_t)sector_offset < disk_op_data.metadata->nb_backup_sectors)
(uint64_t)sector_offset < io_data->metadata->nb_backup_sectors)
{
/*
* The firsts sectors are encrypted in a different place on a
* Windows 7 volume
*/
fix_read_sector_seven(
&disk_op_data,
io_data,
offset,
loop_output
);
}
else if(version == V_SEVEN &&
(uint64_t)offset >= disk_op_data.metadata->encrypted_volume_size)
(uint64_t)offset >= io_data->metadata->encrypted_volume_size)
{
/* Do not decrypt when there's nothing to */
xprintf(L_DEBUG,
@@ -378,9 +405,9 @@ static void* thread_decrypt(void* params)
*/
if(sector_offset < 1)
fix_read_sector_vista(
&disk_op_data,
loop_input,
loop_output
io_data,
loop_input,
loop_output
);
else
{
@@ -396,7 +423,7 @@ static void* thread_decrypt(void* params)
{
/* Decrypt the sector */
if(!decrypt_sector(
&disk_op_data,
io_data,
loop_input,
offset,
loop_output
@@ -420,7 +447,8 @@ static void* thread_encrypt(void* params)
if(!params)
return NULL;
thread_arg_t* args = (thread_arg_t*)params;
thread_arg_t* args = (thread_arg_t*)params;
dis_iodata_t* io_data = args->io_data;
off_t loop = 0;
off_t offset = args->sector_start;
@@ -428,7 +456,7 @@ static void* thread_encrypt(void* params)
uint8_t* loop_input = args->input;
uint8_t* loop_output = args->output;
uint16_t version = disk_op_data.metadata->version;
uint16_t version = io_data->metadata->version;
for(loop = 0; loop < (off_t)args->nb_loop; ++loop,
@@ -451,7 +479,7 @@ static void* thread_encrypt(void* params)
/*
* NOTE: Seven specificities are dealt with earlier in the process
* see fuse.c:fs_write()
* see dislocker.c:enlock()
*/
if(version == V_VISTA && sector_offset < 16)
{
@@ -460,22 +488,22 @@ static void* thread_encrypt(void* params)
*/
if(sector_offset < 1)
fix_write_sector_vista(
&disk_op_data,
loop_input,
loop_output
io_data,
loop_input,
loop_output
);
else
memcpy(loop_output, loop_input, args->sector_size);
}
else if(version == V_SEVEN &&
(uint64_t)offset >= disk_op_data.metadata->encrypted_volume_size)
(uint64_t)offset >= io_data->metadata->encrypted_volume_size)
{
memcpy(loop_output, loop_input, args->sector_size);
}
else
{
if(!encrypt_sector(
&disk_op_data,
io_data,
loop_input,
offset,
loop_output
@@ -497,12 +525,11 @@ static void* thread_encrypt(void* params)
* "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Seven for
* read operation
*
* @param disk_op_data Data needed by FUSE and the decryption to deal with
* encrypted data
* @param io_data Data needed by the decryption to deal with encrypted data
* @param sector_address Address of the sector to decrypt
* @param output The buffer where to put fixed data
*/
static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
static void fix_read_sector_seven(dis_iodata_t* io_data,
off_t sector_address, uint8_t *output)
{
// Check parameter
@@ -515,19 +542,19 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
* So we can use them here to give a good NTFS partition's beginning.
*/
off_t from = sector_address;
off_t to = from + (off_t)disk_op_data->metadata->boot_sectors_backup;
off_t to = from + (off_t)io_data->metadata->boot_sectors_backup;
xprintf(L_DEBUG, " Fixing sector (7): from %#" F_OFF_T " to %#" F_OFF_T
"\n", from, to);
to += disk_op_data->part_off;
to += io_data->part_off;
uint8_t* input = malloc(disk_op_data->sector_size);
memset(input, 0, disk_op_data->sector_size);
uint8_t* input = malloc(io_data->sector_size);
memset(input, 0, io_data->sector_size);
/* Be sure to lock for lseek/read */
if(pthread_mutex_lock(&disk_op_data->mutex_lseek_rw) != 0)
if(pthread_mutex_lock(&io_data->mutex_lseek_rw) != 0)
{
free(input);
xprintf(L_ERROR, "Can't lock rw mutex: %s\n", strerror(errno));
@@ -535,7 +562,7 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
}
/* Go where we need to read the new sector */
if(lseek(disk_op_data->volume_fd, to, SEEK_SET) <0)
if(lseek(io_data->volume_fd, to, SEEK_SET) <0)
{
free(input);
xprintf(L_ERROR, "Unable to lseek to %#" F_OFF_T "\n", to);
@@ -543,12 +570,11 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
}
/* Read the real sector we need */
ssize_t read_size = read(disk_op_data->volume_fd, input,
disk_op_data->sector_size);
ssize_t read_size = read(io_data->volume_fd, input, io_data->sector_size);
/* Unlock the previously locked mutex */
if(pthread_mutex_unlock(&disk_op_data->mutex_lseek_rw) != 0)
if(pthread_mutex_unlock(&io_data->mutex_lseek_rw) != 0)
{
free(input);
xprintf(L_ERROR, "Can't unlock rw mutex: %s\n", strerror(errno));
@@ -560,21 +586,21 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
{
free(input);
xprintf(L_ERROR, "Unable to read %#" F_SIZE_T " bytes from %#" F_OFF_T
"\n", disk_op_data->sector_size, to);
"\n", io_data->sector_size, to);
return;
}
to -= disk_op_data->part_off;
to -= io_data->part_off;
/* If the sector wasn't yet encrypted, don't decrypt it */
if((uint64_t)to >= disk_op_data->metadata->encrypted_volume_size)
if((uint64_t)to >= io_data->metadata->encrypted_volume_size)
{
memcpy(output, input, disk_op_data->sector_size);
memcpy(output, input, io_data->sector_size);
}
else
{
decrypt_sector(
disk_op_data,
io_data,
input,
to,
output
@@ -589,12 +615,11 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
* "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Vista for
* read operation
*
* @param disk_op_data Data needed by FUSE and the decryption to deal with
* encrypted data
* @param io_data Data needed by the decryption to deal with encrypted data
* @param input The sector which needs a fix
* @param output The buffer where to put fixed data
*/
static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
static void fix_read_sector_vista(dis_iodata_t* io_data,
uint8_t* input, uint8_t *output)
{
// Check parameter
@@ -603,12 +628,12 @@ static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
xprintf(L_DEBUG, " Fixing sector (Vista): replacing signature "
"and MFTMirror field by: %#llx\n",
disk_op_data->metadata->mftmirror_backup);
io_data->metadata->mftmirror_backup);
/*
* Only two fields need to be changed: the NTFS signature and the MFT mirror
*/
memcpy(output, input, disk_op_data->sector_size);
memcpy(output, input, io_data->sector_size);
volume_header_t* formatted_output = (volume_header_t*)output;
@@ -616,7 +641,7 @@ static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
memcpy(formatted_output->signature, NTFS_SIGNATURE, NTFS_SIGNATURE_SIZE);
/* And this is for the MFT Mirror field */
formatted_output->mft_mirror = disk_op_data->metadata->mftmirror_backup;
formatted_output->mft_mirror = io_data->metadata->mftmirror_backup;
}
@@ -624,12 +649,11 @@ static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
* "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Vista for
* write operation
*
* @param disk_op_data Data needed by FUSE and the decryption to deal with
* encrypted data
* @param io_data Data needed by the decryption to deal with encrypted data
* @param input The sector which needs a fix
* @param output The buffer where to put fixed data
*/
static void fix_write_sector_vista(dis_iodata_t* disk_op_data,
static void fix_write_sector_vista(dis_iodata_t* io_data,
uint8_t* input, uint8_t *output)
{
// Check parameter
@@ -639,7 +663,7 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data,
/*
* Only two fields need to be changed: the NTFS signature and the MFT mirror
*/
memcpy(output, input, disk_op_data->sector_size);
memcpy(output, input, io_data->sector_size);
volume_header_t* formatted_output = (volume_header_t*)output;
@@ -649,15 +673,17 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data,
/* And this is for the metadata LCN */
formatted_output->metadata_lcn =
disk_op_data->metadata->offset_bl_header[0] /
io_data->metadata->offset_bl_header[0] /
(uint64_t)(
formatted_output->sectors_per_cluster *
formatted_output->sector_size
);
xprintf(L_DEBUG, " Fixing sector (Vista): replacing signature "
"and MFTMirror field by: %#llx\n",
formatted_output->metadata_lcn);
xprintf(
L_DEBUG,
" Fixing sector (Vista): replacing signature "
"and MFTMirror field by: %#llx\n",
formatted_output->metadata_lcn
);
}
+18 -2
View File
@@ -34,6 +34,8 @@
#include <pthread.h>
#include "dislocker.h"
/* Struct we pass to a thread for buffer enc/decryption */
typedef struct _thread_arg
@@ -48,6 +50,8 @@ typedef struct _thread_arg
unsigned int modulo;
unsigned int modulo_result;
dis_iodata_t* io_data;
} thread_arg_t;
@@ -56,7 +60,19 @@ typedef struct _thread_arg
/*
* Functions prototypes
*/
int read_decrypt_sectors( int fd, size_t nb_read_sector, uint16_t sector_size, off_t sector_start, uint8_t* output);
int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size, off_t sector_start, uint8_t* input);
int read_decrypt_sectors(
dis_iodata_t* io_data,
size_t nb_read_sector,
uint16_t sector_size,
off_t sector_start,
uint8_t* output
);
int encrypt_write_sectors(
dis_iodata_t* io_data,
size_t nb_write_sector,
uint16_t sector_size,
off_t sector_start,
uint8_t* input
);
#endif /* SECTORS_H */