NVbit : Accessing Bitlocker volumes from linux.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
8.9KB

  1. /*
  2. nvbit Bitlocker for linux
  3. ------------------------------
  4. Nitin Kumar nitin at nvlabs.in
  5. Vipin Kumar vipin at nvlabs.in
  6. web: http://www.nvlabs.in
  7. Licensed under GPL Version 3
  8. -------------------
  9. Copyright (c) 2008
  10. Released under the GPL Version 3
  11. http://www.gnu.org/licenses/gpl-3.0.txt
  12. */
  13. #define FUSE_USE_VERSION 26
  14. #define _FILE_OFFSET_BITS 64
  15. #include <fuse.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <stdlib.h>
  21. #include <strings.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <unistd.h>
  25. // include bitlocker relaed files
  26. #include "nvbitlocker/common.h"
  27. #include "nvbitlocker/main.h"
  28. #include "nvbitlocker/header.h"
  29. #include "nvbitlocker/interface.h"
  30. #define VERSION "0.04"
  31. static const char *NTFS_FILENAME = "/NV_bitlocker_on_linux";
  32. static struct Globals{
  33. char *Filename;
  34. FILE *FileStruct;
  35. int FD;
  36. struct stat Stat;
  37. Interface* input_interface; // used to communicae wit bitocker encrypted volume
  38. options_structure options; /* used for internal processing such as
  39. keys, volume metadata etc
  40. */
  41. } Global_Data;
  42. /* This function fills the directory structure */
  43. static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  44. off_t offset, struct fuse_file_info *fi);
  45. /*this function opens up the file */
  46. static int fs_open(const char *path, struct fuse_file_info *fi);
  47. /* used to read decrypted buffer */
  48. static int fs_read(const char *path, char *buf, size_t size, off_t offset,
  49. struct fuse_file_info *fi);
  50. // used to obtain attributes of files
  51. static int fs_getattr(const char *path, struct stat *stbuf);
  52. // print usage
  53. void usage( char **argv );
  54. static struct fuse_operations fs_oper = {
  55. /* .getattr = hello_getattr,
  56. .readdir = hello_readdir,
  57. .open = hello_open,
  58. .read = hello_read,
  59. */
  60. .getattr = fs_getattr,
  61. .readdir = fs_readdir,
  62. .open = fs_open,
  63. .read = fs_read,
  64. };
  65. static int fs_getattr(const char *path, struct stat *stbuf)
  66. {
  67. int res = 0;
  68. memset(stbuf, 0, sizeof(struct stat));
  69. if(strcmp(path, "/") == 0) {
  70. stbuf->st_mode = S_IFDIR | 0755;
  71. stbuf->st_nlink = 2;
  72. }
  73. else if(strcmp(path, NTFS_FILENAME) == 0) {
  74. stbuf->st_mode = S_IFREG | 0444;
  75. stbuf->st_nlink = 1;
  76. stbuf->st_size = 1023 * 1024 * 1024; // change limit here , it's currently 1023 GB
  77. // stbuf->st_uid=fuse_get_context()->uid;
  78. // stbuf->st_gid=fuse_get_context()->gid;
  79. }
  80. else
  81. res = -ENOENT;
  82. return res;
  83. }
  84. static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
  85. {
  86. (void) offset;
  87. (void) fi;
  88. if(strcmp(path, "/") != 0)
  89. return -ENOENT;
  90. filler(buf, ".", NULL, 0);
  91. filler(buf, "..", NULL, 0);
  92. filler(buf, NTFS_FILENAME + 1, NULL, 0);
  93. return 0;
  94. }
  95. // since only 1 file will be opened, messy code is not at all required
  96. static int fs_open(const char *path, struct fuse_file_info *fi)
  97. {
  98. if(strcmp(path, NTFS_FILENAME) != 0)
  99. return -ENOENT;
  100. if((fi->flags & 3) != O_RDONLY)
  101. return -EACCES;
  102. return 0;
  103. }
  104. static int fs_read(const char *path, char *buf, size_t size, off_t offset,
  105. struct fuse_file_info *fi)
  106. {
  107. unsigned char *buffer;
  108. long long sector_count;
  109. long long sector_start;
  110. unsigned long loop_var;
  111. unsigned long len;
  112. if(strcmp(path, NTFS_FILENAME) != 0)
  113. return -ENOENT;
  114. if ( size == 0)
  115. return 0;
  116. /* logic to do this is below
  117. count the number of full sectors add 2 to it 1 for lower and one for upper limit
  118. now decode all sectors
  119. now select and copy the data to user and deallocate all buffers
  120. */
  121. // this code cannot service large requests huh but who cares
  122. buffer = NULL;
  123. sector_count = (( size / Global_Data.input_interface->SectorSize ) + 2) ;
  124. sector_start = offset / Global_Data.input_interface->SectorSize;
  125. buffer = malloc ( sector_count * Global_Data.input_interface->SectorSize);
  126. if(!buffer) // if buffer could not be allocated, return with empty size
  127. return 0;
  128. // read all sectors one by one and decrypt them if necessary
  129. for(loop_var = 0 ; loop_var < sector_count; loop_var++){
  130. 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);
  131. // don't decrypt the first 4 sectors whatever might be the case
  132. if ( (long long)((long long)loop_var+(long long)sector_start) < 4) {
  133. // if it is first sector fix it up
  134. if ( (long long)((long long)loop_var+(long long)sector_start) == 0){
  135. fix_sector(&Global_Data.options , buffer + loop_var * Global_Data.input_interface->SectorSize);
  136. }
  137. }
  138. else { // decrypt the sector
  139. decrypt_sector(&Global_Data.options,buffer + loop_var * Global_Data.input_interface->SectorSize,(long long)((long long)loop_var+(long long)sector_start));
  140. }
  141. }
  142. // now copy the required amount of data to the user buffer
  143. memcpy(buf,
  144. buffer + ( offset % Global_Data.input_interface->SectorSize),
  145. size);
  146. free(buffer);
  147. return size;
  148. }
  149. // init necessary stuff here
  150. void init(){
  151. Global_Data.Filename=NULL;
  152. Global_Data.FileStruct=NULL;
  153. Global_Data.FD=-1;
  154. // init fuse function callbacks
  155. //options structure is set to zero
  156. memset(&Global_Data.options,0,sizeof(options_structure));
  157. }
  158. int main(int argc, char *argv[])
  159. {
  160. if (argc <=4 ){
  161. usage(argv);
  162. exit(-1);
  163. }
  164. #ifdef DEBUG_ON
  165. printf("Starting nvbit Bitlocker Volume FUSE Driver\n");
  166. #endif
  167. init();
  168. // process parameters supplied
  169. process_options(argc,argv, &Global_Data.options);
  170. Global_Data.input_interface = InitializeInputInterface ( Global_Data.options.filename );
  171. // we will be here if and only if necessary options have been found and processed
  172. // now we will verify whether the volume is a bitlocker volume
  173. verify_input_volume_and_parse(Global_Data.input_interface, &Global_Data.options);
  174. // everything is fine till now, so we got a key and we got data, so lets decode other set of keys
  175. decrypt_vmk(&Global_Data.options);
  176. if ( Global_Data.options.VMK_key_present < 1 ) {
  177. fprintf(stderr,"VMK could not be decrypted , VERIFY your keys !!! \n");
  178. exit(1);
  179. }
  180. // we have now obainted VMK, now lets hunt down FVEK
  181. decrypt_fvek(&Global_Data.options);
  182. if ( Global_Data.options.FVEK_key_present < 1 ) {
  183. // this situation means something is not correct with the bitlocker volume
  184. // this situation should never occur, until the partition is manually damaged or th disk gets damaged
  185. fprintf(stderr,"FVEK could not be decrypted. Your partition is most probably corrupt !!! \n");
  186. exit(1);
  187. }
  188. // inform user about encryption used
  189. switch (Global_Data.options.Encryption_Type) {
  190. case AES128:
  191. printf("This Volume was encrypted using AES 128\n");
  192. break;
  193. case AES256:
  194. printf("This Volume was encrypted using AES 256\n");
  195. break;
  196. case AES128_diffuser:
  197. printf("This Volume was encrypted using AES 128 + diffuser\n");
  198. break;
  199. case AES256_diffuser:
  200. printf("This Volume was encrypted using AES 256 + diffuser\n");
  201. break;
  202. default:
  203. printf("Unknown Algorithm\n"
  204. "Cannot Continue, Quitting \n");
  205. exit(1);
  206. }
  207. // init keys once and for all
  208. init_keys(&Global_Data.options);
  209. #ifdef DEBUG_ON
  210. printf("Volume successfully mounted\n");
  211. #endif
  212. // assumming our program always takes 2 paramters
  213. { /* basic fuse stuff */
  214. int i;
  215. int diff;
  216. char **nargv = (char **) malloc(argc * sizeof(char *));
  217. diff = 4; // number of paramters for our program excluding the program name
  218. int nargc = argc - diff;
  219. nargv[0] = argv[0];
  220. for(i = 0; i < nargc; i++) {
  221. nargv[i + 1] = argv[i + diff +1];
  222. };
  223. return fuse_main(nargc, nargv, &fs_oper,NULL);
  224. }
  225. }
  226. void usage( char **argv ){
  227. printf("nvbit %s: Bitlocker for Linux \n" , VERSION );
  228. printf ("\n"
  229. "This is free software. You may redistribute copies of it under the terms\n"
  230. "of the GNU General Public License Version 3<http://www.gnu.org/licenses/gpl-3.0.txt>.\n"
  231. "There is NO WARRANTY, to the extent permitted by law.\n");
  232. printf("\n"
  233. "usage:\n"
  234. "nvbit options mount_point [<FUSE library options>]\n"
  235. "The following options are supported.\n"
  236. "-i /i the name of input bitlocker voume which is to be decrypted\n"
  237. "-sk /sk Startup Key file or Recovery key file (normally stored on USB key)\n"
  238. "-rp /rp Recovery password which can be entered by hand and is of the form xxxxx-xxxxx--xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx\n"
  239. "\n\n Visit www.nvlabs.in for updates/information\n\n");
  240. }