@@ -0,0 +1,21 @@ | |||
CC=gcc | |||
CFLAGS=`pkg-config --cflags fuse` -O2 -Wall -D_REENTRANT -DDRIVER -DDEBUG_ON -o nvbit | |||
# -DHAVE_CONFIG_H -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=/usr/local/lib -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -g -O2 -Wall -W | |||
LDFLAGS=`pkg-config --libs fuse` | |||
nvbit: | |||
${CC} ${CFLAGS} ${LDFLAGS} *.c nvbitlocker/*.c nvbitlocker/aes/*.c nvbitlocker/sha256/*.c nvbitlocker/decrypt_key/*.c nvbitlocker/VMK_PASSWORD/*.c | |||
#$^ -o $@ | |||
clean: | |||
rm -f *.o *.obj | |||
rm -f nvbit | |||
${RM} *~ | |||
${RM} nvbit | |||
@@ -0,0 +1,409 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
#define FUSE_USE_VERSION 26 | |||
#define _FILE_OFFSET_BITS 64 | |||
#include <fuse.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <fcntl.h> | |||
#include <stdlib.h> | |||
#include <strings.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <unistd.h> | |||
// include bitlocker relaed files | |||
#include "nvbitlocker/common.h" | |||
#include "nvbitlocker/main.h" | |||
#include "nvbitlocker/header.h" | |||
#include "nvbitlocker/interface.h" | |||
#define VERSION "0.04" | |||
static const char *NTFS_FILENAME = "/NV_bitlocker_on_linux"; | |||
static struct Globals{ | |||
char *Filename; | |||
FILE *FileStruct; | |||
int FD; | |||
struct stat Stat; | |||
Interface* input_interface; // used to communicae wit bitocker encrypted volume | |||
options_structure options; /* used for internal processing such as | |||
keys, volume metadata etc | |||
*/ | |||
} Global_Data; | |||
/* This function fills the directory structure */ | |||
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | |||
off_t offset, struct fuse_file_info *fi); | |||
/*this function opens up the file */ | |||
static int fs_open(const char *path, struct fuse_file_info *fi); | |||
/* used to read decrypted buffer */ | |||
static int fs_read(const char *path, char *buf, size_t size, off_t offset, | |||
struct fuse_file_info *fi); | |||
// used to obtain attributes of files | |||
static int fs_getattr(const char *path, struct stat *stbuf); | |||
// print usage | |||
void usage( char **argv ); | |||
static struct fuse_operations fs_oper = { | |||
/* .getattr = hello_getattr, | |||
.readdir = hello_readdir, | |||
.open = hello_open, | |||
.read = hello_read, | |||
*/ | |||
.getattr = fs_getattr, | |||
.readdir = fs_readdir, | |||
.open = fs_open, | |||
.read = fs_read, | |||
}; | |||
static int fs_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, NTFS_FILENAME) == 0) { | |||
stbuf->st_mode = S_IFREG | 0444; | |||
stbuf->st_nlink = 1; | |||
stbuf->st_size = 1023 * 1024 * 1024; // change limit here , it's currently 1023 GB | |||
// stbuf->st_uid=fuse_get_context()->uid; | |||
// stbuf->st_gid=fuse_get_context()->gid; | |||
} | |||
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) | |||
{ | |||
(void) offset; | |||
(void) fi; | |||
if(strcmp(path, "/") != 0) | |||
return -ENOENT; | |||
filler(buf, ".", NULL, 0); | |||
filler(buf, "..", NULL, 0); | |||
filler(buf, NTFS_FILENAME + 1, NULL, 0); | |||
return 0; | |||
} | |||
// since only 1 file will be opened, messy code is not at all required | |||
static int fs_open(const char *path, struct fuse_file_info *fi) | |||
{ | |||
if(strcmp(path, NTFS_FILENAME) != 0) | |||
return -ENOENT; | |||
if((fi->flags & 3) != O_RDONLY) | |||
return -EACCES; | |||
return 0; | |||
} | |||
static int fs_read(const char *path, char *buf, size_t size, off_t offset, | |||
struct fuse_file_info *fi) | |||
{ | |||
unsigned char *buffer; | |||
long long sector_count; | |||
long long sector_start; | |||
unsigned long loop_var; | |||
unsigned long len; | |||
if(strcmp(path, NTFS_FILENAME) != 0) | |||
return -ENOENT; | |||
if ( size == 0) | |||
return 0; | |||
/* logic to do this is below | |||
count the number of full sectors add 2 to it 1 for lower and one for upper limit | |||
now decode all sectors | |||
now select and copy the data to user and deallocate all buffers | |||
*/ | |||
// this code cannot service large requests huh but who cares | |||
buffer = NULL; | |||
sector_count = (( size / Global_Data.input_interface->SectorSize ) + 2) ; | |||
sector_start = offset / Global_Data.input_interface->SectorSize; | |||
buffer = malloc ( sector_count * Global_Data.input_interface->SectorSize); | |||
if(!buffer) // if buffer could not be allocated, return with empty size | |||
return 0; | |||
// read all sectors one by one and decrypt them if necessary | |||
for(loop_var = 0 ; loop_var < sector_count; loop_var++){ | |||
Read_Sector(Global_Data.input_interface,(long long)((long long)loop_var+(long long)sector_start) ,1, buffer + loop_var * Global_Data.input_interface->SectorSize); | |||
// don't decrypt the first 4 sectors whatever might be the case | |||
if ( (long long)((long long)loop_var+(long long)sector_start) < 4) { | |||
// if it is first sector fix it up | |||
if ( (long long)((long long)loop_var+(long long)sector_start) == 0){ | |||
fix_sector(&Global_Data.options , buffer + loop_var * Global_Data.input_interface->SectorSize); | |||
} | |||
} | |||
else { // decrypt the sector | |||
decrypt_sector(&Global_Data.options,buffer + loop_var * Global_Data.input_interface->SectorSize,(long long)((long long)loop_var+(long long)sector_start)); | |||
} | |||
} | |||
// now copy the required amount of data to the user buffer | |||
memcpy(buf, | |||
buffer + ( offset % Global_Data.input_interface->SectorSize), | |||
size); | |||
free(buffer); | |||
return size; | |||
} | |||
// init necessary stuff here | |||
void init(){ | |||
Global_Data.Filename=NULL; | |||
Global_Data.FileStruct=NULL; | |||
Global_Data.FD=-1; | |||
// init fuse function callbacks | |||
//options structure is set to zero | |||
memset(&Global_Data.options,0,sizeof(options_structure)); | |||
} | |||
int main(int argc, char *argv[]) | |||
{ | |||
if (argc <=4 ){ | |||
usage(argv); | |||
exit(-1); | |||
} | |||
#ifdef DEBUG_ON | |||
printf("Starting nvbit Bitlocker Volume FUSE Driver\n"); | |||
#endif | |||
init(); | |||
// process parameters supplied | |||
process_options(argc,argv, &Global_Data.options); | |||
Global_Data.input_interface = InitializeInputInterface ( Global_Data.options.filename ); | |||
// we will be here if and only if necessary options have been found and processed | |||
// now we will verify whether the volume is a bitlocker volume | |||
verify_input_volume_and_parse(Global_Data.input_interface, &Global_Data.options); | |||
// everything is fine till now, so we got a key and we got data, so lets decode other set of keys | |||
decrypt_vmk(&Global_Data.options); | |||
if ( Global_Data.options.VMK_key_present < 1 ) { | |||
fprintf(stderr,"VMK could not be decrypted , VERIFY your keys !!! \n"); | |||
exit(1); | |||
} | |||
// we have now obainted VMK, now lets hunt down FVEK | |||
decrypt_fvek(&Global_Data.options); | |||
if ( Global_Data.options.FVEK_key_present < 1 ) { | |||
// this situation means something is not correct with the bitlocker volume | |||
// this situation should never occur, until the partition is manually damaged or th disk gets damaged | |||
fprintf(stderr,"FVEK could not be decrypted. Your partition is most probably corrupt !!! \n"); | |||
exit(1); | |||
} | |||
// inform user about encryption used | |||
switch (Global_Data.options.Encryption_Type) { | |||
case AES128: | |||
printf("This Volume was encrypted using AES 128\n"); | |||
break; | |||
case AES256: | |||
printf("This Volume was encrypted using AES 256\n"); | |||
break; | |||
case AES128_diffuser: | |||
printf("This Volume was encrypted using AES 128 + diffuser\n"); | |||
break; | |||
case AES256_diffuser: | |||
printf("This Volume was encrypted using AES 256 + diffuser\n"); | |||
break; | |||
default: | |||
printf("Unknown Algorithm\n" | |||
"Cannot Continue, Quitting \n"); | |||
exit(1); | |||
} | |||
// init keys once and for all | |||
init_keys(&Global_Data.options); | |||
#ifdef DEBUG_ON | |||
printf("Volume successfully mounted\n"); | |||
#endif | |||
// assumming our program always takes 2 paramters | |||
{ /* basic fuse stuff */ | |||
int i; | |||
int diff; | |||
char **nargv = (char **) malloc(argc * sizeof(char *)); | |||
diff = 4; // number of paramters for our program excluding the program name | |||
int nargc = argc - diff; | |||
nargv[0] = argv[0]; | |||
for(i = 0; i < nargc; i++) { | |||
nargv[i + 1] = argv[i + diff +1]; | |||
}; | |||
return fuse_main(nargc, nargv, &fs_oper,NULL); | |||
} | |||
} | |||
void usage( char **argv ){ | |||
printf("nvbit %s: Bitlocker for Linux \n" , VERSION ); | |||
printf ("\n" | |||
"This is free software. You may redistribute copies of it under the terms\n" | |||
"of the GNU General Public License Version 3<http://www.gnu.org/licenses/gpl-3.0.txt>.\n" | |||
"There is NO WARRANTY, to the extent permitted by law.\n"); | |||
printf("\n" | |||
"usage:\n" | |||
"nvbit options mount_point [<FUSE library options>]\n" | |||
"The following options are supported.\n" | |||
"-i /i the name of input bitlocker voume which is to be decrypted\n" | |||
"-sk /sk Startup Key file or Recovery key file (normally stored on USB key)\n" | |||
"-rp /rp Recovery password which can be entered by hand and is of the form xxxxx-xxxxx--xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx\n" | |||
"\n\n Visit www.nvlabs.in for updates/information\n\n"); | |||
} |
@@ -0,0 +1,143 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
/* this file implement recovery password related functions such as verify, testing etc | |||
sample recovery password 428593-377069-419914-450824-036729-210243-469029-482394 | |||
*/ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <malloc.h> | |||
#include "../common.h" | |||
#include "recoverypassword.h" | |||
#include "../sha256/sha.h" | |||
long Calculate_Recovery_Key_From_Password(unsigned char *recovery_password, | |||
unsigned char *header, unsigned long *output); | |||
long Calculate_Key(unsigned char *recovery_password, unsigned long | |||
recovery_password_length, unsigned char *salt, unsigned long *output); | |||
long Calculate_Recovery_Key_From_Password(unsigned char *recovery_password, | |||
unsigned char *header, unsigned long *output){ | |||
//since recovery key consists of 8 blocks of data, | |||
// preprocess them, at this stage recovery password is of the form | |||
// 1111-1111-11111-11111 and so on | |||
unsigned long temporary_password_block[8]; | |||
int16 recovery_pass[8]; | |||
unsigned long loop_var_i; | |||
unsigned char buffer[2000]; | |||
unsigned char buffer2[2000]; | |||
memset(temporary_password_block, 0, sizeof(temporary_password_block)); | |||
sscanf(recovery_password, "%d-%d-%d-%d-%d-%d-%d-%d", | |||
&temporary_password_block[0], &temporary_password_block[1], | |||
&temporary_password_block[2], &temporary_password_block[3], | |||
&temporary_password_block[4], &temporary_password_block[5], | |||
&temporary_password_block[6], &temporary_password_block[7]); | |||
for (loop_var_i = 0; loop_var_i <= 7; loop_var_i++){ | |||
// each block should be independantly perfectly divisible by 11 | |||
if ((temporary_password_block[loop_var_i] % 11) == 0) | |||
recovery_pass[loop_var_i] = (int16)(temporary_password_block[loop_var_i] | |||
/ 11); | |||
else | |||
return 0; | |||
} | |||
// we are here means password looks valid | |||
// now try to obtain actual key | |||
return Calculate_Key((unsigned char*)recovery_pass, 16, | |||
// since this is 128 bit key | |||
header + 12, output); | |||
} | |||
long Calculate_Key(unsigned char *recovery_password, unsigned long | |||
recovery_password_length, unsigned char *salt, unsigned long *output){ | |||
blob my_blob; | |||
unsigned char *output_buffer; | |||
unsigned long max_loop_count = 0x100000; | |||
memset(&my_blob, 0, sizeof(blob)); | |||
memcpy(my_blob.salt, salt, 0x10); // we only take 16 bytes of salt | |||
if (recovery_password_length < 0x65535){ | |||
sha256(recovery_password, recovery_password_length, my_blob.sha_password); | |||
} | |||
else | |||
return 0; | |||
/// return due to error caused | |||
while (max_loop_count){ | |||
sha256((unsigned char*) &my_blob, sizeof(blob), my_blob.sha_current); | |||
my_blob.hash_count++; | |||
max_loop_count--; | |||
} | |||
output_buffer = malloc(0xc + 0x20); | |||
memset(output_buffer, 0, 0x2c); | |||
// copy the resultant key out to the buffer | |||
memcpy((output_buffer + 0xC), &my_blob.sha_current, 0x20); | |||
*output = (int32)output_buffer; | |||
// TODO zero out the buffers | |||
// also clear up the the internal state of SHA function | |||
return 0; | |||
} |
@@ -0,0 +1,42 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
#ifndef RECOVERY_PASSWORD_H | |||
#define RECOVERY_PASSWORD_H | |||
#include "../common.h" | |||
// this blob is used for calculating recovery key from recovery password | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct { | |||
unsigned char sha_current[32]; | |||
unsigned char sha_password[32]; | |||
unsigned char salt[16]; | |||
int64 hash_count; | |||
}blob; | |||
# pragma pack () // restore original packing | |||
long Calculate_Recovery_Key_From_Password( | |||
unsigned char *recovery_password, | |||
unsigned char *header, | |||
unsigned long *output); | |||
#endif |
@@ -0,0 +1,103 @@ | |||
/** | |||
* \file aes.h | |||
*/ | |||
#ifndef XYSSL_AES_H | |||
#define XYSSL_AES_H | |||
#define AES_ENCRYPT 0 | |||
#define AES_DECRYPT 1 | |||
/** | |||
* \brief AES context structure | |||
*/ | |||
typedef struct | |||
{ | |||
int nr; /*!< number of rounds */ | |||
unsigned long *rk; /*!< AES round keys */ | |||
unsigned long buf[68]; /*!< unaligned data */ | |||
} | |||
aes_context; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
* \brief AES key schedule (encryption) | |||
* | |||
* \param ctx AES context to be initialized | |||
* \param key encryption key | |||
* \param keysize must be 128, 192 or 256 | |||
*/ | |||
void aes_setkey_enc( aes_context *ctx, unsigned char *key, int keysize ); | |||
/** | |||
* \brief AES key schedule (decryption) | |||
* | |||
* \param ctx AES context to be initialized | |||
* \param key decryption key | |||
* \param keysize must be 128, 192 or 256 | |||
*/ | |||
void aes_setkey_dec( aes_context *ctx, unsigned char *key, int keysize ); | |||
/** | |||
* \brief AES-ECB block encryption/decryption | |||
* | |||
* \param ctx AES context | |||
* \param mode AES_ENCRYPT or AES_DECRYPT | |||
* \param input 16-byte input block | |||
* \param output 16-byte output block | |||
*/ | |||
void aes_crypt_ecb( aes_context *ctx, | |||
int mode, | |||
unsigned char input[16], | |||
unsigned char output[16] ); | |||
/** | |||
* \brief AES-CBC buffer encryption/decryption | |||
* | |||
* \param ctx AES context | |||
* \param mode AES_ENCRYPT or AES_DECRYPT | |||
* \param length length of the input data | |||
* \param iv initialization vector (updated after use) | |||
* \param input buffer holding the input data | |||
* \param output buffer holding the output data | |||
*/ | |||
void aes_crypt_cbc( aes_context *ctx, | |||
int mode, | |||
int length, | |||
unsigned char iv[16], | |||
unsigned char *input, | |||
unsigned char *output ); | |||
/** | |||
* \brief AES-CFB buffer encryption/decryption | |||
* | |||
* \param ctx AES context | |||
* \param mode AES_ENCRYPT or AES_DECRYPT | |||
* \param length length of the input data | |||
* \param iv_off offset in IV (updated after use) | |||
* \param iv initialization vector (updated after use) | |||
* \param input buffer holding the input data | |||
* \param output buffer holding the output data | |||
*/ | |||
void aes_crypt_cfb( aes_context *ctx, | |||
int mode, | |||
int length, | |||
int *iv_off, | |||
unsigned char iv[16], | |||
unsigned char *input, | |||
unsigned char *output ); | |||
/** | |||
* \brief Checkup routine | |||
* | |||
* \return 0 if successful, or 1 if the test failed | |||
*/ | |||
int aes_self_test( int verbose ); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* aes.h */ |
@@ -0,0 +1,70 @@ | |||
/** | |||
* \file config.h | |||
* | |||
* This set of compile-time options may be used to enable | |||
* or disable features selectively, and reduce the global | |||
* memory footprint. | |||
*/ | |||
#ifndef XYSSL_CONFIG_H | |||
#define XYSSL_CONFIG_H | |||
#ifndef _CRT_SECURE_NO_DEPRECATE | |||
#define _CRT_SECURE_NO_DEPRECATE 1 | |||
#endif | |||
/* | |||
* Uncomment if native integers are 8-bit wide. | |||
* | |||
#define XYSSL_HAVE_INT8 | |||
*/ | |||
/* | |||
* Uncomment if native integers are 16-bit wide. | |||
* | |||
#define XYSSL_HAVE_INT16 | |||
*/ | |||
/* | |||
* Uncomment if the compiler supports long long. | |||
* | |||
#define XYSSL_HAVE_LONGLONG | |||
*/ | |||
/* | |||
* Uncomment if the CPU supports SSE2 (IA-32 specific). | |||
* | |||
#define XYSSL_HAVE_SSE2 | |||
*/ | |||
/* | |||
* Enable all SSL/TLS debugging messages. | |||
*/ | |||
#define XYSSL_DEBUG_MSG | |||
/* | |||
* Enable the checkup functions (*_self_test). | |||
*/ | |||
#define XYSSL_SELF_TEST | |||
/* | |||
* Enable the prime-number generation code. | |||
*/ | |||
#define XYSSL_GENPRIME | |||
/* | |||
* Uncomment this macro to store the AES tables in ROM. | |||
* | |||
#define XYSSL_AES_ROM_TABLES | |||
*/ | |||
/* | |||
* Module: library/aes.c | |||
* Caller: library/ssl_tls.c | |||
* | |||
* This module enables the following ciphersuites: | |||
* SSL_RSA_AES_256_SHA | |||
* SSL_EDH_RSA_AES_256_SHA | |||
*/ | |||
#define XYSSL_AES_C | |||
#endif |
@@ -0,0 +1,69 @@ | |||
/** | |||
* \file padlock.h | |||
*/ | |||
#ifndef XYSSL_PADLOCK_H | |||
#define XYSSL_PADLOCK_H | |||
#include "aes.h" | |||
#if (defined(__GNUC__) && defined(__i386__)) | |||
#ifndef XYSSL_HAVE_X86 | |||
#define XYSSL_HAVE_X86 | |||
#endif | |||
#define PADLOCK_RNG 0x000C | |||
#define PADLOCK_ACE 0x00C0 | |||
#define PADLOCK_PHE 0x0C00 | |||
#define PADLOCK_PMM 0x3000 | |||
#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15)) | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
* \brief PadLock detection routine | |||
* | |||
* \return 1 if CPU has support for the feature, 0 otherwise | |||
*/ | |||
int padlock_supports( int feature ); | |||
/** | |||
* \brief PadLock AES-ECB block en(de)cryption | |||
* | |||
* \param ctx AES context | |||
* \param mode AES_ENCRYPT or AES_DECRYPT | |||
* \param input 16-byte input block | |||
* \param output 16-byte output block | |||
*/ | |||
void padlock_xcryptecb( aes_context *ctx, | |||
int mode, | |||
unsigned char input[16], | |||
unsigned char output[16] ); | |||
/** | |||
* \brief PadLock AES-CBC buffer en(de)cryption | |||
* | |||
* \param ctx AES context | |||
* \param mode AES_ENCRYPT or AES_DECRYPT | |||
* \param length length of the input data | |||
* \param iv initialization vector (updated after use) | |||
* \param input buffer holding the input data | |||
* \param output buffer holding the output data | |||
*/ | |||
void padlock_xcryptcbc( aes_context *ctx, | |||
int mode, | |||
int length, | |||
unsigned char iv[16], | |||
unsigned char *input, | |||
unsigned char *output ); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* HAVE_X86 */ | |||
#endif /* padlock.h */ |
@@ -0,0 +1,77 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
// This file contains some common definitions | |||
#include <stdio.h> | |||
#include <malloc.h> | |||
#include "common.h" | |||
#include "header.h" | |||
// all keys are 32 bytes or 256 bit | |||
// though this sgould be a function which should calculate key size from header and after header data | |||
// however, at this time it's hard code, however it's working till now !!!!! | |||
#define GetKeySize(x) 0x20 | |||
// this will return a pointer to the next header | |||
HEADER *Next_Header(HEADER * header_ptr) | |||
{ | |||
HEADER *header; | |||
header = header_ptr; | |||
header = (HEADER *)((int8 *)header + header->Size); | |||
if(header) | |||
return header; | |||
return NULL; | |||
} | |||
// this will return a pointer to data contained in the header | |||
int8 *Header_Data_Pointer(HEADER * header) | |||
{ | |||
if ( header->Size > sizeof(HEADER)) | |||
return ((int8 *)header + sizeof(HEADER)); | |||
else | |||
return 0; // if no data then return 0 | |||
} | |||
// this will allocate a buffer and zero it out | |||
void *malloc_zero(int32 Size) | |||
{ | |||
void *ptr; | |||
ptr = malloc(Size); | |||
if(!ptr) | |||
return 0; // return if memory could not be allocated | |||
// now do a memset | |||
memset(ptr,0,Size); | |||
return ptr; | |||
} |
@@ -0,0 +1,97 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
// this header file contains all common definitions including data types | |||
// disable warnings | |||
#pragma warning( disable : 4047 4244 4996 4267 4013 4311) | |||
#ifndef COMMON_H | |||
#define COMMON_H | |||
#include <stdio.h> | |||
#define LINUX | |||
// data type defines for VC++ 6.0 | |||
#ifdef WIN32 | |||
typedef unsigned __int8 int8; | |||
typedef unsigned __int16 int16; | |||
typedef unsigned __int32 int32; | |||
typedef unsigned __int64 int64; | |||
#endif | |||
#ifdef LINUX // data type define for linux | |||
typedef unsigned char int8; | |||
typedef unsigned short int16; | |||
typedef unsigned long int32; | |||
typedef unsigned long long int64; | |||
#endif | |||
typedef int64 FILETIME; | |||
/* guids are of the following type | |||
02DD640E-E6E7-439E-B526-3F419CA3CE95 | |||
1 2 3 4 5 | |||
*/ | |||
/*#ifdef GUID | |||
#undefine GUID | |||
#endif | |||
*/ | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _GUID { | |||
int32 first; // it should be value defined in FVE_SIGNATURE in fve.h | |||
int16 second; | |||
int16 third; | |||
int8 fourth[2]; | |||
int8 fifth[6] ; | |||
} GUID; | |||
# pragma pack () // restore original packing | |||
#endif // COMMON_H | |||
@@ -0,0 +1,451 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
/* This file contains sector decrytion releated functions.This file also contains diffuser implementation (one sided) | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> // for _lrotr function | |||
#include <malloc.h> | |||
#include <time.h> | |||
#include "common.h" | |||
#include "header.h" | |||
#include "interface.h" | |||
#include "aes/aes.h" | |||
#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) | |||
/* Only first and last sectors need to be patched */ | |||
void fix_sector( options_structure *options, | |||
int8 *buffer) // the buffer which needs to be fixed | |||
{ | |||
/* only changes that are made to a ntfs boot sector after enabling bitlocker are | |||
the MFT mirror paramter is chaged to point to FVE meta data | |||
the volume identifier is changed from "NTFS " to "-FVE-FS-" | |||
then changed MFT mirror value is stored in the FVE-metadata | |||
*/ | |||
FVE_META_DATA *meta_data; | |||
meta_data = (FVE_META_DATA *)buffer; | |||
meta_data->MetaDataLCN = options->more_fve_data.MFT_Mirror ; | |||
// now update the the partion id | |||
memcpy( meta_data->Signature,NTFS_SIGNATURE,8); | |||
// successful patching done so return | |||
} | |||
void init_keys(options_structure *options) | |||
{ | |||
// volume keys are always 256 bit whatevr the condition | |||
aes_setkey_enc( &options->context.VMK_E_ctx, options->VMK_key+12,256); | |||
aes_setkey_dec( &options->context.VMK_D_ctx, options->VMK_key+12,256); | |||
//FVEK keys depend on algorithm | |||
if ( options->Encryption_Type == AES128 || options->Encryption_Type == AES128_diffuser ) { | |||
aes_setkey_enc( &options->context.FVEK_E_ctx, options->FVEK_key+12,128); | |||
aes_setkey_dec( &options->context.FVEK_D_ctx, options->FVEK_key+12,128); | |||
} | |||
if ( options->Encryption_Type == AES256 || options->Encryption_Type == AES256_diffuser ) { | |||
aes_setkey_enc( &options->context.FVEK_E_ctx, options->FVEK_key+12,256); | |||
aes_setkey_dec( &options->context.FVEK_D_ctx, options->FVEK_key+12,256); | |||
} | |||
// TWEAK keys also depend on algorithm | |||
if ( options->Encryption_Type == AES128_diffuser ) { | |||
aes_setkey_enc( &options->context.TWEAK_E_ctx, options->Tweak_Key+12,128); | |||
aes_setkey_dec( &options->context.TWEAK_D_ctx, options->Tweak_Key+12,128); | |||
} | |||
if ( options->Encryption_Type == AES256_diffuser ) { | |||
aes_setkey_enc( &options->context.TWEAK_E_ctx, options->Tweak_Key+12,256); | |||
aes_setkey_dec( &options->context.TWEAK_D_ctx, options->Tweak_Key+12,256); | |||
} | |||
// all key contexts have been set | |||
} | |||
void decrypt_diffused_sector( options_structure *options, // the usual keys | |||
int8 *sector_data, // actual encrypted data after decrypted data is also available here | |||
int32 sector_size, // size of sector which is being decoded | |||
int64 sector ); | |||
// this means a sector encrypted with pure AES 128 or AES 256 | |||
unsigned long decrypt_normal_sector( options_structure *options, // the usual keys | |||
int8 *sector_data, // actual encrypted data after decrypted data is also available here | |||
int32 sector_size, // size of sector which is being decoded | |||
int64 sector ) // this means if a 4 th sector sector is being decoded | |||
{ | |||
aes_context fvek_d_ctxt; | |||
int8 IV[20] ; // initilization vector | |||
/* | |||
// if algorithm is not AES 128 or AES 256 return -1 | |||
if ( options->Encryption_Type == AES128_diffuser || | |||
options->Encryption_Type == AES256_diffuser ) | |||
return -1; | |||
// setup key schedule according to the algorithm | |||
if ( options->Encryption_Type == AES128 ) | |||
aes_setkey_dec( &fvek_d_ctxt, options->FVEK_key + 12, 128); // 128 bit encryption | |||
else if (options->Encryption_Type == AES256) | |||
aes_setkey_dec( &fvek_d_ctxt, options->FVEK_key + 12, 256); // select 256 bit encryption | |||
else | |||
return -1; | |||
*/ | |||
memset(IV,0,sizeof(IV)); // init initialization vector | |||
aes_crypt_cbc(&options->context.FVEK_D_ctx,AES_DECRYPT,sector_size,IV,sector_data,sector_data); | |||
return 0; | |||
} | |||
// this will select a decryptor based on the algorithm selected in the FVEK | |||
// and return result | |||
void decrypt_sector(options_structure *options, | |||
int8 *sector_data, | |||
int64 sector ) | |||
{ | |||
// select a function based on algorithm | |||
if ( options->Encryption_Type == AES128 || options->Encryption_Type == AES256 ) | |||
return decrypt_normal_sector(options,sector_data,options->fve_meta_data.BytesPerSector,sector); | |||
if ( options->Encryption_Type == AES128_diffuser || options->Encryption_Type == AES256_diffuser ) | |||
return decrypt_diffused_sector(options,sector_data,options->fve_meta_data.BytesPerSector,sector); | |||
// we are here means unknown algorithm | |||
return -1; | |||
} | |||
// this function does the actual decryption of data | |||
void decrypt_data(Interface* input_interface, options_structure *options) { | |||
unsigned char encrypted_buffer[ 8192]; | |||
unsigned char decrypted_buffer[8192]; | |||
FILE *stream; | |||
unsigned long loop_var; | |||
if( (stream = fopen( "decrypted", "w+b" )) == NULL ) { | |||
printf("Output file could not be opned"); | |||
return ; | |||
} | |||
// process first sector and write it | |||
Read_Sector( input_interface,0 ,1, encrypted_buffer); | |||
fix_sector(options,encrypted_buffer); | |||
fwrite(encrypted_buffer,1,512,stream); | |||
loop_var =0; // start decrypting from the 9 sector | |||
#define DECRYPTED_SECTORS 10 | |||
for ( loop_var =1 ;loop_var < DECRYPTED_SECTORS;loop_var++) | |||
{ | |||
Read_Sector( input_interface,loop_var ,1, encrypted_buffer); | |||
fwrite(encrypted_buffer,1,512,stream); | |||
} | |||
loop_var = DECRYPTED_SECTORS ; | |||
//for(loop_var = 0; loop_var < 100000 ;loop_var++) | |||
while( 1)//!feof(input_interface->stream )) | |||
{ | |||
loop_var++; | |||
// read one sector at a time and decrypt it | |||
//if (! feof( input_interface->stream)) { | |||
Read_Sector( input_interface,loop_var ,1, encrypted_buffer); | |||
//} | |||
// if eof break; | |||
if ( feof(input_interface->stream )) | |||
break; | |||
// sector has been read now decrypt it | |||
decrypt_sector(options,encrypted_buffer,loop_var); | |||
fwrite(encrypted_buffer,1,512,stream); | |||
} | |||
// we are here means whole file has been decrypte including the last sector | |||
// so fix it up | |||
// it is done by seeking back 512 bytes | |||
// reading 0 sector , fixing it up | |||
// and then writing it again | |||
custom_fseek(stream, (int64)0 - (int64)input_interface->SectorSize ,SEEK_CUR); | |||
Read_Sector( input_interface,0 ,1, encrypted_buffer); | |||
fix_sector(options,encrypted_buffer); | |||
fwrite(encrypted_buffer,1,512,stream); | |||
fclose(stream); | |||
} | |||
unsigned long Diffuser_B_Decrypt(unsigned char *input, int32 input_size); | |||
unsigned long Diffuser_A_Decrypt(unsigned char *input, int32 input_size); | |||
void decrypt_diffused_sector( options_structure *options, // the usual keys | |||
unsigned char *sector_data, // actual encrypted data after decrypted data is also available here | |||
int32 sector_size, // size of sector which is being decoded | |||
int64 sector ) // this means if a 4 th sector sector is being decoded | |||
{ | |||
unsigned char IV[20]; // used to stor IV which is sector specific | |||
unsigned char e[20] ; // used to store sector byte offset | |||
unsigned char sector_key_buffer[40]; // it's actuall a 512 bit value which is xored into the plain text | |||
int64 temp_var_e; | |||
unsigned long loop_var; | |||
/*aes_context fvek_e_ctxt,fvek_d_ctxt; | |||
aes_context tweak_e_ctxt,tweak_d_ctxt; | |||
// initialise contexts | |||
aes_setkey_dec( &fvek_d_ctxt, options->FVEK_key + 12, 128); | |||
aes_setkey_enc( &fvek_e_ctxt, options->FVEK_key + 12, 128); | |||
aes_setkey_dec (&tweak_d_ctxt, options->Tweak_Key + 12 , 128); | |||
aes_setkey_enc (&tweak_e_ctxt, options->Tweak_Key + 12 , 128); // this key is used to get sector key | |||
*/ | |||
// let us compute e and other data which is necessary for decryption | |||
/*first e is computed | |||
e is nothing byt byte offset of that sector from start of volume | |||
*/ | |||
temp_var_e = sector * options->fve_meta_data.BytesPerSector ; | |||
memset(e,0,sizeof(e)); | |||
memcpy(e, &temp_var_e , sizeof(temp_var_e)); // copy this number into a buffer in least byte first encoding | |||
// now let us fill in IV for this sector | |||
aes_crypt_ecb(&options->context.FVEK_E_ctx,AES_ENCRYPT,e , IV); | |||
// this block will fill the sector key | |||
{ | |||
// now let us compuet sector_key_buffer | |||
aes_crypt_ecb(&options->context.TWEAK_E_ctx,AES_ENCRYPT,e,sector_key_buffer) ; | |||
//now put 128 in the 16th byte of e | |||
e[15] = 128; // now e represent's e' | |||
aes_crypt_ecb(&options->context.TWEAK_E_ctx,AES_ENCRYPT,e,sector_key_buffer+ 16) ; | |||
} | |||
// now decrypt the buffer usinf AESCBC using the fvek key decryption context | |||
// we use the same buffer as both input and output | |||
aes_crypt_cbc(&options->context.FVEK_D_ctx,AES_DECRYPT,options->fve_meta_data.BytesPerSector,IV,sector_data,sector_data); | |||
// now let us call the diffuser B decryptor | |||
Diffuser_B_Decrypt(sector_data,options->fve_meta_data.BytesPerSector); | |||
// now let us call the diffuser B decryptor | |||
Diffuser_A_Decrypt(sector_data,options->fve_meta_data.BytesPerSector); | |||
// apply sector XOR wit sector key | |||
for( loop_var = 0 ; loop_var < options->fve_meta_data.BytesPerSector ;loop_var++) | |||
sector_data[loop_var] = sector_data[loop_var] ^ sector_key_buffer[ loop_var % 32] ; | |||
// at this stage the buffer is already decrypted succesfully, if everything went right | |||
return ; | |||
} | |||
// TODO write an ecryption function just convertting first plus into minus will make an encryption function | |||
//this applies to both Diffuser A and Diffuser B , thus we can have write support | |||
// this will apply an in place diffuser B decryption function | |||
int32 Diffuser_B_Decrypt(unsigned char *input, unsigned long input_size) | |||
{ | |||
int32 temp_array[512]; | |||
int32 loop_var; | |||
int32 max_loop; | |||
int32 total_loop; // no . of times diffuser is applied to whole block | |||
//init array with supplied data | |||
memcpy(temp_array,input, input_size); | |||
max_loop = input_size / 4; | |||
total_loop = 3; // the diffuser function is applied a total of 3 times | |||
while ( total_loop) { | |||
// the below loop should be executed | |||
for ( loop_var = 0 ; loop_var < (max_loop-1) ;) { | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var +2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var + 5) % max_loop]),0)); | |||
loop_var++; | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var +2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var + 5) % max_loop]),10)); | |||
loop_var++; | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var +2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var + 5) % max_loop]),0)); | |||
loop_var++; | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var +2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var + 5) % max_loop]),25)); | |||
loop_var++; | |||
} | |||
total_loop-- ; | |||
} // end total_loop | |||
// now copy the output onto to the input | |||
memcpy(input, temp_array, input_size); | |||
return 0; | |||
} | |||
// this will apply an in place diffuser A decryption function | |||
int32 Diffuser_A_Decrypt(unsigned char *input, int32 input_size) | |||
{ | |||
unsigned long temp_array[512]; | |||
unsigned long loop_var; | |||
unsigned long max_loop; | |||
unsigned long total_loop; // no . of times diffuser is applied to whole block | |||
//init array with supplied data | |||
memcpy(temp_array,input, input_size); | |||
max_loop = input_size / 4; | |||
total_loop = 5; // the diffuser function is applied a total of 3 times | |||
while ( total_loop) { | |||
// the below loop should be executed | |||
for ( loop_var = 0 ; loop_var < (max_loop-1) ;) { | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var -2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var - 5) % max_loop]),9)); | |||
loop_var++; | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var -2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var - 5) % max_loop]),0)); | |||
loop_var++; | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var -2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var - 5) % max_loop]),13)); | |||
loop_var++; | |||
temp_array[loop_var] = temp_array[loop_var] + ( temp_array [ (loop_var -2 ) % max_loop] ^ ROTATE( (temp_array [ ( loop_var - 5) % max_loop]),0)); | |||
loop_var++; | |||
} | |||
total_loop-- ; | |||
} // end total_loop | |||
// now copy the output onto to the input | |||
memcpy(input, temp_array, input_size); | |||
return 0; | |||
} |
@@ -0,0 +1,184 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
/* this file implements functions to decrypt in AESS, CCM mode as done by bitlocker | |||
*/ | |||
#include <string.h> | |||
#include "decryptkey.h" | |||
#include "../aes/aes.h" | |||
#include "../header.h" | |||
/* | |||
when encrypting a microsoft compatible style a 16 byte hash is prepended to data | |||
which contains AES form authentication code, but really we don't care about | |||
or should we start caring ???? | |||
*/ | |||
// user is responsible for aligning the input to align on 6 byte boundary | |||
void aes_ccm_encrypt_decrypt(aes_context *ctxt, | |||
unsigned char *iv, unsigned long iv_length, | |||
unsigned char *input, unsigned long input_length, | |||
unsigned char *output) | |||
{ | |||
unsigned char internal_iv[20]; | |||
unsigned char loop_var; | |||
unsigned char temp_buf[16]; | |||
int32 local_input_length; | |||
/* | |||
here is how the counter works in microsoft compatible ccm implementation | |||
user supplies less than 16 byte iv | |||
after copying it forms into this format | |||
1 byte field | |||
15-iv_length-1 | iv (max 14 bytes) | a single byte counter counting from zero | |||
now applying counter mode of aes | |||
*/ | |||
memset(internal_iv,0,sizeof(internal_iv)); | |||
memcpy(internal_iv+1 , iv, (iv_length % 16)); // avoiding buffer overflow | |||
*internal_iv = 15 -iv_length -1; | |||
/* aes_crypt_ecb( ctxt, mode, internal_iv, temp_buf ); | |||
// xor it encoded internal_iv (present in temp_buf | |||
for(loop_var =0 ; loop_var <=15;loop_var++) | |||
output[loop_var] = input[loop_var] ^ temp_buf[loop_var]; | |||
// increment internal_iv | |||
internal_iv[15] = 1; | |||
// now process the whole data | |||
input = input+16; | |||
output = output+16; | |||
*/ | |||
local_input_length = input_length; | |||
while ( local_input_length > 0) { | |||
aes_crypt_ecb( ctxt, AES_ENCRYPT, internal_iv, temp_buf ); | |||
for(loop_var =0 ; loop_var <=15;loop_var++) | |||
output[loop_var] = input[loop_var] ^ temp_buf[loop_var]; | |||
internal_iv[15]++; | |||
local_input_length -= 16; | |||
input = input+16; | |||
output = output+16; | |||
// handle last block since data could be misaligned | |||
if ( local_input_length > 0 && | |||
local_input_length < 16) | |||
{ | |||
aes_crypt_ecb( ctxt, AES_ENCRYPT, internal_iv, temp_buf ); | |||
for(loop_var =0 ; loop_var <=15;loop_var++) | |||
output[loop_var] = input[loop_var] ^ temp_buf[loop_var]; | |||
break; // jump out of loop | |||
} | |||
} | |||
} | |||
long decrypt(unsigned char *input, | |||
unsigned char *key, | |||
unsigned long *output, | |||
unsigned long *output_size) | |||
{ | |||
aes_context ctx; | |||
unsigned char local_input_buffer[1024]; | |||
unsigned char local_output_buffer[1024]; | |||
unsigned long input_size; | |||
unsigned long local_output_size; | |||
unsigned char *output_buffer; | |||
HEADER *header = (HEADER *)input; | |||
//allocate output_buffer | |||
output_buffer = malloc(header->Size - 36); /* 8 byte header | |||
12 byte nounce | |||
16 byte authenticator */ | |||
local_output_size= header->Size - 36; | |||
input_size = header->Size - 20 ; /* 8 byte header | |||
12 byte nounce | |||
auhtenticator is used while decrypting | |||
*/ | |||
memcpy ( local_input_buffer , input + 20 , input_size) ; | |||
// set key which is used to decrypt | |||
aes_setkey_enc( &ctx, key + 12, 256); | |||
aes_ccm_encrypt_decrypt (&ctx, | |||
input+8, | |||
0xc , // nounce is hardcode to be 0xc or 12 bytes | |||
local_input_buffer, | |||
input_size, | |||
output); | |||
//local_output_buffer); | |||
*output_size = local_output_size; | |||
memmove(output, ((long)output + 16),local_output_size); | |||
memset ( ((long)output+local_output_size), 0 , 32); | |||
//memset(local_output_buffer,0,output_size+16); | |||
free(output_buffer); | |||
return 0; | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
#ifndef DECRYPT_KEY_H | |||
#define DECRYPT_KEY_H | |||
long decrypt(unsigned char *input, | |||
unsigned char *key, | |||
unsigned long *output, | |||
unsigned long *output_size); | |||
#endif |
@@ -0,0 +1,45 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
// this header file contains all common definitions including data types | |||
// disable warnings | |||
#pragma warning( disable : 4047 4244 4996 4267 4013 4311) | |||
#ifndef ERROR_CODES_H | |||
#define ERROR_CODES_H | |||
#define NO_RECOVERY_PASSWORD_CONTAINER_FOUND 0xC0000101 | |||
#define NO_STARTUP_PASSWORD_CONTAINER_FOUND 0xC0000102 | |||
#define INVALID_STARTUP_KEY 0xC0000200 | |||
#define INVALID_FVEK_KEY 0xC0000201 | |||
#endif // ERROR_CODES_H | |||
@@ -0,0 +1,88 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
// this header file contains all definition to to FVE ( Full volume Encryption of Bitlocker) | |||
#include "common.h" | |||
#ifndef FVE_H | |||
#define FVE_H | |||
// this is the signature for FVE partition | |||
#define FVE_SIGNATURE "-FVE-FS-" | |||
#define NTFS_SIGNATURE "NTFS " | |||
// this is the structure of the first sector of FVE encrypted Volume | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _FVE_META_DATA { | |||
int8 jmp[3]; //offset 0x0 // this is the jmp // never used | |||
int8 Signature[8]; //offset 0x3 // 8 bytes signature | |||
int16 BytesPerSector; //offset 0xB // it can be 512,1024 and so on | |||
int8 SectorPerCluster;//offset 0xD | |||
/* it can be | |||
0x1 ,0x2, 0x4 ,0x8 | |||
0x10,0x20,0x40,0x80 */ | |||
int16 ReservedClusters; //offset 0xe // 0x0000 | |||
int8 FATCount; //offset 0x10 // 0x00 | |||
int16 RootEntries; //offset 0x11 // 0x0000 | |||
int16 Sectors; //offset 0x13 // 0x0000 | |||
int16 SectorsPerFAT; //offset 0x16 // 0x0000 | |||
int16 unknown1; // just a placeholder | |||
int32 LargeSectors; //offset 0x20 // 0x00000000 | |||
int32 unknown; // offset 0x24 | |||
int32 unknown2; // place holder | |||
int16 unknown3; | |||
int8 unknown4; | |||
int64 Total_Sectors; // total number of sectors in volu me | |||
int64 MFT; | |||
int64 MetaDataLCN; //offset 0x38 | |||
// This points to cluster containing VMK metadata | |||
// to calculate sectornumber = MetaDataLCN * SectorPerCluster | |||
} FVE_META_DATA; | |||
typedef struct _MORE_FVE_DATA { | |||
int8 Signature[8]; | |||
int8 header[8]; | |||
int8 reserved[16] ; | |||
int64 FVE_MetaData[3]; | |||
int64 MFT_Mirror; // this value is filled from NTFS boot sector before conversion | |||
} MORE_FVE_DATA; | |||
# pragma pack () // restore original packing | |||
#endif // FVE_H | |||
@@ -0,0 +1,320 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||
------------------- | |||
Copyright (c) 2008 | |||
Released under the GPL Version 3 | |||
http://www.gnu.org/licenses/gpl-3.0.txt | |||
*/ | |||
// this header file contains all definition to header structure | |||
#include "common.h" | |||
#include "fve.h" | |||
#include "time.h" | |||
#include "aes/aes.h" | |||
#ifndef HEADER_H | |||
#define HEADER_H | |||
// this is the header of every data contained in FVE_METADATA | |||
/* here goes a brief tree for the structure | |||
MAIN_HEADER | |||
HEADER // this contains drive label | |||
KEY_CONTAINER // there can be a number of key conatiner | |||
HEADER after some random no of bytes another HEADER is present | |||
the above 2 headers are no in the key container, is there something special about them | |||
the KEY_CONTAINER itself itself consists of a number of HEADER | |||
KEY_CONTAINER HEADER | |||
HEADER // contains info such as External Key, DiskPassword etc | |||
HEADER // the VMK key most probably | |||
HEADER // another key MOST probably FVEK | |||
*/ | |||
// this header is starts at 0x40 always | |||
// VMK header is prepended by this header | |||
//Main header, it acts like a sub container for other information | |||
///structure is a minimum of 0x30 or 48 bytes total | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _MAIN_HEADER { | |||
int32 Size; // it should be value defined in FVE_SIGNATURE in fve.h | |||
int32 Version; // it's 1 for now | |||
int32 Isize; // it is size of initial structure and is always 0x30 // does it reallly serve any purpose | |||
int32 Size1; //a copy of Size | |||
int8 Reserved1[16]; // it's probably used to store something hash or salt but unknown, | |||
int32 Reserved2; // it's the same as Version | |||
int32 Encryption_Type; /* it's should be one of these | |||
0x8000 AES 128 + diffuser | |||
0x8001 AES 256 + diffuser | |||
0x8002 AES 128 | |||
0x8003 AES 256 | |||
*/ | |||
FILETIME Time; // it is the time when this structure was started to fill up; | |||
// so we can analyse this to found time or when it was last updated and tell when was Bitlocker enabled | |||
// this is just an assumption | |||
} MAIN_HEADER; | |||
# pragma pack () // restore original packing | |||
// codes assigned by M$FT, to various algorithms | |||
#define AES128_diffuser 0x8000 | |||
#define AES256_diffuser 0x8001 | |||
#define AES128 0x8002 | |||
#define AES256 0x8003 | |||
/* KEY_CONTAINER stores the data after the header, | |||
after header there are 3 header, one contains name, the other 2 contain keys | |||
*/ | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _KEY_CONTAINER { | |||
int16 Size; // it should be value defined in FVE_SIGNATURE in fve.h | |||
// if size is zero means no more headers | |||
int16 unknown1; | |||
int16 Type; /* the following types have been identified for now | |||
0x2 for label , label data starts after this header and is in unicode | |||
0x3 for VMK structure , it is immediately followed by guid | |||
then follow 12 byte unknown | |||
then comes the name such as "DiskPassword" | |||
0x5 for key | |||
0x8 This means it has the VMK means this header contains sub header | |||
after headr follows the GUID then a number of bytes with unknown type | |||
// however first sub header header starts at offset 36 | |||
*/ | |||
int16 Version; | |||
GUID Guid; // it's used to store GUID, | |||
FILETIME Time; // it is the time when this structure was started to fill up; | |||
// so we can analyse this to found time or when it was last updated and tell when was Bitlocker enabled | |||
// this is just an assumption | |||
int32 Reserved2; // it's the same as Version | |||
} KEY_CONTAINER; | |||
# pragma pack () // restore original packing | |||
// this header is always followed by data , data size = Size - ( sizeof(_HEADER)) | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _HEADER { | |||
int16 Size; // it should be value defined in FVE_SIGNATURE in fve.h | |||
// if size is zero means no more headers | |||
int16 unknown1; | |||
int16 Type; /* the following types have been identified for now | |||
0x2 for label , label data starts after this header and is in unicode | |||
0x3 for VMK structure , it is immediately followed by guid | |||
then follow 12 byte unknown | |||
then comes the name such as "DiskPassword" | |||
0x5 for key | |||
0x8 This means it has the VMK means this header contains sub header | |||
after headr follows the GUID then a number of bytes with unknown type | |||
// however first sub header header starts at offset 36 | |||
*/ | |||
int16 Version; | |||
} HEADER; | |||
# pragma pack () // restore original packing | |||
/* BEK_CONTAINER stores the data after the header, | |||
after header there are 2 header, one contains name, the other one contains key | |||
BEK conatiner is only found in BEK extension files which are stored mostly on External USB drives | |||
NOTE: - Sometimes BEK conatins only 1 header the KEY header | |||
*/ | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _BEK_CONTAINER { | |||
int16 Size; // it should be value defined in FVE_SIGNATURE in fve.h | |||
// if size is zero means no more headers | |||
int16 unknown1; | |||
int16 Type; /* the following types have been identified for now | |||
0x2 for label , label data starts after this header and is in unicode | |||
0x3 for VMK structure , it is immediately followed by guid | |||
then follow 12 byte unknown | |||
then comes the name such as "DiskPassword" | |||
0x5 for key | |||
0x8 This means it has the VMK means this header contains sub header | |||
after headr follows the GUID then a number of bytes with unknown type | |||
// however first sub header header starts at offset 36 | |||
*/ | |||
int16 Version; | |||
GUID Guid; // it's used to store GUID, | |||
FILETIME Time; // it is the time when this structure was started to fill up; | |||
// so we can analyse this to found time or when it was last updated and tell when was Bitlocker enabled | |||
// this is just an assumption | |||
} BEK_CONTAINER; | |||
# pragma pack () // restore original packing | |||
/* | |||
The type field in header denotes one of these, any extra header that is required | |||
is present just after header | |||
HEADER + (optional extra header) + data | |||
*/ | |||
enum int16 { | |||
HEADER_KEY = 1, /* extra header KEY_TYPE | |||
KEY is present in uncrypted form after optional header */ | |||
HEADER_LABEL = 2, /* a unicode string is present as data or label */ | |||
HEADER_KEY_DISK = 3, /* header + time + int32 unknown + | |||
44 byte encrypted HEADER_KEY/60 byte encrypted blob*/ | |||
HEADER_KEY_EXTERNAL = 4, | |||
HEADER_KEY_FVEK = 5, | |||
HEADER_KEY_CONTAINER =8, /* header + GUID + time +int32 + 1 or more headers*/ | |||
HEADER_BEK_CONTAINER =9 /* header + GUID + time +int32 + 1 or more headers*/ | |||
}; | |||
enum KEY_TYPE{ | |||
KEY_SALT = 0x00001000, | |||
KEY_VMK_COMPOSITE = 0x00002000, | |||
KEY_VMK = 0x00002003, | |||
KEY_VMK_USB = 0x00002002, // this key can be used to decode appropriate VMK key | |||
/* | |||
also encryption method is also stored here probably | |||
*/ | |||
KEY_FVEK_0 = 0x00008000, /* size including header is 0x40 bytes*/ | |||
KEY_FVEK_1 = 0x00008001, /* size including header is 0x40 bytes*/ | |||
KEY_FVEK_2 = 0x00008002, /* size is 0x10 bytes */ | |||
KEY_FVEK_3 = 0x00008003 /* size is 0x20 bytes */ | |||
}; | |||
# pragma pack (1) // 1 byte packing | |||
typedef struct _PROCESSED_FVE_META_DATA { | |||
MAIN_HEADER Main_Header; | |||
HEADER Header; // a maximum of 3 have been seen till tonight | |||
unsigned char Header_Copy[1024]; // this also includes header | |||
struct { | |||
KEY_CONTAINER Container; | |||
struct { | |||
HEADER Header; // a maximum of 3 have been seen till tonight | |||
unsigned char Header_Copy[1024]; // this also includes header | |||
}Header[5]; | |||
long Header_Count; | |||
}Key[8]; // unknown maximum number but only a few can exist | |||
// below we have 2 unlinked keys inaccessible from normal go through, fill them in here | |||
unsigned char UNLINKED_Header_Copy[2][1024]; // this also includes header | |||
long Key_Count; | |||
} PROCESSED_FVE_META_DATA; | |||
# pragma pack () // restore original packing | |||
#define KEY_RECOVERY_PASSWORD 1 | |||
#define KEY_STARTUP_PASSWORD 2 | |||
typedef struct _options_structure { | |||
unsigned char filename[512]; // this will store either the name of file or drive letter in windows | |||
int8 file; | |||
unsigned char recovery_password[512]; // this will store recovery password | |||
int8 rp; | |||
unsigned char startup_key_filename[512]; // file name for key | |||
unsigned char startup_key[512]; | |||
int8 sk; | |||
long using_container; // this contain index of container which was used to obtain VMK | |||
long using_key; | |||
unsigned char key[512]; // this is used to store key which decrypts VMK; | |||
int8 key_present; | |||
unsigned char VMK_key[512]; // this is used to store key which decryptes FVEK | |||
int8 VMK_key_present; | |||
unsigned char FVEK_key[512]; // this is used to store key which actually decrypts the volume | |||
int8 FVEK_key_present; | |||
unsigned char Tweak_Key[512]; // this is the sector key which can be obtained from FVEK if diffuser is enabled | |||
int8 Tweak_key_present; | |||
PROCESSED_FVE_META_DATA processed_fve_meta_data; | |||
FVE_META_DATA fve_meta_data; | |||
MORE_FVE_DATA more_fve_data; | |||
unsigned long Encryption_Type; | |||
// keys are expanded and kept ready for use | |||
struct { | |||
aes_context VMK_E_ctx; // vmk encryption ctx | |||
aes_context VMK_D_ctx; // decryption ctx | |||
aes_context FVEK_E_ctx; //FVEK enc ctx | |||
aes_context FVEK_D_ctx; //FVEK dec ctx | |||
aes_context TWEAK_E_ctx; // tweak key enc ctx | |||
aes_context TWEAK_D_ctx; // tweak key dec ctx | |||
}context; | |||
}options_structure; | |||
// this function does the command line argument processing and fill the structure above | |||
int process_options (int argc, char *argv[], options_structure *options); | |||
void init_keys(options_structure *options); | |||
typedef struct _decrypt_structure { | |||
aes_context FVEK_ctx; | |||
aes_context Sector_ctx; | |||
}decrypt_context; | |||
#endif | |||
@@ -0,0 +1,99 @@ | |||
/* | |||
nvbit Bitlocker for linux | |||
------------------------------ | |||
Nitin Kumar nitin at nvlabs.in | |||
Vipin Kumar vipin at nvlabs.in | |||
web: http://www.nvlabs.in | |||
Licensed under GPL Version 3 | |||