pax_global_header00006660000000000000000000000064137550312570014522gustar00rootroot0000000000000052 comment=6662821483d953bf23464ffd64d100d0b8dc3e4c dislocker-0.7.3/000077500000000000000000000000001375503125700135105ustar00rootroot00000000000000dislocker-0.7.3/.gitignore000066400000000000000000000006101375503125700154750ustar00rootroot00000000000000*.o *.kate-swp #*~ *.swp *.gz src/dislocker src/dislocker-bek src/dislocker-file src/dislocker-find src/dislocker-fuse src/dislocker-metadata src/libdislocker.so* # Configured files include/dislocker/ssl_bindings.h src/dislocker-find.rb # Unit test files *.gcno *.gcda *.gcov # cmake files CMakeCache.txt CMakeFiles Makefile cmake_install.cmake cmake_uninstall.cmake install_manifest.txt dislocker-0.7.3/.travis.yml000066400000000000000000000016641375503125700156300ustar00rootroot00000000000000language: c compiler: - clang - gcc jobs: include: - os: linux disk: focal - os: linux disk: bionic - os: linux dist: xenial - os: osx before_install: - echo $PATH - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get install -qq libfuse-dev ruby-dev libmbedtls-dev; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install -v Caskroom/cask/osxfuse; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./src/mbed_install.sh; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export PATH="/usr/bin:/usr/local/bin:$PATH"; fi install: - cmake . - make VERBOSE=1 - sudo make install script: - make travis-test notifications: email: recipients: - aorimn@gmail.com on_success: always on_failure: always dislocker-0.7.3/CHANGELOG.md000066400000000000000000000133531375503125700153260ustar00rootroot00000000000000# v0.7.3 This version is only used to update dislocker's brew file and the BitBake recipe for OSX's and BitBake's users to be able to download v0.7.2. If you're not an OSX nor a BitBake user, you can use either v0.7.2 or v0.7.3, this won't make any difference. # v0.7.2 - Bugfixes: - Fix compilation on OSX when ruby dependency is installed - Feature improvement: - Reported NTFS volume size is more accurate (thanks @haobinnan) - Add ability to decrypt from a VMK file (thanks Seunghun Han) - Add ability to read the user password from the envrironment variable `DISLOCKER_PASSWORD` (thanks @mhogomchungu) - Add ability to read the user password from pipes (thanks @mhogomchungu) - Decryption/encryption speed has been improved by disabling faulty threading # v0.7.1 This version is only used to update dislocker's brew file and the BitBake recipe for OSX's and BitBake's users to be able to download v0.7. If you're not an OSX nor a BitBake user, you can use either v0.7 or v0.7.1, this won't make any difference. # v0.7 - Feature improvement: - dislocker can now be run from /etc/fstab. This also means that the `-o` option for the offset had to be changed. It is now `-O`; - dislocker on FreeBSD can now read devices, not just partition dumps. - Compatiblity improvement: - OSX support and dependencies have been updated; - Thanks to Eric Johnson, from Leidos, a BitBake recipe is now available. # v0.6.1 This version is only used to update dislocker's brew file for OSX users to be able to download v0.6. If you're not an OSX user, you can use either v0.6 or v0.6.1, this won't make any difference. # v0.6 - Features improvement: - Read/write on Windows 10 (v1511) encrypted volumes - AES-XTS 128/256. # v0.5.2 Minor fixes for downstream packaging and larger distribution coverage. # v0.5.1 This version is only used to update dislocker's brew file for OSX users to be able to download v0.5. If you're not an OSX user, you can use either v0.5 or v0.5.1, this won't make any difference. # v0.5 - Bugfixes: - Support for old and new versions of PolarSSL (now called mbedTLS); - Various crashes have been fixed. - Features improvement: - Read/write on FAT-formatted volumes encrypted by BitLocker; - Some Ruby bindings have been added to the library; - A Ruby script has thus been added to look for BitLocker-encrypted volumes. - Notable changes: - Compilation/installation now goes through [cmake](https://cmake.org/), be sure to review the INSTALL.md file. # v0.4.1 This version is only used to update dislocker's brew file for OSX users to be able to download v0.4. If you're not an OSX user, you can use either v0.4 or v0.4.1, this won't make any difference. # v0.4 - Bugfixes: - Installation process is now ok; - Various crashes have been fixed; - Some minor display errors have been fixed. - Features improvement: - Adding of the write capability on some Windows 8 encrypted volumes; - Stealth password and recovery key in `ps' output; - Adding `--stateok' argument to tell dislocker not to check for the BitLocker volume state - as in 'partially decrypted', 'partially encrypted', and so on: - One can read partially encrypted volumes now! - Notable changes: - A brew file is now available for OSX users; - The embedded PolarSSL library has been removed, due to licensing problems when packaging, so users need to install PolarSSL on their own now - see INSTALL.md for hints on how to do it; - The core part is now a library - dynamic shared object or dynamic library, depending on the OS - and four binaries are now using this library. - The library is not yet for use by other developers, its interface is not well enough defined yet. - The NOTE part of the README.md/INSTALL.md files lists these binaries. - Portability: - Support added for FreeBSD. # v0.3 - Bugfixes: - One can now read from a device from /dev; - The stat() syscall returns a *null size* (0) for these devices and dislocker used this size to tell the partition's size, which induced to present a zero-length NTFS file hence this bug. - Code cleaned and reorganised (yes, it's a bugfix); - Better BitLocker's files handling. This is not optimal yet, as it should involve the NTFS layer, which is currently completely dislocker-independant. - Features improvement: - One can write on a BitLocker encrypted volume; - Adding `--readonly' argument to deny writes on the BitLocker volume; - Adding `--fvek' argument to decrypt a volume directly from a specially crafted FVEK file; - Default verbosity to CRITICAL level instead of QUIET, hence the `--quiet' option has been added; - One can use a user password to decrypt a volume through the '--user-password' option now. - Notable changes: - OpenSSL is no longer used for decryption (and encryption). An embedded PolarSSL code is compiled along with the rest of Dislocker. # v0.2 - Features improvement: - Now also able to decrypt/read BitLocker encrypted partitions from Windows Vista; - Better arguments handling (added verbosity and logging redirection); - Now able to pass an offset for the beginning of the partition (useful when all the disk has been copied instead of the partition); - Rules added into the Makefile: "make file" and "make fuse" to make binaries for using with FUSE or decrypting in a different file. - Portability: - Support added for MacOSX (using osxfuse, tested on Snow Leopard). # v0.1 - Features: - Decrypt BitLocker encrypted partitions from Windows 7 only; - A FUSE module is available for reading partitions; - Possibility to decrypt the entire partition into a file. dislocker-0.7.3/CMakeLists.txt000066400000000000000000000037011375503125700162510ustar00rootroot00000000000000# 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. cmake_minimum_required (VERSION 2.6) project (dislocker C) set (AUTHOR "Romain Coltel") find_program (GIT_EXE NAMES git PATHS /usr/bin /usr/local/bin) if(GIT_EXE) execute_process ( COMMAND ${GIT_EXE} rev-parse --abbrev-ref HEAD WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE GIT_RELEASE_BRANCH ) execute_process ( COMMAND ${GIT_EXE} log -n 1 --pretty=format:%t WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE GIT_RELEASE_COMMIT ) string (STRIP "${GIT_RELEASE_BRANCH}" GIT_RELEASE_BRANCH) string (STRIP "${GIT_RELEASE_COMMIT}" GIT_RELEASE_COMMIT) add_definitions (-DVERSION_DBG="${GIT_RELEASE_BRANCH}:${GIT_RELEASE_COMMIT}") endif() set (VERSION_MAJOR 0) set (VERSION_MINOR 7) set (VERSION_RELEASE 2) set (VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}") add_subdirectory (${PROJECT_SOURCE_DIR}/src) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY ) add_custom_target(uninstall COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" ) dislocker-0.7.3/INSTALL.md000066400000000000000000000117201375503125700151410ustar00rootroot00000000000000# INTRODUCTION This file describes how to install dislocker onto your machine. # REQUIREMENTS You need: - Compiler, gcc or clang; - cmake (at least version 2.6); - make (or gmake, for FreeBSD); - Headers for FUSE; - Headers for mbedTLS (previously known as PolarSSL); - A partition encrypted with BitLocker, from Windows Vista, 7 or 8. If you have Ruby headers, the library will compile with some Ruby bindings and another program - see the NOTE section below - will be available. For Debian-like distos based on Debian Jessie or Ubuntu 14.04 or older: - `aptitude install gcc cmake make libfuse-dev libpolarssl-dev ruby-dev` For Debian-like distos based on Debian Stretch or Ubuntu 16.04 or later: - `aptitude install gcc cmake make libfuse-dev libmbedtls-dev ruby-dev` For Fedora-like: - `dnf install gcc cmake make fuse-devel mbedtls-devel ruby-devel rubypick` Alternatively, running `dnf install dislocker fuse-dislocker` to use the already existing RPM packages in Fedora could be a clever idea. For RHEL-like (including CentOS Scientific Linux): - `yum install gcc cmake make fuse-devel mbedtls-devel ruby-devel /usr/bin/ruby` Alternatively, running `yum install dislocker fuse-dislocker` to use the already existing RPM packages in EPEL could be a clever idea. For FreeBSD: - `pkg install cmake gmake fusefs-libs mbedtls` For OSX: Follow the instructions in the next section. Note that the code expects at least FUSE 2.6. # INSTALLING Each OS type has its own section below, beware to follow yours: ## If you are on MacOSX... Just install Homebrew (http://brew.sh/) and run the following commands: ``` brew update brew install Caskroom/cask/osxfuse brew install src/dislocker.rb ``` This will install dislocker. ## If you're on FreeBSD... Follow the instructions below (next subsection) by replacing 'make' with 'gmake'. ## If you are NOT on MacOSX... If you already have installed the dependencies (see REQUIREMENTS section above), you have to type the following commands to install the binaries on your system: ``` cmake . make sudo make install ``` Don't forget the dot (.) on the cmake command-line. If you only want to generate the binaries, without installing them, you can skip the last command (the one beginning with sudo). Note that the '-Werror' flag in the cmake WARN_FLAGS variable may break the compilation for useless warnings. If you know what you're doing, you can remove it by running the following cmake command instead of the one above: ``` cmake -D WARN_FLAGS:STRING="-Wall -Wextra" . ``` See the [cmake documentation](http://www.cmake.org/documentation/) if you want to customize the build. Once installed, see `dislocker(1)` for details on how to use it. # UNINSTALLING I'm sure you don't want to do that. But if you're really forced by someone, just type `make uninstall` as super-user. # mbedTLS 2.0.0 Since the version 2.0.0 of mbedTLS, the build moves "crypto" functions such as AES and SHA256 into a separate, libmbedcrypto, library. However, a typo didn't installed this library, resulting in some packagers not providing this library, thus breaking the dislocker compilation. If you have this problem, it's recommended to run the following commands (they have been put in the src/mbed_install.sh script, if you don't want to copy/paste from here): ``` git clone https://github.com/ARMmbed/mbedtls.git cd mbedtls git checkout mbedtls-2.0.0 ``` Then apply the patch given by the following command: ``` git show 6f42417b library/CMakeLists.txt ``` And compile/install the library: ``` cmake . make sudo make install ``` You can then resume the installation where you have left it. # PORTABILITY Globally, this was successfully tested on Linux x86/x86_64, MacOSX and FreeBSD. It won't work on Windows and may not work on other BSDs (not tested). For MacOSX, it has been tested against OSXFUSE 2.3.8 and 2.3.9. Cases where you need to remove the '-Werror' from the WARN_FLAGS variable: - You're on Ubuntu 10.04; - You're using GCC with a version older than 4.3. Whether it works or not, feel free to send comments and feedbacks to [dislocker __AT__ hsc __DOT__ fr](). # NOTE Five binaries are built when compiling dislocker as described in the `INSTALL.md` file: 1. `dislocker-bek`: for dissecting a .bek file and printing information about it 2. `dislocker-metadata`: for printing information about a BitLocker-encrypted volume 3. `dislocker-find`: not a binary but a Ruby script which tries to find BitLocker encrypted partition among the plugged-in disks (only work if the library is compiled with the Ruby bindings) 4. `dislocker-file`: for decrypting a BitLocker encrypted partition into a flat file formatted as an NTFS partition you can mount 5. `dislocker-fuse`: the one you're using when calling `dislocker', which dynamically decrypts a BitLocker encrypted partition using FUSE You can build each one independently providing it as the makefile target. For instance, if you want to compile dislocker-fuse only, you'd simply run: ```bash $ cmake . $ make dislocker-fuse ``` dislocker-0.7.3/LICENSE.txt000066400000000000000000000302171375503125700153360ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. dislocker-0.7.3/README.md000066400000000000000000000106701375503125700147730ustar00rootroot00000000000000# Dislocker [![Build Status](https://travis-ci.org/Aorimn/dislocker.svg?branch=develop)](https://travis-ci.org/Aorimn/dislocker) ## Introduction and explanations This software has been designed to read BitLocker encrypted partitions under a Linux system. The driver has the capability to read/write on: - Windows Vista, 7, 8, 8.1 and 10 encrypted partitions - that's AES-CBC, AES-XTS, 128 or 256 bits, with or without the Elephant diffuser, encrypted partitions; - BitLocker-To-Go encrypted partitions - that's USB/FAT32 partitions. The core driver is composed of a library, with multiple binaries (see the NOTES section below) using this library. Two binaries are of interest when wanting to decrypt a BitLocker encrypted partition: 1. `dislocker-fuse`: binary using FUSE to dynamically decrypt the BitLocker-ed partition. You have to give it a mount point where, once keys are decrypted, a file named `dislocker-file` appears. This file is a virtual NTFS partition, so you can mount it as any NTFS partition and then read from or write to it. Note that writing to the NTFS virtual file will change the underlying BitLocker partition's content. 2. `dislocker-file`: binary decrypting a BitLocker encrypted partition into a flat file. This file has to be given through command line and, once dislocker-file is finished, will be an NTFS partition. It won't have any link to the original BitLocker partition. Therefore, if you write to this file, the BitLocker volume won't change, only the NTFS file will. Note that this may take a long time to create that file, depending on the size of the encrypted partition. But afterward, once the partition is decrypted, the access to the NTFS partition will be faster. Another thing to think about is the size on your disk this binary needs: the same size as the volume you're trying to decrypt. Nevertheless, once the partition is decrypted, you can mount your file as any NTFS partition. Thanks goes to Rogier Wolff for testing, hugsy for all the OSX support and patches, Will Dyson for the patches, and all the people who give feedbacks. ## Installation and requirements See `INSTALL.md` for things dealing with the install process. Once installed, see `dislocker(1)` for details on how to use it. ## Bugs There may be bugs, and I'll be happy to hear about it! Feel free to send comments and feedbacks to [dislocker __AT__ hsc __DOT__ fr](), or to open an [issue](https://github.com/Aorimn/dislocker/issues). ## A note on Bitlocker-To-Go Microsoft's idea behind BitLocker-To-Go is that computers running Microsoft operating systems will be able to mount encrypted removable media without too much trouble. To achieve this, the data on the media has a dual format. First it is a valid FAT32 filesystem. In that filesystem they store executables and datafiles that allow access to the encrypted volume. Besides that you will see big "encrypted" files that hold the actual encrypted volume. On the other side, it is a BitLocker volume. Just with some unused space, from the BitLocker point-of-view. That's where the FAT32 stuff lives. So, to access a BitLocker-To-Go encrypted media, the whole partition is the volume that dislocker works with. The use of dislocker is therefore the same whether the volume is a standard BitLocker partition or a BitLocker-To-Go one. ## A note on fstab BitLocker partitions can be mount-ed using the /etc/fstab file and dislocker's long options. The line below is an example line, which has to be adapted to each case: ``` /dev/sda2 /mnt/dislocker fuse.dislocker user-password=blah,nofail 0 0 ``` ## Note Five binaries are built when compiling dislocker as described in the `INSTALL.md` file: 1. `dislocker-bek`: for dissecting a .bek file and printing information about it 2. `dislocker-metadata`: for printing information about a BitLocker-encrypted volume 3. `dislocker-find`: not a binary but a Ruby script which tries to find BitLocker encrypted partition among the plugged-in disks (only work if the library is compiled with the Ruby bindings) 4. `dislocker-file`: for decrypting a BitLocker encrypted partition into a flat file formatted as an NTFS partition you can mount 5. `dislocker-fuse`: the one you're using when calling `dislocker', which dynamically decrypts a BitLocker encrypted partition using FUSE You can build each one independently providing it as the makefile target. For instance, if you want to compile dislocker-fuse only, you'd simply run: ```bash $ cmake . $ make dislocker-fuse ``` dislocker-0.7.3/cmake/000077500000000000000000000000001375503125700145705ustar00rootroot00000000000000dislocker-0.7.3/cmake/FindFUSE.cmake000066400000000000000000000016051375503125700171370ustar00rootroot00000000000000# Find the FUSE includes and library # # FUSE_INCLUDE_DIRSS - where to find fuse.h, etc. # FUSE_LIBRARIES - List of libraries when using FUSE. # FUSE_FOUND - True if FUSE lib is found. # check if already in cache, be silent IF (FUSE_INCLUDE_DIRS) SET (FUSE_FIND_QUIETLY TRUE) ENDIF (FUSE_INCLUDE_DIRS) # find includes FIND_PATH (FUSE_INCLUDE_DIRS fuse.h /usr/local/include/osxfuse /usr/local/include /usr/include ) # find lib if (APPLE) SET(FUSE_NAMES libosxfuse.dylib fuse) else (APPLE) SET(FUSE_NAMES fuse) endif (APPLE) FIND_LIBRARY(FUSE_LIBRARIES NAMES ${FUSE_NAMES} PATHS /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib ) include ("FindPackageHandleStandardArgs") find_package_handle_standard_args ("FUSE" DEFAULT_MSG FUSE_INCLUDE_DIRS FUSE_LIBRARIES) mark_as_advanced (FUSE_INCLUDE_DIRS FUSE_LIBRARIES) dislocker-0.7.3/cmake/FindPackageHandleStandardArgs.cmake000066400000000000000000000227251375503125700233500ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) # internal helper macro macro(_FPHSA_FAILURE_MESSAGE _msg) if (${_NAME}_FIND_REQUIRED) message(FATAL_ERROR "${_msg}") else () if (NOT ${_NAME}_FIND_QUIETLY) message(STATUS "${_msg}") endif () endif () endmacro() # internal helper macro to generate the failure message when used in CONFIG_MODE: macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: if(${_NAME}_CONFIG) _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") else() # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. # List them all in the error message: if(${_NAME}_CONSIDERED_CONFIGS) set(configsText "") list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) math(EXPR configsCount "${configsCount} - 1") foreach(currentConfigIndex RANGE ${configsCount}) list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) string(APPEND configsText " ${filename} (version ${version})\n") endforeach() if (${_NAME}_NOT_FOUND_MESSAGE) string(APPEND configsText " Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") endif() _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") else() # Simple case: No Config-file was found at all: _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") endif() endif() endmacro() function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) # Set up the arguments for `cmake_parse_arguments`. set(options CONFIG_MODE HANDLE_COMPONENTS) set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) set(multiValueArgs REQUIRED_VARS) # Check whether we are in 'simple' or 'extended' mode: set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) if(${INDEX} EQUAL -1) set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) set(FPHSA_REQUIRED_VARS ${ARGN}) set(FPHSA_VERSION_VAR) else() cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) if(FPHSA_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") endif() if(NOT FPHSA_FAIL_MESSAGE) set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") endif() # In config-mode, we rely on the variable _CONFIG, which is set by find_package() # when it successfully found the config-file, including version checking: if(FPHSA_CONFIG_MODE) list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) set(FPHSA_VERSION_VAR ${_NAME}_VERSION) endif() if(NOT FPHSA_REQUIRED_VARS) message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") endif() endif() # now that we collected all arguments, process them if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") endif() list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) string(TOUPPER ${_NAME} _NAME_UPPER) string(TOLOWER ${_NAME} _NAME_LOWER) if(FPHSA_FOUND_VAR) if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$") set(_FOUND_VAR ${FPHSA_FOUND_VAR}) else() message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.") endif() else() set(_FOUND_VAR ${_NAME_UPPER}_FOUND) endif() # collect all variables which were not found, so they can be printed, so the # user knows better what went wrong (#6375) set(MISSING_VARS "") set(DETAILS "") # check if all passed variables are valid set(FPHSA_FOUND_${_NAME} TRUE) foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) if(NOT ${_CURRENT_VAR}) set(FPHSA_FOUND_${_NAME} FALSE) string(APPEND MISSING_VARS " ${_CURRENT_VAR}") else() string(APPEND DETAILS "[${${_CURRENT_VAR}}]") endif() endforeach() if(FPHSA_FOUND_${_NAME}) set(${_NAME}_FOUND TRUE) set(${_NAME_UPPER}_FOUND TRUE) else() set(${_NAME}_FOUND FALSE) set(${_NAME_UPPER}_FOUND FALSE) endif() # component handling unset(FOUND_COMPONENTS_MSG) unset(MISSING_COMPONENTS_MSG) if(FPHSA_HANDLE_COMPONENTS) foreach(comp ${${_NAME}_FIND_COMPONENTS}) if(${_NAME}_${comp}_FOUND) if(NOT DEFINED FOUND_COMPONENTS_MSG) set(FOUND_COMPONENTS_MSG "found components: ") endif() string(APPEND FOUND_COMPONENTS_MSG " ${comp}") else() if(NOT DEFINED MISSING_COMPONENTS_MSG) set(MISSING_COMPONENTS_MSG "missing components: ") endif() string(APPEND MISSING_COMPONENTS_MSG " ${comp}") if(${_NAME}_FIND_REQUIRED_${comp}) set(${_NAME}_FOUND FALSE) string(APPEND MISSING_VARS " ${comp}") endif() endif() endforeach() set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") string(APPEND DETAILS "[c${COMPONENT_MSG}]") endif() # version handling: set(VERSION_MSG "") set(VERSION_OK TRUE) # check with DEFINED here as the requested or found version may be "0" if (DEFINED ${_NAME}_FIND_VERSION) if(DEFINED ${FPHSA_VERSION_VAR}) set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}}) if(${_NAME}_FIND_VERSION_EXACT) # exact version required # count the dots in the version string string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${_FOUND_VERSION}") # add one dot because there is one dot more than there are components string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT # is at most 4 here. Therefore a simple lookup table is used. if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) set(_VERSION_REGEX "[^.]*") elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) set(_VERSION_REGEX "[^.]*\\.[^.]*") elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") else () set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") endif () string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${_FOUND_VERSION}") unset(_VERSION_REGEX) if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") set(VERSION_OK FALSE) else () set(VERSION_MSG "(found suitable exact version \"${_FOUND_VERSION}\")") endif () unset(_VERSION_HEAD) else () if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _FOUND_VERSION) set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") set(VERSION_OK FALSE) else () set(VERSION_MSG "(found suitable exact version \"${_FOUND_VERSION}\")") endif () endif () unset(_VERSION_DOTS) else() # minimum version specified: if (${_NAME}_FIND_VERSION VERSION_GREATER _FOUND_VERSION) set(VERSION_MSG "Found unsuitable version \"${_FOUND_VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") set(VERSION_OK FALSE) else () set(VERSION_MSG "(found suitable version \"${_FOUND_VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") endif () endif() else() # if the package was not found, but a version was given, add that to the output: if(${_NAME}_FIND_VERSION_EXACT) set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") else() set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") endif() endif() else () # Check with DEFINED as the found version may be 0. if(DEFINED ${FPHSA_VERSION_VAR}) set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")") endif() endif () if(VERSION_OK) string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]") else() set(${_NAME}_FOUND FALSE) endif() # print the result: if (${_NAME}_FOUND) FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") else () if(FPHSA_CONFIG_MODE) _FPHSA_HANDLE_FAILURE_CONFIG_MODE() else() if(NOT VERSION_OK) _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") else() _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}") endif() endif() endif () set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) endfunction() dislocker-0.7.3/cmake/FindPackageMessage.cmake000066400000000000000000000013541375503125700212360ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. function(find_package_message pkg msg details) # Avoid printing a message repeatedly for the same find result. if(NOT ${pkg}_FIND_QUIETLY) string(REPLACE "\n" "" details "${details}") set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") # The message has not yet been printed. message(STATUS "${msg}") # Save the find details in the cache to avoid printing the same # message again. set("${DETAILS_VAR}" "${details}" CACHE INTERNAL "Details about finding ${pkg}") endif() endif() endfunction() dislocker-0.7.3/cmake/FindPolarSSL.cmake000066400000000000000000000063621375503125700200410ustar00rootroot00000000000000# Try to find PolarSSL/mbedtls library # # Returns # POLARSSL_FOUND # POLARSSL_INCLUDE_DIRS # POLARSSL_LIBRARIES # POLARSSL_VERSION_MAJOR # POLARSSL_VERSION_MINOR # POLARSSL_VERSION_PATCH # POLARSSL_VERSION_STRING # POLARSSL_INC_FOLDER # POLARSSL_REAL_NAME include(FindPackageHandleStandardArgs) find_path(POLARSSL_INCLUDE_DIRS NAMES mbedtls/ssl.h HINTS /usr/local/include) set(POLARSSL_REAL_NAME MBEDTLS) if( "${POLARSSL_INCLUDE_DIRS}" STREQUAL "POLARSSL_INCLUDE_DIRS-NOTFOUND") find_path(POLARSSL_INCLUDE_DIRS NAMES polarssl/ssl.h) set(POLARSSL_REAL_NAME POLARSSL) endif() string(TOLOWER "${POLARSSL_REAL_NAME}" POLARSSL_INC_FOLDER) # # polarssl -> mbedtls # Try to find first libmbedcrypto.a, then libmbedtls.a, and if this fails tries # to find polarssl. # Only because mbed is separating ssl/tls functions from crypto (aes/sha) # functions and some distrib (like osx or fedora) do not symbolically link # libmbedtls to polarssl for compat # find_library(POLARSSL_LIBRARIES NAMES mbedcrypto) set(POLARSSL_USED_LIBRARY mbedcrypto) if( "${POLARSSL_LIBRARIES}" STREQUAL "POLARSSL_LIBRARIES-NOTFOUND" ) find_library(POLARSSL_LIBRARIES NAMES mbedtls) set(POLARSSL_USED_LIBRARY mbedtls) if( "${POLARSSL_LIBRARIES}" STREQUAL "POLARSSL_LIBRARIES-NOTFOUND" ) find_library(POLARSSL_LIBRARIES NAMES polarssl) set(POLARSSL_USED_LIBRARY polarssl) endif() endif() find_package_handle_standard_args(POLARSSL REQUIRED_VARS POLARSSL_INCLUDE_DIRS POLARSSL_LIBRARIES) if( ${POLARSSL_LIBRARIES-NOTFOUND} ) message(FATAL_ERROR "Failed to get info from PolarSSL library, check your PolarSSL installation") set(POLARSSL_FOUND False) return() endif() if( NOT CMAKE_CROSSCOMPILING ) execute_process( COMMAND echo "#include <${POLARSSL_INC_FOLDER}/version.h>\n#include \nint main(){printf(${POLARSSL_REAL_NAME}_VERSION_STRING);return 0;}" OUTPUT_FILE a.c ) execute_process( COMMAND ${CMAKE_C_COMPILER} a.c -I${POLARSSL_INCLUDE_DIRS} ${POLARSSL_LIBRARIES} ) execute_process( COMMAND ./a.out OUTPUT_VARIABLE POLARSSL_VERSION_STRING ) execute_process( COMMAND ${CMAKE_COMMAND} -E remove a.c a.out ) else() execute_process( COMMAND grep -w "MBEDTLS_VERSION_STRING" ${POLARSSL_INCLUDE_DIRS}/${POLARSSL_INC_FOLDER}/version.h COMMAND sed -e "s@\s\+@ @g" COMMAND cut -d\ -f3 COMMAND sed -e "s@\"@@g" OUTPUT_VARIABLE POLARSSL_VERSION_STRING ) endif() message("PolarSSL/mbedTLS version: " ${POLARSSL_VERSION_STRING}) if( "${POLARSSL_VERSION_STRING}" STREQUAL "2.0.0" AND NOT "${POLARSSL_USED_LIBRARY}" STREQUAL "mbedcrypto" ) message("*** WARNING *** Your mbedTLS version is 2.0.0, it's possible the `make' command doesn't work.\nPlease refer to the INSTALL.md's \"mbedTLS 2.0.0\" section if you have any problem.\n") endif() string(REPLACE "." ";" POLARSSL_VERSION_LIST ${POLARSSL_VERSION_STRING}) list(GET ${POLARSSL_VERSION_LIST} 0 POLARSSL_VERSION_MAJOR) list(GET ${POLARSSL_VERSION_LIST} 1 POLARSSL_VERSION_MINOR) list(GET ${POLARSSL_VERSION_LIST} 2 POLARSSL_VERSION_PATCH) set(POLARSSL_FOUND True) mark_as_advanced( POLARSSL_FOUND POLARSSL_INCLUDE_DIRS POLARSSL_LIBRARIES POLARSSL_VERSION_MAJOR POLARSSL_VERSION_MINOR POLARSSL_VERSION_PATCH POLARSSL_VERSION_STRING POLARSSL_INC_FOLDER POLARSSL_REAL_NAME ) dislocker-0.7.3/cmake/FindRuby.cmake000066400000000000000000000430361375503125700173220ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindRuby -------- Find Ruby This module finds if Ruby is installed and determines where the include files and libraries are. Ruby 1.8 through 2.7 are supported. The minimum required version of Ruby can be specified using the standard syntax, e.g. .. code-block:: cmake find_package(Ruby 2.5.1 EXACT REQUIRED) # OR find_package(Ruby 2.4) It also determines what the name of the library is. Virtual environments such as RVM are handled as well, by passing the argument ``Ruby_FIND_VIRTUALENV`` Result Variables ^^^^^^^^^^^^^^^^ This module will set the following variables in your project: ``Ruby_FOUND`` set to true if ruby was found successfully ``Ruby_EXECUTABLE`` full path to the ruby binary ``Ruby_INCLUDE_DIRS`` include dirs to be used when using the ruby library ``Ruby_LIBRARIES`` libraries needed to use ruby from C. ``Ruby_VERSION`` the version of ruby which was found, e.g. "1.8.7" ``Ruby_VERSION_MAJOR`` Ruby major version. ``Ruby_VERSION_MINOR`` Ruby minor version. ``Ruby_VERSION_PATCH`` Ruby patch version. The following variables are also provided for compatibility reasons, don't use them in new code: ``RUBY_EXECUTABLE`` same as Ruby_EXECUTABLE. ``RUBY_INCLUDE_DIRS`` same as Ruby_INCLUDE_DIRS. ``RUBY_INCLUDE_PATH`` same as Ruby_INCLUDE_DIRS. ``RUBY_LIBRARY`` same as Ruby_LIBRARY. ``RUBY_VERSION`` same as Ruby_VERSION. ``RUBY_FOUND`` same as Ruby_FOUND. Hints ^^^^^ ``Ruby_ROOT_DIR`` Define the root directory of a Ruby installation. ``Ruby_FIND_VIRTUALENV`` This variable defines the handling of virtual environments managed by ``rvm``. It is meaningful only when a virtual environment is active (i.e. the ``rvm`` script has been evaluated or at least the ``MY_RUBY_HOME`` environment variable is set). The ``Ruby_FIND_VIRTUALENV`` variable can be set to empty or one of the following: * ``FIRST``: The virtual environment is used before any other standard paths to look-up for the interpreter. This is the default. * ``ONLY``: Only the virtual environment is used to look-up for the interpreter. * ``STANDARD``: The virtual environment is not used to look-up for the interpreter (assuming it isn't still in the PATH...) #]=======================================================================] # Backwards compatibility # Define camel case versions of input variables foreach(UPPER RUBY_EXECUTABLE RUBY_LIBRARY RUBY_INCLUDE_DIR RUBY_CONFIG_INCLUDE_DIR ) if (DEFINED ${UPPER}) string(REPLACE "RUBY_" "Ruby_" Camel ${UPPER}) if (NOT DEFINED ${Camel}) set(${Camel} ${${UPPER}}) endif() endif() endforeach() # Ruby_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'` # Ruby_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'` # Ruby_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'` # Ruby_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'` # Ruby_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'` # uncomment the following line to get debug output for this file # set(_Ruby_DEBUG_OUTPUT TRUE) # Determine the list of possible names of the ruby executable depending # on which version of ruby is required set(_Ruby_POSSIBLE_EXECUTABLE_NAMES ruby) # If not specified, allow everything as far back as 1.8.0 if(NOT DEFINED Ruby_FIND_VERSION_MAJOR) set(Ruby_FIND_VERSION "1.8.0") set(Ruby_FIND_VERSION_MAJOR 1) set(Ruby_FIND_VERSION_MINOR 8) set(Ruby_FIND_VERSION_PATCH 0) endif() if(_Ruby_DEBUG_OUTPUT) message("Ruby_FIND_VERSION=${Ruby_FIND_VERSION}") message("Ruby_FIND_VERSION_MAJOR=${Ruby_FIND_VERSION_MAJOR}") message("Ruby_FIND_VERSION_MINOR=${Ruby_FIND_VERSION_MINOR}") message("Ruby_FIND_VERSION_PATCH=${Ruby_FIND_VERSION_PATCH}") endif() set(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${Ruby_FIND_VERSION_MINOR}") # Set name of possible executables, ignoring the minor # Eg: # 2.1.1 => from ruby27 to ruby21 included # 2.1 => from ruby27 to ruby21 included # 2 => from ruby26 to ruby20 included # empty => from ruby27 to ruby18 included if(NOT Ruby_FIND_VERSION_EXACT) foreach(_ruby_version RANGE 27 18 -1) string(SUBSTRING "${_ruby_version}" 0 1 _ruby_major_version) string(SUBSTRING "${_ruby_version}" 1 1 _ruby_minor_version) if(NOT "${_ruby_major_version}${_ruby_minor_version}" VERSION_LESS ${Ruby_FIND_VERSION_SHORT_NODOT}) # Append both rubyX.Y and rubyXY (eg: ruby2.7 ruby27) list(APPEND _Ruby_POSSIBLE_EXECUTABLE_NAMES ruby${_ruby_major_version}.${_ruby_minor_version} ruby${_ruby_major_version}${_ruby_minor_version}) else() break() endif() endforeach() list(REMOVE_DUPLICATES _Ruby_POSSIBLE_EXECUTABLE_NAMES) endif() # virtual environments handling (eg RVM) if (DEFINED ENV{MY_RUBY_HOME}) if(_Ruby_DEBUG_OUTPUT) message("My ruby home is defined: $ENV{MY_RUBY_HOME}") endif() if (DEFINED Ruby_FIND_VIRTUALENV) if (NOT Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$") message (AUTHOR_WARNING "FindRuby: ${Ruby_FIND_VIRTUALENV}: invalid value for 'Ruby_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.") set (_Ruby_FIND_VIRTUALENV "FIRST") else() set (_Ruby_FIND_VIRTUALENV ${Ruby_FIND_VIRTUALENV}) endif() else() set (_Ruby_FIND_VIRTUALENV FIRST) endif() else() if (DEFINED Ruby_FIND_VIRTUALENV) message("Environment variable MY_RUBY_HOME isn't set, defaulting back to Ruby_FIND_VIRTUALENV=STANDARD") endif() set (_Ruby_FIND_VIRTUALENV STANDARD) endif() if(_Ruby_DEBUG_OUTPUT) message("_Ruby_POSSIBLE_EXECUTABLE_NAMES=${_Ruby_POSSIBLE_EXECUTABLE_NAMES}") message("_Ruby_FIND_VIRTUALENV=${_Ruby_FIND_VIRTUALENV}") endif() function (_RUBY_VALIDATE_INTERPRETER) if (NOT Ruby_EXECUTABLE) return() endif() cmake_parse_arguments (PARSE_ARGV 0 _RVI "EXACT;CHECK_EXISTS" "" "") if (_RVI_UNPARSED_ARGUMENTS) set (expected_version ${_RVI_UNPARSED_ARGUMENTS}) else() unset (expected_version) endif() if (_RVI_CHECK_EXISTS AND NOT EXISTS "${Ruby_EXECUTABLE}") # interpreter does not exist anymore set (_Ruby_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${Ruby_EXECUTABLE}\"") set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND") return() endif() # Check the version it returns # executable found must have a specific version execute_process (COMMAND "${Ruby_EXECUTABLE}" -e "puts RUBY_VERSION" RESULT_VARIABLE result OUTPUT_VARIABLE version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (result OR (_RVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version)) # interpreter not usable or has wrong major version if (result) set (_Ruby_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${Ruby_EXECUTABLE}\"") else() set (_Ruby_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${Ruby_EXECUTABLE}\"") endif() set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND") return() endif() endfunction() while(1) # Virtual environments handling if(_Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") if(_Ruby_DEBUG_OUTPUT) message("Inside Matches") endif() find_program (Ruby_EXECUTABLE NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES} NAMES_PER_DIR PATHS ENV MY_RUBY_HOME PATH_SUFFIXES bin Scripts NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) if(_Ruby_DEBUG_OUTPUT) message("Ruby_EXECUTABLE=${Ruby_EXECUTABLE}") endif() _RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION}}) if(Ruby_EXECUTABLE) break() endif() if(NOT _Ruby_FIND_VIRTUALENV STREQUAL "ONLY") break() endif() elseif(_Ruby_DEBUG_OUTPUT) message("_Ruby_FIND_VIRTUALENV doesn't match: ${_Ruby_FIND_VIRTUALENV}") endif() # try using standard paths find_program (Ruby_EXECUTABLE NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES} NAMES_PER_DIR) _RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION}) if (Ruby_EXECUTABLE) break() endif() break() endwhile() if(Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR) function(_RUBY_CONFIG_VAR RBVAR OUTVAR) execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']" RESULT_VARIABLE _Ruby_SUCCESS OUTPUT_VARIABLE _Ruby_OUTPUT ERROR_QUIET) if(_Ruby_SUCCESS OR _Ruby_OUTPUT STREQUAL "") execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['${RBVAR}']" RESULT_VARIABLE _Ruby_SUCCESS OUTPUT_VARIABLE _Ruby_OUTPUT ERROR_QUIET) endif() set(${OUTVAR} "${_Ruby_OUTPUT}" PARENT_SCOPE) endfunction() # query the ruby version _RUBY_CONFIG_VAR("MAJOR" Ruby_VERSION_MAJOR) _RUBY_CONFIG_VAR("MINOR" Ruby_VERSION_MINOR) _RUBY_CONFIG_VAR("TEENY" Ruby_VERSION_PATCH) # query the different directories _RUBY_CONFIG_VAR("archdir" Ruby_ARCH_DIR) _RUBY_CONFIG_VAR("arch" Ruby_ARCH) _RUBY_CONFIG_VAR("rubyhdrdir" Ruby_HDR_DIR) _RUBY_CONFIG_VAR("rubyarchhdrdir" Ruby_ARCHHDR_DIR) _RUBY_CONFIG_VAR("libdir" Ruby_POSSIBLE_LIB_DIR) _RUBY_CONFIG_VAR("rubylibdir" Ruby_RUBY_LIB_DIR) # site_ruby _RUBY_CONFIG_VAR("sitearchdir" Ruby_SITEARCH_DIR) _RUBY_CONFIG_VAR("sitelibdir" Ruby_SITELIB_DIR) # vendor_ruby available ? execute_process(COMMAND ${Ruby_EXECUTABLE} -r vendor-specific -e "print 'true'" OUTPUT_VARIABLE Ruby_HAS_VENDOR_RUBY ERROR_QUIET) if(Ruby_HAS_VENDOR_RUBY) _RUBY_CONFIG_VAR("vendorlibdir" Ruby_VENDORLIB_DIR) _RUBY_CONFIG_VAR("vendorarchdir" Ruby_VENDORARCH_DIR) endif() # save the results in the cache so we don't have to run ruby the next time again set(Ruby_VERSION_MAJOR ${Ruby_VERSION_MAJOR} CACHE PATH "The Ruby major version" FORCE) set(Ruby_VERSION_MINOR ${Ruby_VERSION_MINOR} CACHE PATH "The Ruby minor version" FORCE) set(Ruby_VERSION_PATCH ${Ruby_VERSION_PATCH} CACHE PATH "The Ruby patch version" FORCE) set(Ruby_ARCH_DIR ${Ruby_ARCH_DIR} CACHE PATH "The Ruby arch dir" FORCE) set(Ruby_HDR_DIR ${Ruby_HDR_DIR} CACHE PATH "The Ruby header dir (1.9+)" FORCE) set(Ruby_ARCHHDR_DIR ${Ruby_ARCHHDR_DIR} CACHE PATH "The Ruby arch header dir (2.0+)" FORCE) set(Ruby_POSSIBLE_LIB_DIR ${Ruby_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE) set(Ruby_RUBY_LIB_DIR ${Ruby_RUBY_LIB_DIR} CACHE PATH "The Ruby ruby-lib dir" FORCE) set(Ruby_SITEARCH_DIR ${Ruby_SITEARCH_DIR} CACHE PATH "The Ruby site arch dir" FORCE) set(Ruby_SITELIB_DIR ${Ruby_SITELIB_DIR} CACHE PATH "The Ruby site lib dir" FORCE) set(Ruby_HAS_VENDOR_RUBY ${Ruby_HAS_VENDOR_RUBY} CACHE BOOL "Vendor Ruby is available" FORCE) set(Ruby_VENDORARCH_DIR ${Ruby_VENDORARCH_DIR} CACHE PATH "The Ruby vendor arch dir" FORCE) set(Ruby_VENDORLIB_DIR ${Ruby_VENDORLIB_DIR} CACHE PATH "The Ruby vendor lib dir" FORCE) mark_as_advanced( Ruby_ARCH_DIR Ruby_ARCH Ruby_HDR_DIR Ruby_ARCHHDR_DIR Ruby_POSSIBLE_LIB_DIR Ruby_RUBY_LIB_DIR Ruby_SITEARCH_DIR Ruby_SITELIB_DIR Ruby_HAS_VENDOR_RUBY Ruby_VENDORARCH_DIR Ruby_VENDORLIB_DIR Ruby_VERSION_MAJOR Ruby_VERSION_MINOR Ruby_VERSION_PATCH ) endif() # In case Ruby_EXECUTABLE could not be executed (e.g. cross compiling) # try to detect which version we found. This is not too good. if(Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR) # by default assume 1.8.0 set(Ruby_VERSION_MAJOR 1) set(Ruby_VERSION_MINOR 8) set(Ruby_VERSION_PATCH 0) # check whether we found 1.9.x if(${Ruby_EXECUTABLE} MATCHES "ruby1\\.?9") set(Ruby_VERSION_MAJOR 1) set(Ruby_VERSION_MINOR 9) endif() # check whether we found 2.0.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?0") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 0) endif() # check whether we found 2.1.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?1") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 1) endif() # check whether we found 2.2.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?2") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 2) endif() # check whether we found 2.3.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?3") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 3) endif() # check whether we found 2.4.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?4") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 4) endif() # check whether we found 2.5.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?5") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 5) endif() # check whether we found 2.6.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?6") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 6) endif() # check whether we found 2.7.x if(${Ruby_EXECUTABLE} MATCHES "ruby2\\.?7") set(Ruby_VERSION_MAJOR 2) set(Ruby_VERSION_MINOR 7) endif() endif() if(Ruby_VERSION_MAJOR) set(Ruby_VERSION "${Ruby_VERSION_MAJOR}.${Ruby_VERSION_MINOR}.${Ruby_VERSION_PATCH}") set(_Ruby_VERSION_SHORT "${Ruby_VERSION_MAJOR}.${Ruby_VERSION_MINOR}") set(_Ruby_VERSION_SHORT_NODOT "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}") set(_Ruby_NODOT_VERSION "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}${Ruby_VERSION_PATCH}") endif() # FIXME: Currently we require both the interpreter and development components to be found # in order to use either. See issue #20474. find_path(Ruby_INCLUDE_DIR NAMES ruby.h HINTS ${Ruby_HDR_DIR} ${Ruby_ARCH_DIR} /usr/lib/ruby/${_Ruby_VERSION_SHORT}/i586-linux-gnu/ ) set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIR}) # if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir if( Ruby_FIND_VERSION VERSION_GREATER_EQUAL "1.9" OR Ruby_VERSION VERSION_GREATER_EQUAL "1.9" OR Ruby_HDR_DIR) find_path(Ruby_CONFIG_INCLUDE_DIR NAMES ruby/config.h config.h HINTS ${Ruby_HDR_DIR}/${Ruby_ARCH} ${Ruby_ARCH_DIR} ${Ruby_ARCHHDR_DIR} ) set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIRS} ${Ruby_CONFIG_INCLUDE_DIR} ) endif() # Determine the list of possible names for the ruby library set(_Ruby_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_Ruby_VERSION_SHORT} ruby${_Ruby_VERSION_SHORT_NODOT} ruby-${_Ruby_VERSION_SHORT} ruby-${Ruby_VERSION}) if(WIN32) if(MSVC_TOOLSET_VERSION) set(_Ruby_MSVC_RUNTIME "${MSVC_TOOLSET_VERSION}") else() set(_Ruby_MSVC_RUNTIME "") endif() set(_Ruby_ARCH_PREFIX "") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_Ruby_ARCH_PREFIX "x64-") endif() list(APPEND _Ruby_POSSIBLE_LIB_NAMES "${_Ruby_ARCH_PREFIX}msvcr${_Ruby_MSVC_RUNTIME}-ruby${_Ruby_NODOT_VERSION}" "${_Ruby_ARCH_PREFIX}msvcr${_Ruby_MSVC_RUNTIME}-ruby${_Ruby_NODOT_VERSION}-static" "${_Ruby_ARCH_PREFIX}msvcrt-ruby${_Ruby_NODOT_VERSION}" "${_Ruby_ARCH_PREFIX}msvcrt-ruby${_Ruby_NODOT_VERSION}-static" ) endif() find_library(Ruby_LIBRARY NAMES ${_Ruby_POSSIBLE_LIB_NAMES} HINTS ${Ruby_POSSIBLE_LIB_DIR} ) set(_Ruby_REQUIRED_VARS Ruby_EXECUTABLE Ruby_INCLUDE_DIR Ruby_LIBRARY) if(_Ruby_VERSION_SHORT_NODOT GREATER 18) list(APPEND _Ruby_REQUIRED_VARS Ruby_CONFIG_INCLUDE_DIR) endif() if(_Ruby_DEBUG_OUTPUT) message(STATUS "--------FindRuby.cmake debug------------") message(STATUS "_Ruby_POSSIBLE_EXECUTABLE_NAMES: ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}") message(STATUS "_Ruby_POSSIBLE_LIB_NAMES: ${_Ruby_POSSIBLE_LIB_NAMES}") message(STATUS "Ruby_ARCH_DIR: ${Ruby_ARCH_DIR}") message(STATUS "Ruby_HDR_DIR: ${Ruby_HDR_DIR}") message(STATUS "Ruby_POSSIBLE_LIB_DIR: ${Ruby_POSSIBLE_LIB_DIR}") message(STATUS "Found Ruby_VERSION: \"${Ruby_VERSION}\" , short: \"${_Ruby_VERSION_SHORT}\", nodot: \"${_Ruby_VERSION_SHORT_NODOT}\"") message(STATUS "_Ruby_REQUIRED_VARS: ${_Ruby_REQUIRED_VARS}") message(STATUS "Ruby_EXECUTABLE: ${Ruby_EXECUTABLE}") message(STATUS "Ruby_LIBRARY: ${Ruby_LIBRARY}") message(STATUS "Ruby_INCLUDE_DIR: ${Ruby_INCLUDE_DIR}") message(STATUS "Ruby_CONFIG_INCLUDE_DIR: ${Ruby_CONFIG_INCLUDE_DIR}") message(STATUS "--------------------") endif() include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ruby REQUIRED_VARS ${_Ruby_REQUIRED_VARS} VERSION_VAR Ruby_VERSION ) if(Ruby_FOUND) set(Ruby_LIBRARIES ${Ruby_LIBRARY}) endif() mark_as_advanced( Ruby_EXECUTABLE Ruby_LIBRARY Ruby_INCLUDE_DIR Ruby_CONFIG_INCLUDE_DIR ) # Set some variables for compatibility with previous version of this file (no need to provide a CamelCase version of that...) set(RUBY_POSSIBLE_LIB_PATH ${Ruby_POSSIBLE_LIB_DIR}) set(RUBY_RUBY_LIB_PATH ${Ruby_RUBY_LIB_DIR}) set(RUBY_INCLUDE_PATH ${Ruby_INCLUDE_DIRS}) # Backwards compatibility # Define upper case versions of output variables foreach(Camel Ruby_EXECUTABLE Ruby_INCLUDE_DIRS Ruby_LIBRARY Ruby_VERSION Ruby_VERSION_MAJOR Ruby_VERSION_MINOR Ruby_VERSION_PATCH Ruby_ARCH_DIR Ruby_ARCH Ruby_HDR_DIR Ruby_ARCHHDR_DIR Ruby_POSSIBLE_LIB_DIR Ruby_RUBY_LIB_DIR Ruby_SITEARCH_DIR Ruby_SITELIB_DIR Ruby_HAS_VENDOR_RUBY Ruby_VENDORARCH_DIR ) string(TOUPPER ${Camel} UPPER) set(${UPPER} ${${Camel}}) endforeach()dislocker-0.7.3/cmake/cmake_uninstall.cmake.in000066400000000000000000000017561375503125700213610ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) dislocker-0.7.3/include/000077500000000000000000000000001375503125700151335ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/000077500000000000000000000000001375503125700171125ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/accesses/000077500000000000000000000000001375503125700207035ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/accesses/accesses.h000066400000000000000000000022771375503125700226550ustar00rootroot00000000000000/* -*- 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 DIS_ACCESSES_H #define DIS_ACCESSES_H #include "dislocker/dislocker.h" /** * Prototypes */ int dis_get_access(dis_context_t dis_ctx); #ifdef _HAVE_RUBY #include "dislocker/ruby.h" void Init_accesses(VALUE rb_mDislocker); #endif #endif /* DIS_ACCESSES_H */ dislocker-0.7.3/include/dislocker/accesses/bek/000077500000000000000000000000001375503125700214445ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/accesses/bek/bekfile.h000066400000000000000000000027261375503125700232250ustar00rootroot00000000000000/* -*- 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 READ_BEKFILE_H #define READ_BEKFILE_H #include "dislocker/config.priv.h" #include "dislocker/ntfs/clock.h" #include "dislocker/metadata/guid.h" #include "dislocker/metadata/datums.h" #include "dislocker/metadata/extended_info.h" #include "dislocker/metadata/metadata.h" /* * Prototypes */ int get_vmk_from_bekfile(dis_metadata_t dis_meta, dis_config_t* cfg, void** vmk_datum); int get_vmk_from_bekfile2(dis_metadata_t dis_meta, char* bek_file, void** vmk_datum); int get_bek_dataset(int fd, void** bek_dataset); #endif // READ_BEKFILE_H dislocker-0.7.3/include/dislocker/accesses/rp/000077500000000000000000000000001375503125700213245ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/accesses/rp/recovery_password.h000066400000000000000000000031411375503125700252540ustar00rootroot00000000000000/* -*- 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 RECOVERY_PASSWORD_H #define RECOVERY_PASSWORD_H #include "dislocker/common.h" #include "dislocker/config.priv.h" #include "dislocker/accesses/stretch_key.h" #include "dislocker/metadata/metadata.h" /* * Prototypes */ int get_vmk_from_rp(dis_metadata_t dis_meta, dis_config_t* cfg, void** vmk_datum); int get_vmk_from_rp2(dis_metadata_t dis_meta, uint8_t* recovery_password, void** vmk_datum); int is_valid_key(const uint8_t *recovery_password, uint16_t *short_password); int intermediate_key(const uint8_t *recovery_key, const uint8_t *salt, uint8_t *result_key); int prompt_rp(uint8_t** rp); void print_intermediate_key(uint8_t *result_key); #endif // RECOVERY_PASSWORD_H dislocker-0.7.3/include/dislocker/accesses/stretch_key.h000066400000000000000000000024031375503125700233770ustar00rootroot00000000000000/* -*- 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 STRETCH_KEY_H #define STRETCH_KEY_H #include "dislocker/common.h" #include "dislocker/ssl_bindings.h" /* * Prototypes */ int stretch_recovery_key(const uint8_t *recovery_key, const uint8_t *salt, uint8_t *result); int stretch_user_key(const uint8_t *user_hash, const uint8_t *salt, uint8_t *result); #endif // STRETCH_KEY_H dislocker-0.7.3/include/dislocker/accesses/user_pass/000077500000000000000000000000001375503125700227075ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/accesses/user_pass/user_pass.h000066400000000000000000000027601375503125700250710ustar00rootroot00000000000000/* -*- 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 USER_PASS_H #define USER_PASS_H #include "dislocker/common.h" #include "dislocker/config.priv.h" #include "dislocker/accesses/stretch_key.h" #include "dislocker/ntfs/encoding.h" #include "dislocker/metadata/metadata.h" /* * Prototypes */ int get_vmk_from_user_pass(dis_metadata_t dis_meta, dis_config_t* cfg, void** vmk_datum); int get_vmk_from_user_pass2(dis_metadata_t dis_meta, uint8_t** user_password, void** vmk_datum); int user_key(const uint8_t *user_password, const uint8_t *salt, uint8_t *result_key); int prompt_up(uint8_t** up); #endif // USER_PASS_H dislocker-0.7.3/include/dislocker/common.h000066400000000000000000000043551375503125700205620ustar00rootroot00000000000000/* -*- 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 COMMON_H #define COMMON_H /* Generic includes */ #include "dislocker/xstd/xstdio.h" #include "dislocker/xstd/xstdlib.h" #include #include #include /* Convention */ #define TRUE 1 #define FALSE 0 /* Signatures of volumes */ #define BITLOCKER_SIGNATURE "-FVE-FS-" #define BITLOCKER_SIGNATURE_SIZE strlen(BITLOCKER_SIGNATURE) #define NTFS_SIGNATURE "NTFS " #define NTFS_SIGNATURE_SIZE strlen(NTFS_SIGNATURE) #define BITLOCKER_TO_GO_SIGNATURE "MSWIN4.1" #define BITLOCKER_TO_GO_SIGNATURE_SIZE strlen(BITLOCKER_TO_GO_SIGNATURE) #ifdef __ARCH_X86_64 # define F_OFF_T "tx" #else # define F_OFF_T "llx" #endif /* __ARCH_X86_64 */ #define F_SIZE_T "zx" /* * Prototypes of functions from common.c */ int dis_open(const char *file, int mode); int dis_close(int fd); ssize_t dis_read(int fd, void* buf, size_t count); ssize_t dis_write(int fd, void* buf, size_t count); off_t dis_lseek(int fd, off_t offset, int whence); void hexdump(DIS_LOGS level, uint8_t* data, size_t data_size); void xor_buffer(unsigned char* buf1, const unsigned char* buf2, unsigned char* output, size_t size); void memclean(void* ptr, size_t size); #ifdef _HAVE_RUBY #include "dislocker/ruby.h" VALUE rb_hexdump(uint8_t* data, size_t data_len); #endif /* _HAVE_RUBY */ #endif // COMMON_H dislocker-0.7.3/include/dislocker/config.h000066400000000000000000000051361375503125700205350ustar00rootroot00000000000000/* -*- 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 DISLOCKER_CFG_H #define DISLOCKER_CFG_H #include #include "dislocker/dislocker.h" typedef enum { /* Below are options dis_getopts() can parse out of the command line */ DIS_OPT_VOLUME_PATH = 1, DIS_OPT_USE_CLEAR_KEY, DIS_OPT_USE_BEK_FILE, DIS_OPT_SET_BEK_FILE_PATH, DIS_OPT_USE_RECOVERY_PASSWORD, DIS_OPT_SET_RECOVERY_PASSWORD, DIS_OPT_USE_USER_PASSWORD, DIS_OPT_SET_USER_PASSWORD, DIS_OPT_USE_FVEK_FILE, DIS_OPT_SET_FVEK_FILE_PATH, DIS_OPT_USE_VMK_FILE, DIS_OPT_SET_VMK_FILE_PATH, DIS_OPT_VERBOSITY, DIS_OPT_LOG_FILE_PATH, DIS_OPT_FORCE_BLOCK, DIS_OPT_VOLUME_OFFSET, DIS_OPT_READ_ONLY, DIS_OPT_DONT_CHECK_VOLUME_STATE, /* Below are options for users of the library (i.e: developers) */ DIS_OPT_INITIALIZE_STATE } dis_opt_e; /** * dis_initialize() function does a lot of things. So, in order to provide * flexibility, place some kind of breakpoint after majors steps. */ typedef enum { DIS_STATE_COMPLETE_EVERYTHING = 0, DIS_STATE_AFTER_OPEN_VOLUME, DIS_STATE_AFTER_VOLUME_HEADER, DIS_STATE_AFTER_VOLUME_CHECK, DIS_STATE_AFTER_BITLOCKER_INFORMATION_CHECK, DIS_STATE_AFTER_VMK, DIS_STATE_AFTER_FVEK, DIS_STATE_BEFORE_DECRYPTION_CHECKING, } dis_state_e; /* * Function's prototypes */ void dis_usage(); int dis_getopts(dis_context_t dis_ctx, int argc, char** argv); int dis_getopt(dis_context_t dis_ctx, dis_opt_e opt_name, void** opt_value); int dis_setopt(dis_context_t dis_ctx, dis_opt_e opt_name, const void* opt_value); void dis_free_args(dis_context_t dis_ctx); void dis_print_args(dis_context_t dis_ctx); int dis_is_read_only(dis_context_t dis_ctx); int dis_is_volume_state_checked(dis_context_t dis_ctx); #endif /* DISLOCKER_CFG_H */ dislocker-0.7.3/include/dislocker/config.priv.h000066400000000000000000000060151375503125700215110ustar00rootroot00000000000000/* -*- 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 DIS_CONFIG_PRIV_H #define DIS_CONFIG_PRIV_H #include "dislocker/config.h" /** * Different methods to decrypt the VMK */ typedef enum { DIS_USE_CLEAR_KEY = (1 << 0), DIS_USE_USER_PASSWORD = (1 << 1), DIS_USE_RECOVERY_PASSWORD = (1 << 2), DIS_USE_BEKFILE = (1 << 3), DIS_USE_FVEKFILE = (1 << 4), DIS_USE_VMKFILE = (1 << 8) } DIS_DECRYPT_MEAN; /* Don't use this as a decryption mean, but as the last one */ #define LAST_MEAN (1 << 5) /** * Just an enum not to have a random constant written everytime we use this */ typedef enum { /* Make the volume read-only, in order not to corrupt it */ DIS_FLAG_READ_ONLY = (1 << 0), /* * By default, dislocker will check for unstable state that may corrupt data * if mounted using fuse */ DIS_FLAG_DONT_CHECK_VOLUME_STATE = (1 << 1), } dis_flags_e; /** * Structure containing options (command line ones and others if need be) */ typedef struct _dis_cfg { /* BitLocker-volume-to-mount path */ char* volume_path; /* Which method to use to decrypt */ DIS_DECRYPT_MEAN decryption_mean; /* Path to the .bek file in case of using the BEKFILE DECRYPT_MEAN */ char* bek_file; /* * Recovery password to use in case of using the RECOVERY_PASSWORD * DECRYPT_MEAN */ uint8_t* recovery_password; /* User password to use in case of using the USER_PASSWORD DECRYPT_MEAN */ uint8_t* user_password; /* Use directly the FVEK file DECRYPT_MEAN */ char* fvek_file; /* Use directly the VMK file DECRYPT_MEAN */ char* vmk_file; /* Output verbosity */ DIS_LOGS verbosity; /* Output file */ char* log_file; /* Use this block of metadata and not another one (begin at 1) */ unsigned char force_block; /* * Begin to read the BitLocker volume at this offset, making this offset the * zero-one */ off_t offset; /* * Various flags one can use. See dis_flags_e enum above for possible values */ dis_flags_e flags; /* Where dis_initialize() should stop */ dis_state_e init_stop_at; } dis_config_t; #endif /* DIS_CONFIG_PRIV_H */ dislocker-0.7.3/include/dislocker/dislocker.h000066400000000000000000000071041375503125700212440ustar00rootroot00000000000000/* -*- 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 DISLOCKER_MAIN_H #define DISLOCKER_MAIN_H #include #include #include "dislocker/xstd/xstdio.h" // Only for off_t /** * Main structure to pass to dislocker functions. These keeps various * information in it. */ typedef struct _dis_ctx* dis_context_t; /** * Public prototypes */ /** * Allocate internal structure, named a context here. This structure is to be * passed to this API's functions and records internal state. */ dis_context_t dis_new(); /** * 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 (through the use of the * dis_new() function). * This function malloc(3)s structures, see dis_destroy() below for free(3)ing * it. If you're weary of memory leaks, you'll make sure to call dis_destroy() * to free the dis_new()-allocated context. * dislock() & enlock() function may not be called before executing this * function - or at least they won't work. * * @param dis_ctx The dislocker context needed for all operations. As stated * above, this parameter has to be pre-allocated through the use of the * dis_new() function. */ 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); /** * Retrieve the fd for the FVE volume. This permits reading/writing - although * not encouraged - directly to the volume. */ int get_fvevol_fd(dis_context_t dis_ctx); #endif /* DISLOCKER_MAIN_H */ dislocker-0.7.3/include/dislocker/dislocker.priv.h000066400000000000000000000050421375503125700222220ustar00rootroot00000000000000/* -*- 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 DIS_DISLOCKER_PRIV_H #define DIS_DISLOCKER_PRIV_H #include #include "dislocker/dislocker.h" #include "dislocker/config.priv.h" #include "dislocker/inouts/inouts.priv.h" #include "dislocker/metadata/metadata.priv.h" #include "dislocker/return_values.h" #define checkupdate_dis_state(ctx, state) \ do { \ (ctx)->curr_state = (state); \ if((state) == (ctx)->cfg.init_stop_at) { \ dis_printf(L_DEBUG, "Library end init at state %d\n", (state)); \ return (state); \ } \ } while(0); /** * Main structure to pass to dislocker functions. These keeps various * information in it. */ struct _dis_ctx { /* * Dislocker's configuration. * Note that there's the dis_getopts() function to fill this structure from * command-line's arguments and the dis_setopt() function */ dis_config_t cfg; /* * Structure to keep volume metadata around. */ dis_metadata_t metadata; /* * Structure needed for dec/encryption processes. */ dis_iodata_t io_data; /* * States dislocker initialisation is at or will be stopped at. */ dis_state_e curr_state; /* The file descriptor to the encrypted volume */ int fve_fd; }; #ifdef _HAVE_RUBY enum { DIS_RB_CLASS_DISLOCKER = 0, DIS_RB_CLASS_METADATA, DIS_RB_CLASS_DATUM, DIS_RB_CLASS_ACCESSES, DIS_RB_CLASS_MAX }; #endif /* _HAVE_RUBY */ #endif /* DIS_DISLOCKER_PRIV_H */ dislocker-0.7.3/include/dislocker/encryption/000077500000000000000000000000001375503125700213045ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/encryption/aes-xts.h000066400000000000000000000026151375503125700230450ustar00rootroot00000000000000/* -*- 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 DIS_AES_XTS_H #define DIS_AES_XTS_H #include "dislocker/ssl_bindings.h" /* * Prototypes */ int dis_aes_crypt_xex( AES_CONTEXT *crypt_ctx, AES_CONTEXT *tweak_ctx, int mode, size_t length, unsigned char *iv, const unsigned char *input, unsigned char *output ); int dis_aes_crypt_xts( AES_CONTEXT *crypt_ctx, AES_CONTEXT *tweak_ctx, int mode, size_t length, unsigned char *iv, const unsigned char *input, unsigned char *output ); #endif /* DIS_AES_XTS_H */ dislocker-0.7.3/include/dislocker/encryption/crc32.h000066400000000000000000000020751375503125700223750ustar00rootroot00000000000000/* -*- 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 CRC32_H #define CRC32_H /* * Prototypes */ unsigned int crc32(const unsigned char *buf, const unsigned int len); #endif /* CRC32_H */ dislocker-0.7.3/include/dislocker/encryption/decrypt.h000066400000000000000000000035201375503125700231270ustar00rootroot00000000000000/* -*- 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 DECRYPT_H #define DECRYPT_H #define AUTHENTICATOR_LENGTH 16 #include #include "dislocker/xstd/xstdio.h" // Only for off_t #include "dislocker/encryption/encommon.h" /* * Prototypes */ int decrypt_key( unsigned char* input, unsigned int input_size, unsigned char* mac, unsigned char* nonce, unsigned char* key, unsigned int keybits, void** output ); void decrypt_cbc_without_diffuser( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); void decrypt_cbc_with_diffuser( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); void decrypt_xts( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); int decrypt_sector(dis_crypt_t crypt, uint8_t* sector, off_t sector_address, uint8_t* buffer); #endif /* DECRYPT_H */ dislocker-0.7.3/include/dislocker/encryption/diffuser.h000066400000000000000000000025421375503125700232670ustar00rootroot00000000000000/* -*- 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 DIFFUSER_H #define DIFFUSER_H #include /* * Prototypes */ void diffuserA_decrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer); void diffuserB_decrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer); void diffuserA_encrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer); void diffuserB_encrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer); #endif /* DIFFUSER_H */ dislocker-0.7.3/include/dislocker/encryption/encommon.h000066400000000000000000000040041375503125700232660ustar00rootroot00000000000000/* -*- 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 ENCOMMON_H #define ENCOMMON_H #include /** * Cipher used within BitLocker */ enum cipher_types { STRETCH_KEY = 0x1000, AES_CCM_256_0 = 0x2000, AES_CCM_256_1 = 0x2001, EXTERN_KEY = 0x2002, VMK = 0x2003, AES_CCM_256_2 = 0x2004, HASH_256 = 0x2005, AES_128_DIFFUSER = 0x8000, AES_256_DIFFUSER = 0x8001, AES_128_NO_DIFFUSER = 0x8002, AES_256_NO_DIFFUSER = 0x8003, AES_XTS_128 = 0x8004, AES_XTS_256 = 0x8005, DIS_CIPHER_LOWEST_SUPPORTED = 0x8000, DIS_CIPHER_HIGHEST_SUPPORTED = 0x8005, }; typedef uint16_t cipher_t; /** * AES contexts "used" during encryption/decryption * @see encryption/decrypt.c * @see encryption/encrypt.c */ typedef struct _aes_contexts dis_aes_contexts_t; /** * Crypt structure used for the encryption operations */ typedef struct _dis_crypt* dis_crypt_t; /* * Prototypes */ dis_crypt_t dis_crypt_new(uint16_t sector_size, cipher_t disk_cipher); int dis_crypt_set_fvekey(dis_crypt_t crypt, uint16_t algorithm, uint8_t* fvekey); void dis_crypt_destroy(dis_crypt_t crypt); #endif /* ENCOMMON_H */ dislocker-0.7.3/include/dislocker/encryption/encommon.priv.h000066400000000000000000000034431375503125700242530ustar00rootroot00000000000000/* -*- 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 ENCOMMON_PRIV_H #define ENCOMMON_PRIV_H #include "dislocker/encryption/encommon.h" #include "dislocker/ssl_bindings.h" /** * AES contexts "used" during encryption/decryption * @see encryption/decrypt.c * @see encryption/encrypt.c */ struct _aes_contexts { AES_CONTEXT FVEK_E_ctx; AES_CONTEXT FVEK_D_ctx; AES_CONTEXT TWEAK_E_ctx; AES_CONTEXT TWEAK_D_ctx; /* useless, never used */ }; typedef enum { DIS_ENC_FLAG_USE_DIFFUSER = (1 << 0) } dis_enc_flags_e; struct _dis_crypt { struct _aes_contexts ctx; dis_enc_flags_e flags; uint16_t sector_size; void (*decrypt_fn)( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); void (*encrypt_fn)( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); }; #endif /* ENCOMMON_PRIV_H */ dislocker-0.7.3/include/dislocker/encryption/encrypt.h000066400000000000000000000030571375503125700231460ustar00rootroot00000000000000/* -*- 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 ENCRYPT_H #define ENCRYPT_H #include "dislocker/encryption/encommon.h" /* * Prototypes */ void encrypt_cbc_without_diffuser( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); void encrypt_cbc_with_diffuser( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); void encrypt_xts( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer ); int encrypt_sector(dis_crypt_t crypt, uint8_t* sector, off_t sector_address, uint8_t* buffer); #endif /* ENCRYPT_H */ dislocker-0.7.3/include/dislocker/inouts/000077500000000000000000000000001375503125700204335ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/inouts/inouts.h000066400000000000000000000025511375503125700221300ustar00rootroot00000000000000/* -*- 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 DIS_INOUTS_H #define DIS_INOUTS_H #include #include "dislocker/dislocker.h" /** * Structure used for operation on disk (encryption/decryption) */ typedef struct _data dis_iodata_t; /** * Function to get the volume's size */ uint64_t dis_inouts_volume_size(dis_context_t dis_ctx); /** * Function to get the volume's sector size */ uint16_t dis_inouts_sector_size(dis_context_t dis_ctx); #endif /* DIS_INOUTS_H */ dislocker-0.7.3/include/dislocker/inouts/inouts.priv.h000066400000000000000000000047231375503125700231120ustar00rootroot00000000000000/* -*- 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 DIS_INOUTS_PRIV_H #define DIS_INOUTS_PRIV_H #include #include "dislocker/inouts/inouts.h" #include "dislocker/metadata/datums.h" #include "dislocker/metadata/metadata.h" #include "dislocker/encryption/encommon.h" /** * Structure used for operation on disk (encryption/decryption) */ struct _data { /* The metadata structure object */ dis_metadata_t metadata; /* The VMK */ datum_key_t* vmk; /* The FVEK */ datum_key_t* fvek; /* Where the real partition begins */ off_t part_off; /* Volume sector size */ uint16_t sector_size; /* Volume size, in bytes */ uint64_t volume_size; /* File descriptor to access the volume */ int volume_fd; /* Size of the encrypted part of the volume */ uint64_t encrypted_volume_size; union { /* Address of the NTFS sectors backuped */ uint64_t backup_sectors_addr; /* MFTMirror field */ uint64_t mftmirror_backup; }; /* Number of NTFS sectors backuped */ uint32_t nb_backup_sectors; /* Structure used to encrypt or decrypt */ dis_crypt_t crypt; /* Volume's state is kept here */ int volume_state; /* Function to decrypt a region of the volume */ 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)( struct _data* io_data, size_t nb_write_sector, uint16_t sector_size, off_t sector_start, uint8_t* input ); }; #endif /* DIS_INOUTS_PRIV_H */ dislocker-0.7.3/include/dislocker/inouts/prepare.h000066400000000000000000000027161375503125700222500ustar00rootroot00000000000000/* -*- 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 PREPARE_H #define PREPARE_H #include #include "dislocker/dislocker.priv.h" #include "dislocker/encryption/encommon.h" #include "dislocker/metadata/datums.h" #include "dislocker/metadata/metadata.h" /** * Function used to initialize keys used for decryption/encryption */ int init_keys(bitlocker_dataset_t* dataset, datum_key_t* fvek, dis_crypt_t crypt); /** * Function used to prepare a structure which hold data used for * decryption/encryption */ int prepare_crypt(dis_context_t dis_ctx); #endif /* PREPARE_H */ dislocker-0.7.3/include/dislocker/inouts/sectors.h000066400000000000000000000025731375503125700222750ustar00rootroot00000000000000/* -*- 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 SECTORS_H #define SECTORS_H #include #include "dislocker/xstd/xstdio.h" #include "dislocker/inouts/inouts.h" /* * Functions prototypes */ 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 */ dislocker-0.7.3/include/dislocker/metadata/000077500000000000000000000000001375503125700206725ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/metadata/datums.h000066400000000000000000000207731375503125700223510ustar00rootroot00000000000000/* -*- 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 DATUM_HEADER_H #define DATUM_HEADER_H #include "dislocker/common.h" #include "dislocker/metadata/metadata.h" #include "dislocker/metadata/extended_info.h" #include "dislocker/metadata/guid.h" #include "dislocker/ntfs/clock.h" #include "dislocker/ntfs/encoding.h" #include "dislocker/encryption/encommon.h" #include #ifndef static_assert #define static_assert(x, s) extern int static_assertion[2*!!(x)-1] #endif /** * Here stand datums' value types stuff */ #define NB_DATUMS_VALUE_TYPES 22 enum value_types { /* 0 */ DATUMS_VALUE_ERASED = 0x0000, /* 1 */ DATUMS_VALUE_KEY, /* 2 */ DATUMS_VALUE_UNICODE, /* 3 */ DATUMS_VALUE_STRETCH_KEY, /* 4 */ DATUMS_VALUE_USE_KEY, /* 5 */ DATUMS_VALUE_AES_CCM, /* 6 */ DATUMS_VALUE_TPM_ENCODED, /* 7 */ DATUMS_VALUE_VALIDATION, /* 8 */ DATUMS_VALUE_VMK, /* 9 */ DATUMS_VALUE_EXTERNAL_KEY, /* 10 */ DATUMS_VALUE_UPDATE, /* 11 */ DATUMS_VALUE_ERROR, /* Below is only available on Windows Seven */ /* 12 */ DATUMS_VALUE_ASYM_ENC, /* 13 */ DATUMS_VALUE_EXPORTED_KEY, /* 14 */ DATUMS_VALUE_PUBLIC_KEY, /* 15 */ DATUMS_VALUE_VIRTUALIZATION_INFO, /* 16 */ DATUMS_VALUE_SIMPLE_1, /* 17 */ DATUMS_VALUE_SIMPLE_2, /* 18 */ DATUMS_VALUE_CONCAT_HASH_KEY, /* 19 */ DATUMS_VALUE_SIMPLE_3 }; typedef uint16_t dis_datums_value_type_t; /* Here are some specifics entry types (second field of the safe header) */ #define NB_DATUMS_ENTRY_TYPES 12 enum entry_types { DATUMS_ENTRY_UNKNOWN1 = 0x0000, DATUMS_ENTRY_UNKNOWN2, DATUMS_ENTRY_VMK, DATUMS_ENTRY_FVEK, DATUMS_ENTRY_UNKNOWN3, DATUMS_ENTRY_UNKNOWN4, DATUMS_ENTRY_STARTUP_KEY, DATUMS_ENTRY_ENCTIME_INFORMATION, DATUMS_ENTRY_UNKNOWN7, DATUMS_ENTRY_UNKNOWN8, DATUMS_ENTRY_UNKNOWN9, DATUMS_ENTRY_UNKNOWN10, DATUMS_ENTRY_FVEK_2 }; typedef uint16_t dis_datums_entry_type_t; /** * This is the minimal header a datum has */ #pragma pack (1) typedef struct _header_safe { uint16_t datum_size; dis_datums_entry_type_t entry_type; dis_datums_value_type_t value_type; uint16_t error_status; } datum_header_safe_t; static_assert( sizeof(struct _header_safe) == 8, "Datum header structure's size isn't equal to 8" ); /** * Used if the datum header is not implemented yet, according to the datum type */ typedef struct _datum_generic { datum_header_safe_t header; // uint8_t* payload; } datum_generic_type_t; /** * Here are datum headers, according to their datum type */ /* Datum type = 0 */ typedef struct _datum_erased { datum_header_safe_t header; } datum_erased_t; /* Datum type = 1 */ typedef struct _datum_key { datum_header_safe_t header; cipher_t algo; uint16_t padd; } datum_key_t; /* Datum type = 2 */ typedef struct _datum_unicode { datum_header_safe_t header; } datum_unicode_t; /* Datum type = 3 */ typedef struct _datum_stretch_key { datum_header_safe_t header; cipher_t algo; uint16_t padd; uint8_t salt[16]; } datum_stretch_key_t; /* Datum type = 4 */ typedef struct _datum_use_key { datum_header_safe_t header; cipher_t algo; uint16_t padd; } datum_use_key_t; /* Datum type = 5 */ typedef struct _datum_aes_ccm { datum_header_safe_t header; uint8_t nonce[12]; uint8_t mac[16]; } datum_aes_ccm_t; /* Datum type = 6 */ typedef struct _datum_tpm_enc { datum_header_safe_t header; uint32_t unknown; // See properties below, the header size of this datum is 0xc => header + int32 (int32 possibly divided into more members) } datum_tpm_enc_t; /* Datum type = 8 */ typedef struct _datum_vmk { datum_header_safe_t header; guid_t guid; uint8_t nonce[12]; } datum_vmk_t; /* Datum type = 9 */ typedef struct _datum_external { datum_header_safe_t header; guid_t guid; ntfs_time_t timestamp; } datum_external_t; /* Datum type = 15 */ typedef struct _datum_virtualization { datum_header_safe_t header; uint64_t ntfs_boot_sectors; uint64_t nb_bytes; /* * Below is a structure added to this virtualization structure in Windows 8 * The header is still 0x18 in size, which means xinfo is a payload */ extended_info_t xinfo; } datum_virtualization_t; #pragma pack () /** * A hardcoded table defining some properties for each datum */ typedef struct _datum_value_types_properties { /* * The header size of the datum, this is including the datum_header_safe_t * structure which is beginning each one of them */ uint16_t size_header; /* * A flag which tells us if the datum has one or more nested datum * 0 = No nested datum * 1 = One or more nested datum */ uint8_t has_nested_datum; /* Always equal to 0, maybe for padding */ uint8_t zero; } value_types_properties_t; static const value_types_properties_t datum_value_types_prop[] = { { 8, 0, 0 }, // ERASED { 0xc, 0, 0 }, // KEY { 8, 0, 0 }, // UNICODE { 0x1c, 1, 0 }, // STRETCH { 0xc, 1, 0 }, // USE KEY { 0x24, 0, 0 }, // AES CCM { 0xc, 0, 0 }, // TPM ENCODED { 8, 0, 0 }, // VALIDATION { 0x24, 1, 0 }, // VMK { 0x20, 1, 0 }, // EXTERNAL KEY { 0x2c, 1, 0 }, // UPDATE { 0x34, 0, 0 }, // ERROR /* These ones below were added for Seven */ { 8, 0, 0 }, // ASYM ENC { 8, 0, 0 }, // EXPORTED KEY { 8, 0, 0 }, // PUBLIC KEY { 0x18, 0, 0 }, // VIRTUALIZATION INFO { 0xc, 0, 0 }, // SIMPLE { 0xc, 0, 0 }, // SIMPLE { 0x1c, 0, 0 }, // CONCAT HASH KEY { 0xc, 0, 0 } // SIMPLE }; /* * Here are prototypes of functions dealing with data */ char* cipherstr(cipher_t enc); char* datumvaluetypestr(dis_datums_value_type_t value_type); int get_header_safe(void* data, datum_header_safe_t* header); int get_payload_safe(void* data, void** payload, size_t* size_payload); void print_one_datum(DIS_LOGS level, void* datum); void print_header(DIS_LOGS level, datum_header_safe_t* header); void print_datum_generic(DIS_LOGS level, void* vdatum); void print_datum_erased(DIS_LOGS level, void* vdatum); void print_datum_key(DIS_LOGS level, void* vdatum); void print_datum_unicode(DIS_LOGS level, void* vdatum); void print_datum_stretch_key(DIS_LOGS level, void* vdatum); void print_datum_use_key(DIS_LOGS level, void* vdatum); void print_datum_aes_ccm(DIS_LOGS level, void* vdatum); void print_datum_tpmenc(DIS_LOGS level, void* vdatum); void print_datum_vmk(DIS_LOGS level, void* vdatum); void print_datum_external(DIS_LOGS level, void* vdatum); void print_datum_virtualization(DIS_LOGS level, void* vdatum); void print_nonce(DIS_LOGS level, uint8_t* nonce); void print_mac(DIS_LOGS level, uint8_t* mac); int get_next_datum( dis_metadata_t dis_metadata, dis_datums_entry_type_t entry_type, dis_datums_value_type_t value_type, void* datum_begin, void** datum_result ); int get_nested_datum(void* datum, void** datum_nested); int get_nested_datumvaluetype(void* datum, dis_datums_value_type_t value_type, void** datum_nested); int datum_value_type_must_be(void* datum, dis_datums_value_type_t value_type); int dis_metadata_has_clear_key(dis_metadata_t dis_meta, void** vmk_datum); typedef void(*print_datum_f)(DIS_LOGS, void*); static const print_datum_f print_datum_tab[NB_DATUMS_VALUE_TYPES] = { print_datum_erased, print_datum_key, print_datum_unicode, print_datum_stretch_key, print_datum_use_key, print_datum_aes_ccm, print_datum_tpmenc, print_datum_generic, print_datum_vmk, print_datum_external, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_virtualization, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, print_datum_generic, }; #ifdef _HAVE_RUBY #include "dislocker/ruby.h" void Init_datum(VALUE rb_cDislockerMetadata); VALUE rb_cDislockerMetadataDatum_new(VALUE klass, VALUE datum); #endif #endif // DATUM_HEADER_H dislocker-0.7.3/include/dislocker/metadata/extended_info.h000066400000000000000000000031521375503125700236570ustar00rootroot00000000000000/* -*- 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 EXTENDED_INFO_H #define EXTENDED_INFO_H #include "dislocker/common.h" /** * This structure is new to Windows 8 * It's the virtualization datum's payload */ typedef struct _extended_info { uint16_t unknown1; uint16_t size; uint32_t unknown2; uint64_t flags; uint64_t convertlog_addr; uint32_t convertlog_size; uint32_t sector_size1; uint32_t sector_size2; } extended_info_t; /* * Here are prototypes of functions dealing extended info */ void print_extended_info(DIS_LOGS level, extended_info_t* xinfo); #ifdef _HAVE_RUBY #include "dislocker/ruby.h" VALUE rb_datum_virtualization_extinfo_to_s(extended_info_t* xinfo); #endif /* _HAVE_RUBY */ #endif // EXTENDED_INFO_H dislocker-0.7.3/include/dislocker/metadata/fvek.h000066400000000000000000000023401375503125700217750ustar00rootroot00000000000000/* -*- 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 FVEK_H #define FVEK_H #include "dislocker/config.priv.h" #include "dislocker/metadata/metadata.h" /* * Functions prototypes */ int get_fvek(dis_metadata_t dis_metadata, void* vmk_datum, void** fvek_datum); int build_fvek_from_file(dis_config_t* cfg, void** fvek_datum); #endif /* FVEK_H */ dislocker-0.7.3/include/dislocker/metadata/guid.h000066400000000000000000000024571375503125700220030ustar00rootroot00000000000000/* -*- 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 GUID_H #define GUID_H #include "dislocker/common.h" // GUID type = array of 16 unsigned bytes typedef uint8_t guid_t[16]; /* * Prototypes */ void format_guid(uint8_t *raw_guid, char* formated_guid); int check_match_guid(guid_t guid_1, guid_t guid_2); #ifdef _HAVE_RUBY #include "dislocker/ruby.h" void Init_guid(VALUE rb_mDislockerMetadata); #endif #endif // GUID_H dislocker-0.7.3/include/dislocker/metadata/metadata.h000066400000000000000000000050061375503125700226240ustar00rootroot00000000000000/* -*- 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 METADATA_H #define METADATA_H #include #include "dislocker/dislocker.h" #include "dislocker/metadata/metadata_config.h" /** Known BitLocker versions */ enum { V_VISTA = 1, V_SEVEN = 2 // Same version used by Windows 8 }; typedef uint16_t version_t; /** * Metadata structure to use to query the functions below */ typedef struct _dis_metadata* dis_metadata_t; /* * Prototypes */ dis_metadata_t dis_metadata_new(dis_metadata_config_t dis_metadata_cfg); dis_metadata_t dis_metadata_get(dis_context_t dis_ctx); int dis_metadata_initialize(dis_metadata_t dis_metadata); int dis_metadata_destroy(dis_metadata_t dis_metadata); int check_state(dis_metadata_t dis_metadata); void dis_metadata_vista_vbr_fve2ntfs(dis_metadata_t dis_meta, void* vbr); void dis_metadata_vista_vbr_ntfs2fve(dis_metadata_t dis_meta, void* vbr); int dis_metadata_is_overwritten( dis_metadata_t dis_metadata, off_t offset, size_t size ); uint64_t dis_metadata_volume_size_from_vbr(dis_metadata_t dis_meta); void* dis_metadata_set_dataset( dis_metadata_t dis_metadata, void* new_dataset ); void* dis_metadata_set_volume_header( dis_metadata_t dis_metadata, void* new_volume_header ); uint16_t dis_metadata_sector_size(dis_metadata_t dis_meta); version_t dis_metadata_information_version(dis_metadata_t dis_meta); uint64_t dis_metadata_encrypted_volume_size(dis_metadata_t dis_meta); uint64_t dis_metadata_ntfs_sectors_address(dis_metadata_t dis_meta); uint64_t dis_metadata_mftmirror(dis_metadata_t dis_meta); uint32_t dis_metadata_backup_sectors_count(dis_metadata_t dis_meta); #endif // METADATA_H dislocker-0.7.3/include/dislocker/metadata/metadata.priv.h000066400000000000000000000272311375503125700236070ustar00rootroot00000000000000/* -*- 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 DIS_METADATA_PRIV_H #define DIS_METADATA_PRIV_H #include "dislocker/common.h" #include "dislocker/metadata/metadata.h" #include "dislocker/metadata/extended_info.h" #include "dislocker/metadata/guid.h" #include "dislocker/ntfs/clock.h" #include "dislocker/return_values.h" #define checkupdate_dis_meta_state(ctx, state) \ do { \ (ctx)->curr_state = (state); \ if((state) == (ctx)->init_stop_at) { \ dis_printf(L_DEBUG, "Library end init at state %d\n", (state)); \ return (state); \ } \ } while(0); #include #ifndef static_assert #define static_assert(x, s) extern int static_assertion[2*!!(x)-1] #endif #pragma pack (1) /** First sector of an NTFS or BitLocker volume */ typedef struct _volume_header { /* 512 bytes long */ uint8_t jump[3]; // -- offset 0 uint8_t signature[8]; // = "-FVE-FS-" (without 0 at the string's end) -- offset 3 // = "NTFS " (idem) for NTFS volumes (ORLY?) // = "MSWIN4.1" for BitLocker-To-Go encrypted volumes uint16_t sector_size; // = 0x0200 = 512 bytes -- offset 0xb uint8_t sectors_per_cluster; // -- offset 0xd uint16_t reserved_clusters; // -- offset 0xe uint8_t fat_count; // -- offset 0x10 uint16_t root_entries; // -- offset 0x11 uint16_t nb_sectors_16b; // -- offset 0x13 uint8_t media_descriptor; // -- offset 0x15 uint16_t sectors_per_fat; // -- offset 0x16 uint16_t sectors_per_track; // -- offset 0x18 uint16_t nb_of_heads; // -- offset 0x1a uint32_t hidden_sectors; // -- offset 0x1c uint32_t nb_sectors_32b; // -- offset 0x20 union { // -- offset 0x24 struct { // Classic BitLocker uint8_t unknown2[4]; // NTFS = 0x00800080 (little endian) uint64_t nb_sectors_64b; // -- offset 0x28 uint64_t mft_start_cluster; // -- offset 0x30 union { // Metadata LCN or MFT Mirror -- offset 0x38 uint64_t metadata_lcn; // depending on whether we're talking about a Vista volume uint64_t mft_mirror; // or an NTFS one }; uint8_t unknown3[96]; // -- offset 0x40 guid_t guid; // -- offset 0xa0 uint64_t information_off[3]; // NOT for Vista -- offset 0xb0 uint64_t eow_information_off[2]; // NOT for Vista NOR 7 -- offset 0xc8 uint8_t unknown4[294]; // -- offset 0xd8 }; struct { // BitLocker-To-Go uint8_t unknown5[35]; uint8_t fs_name[11]; // -- offset 0x47 uint8_t fs_signature[8]; // -- offset 0x52 uint8_t unknown6[334]; // -- offset 0x5a guid_t bltg_guid; // -- offset 0x1a8 uint64_t bltg_header[3]; // -- offset 0x1b8 uint8_t Unknown7[46]; // -- offset 0x1d0 }; }; uint16_t boot_partition_identifier; // = 0xaa55 -- offset 0x1fe } volume_header_t; // Size = 512 static_assert( sizeof(struct _volume_header) == 512, "Volume header structure's size isn't equal to 512" ); /** Header of a data set, used in the bitlocker header below */ typedef struct _bitlocker_dataset { uint32_t size; // -- offset 0 uint32_t unknown1; // = 0x0001 FIXME -- offset 4 uint32_t header_size; // = 0x0030 -- offset 8 uint32_t copy_size; // = dataset_size -- offset 0xc guid_t guid; // dataset GUID -- offset 0x10 uint32_t next_counter; // -- offset 0x20 uint16_t algorithm; // -- offset 0x24 uint16_t trash; // -- offset 0x26 ntfs_time_t timestamp; // -- offset 0x28 } bitlocker_dataset_t; // Size = 0x30 static_assert( sizeof(struct _bitlocker_dataset) == 0x30, "BitLocker dataset structure's size isn't equal to 0x30" ); /** Different states BitLocker is in */ enum state_types { METADATA_STATE_NULL = 0, METADATA_STATE_DECRYPTED = 1, METADATA_STATE_SWITCHING_ENCRYPTION = 2, METADATA_STATE_EOW_ACTIVATED = 3, METADATA_STATE_ENCRYPTED = 4, METADATA_STATE_SWITCH_ENCRYPTION_PAUSED = 5 }; typedef uint16_t dis_metadata_state_t; /** * Header of a BitLocker metadata structure, named information * * Datums (protectors) with keys in them follow this header */ typedef struct _bitlocker_information { uint8_t signature[8]; // = "-FVE-FS-" -- offset 0 uint16_t size; // Total size (has to be multiplied by 16 when the version is 2) -- offset 8 version_t version; // = 0x0002 for Windows 7 and 1 for Windows Vista -- offset 0xa /* Not sure about the next two fields */ dis_metadata_state_t curr_state; // Current encryption state -- offset 0xc dis_metadata_state_t next_state; // Next encryption state -- offset 0xe uint64_t encrypted_volume_size; // Size of the encrypted volume -- offset 0x10 /* * The following size describes a virtualized region. This region is only * checked when this->curr_state == 2. It begins at the offset described by * this->encrypted_volume_size */ uint32_t convert_size; // -- offset 0x18 uint32_t nb_backup_sectors; // -- offset 0x1c uint64_t information_off[3]; // -- offset 0x20 union { uint64_t boot_sectors_backup; // Address where the boot sectors have been backed up -- offset 0x38 uint64_t mftmirror_backup; // This is the address of the MftMirror for Vista -- offset 0x38 }; struct _bitlocker_dataset dataset; // See above -- offset 0x40 } bitlocker_information_t; // Size = 0x40 + 0x30 static_assert( sizeof(struct _bitlocker_information) == (0x40 + 0x30), "BitLocker information structure's size isn't equal to 0x70" ); /* * The following structure is followed by a datum of type 5 (DATUM_AES_CCM) or 1 * (DATUM_KEY). When there's a DATUM_AES_CCM, this is actually the DATUM_KEY * encrypted using the VMK. * The key contained in the DATUM_KEY structure is the SHA-256 sum of the entire * BitLocker's metadata fields (bitlocker_information_t + every datum). * * Therefore, the size field contains 8 plus the size of the datum. */ typedef struct _bitlocker_validations { uint16_t size; version_t version; uint32_t crc32; } bitlocker_validations_t; // Size = 8 static_assert( sizeof(struct _bitlocker_validations) == 8, "BitLocker validations structure's size isn't equal to 8" ); /** * The following structure is used when the volume GUID is * EOW_INFORMATION_OFFSET_GUID (see guid.c). * It's followed by some kind of payload I don't know about yet (but that * explains header_size vs infos_size) */ typedef struct _bitlocker_eow_infos { uint8_t signature[8]; // = "FVE-EOW" -- offset 0 uint16_t header_size; // = 0x38 -- offset 8 uint16_t infos_size; // -- offset 0xa uint32_t sector_size1; // -- offset 0xc uint32_t sector_size2; // -- offset 0x10 uint32_t unknown_14; // FIXME -- offset 0x14 uint32_t convlog_size; // -- offset 0x18 uint32_t unknown_1c; // FIXME -- offset 0x1c uint32_t nb_regions; // -- offset 0x20 uint32_t crc32; // -- offset 0x24 uint64_t disk_offsets[2]; // -- offset 0x28 } bitlocker_eow_infos_t; // Size = 0x38 static_assert( sizeof(struct _bitlocker_eow_infos) == 0x38, "BitLocker EOW information structure's size isn't equal to 0x38" ); #pragma pack () /** * A region is used to describe BitLocker metadata on disk */ typedef struct _regions { /* Metadata offset */ uint64_t addr; /* Metadata size on disk */ uint64_t size; } dis_regions_t; struct _dis_metadata { /* The volume header, 512 bytes */ volume_header_t* volume_header; /* BitLocker-volume's main metadata */ bitlocker_information_t* information; /* BitLocker-volume's submain metadata */ bitlocker_dataset_t* dataset; /* BitLocker-volume's EOW main metadata */ bitlocker_eow_infos_t* eow_information; /* * Virtualized regions are presented as zeroes when queried from the NTFS * layer. In these virtualized regions, we find the 3 BitLocker metadata * headers, the area where NTFS boot sectors are backed-up for W$ 7&8, and * an area I don't know about yet for W$ 8. * This last area is used only when BitLocker's state is 2. */ size_t nb_virt_region; dis_regions_t virt_region[5]; /* Size (in bytes) of the NTFS backed-up sectors */ off_t virtualized_size; /* Extended info which may be present (NULL otherwise) */ extended_info_t* xinfo; /* A pointer to the configuration of the metadata */ dis_metadata_config_t cfg; }; #ifdef _HAVE_RUBY #include "dislocker/ruby.h" void Init_metadata(VALUE rb_mDislocker); #endif #endif /* DIS_METADATA_PRIV_H */ dislocker-0.7.3/include/dislocker/metadata/metadata_config.h000066400000000000000000000034521375503125700241540ustar00rootroot00000000000000/* -*- 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 METADATA_CONFIG_H #define METADATA_CONFIG_H #include "dislocker/config.h" /** * Metadata structure to use to query the functions below */ typedef struct _dis_metadata_config* dis_metadata_config_t; struct _dis_metadata_config { /* The file descriptor to the encrypted volume */ int fve_fd; /* * Use this block of metadata and not another one (begin at 1, 0 is for not * forcing anything) */ unsigned char force_block; /* * Begin to read the BitLocker volume at this offset, making this offset the * zero-one */ off_t offset; /* States dislocker's metadata initialisation is at or will be stopped at */ dis_state_e curr_state; dis_state_e init_stop_at; }; /* * Prototypes */ dis_metadata_config_t dis_metadata_config_new(); void dis_metadata_config_destroy(dis_metadata_config_t dis_metadata_cfg); #endif // METADATA_CONFIG_H dislocker-0.7.3/include/dislocker/metadata/print_metadata.h000066400000000000000000000026251375503125700240440ustar00rootroot00000000000000/* -*- 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 PRINT_METADATA_H #define PRINT_METADATA_H #include "dislocker/common.h" #include "dislocker/metadata/metadata.h" void print_volume_header(DIS_LOGS level, dis_metadata_t dis_metadata); void print_information(DIS_LOGS level, dis_metadata_t dis_metadata); void print_eow_infos(DIS_LOGS level, dis_metadata_t dis_metadata); void print_dataset(DIS_LOGS level, dis_metadata_t dis_metadata); void print_data(DIS_LOGS level, dis_metadata_t dis_metadata); #endif // PRINT_METADATA_H dislocker-0.7.3/include/dislocker/metadata/vmk.h000066400000000000000000000030501375503125700216360ustar00rootroot00000000000000/* -*- 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 VMK_H #define VMK_H #include "dislocker/metadata/datums.h" #include "dislocker/metadata/guid.h" #include "dislocker/config.priv.h" /* * Functions prototypes */ int get_vmk_from_clearkey(dis_metadata_t dis_meta, void** vmk_datum); int get_vmk_datum_from_guid(dis_metadata_t dis_meta, guid_t guid, void** vmk_datum); int get_vmk_datum_from_range(dis_metadata_t dis_meta, uint16_t min_range, uint16_t max_range, void** vmk_datum); int get_vmk(datum_aes_ccm_t* vmk_datum, uint8_t* recovery_key, size_t key_size, datum_key_t** vmk); int get_vmk_from_file(dis_config_t* cfg, void** vmk_datum); #endif /* VMK_H */ dislocker-0.7.3/include/dislocker/ntfs/000077500000000000000000000000001375503125700200645ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/ntfs/clock.h000066400000000000000000000022571375503125700213360ustar00rootroot00000000000000/* -*- 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 CLOCK_H #define CLOCK_H #include #include "dislocker/common.h" /* Deal with ntfs timestamps */ typedef uint64_t ntfs_time_t; /* * Prototypes of functions from clock.c */ void ntfs2utc(ntfs_time_t t, time_t *ts); #endif /* CLOCK_H */ dislocker-0.7.3/include/dislocker/ntfs/encoding.h000066400000000000000000000024311375503125700220230ustar00rootroot00000000000000/* -*- 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 ENCODING_H #define ENCODING_H #include #include "dislocker/common.h" /* * Prototypes of functions from encoding.c */ int utf16towchars(uint16_t* utf16, size_t utf16_length, wchar_t* utf32); int asciitoutf16(const uint8_t* ascii, uint16_t* utf16); int utf16bigtolittleendian(uint16_t* utf16, size_t utf16_length); #endif /* ENCODING_H */ dislocker-0.7.3/include/dislocker/return_values.h000066400000000000000000000053201375503125700221610ustar00rootroot00000000000000/* -*- 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 DISLOCKER_RETURN_VALUES_H #define DISLOCKER_RETURN_VALUES_H #include /* * dislocker saves errno in this variable when returning something else than * DIS_RET_SUCCESS. * Returns (listed below) are for `high-level' errors, returned by dislocker, * whereas dis_errno is for `low-levels' ones, the reason why dislocker returned * an error. */ extern int dis_errno; #define DIS_RET_SUCCESS 0 #define DIS_RET_ERROR_ALLOC -1 #define DIS_RET_ERROR_FILE_OPEN -2 #define DIS_RET_ERROR_FILE_CLOSE -3 #define DIS_RET_ERROR_FILE_READ -4 #define DIS_RET_ERROR_FILE_WRITE -5 #define DIS_RET_ERROR_FILE_SEEK -6 #define DIS_RET_ERROR_VOLUME_NOT_GIVEN -10 #define DIS_RET_ERROR_VOLUME_HEADER_READ -11 #define DIS_RET_ERROR_VOLUME_HEADER_CHECK -12 #define DIS_RET_ERROR_VOLUME_SIZE_NOT_FOUND -13 #define DIS_RET_ERROR_VOLUME_STATE_NOT_SAFE -14 #define DIS_RET_ERROR_VOLUME_READ_ONLY -15 #define DIS_RET_ERROR_METADATA_OFFSET -20 #define DIS_RET_ERROR_METADATA_CHECK -21 #define DIS_RET_ERROR_METADATA_VERSION_UNSUPPORTED -22 #define DIS_RET_ERROR_METADATA_FILE_SIZE_NOT_FOUND -23 #define DIS_RET_ERROR_METADATA_FILE_OVERWRITE -24 #define DIS_RET_ERROR_DATASET_CHECK -25 #define DIS_RET_ERROR_VMK_RETRIEVAL -26 #define DIS_RET_ERROR_FVEK_RETRIEVAL -27 #define DIS_RET_ERROR_VIRTUALIZATION_INFO_DATUM_NOT_FOUND -28 #define DIS_RET_ERROR_CRYPTO_INIT -40 #define DIS_RET_ERROR_CRYPTO_ALGORITHM_UNSUPPORTED -41 #define DIS_RET_ERROR_MUTEX_INIT -50 #define DIS_RET_ERROR_MUTEX_LOCK -51 #define DIS_RET_ERROR_MUTEX_UNLOCK -52 #define DIS_RET_ERROR_OFFSET_OUT_OF_BOUND -60 #define DIS_RET_ERROR_DISLOCKER_NOT_INITIALIZED -100 #define DIS_RET_ERROR_DISLOCKER_ENCRYPTION_ERROR -101 #define DIS_RET_ERROR_DISLOCKER_NO_WRITE_ON_METADATA -102 #define DIS_RET_ERROR_DISLOCKER_INVAL -103 #endif /* DISLOCKER_RETURN_VALUES_H */ dislocker-0.7.3/include/dislocker/ruby.h000066400000000000000000000035061375503125700202500ustar00rootroot00000000000000/* -*- 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 DIS_RUBY_H #define DIS_RUBY_H #ifdef _HAVE_RUBY #include #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic ignored "-Wunknown-attributes" #pragma clang diagnostic ignored "-Wunused-parameter" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wsign-conversion" #endif /* defined(__clang__) */ #include #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif /* defined(__clang__) */ #ifndef rb_str_vcatf #define rb_str_vcatf dis_rb_str_vcatf VALUE rb_str_vcatf(VALUE str, const char *fmt, va_list ap); #endif #ifndef rb_str_catf #define rb_str_catf dis_rb_str_catf VALUE rb_str_catf(VALUE str, const char *fmt, ...); #endif #endif /* _HAVE_RUBY */ #endif /* DIS_RUBY_H */ dislocker-0.7.3/include/dislocker/ssl_bindings.h.in000066400000000000000000000076221375503125700223550ustar00rootroot00000000000000/* -*- 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 SSL_BINDINGS_H #define SSL_BINDINGS_H /* * Here stand the bindings for polarssl SHA256/SHA2/SHA-2 function for dislocker */ #include "@POLARSSL_INC_FOLDER@/config.h" #include "@POLARSSL_INC_FOLDER@/version.h" #include "@POLARSSL_INC_FOLDER@/aes.h" // Function's name changed #if defined(MBEDTLS_SHA256_C) # include "mbedtls/sha256.h" # if MBEDTLS_VERSION_NUMBER >= 0x02070000 # define SHA256(input, len, output) mbedtls_sha256_ret(input, len, output, 0) # else # define SHA256(input, len, output) mbedtls_sha256(input, len, output, 0) # endif /* POLARSSL_VERSION_NUMBER >= 0x02070000 */ #else /* defined(MBEDTLS_SHA256_C) */ # if defined(POLARSSL_SHA256_C) # include "polarssl/sha256.h" # define SHA256(input, len, output) sha256(input, len, output, 0) # else /* defined(POLARSSL_SHA256_C) */ # include "polarssl/sha2.h" // 0x00630500 = version 0.99.5, argument's type changed in this release # if POLARSSL_VERSION_NUMBER >= 0x00630500 # define SHA256(input, len, output) sha2(input, len, output, 0) # else # define SHA256(input, len, output) sha2(input, (int)len, output, 0) # endif /* POLARSSL_VERSION_NUMBER >= 0x00630500 */ # endif /* defined(POLARSSL_SHA256_C) */ #endif /* defined(MBEDTLS_SHA256_C) */ /* Here stand the bindings for AES functions and contexts */ #if defined(MBEDTLS_AES_H) # define AES_CONTEXT mbedtls_aes_context # define AES_SETENC_KEY(ctx, key, size) mbedtls_aes_setkey_enc(ctx, key, size) # define AES_SETDEC_KEY(ctx, key, size) mbedtls_aes_setkey_dec(ctx, key, size) # define AES_ECB_ENC(ctx, mode, in, out) mbedtls_aes_crypt_ecb(ctx, mode, in, out) # define AES_CBC(ctx, mode, size, iv, in, out) \ mbedtls_aes_crypt_cbc(ctx, mode, size, iv, in, out); # define AES_ENCRYPT MBEDTLS_AES_ENCRYPT # define AES_DECRYPT MBEDTLS_AES_DECRYPT #else # define AES_CONTEXT aes_context # define AES_SETENC_KEY(ctx, key, size) aes_setkey_enc(ctx, key, size) # define AES_SETDEC_KEY(ctx, key, size) aes_setkey_dec(ctx, key, size) # define AES_ECB_ENC(ctx, mode, in, out) aes_crypt_ecb(ctx, mode, in, out) # define AES_CBC(ctx, mode, size, iv, in, out) \ aes_crypt_cbc(ctx, mode, size, iv, in, out); #endif /* defined(MBEDTLS_AES_H) */ #include "dislocker/encryption/aes-xts.h" #if defined(MBEDTLS_CIPHER_MODE_XEX) # define AES_XEX(ctx1, ctx2, mode, size, iv, in, out) \ mbedtls_aes_crypt_xex(ctx1, ctx2, mode, size, iv, in, out) #else # define AES_XEX(ctx1, ctx2, mode, size, iv, in, out) \ dis_aes_crypt_xex(ctx1, ctx2, mode, size, iv, in, out) #endif /* defined(MBEDTLS_CIPHER_MODE_XEX) */ # define AES_XTS(ctx1, ctx2, mode, size, iv, in, out) \ dis_aes_crypt_xts(ctx1, ctx2, mode, size, iv, in, out) #endif /* SSL_BINDINGS_H */ dislocker-0.7.3/include/dislocker/xstd/000077500000000000000000000000001375503125700200745ustar00rootroot00000000000000dislocker-0.7.3/include/dislocker/xstd/xstdio.h000066400000000000000000000032421375503125700215600ustar00rootroot00000000000000/* -*- 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 XSTDIO_H #define XSTDIO_H #include #include /* Mode in which the log file is opened */ #define LOG_MODE "a" /** Messages debug level */ typedef enum { L_QUIET = -1, L_CRITICAL = 0, /* default level is 0, whatever 0 is */ L_ERROR, L_WARNING, L_INFO, L_DEBUG } DIS_LOGS; /* Do NOT count the L_QUIET level */ #define DIS_LOGS_NB 5 /* * Prototypes of functions from xstdio.c */ void dis_stdio_init(int verbosity, const char* logfile); void dis_stdio_end(); int get_input_fd(); void close_input_fd(); void chomp(char* string); int dis_printf(DIS_LOGS level, const char* format, ...); int dis_vprintf(DIS_LOGS level, const char* format, va_list ap); void dis_perror(char* append); #endif /* XSTDIO_H */ dislocker-0.7.3/include/dislocker/xstd/xstdlib.h000066400000000000000000000021561375503125700217220ustar00rootroot00000000000000/* -*- 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 XSTDLIB_H #define XSTDLIB_H #include /* * Prototypes of functions from xstdlib.c */ void* dis_malloc(size_t size); void dis_free(void *pointer); #endif /* XSTDLIB_H */ dislocker-0.7.3/include/dislocker/xstd/xsys_select.h000066400000000000000000000030441375503125700226130ustar00rootroot00000000000000/* -*- 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 XSYS_SELECT_h #define XSYS_SELECT_h /* According to POSIX.1-2001 */ #include /* According to earlier standards */ #include #include #include /* * Cf commit ceb9e56b3d1f8c1922e0526c2e841373843460e2 in the glibc tree. * * Ubuntu 12.04 LTS uses glibc 2.13. */ #if defined(__GLIBC__) #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 16 # define DIS_FD_SET(fd, set) FD_SET((unsigned) (fd), (set)) #else # define DIS_FD_SET(fd, set) FD_SET((fd), (set)) #endif #else # define DIS_FD_SET(fd, set) FD_SET((fd), (set)) #endif /* defined(__GLIBC__) */ #endif /* XSYS_SELECT_h */ dislocker-0.7.3/man/000077500000000000000000000000001375503125700142635ustar00rootroot00000000000000dislocker-0.7.3/man/darwin/000077500000000000000000000000001375503125700155475ustar00rootroot00000000000000dislocker-0.7.3/man/darwin/dislocker-file.1000066400000000000000000000046741375503125700205400ustar00rootroot00000000000000.\" .\" .TH DISLOCKER 1 2011-09-07 "Linux" "DISLOCKER" .SH NAME Dislocker file - Read BitLocker encrypted volumes under Linux, OSX and FreeBSD. .SH SYNOPSIS dislocker-file [-hqrsv] [-l \fILOG_FILE\fR] [-O \fIOFFSET\fR] [-V \fIVOLUME\fR \fIDECRYPTMETHOD\fR -F[\fIN\fR]] [--] \fINTFS_FILE\fR Where DECRYPTMETHOD = {-p[\fIRECOVERY_PASSWORD\fR] | -f \fIBEK_FILE\fR | -u[\fIUSER_PASSWORD\fR] | -k \fIFVEK_FILE\fR | -K \fIVMK_FILE\fR | -c} .SH DESCRIPTION Given a decryption mean, the program is used to decrypt BitLocker encrypted volumes. This process may take a very long time, depending on the initial volume size, as the program will decrypt the encrypted partition linearly. About this size, note that the created NTFS file will be of the same size as the BitLocker encrypted partition, so you may want to check that you have enough free space on the volume where you put the NTFS file. This NTFS file won't have any link with the original BitLocker encrypted partition, so you may modify it to suit your needs. .SH OPTIONS For program's options description, see dislocker-fuse(1). The only change in the command line is the last argument, which in this case is the \fINTFS_FILE\fR argument: .PP .TB .B NTFS_FILE the newly created file where NTFS data will be put to, once decrypted from the BitLocker encrypted volume. .SH EXAMPLES These are examples you can run directly. Dislock the BitLocker encrypted volume: .IP .B % dislocker -V /dev/sda2 -p563200-557084-108284-218900-019151-415437-694144-239976 -- decrypted.ntfs .IP This will decrypt \fB/dev/sda2\fR into \fBdecrypted.ntfs\fR using the recovery password method. .TP To mount partitions once decrypted, you first need to create the block device: .B % hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount ntfs/dislocker-file .TP Then mount it on a directory into /Volumes, as for instance: .B % mkdir /Volumes/blah && mount -t ntfs /dev/disk1 /Volumes/blah .P -- .TP You may have to completely unmount the NTFS partition before halting the system. In order to do so, you may run this command (replacing your mount point): .B % umount /Volumes/blah && hdiutil detach /dev/disk1 .P -- Note that these are \fBexamples\fR and, as such, you may need to modify the given command lines. For example, you may want to change the decryption method used in them. .SH AUTHOR This tool is developed by Romain Coltel on behalf of HSC (\fBhttp://www.hsc.fr/\fR) .PP Feel free to send bugs report to dislocker-0.7.3/man/darwin/dislocker-find.1000077700000000000000000000000001375503125700250522../linux/dislocker-find.1ustar00rootroot00000000000000dislocker-0.7.3/man/darwin/dislocker-fuse.1000066400000000000000000000124031375503125700205500ustar00rootroot00000000000000.\" .\" .TH DISLOCKER-FUSE 1 2011-09-07 "Linux" "DISLOCKER-FUSE" .SH NAME Dislocker fuse - Read/write BitLocker encrypted volumes under Linux, OSX and FreeBSD. .SH SYNOPSIS dislocker-fuse [-hqrsv] [-l \fILOG_FILE\fR] [-O \fIOFFSET\fR] [-V \fIVOLUME\fR \fIDECRYPTMETHOD\fR -F[\fIN\fR]] [-- \fIARGS\fR...] Where DECRYPTMETHOD = {-p[\fIRECOVERY_PASSWORD\fR] | -f \fIBEK_FILE\fR | -u[\fIUSER_PASSWORD\fR] | -k \fIFVEK_FILE\fR | -c} .SH DESCRIPTION Given a decryption mean, the program is used to read or write BitLocker encrypted volumes. Technically, the program will create a virtual NTFS partition that you can mount as any other NTFS partition. .PP The virtual partition is linked to the underlying BitLocker volume, so any write to this volume is put on the BitLocker volume as well. However, you can use dd(1) to get rid of this limitation -- if it's a limitation for you. An example is provided in the EXAMPLES section of this man page. .SH OPTIONS Program's options are described below: .PP .TP .B -c, --clearkey decrypt volume using a clear key which is searched on the volume (default) .TP .B -f, --bekfile \fIBEK_FILE\fR decrypt volume using the bek file (present on a USB key) .TP .B -F, --force-block=[\fIN\fB]\fR force use of metadata block number \fIN\fR (1, 2 or 3). Without \fIN\fR, the first block is forced. Without this option, the program will try each block until a valid one is found .TP .B -h print the help and exit .TP .B -k, --fvek \fIFVEK_FILE\fR decrypt volume using the FVEK directly. See the FVEK FILE section below to understand what is to be put into this \fIFVEK_FILE\fR .TP .B -K, --vmk \fIVMK_FILE\fR decrypt volume using the VMK directly. See the VMK FILE section below to understand what is to be put into this \fIVMK_FILE\fR .TP .B -l, --logfile \fILOG_FILE\fR put messages into this file (stdout by default) .TP .B -O, --offset \fIOFFSET\fR BitLocker partition offset, in bytes, in base 10 (default is 0). Protip: in your shell, you probably can pass \fB-O $((\fI0xdeadbeef\fB))\fR if you have a 16-based number and are too lazy to convert it in another way. .TP .B -p, --recovery-password=[\fIRECOVERY_PASSWORD\fB]\fR decrypt volume using the recovery password method. If no recovery-password is provided, it will be asked afterward; this has the advantage that the program will validate each block one by one, on the fly, as you type it and not to leak the password on the commandline .TP .B -q, --quiet do NOT display any information. This option has priority on any previous `\fB-v\fR'. One probably wants to check the return value of the program when using this option .TP .B -r, --readonly do not allow to write on the BitLocker volume (read only mode) .TP .B -s, --stateok do not check the volume's state, assume it's ok to mount it. Do not use this if you don't know what you're doing .TP .B -u, --user-password=[\fIUSER_PASSWORD\fB]\fR decrypt the volume using the user password method. If no user-password is provided, it will be asked afterward; this has the advantage not to leak the password on the commandline .TP .B -v, --verbosity increase verbosity (CRITICAL level by default), see also `\fB-q\fR' .TP .B -V, --volume \fIVOLUME\fR volume to get metadata and encrypted keys from .TP .B -- mark the end of program's options and the beginning of FUSE's ones (useful if you want to pass something like -d to FUSE) .PP .B ARGS are any arguments you want to pass to FUSE. Note that you need to pass at least the mount-point. .SH FVEK FILE .TP The FVEK file option expects a specific format from the file. The file is split into two major parts: - 2 bytes describing the encryption in use, from 0x8000 to 0x8003 for AES 128 or 256 bits, with or without diffuser. - 64 bytes (512 bits) which are the FVEK as in the FVEK key protector once decrypted. .PP The file is therefore 66 bytes long, not more nor less. Note that you may have to deal with endianness. .SH EXAMPLES These are examples you can run directly. First, you may want to copy the BitLocker volume: .IP .B % dd if=/dev/sda2 of=encrypted.bitlocker .IP This will copy the entire volume located into \fB/dev/sda2\fR to \fBencrypted.bitlocker\fR. You're not forced to do this step, but this will ensure no write whatsoever is performed on the BitLocker volume. .P Then dislock it: .IP .B % dislocker -V encrypted.bitlocker -f /path/to/usb/file.BEK -- ntfs/ .IP This will create a file into the \fBntfs/\fR directory named dislocker-file. .TP To mount partitions once decrypted, you first need to create the block device: .B % hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount ntfs/dislocker-file .TP Then mount it on a directory into /Volumes, as for instance: .B % mkdir /Volumes/blah && mount -t ntfs /dev/disk1 /Volumes/blah .P -- .TP It seems that you have to unmount the NTFS partition and the dislocker one before halting the system, or you will run into unexpected behaviour. In order to do so, you may run these commands (replacing your mount points): .B % umount /Volumes/blah && hdiutil detach /dev/disk1 && umount /mnt/ntfs/ .P -- .P Note that these are \fBexamples\fR and, as such, may need to be modified. For instance, you may want to change the decryption method used in them. .SH AUTHOR This tool is developed by Romain Coltel on behalf of HSC (\fBhttp://www.hsc.fr/\fR) .PP Feel free to send bugs report to dislocker-0.7.3/man/freebsd/000077500000000000000000000000001375503125700156755ustar00rootroot00000000000000dislocker-0.7.3/man/freebsd/dislocker-file.1000077700000000000000000000000001375503125700251762../linux/dislocker-file.1ustar00rootroot00000000000000dislocker-0.7.3/man/freebsd/dislocker-find.1000077700000000000000000000000001375503125700252002../linux/dislocker-find.1ustar00rootroot00000000000000dislocker-0.7.3/man/freebsd/dislocker-fuse.1000077700000000000000000000000001375503125700252442../linux/dislocker-fuse.1ustar00rootroot00000000000000dislocker-0.7.3/man/linux/000077500000000000000000000000001375503125700154225ustar00rootroot00000000000000dislocker-0.7.3/man/linux/dislocker-file.1000066400000000000000000000043251375503125700204040ustar00rootroot00000000000000.\" .\" .TH DISLOCKER 1 2011-09-07 "Linux" "DISLOCKER" .SH NAME Dislocker file - Read BitLocker encrypted volumes under Linux, OSX and FreeBSD. .SH SYNOPSIS dislocker-file [-hqrsv] [-l \fILOG_FILE\fR] [-O \fIOFFSET\fR] [-V \fIVOLUME\fR \fIDECRYPTMETHOD\fR -F[\fIN\fR]] [--] \fINTFS_FILE\fR Where DECRYPTMETHOD = {-p[\fIRECOVERY_PASSWORD\fR] | -f \fIBEK_FILE\fR | -u[\fIUSER_PASSWORD\fR] | -k \fIFVEK_FILE\fR | -K \fIVMK_FILE\fR | -c} .SH DESCRIPTION Given a decryption mean, the program is used to decrypt BitLocker encrypted volumes. This process may take a very long time, depending on the initial volume size, as the program will decrypt the encrypted partition linearly. About this size, note that the created NTFS file will be of the same size as the BitLocker encrypted partition, so you may want to check that you have enough free space on the volume where you put the NTFS file. This NTFS file won't have any link with the original BitLocker encrypted partition, so you may modify it to suit your needs. .SH OPTIONS For program's options description, see dislocker-fuse(1). The only change in the command line is the last argument, which in this case is the \fINTFS_FILE\fR argument: .PP .TB .B NTFS_FILE the newly created file where NTFS data will be put to, once decrypted from the BitLocker encrypted volume. .SH EXAMPLES These are examples you can run directly. Dislock the BitLocker encrypted volume: .IP .B % dislocker-file -V /dev/sda2 -p563200-557084-108284-218900-019151-415437-694144-239976 -- decrypted.ntfs .IP This will decrypt \fB/dev/sda2\fR into \fBdecrypted.ntfs\fR using the recovery password method. .TP To mount the partition once decrypted, use this sort of line: .B % mount -o loop decrypted.ntfs /mnt/clear .P -- .TP You may have to unmount the NTFS partition before halting the system. In order to do so, you may run this command (replacing your mount point): .B % umount /mnt/clear .P -- Note that these are \fBexamples\fR and, as such, you may need to modify the given command lines. For example, you may want to change the decryption method used in them. .SH AUTHOR This tool is developed by Romain Coltel on behalf of HSC (\fBhttp://www.hsc.fr/\fR) .PP Feel free to send bugs report to dislocker-0.7.3/man/linux/dislocker-find.1000066400000000000000000000025231375503125700204030ustar00rootroot00000000000000.\" .\" .TH DISLOCKER-FIND 1 2011-09-07 "Linux" "DISLOCKER-FIND" .SH NAME Dislocker find - Find BitLocker-encrypted volumes. .SH SYNOPSIS dislocker-find [-h] [files...] .SH DESCRIPTION The program try to find BitLocker-encrypted volumes or check that provided files are BitLocker-encrypted. It will print every file it find to be BitLocker-encrypted, one per line. Each file/line can be passed to the dislocker suite to be decrypted (`-V' option). .SH OPTIONS Program's options are described below: .PP .TP .B -h print the help and exit .PP .TP .B files check for BitLocker-encrypted partitions among these files instead of trying to find them alone .SH RETURN VALUES -1 means an error occurred, other numbers are the number of BitLocker-encrypted volumes found. For example, 0 means no volume has been found, 42 means 42 volumes have been found. .SH EXAMPLES No volume is found automatically, the program returns 0 volume found (the last line comes from the echo): .IP .nf # dislocker-find.rb ; echo $? No BitLocker volume found. 0 .fi .P Two volumes are found, the program returns this number (the last line comes from the echo): .IP .nf # dislocker-find.rb ; echo $? /dev/sda3 /dev/sda7 2 .fi .SH AUTHOR This tool is developed by Romain Coltel on behalf of HSC (\fBhttp://www.hsc.fr/\fR) .PP Feel free to send bugs report to dislocker-0.7.3/man/linux/dislocker-fuse.1000066400000000000000000000121051375503125700204220ustar00rootroot00000000000000.\" .\" .TH DISLOCKER-FUSE 1 2011-09-07 "Linux" "DISLOCKER-FUSE" .SH NAME Dislocker fuse - Read/write BitLocker encrypted volumes under Linux, OSX and FreeBSD. .SH SYNOPSIS dislocker-fuse [-hqrsv] [-l \fILOG_FILE\fR] [-O \fIOFFSET\fR] [-V \fIVOLUME\fR \fIDECRYPTMETHOD\fR -F[\fIN\fR]] [-- \fIARGS\fR...] Where DECRYPTMETHOD = {-p[\fIRECOVERY_PASSWORD\fR] | -f \fIBEK_FILE\fR | -u[\fIUSER_PASSWORD\fR] | -k \fIFVEK_FILE\fR | -K \fIVMK_FILE\fR | -c} .SH DESCRIPTION Given a decryption mean, the program is used to read or write BitLocker encrypted volumes. Technically, the program will create a virtual NTFS partition that you can mount as any other NTFS partition. .PP The virtual partition is linked to the underlying BitLocker volume, so any write to this volume is put on the BitLocker volume as well. However, you can use dd(1) to get rid of this limitation -- if it's a limitation for you. An example is provided in the EXAMPLES section of this man page. .SH OPTIONS Program's options are described below: .PP .TP .B -c, --clearkey decrypt volume using a clear key which is searched on the volume (default) .TP .B -f, --bekfile \fIBEK_FILE\fR decrypt volume using the bek file (present on a USB key) .TP .B -F, --force-block=[\fIN\fB]\fR force use of metadata block number \fIN\fR (1, 2 or 3). Without \fIN\fR, the first block is forced. Without this option, the program will try each block until a valid one is found .TP .B -h print the help and exit .TP .B -k, --fvek \fIFVEK_FILE\fR decrypt volume using the FVEK directly. See the FVEK FILE section below to understand what is to be put into this \fIFVEK_FILE\fR .TP .B -K, --vmk \fIVMK_FILE\fR decrypt volume using the VMK directly. See the VMK FILE section below to understand what is to be put into this \fIVMK_FILE\fR .TP .B -l, --logfile \fILOG_FILE\fR put messages into this file (stdout by default) .TP .B -O, --offset \fIOFFSET\fR BitLocker partition offset, in bytes, in base 10 (default is 0). Protip: in your shell, you probably can pass \fB-O $((\fI0xdeadbeef\fB))\fR if you have a 16-based number and are too lazy to convert it in another way. .TP .B -p, --recovery-password=[\fIRECOVERY_PASSWORD\fB]\fR decrypt volume using the recovery password method. If no recovery-password is provided, it will be asked afterward; this has the advantage that the program will validate each block one by one, on the fly, as you type it and not to leak the password on the commandline .TP .B -q, --quiet do NOT display any information. This option has priority on any previous `\fB-v\fR'. One probably wants to check the return value of the program when using this option .TP .B -r, --readonly do not allow to write on the BitLocker volume (read only mode) .TP .B -s, --stateok do not check the volume's state, assume it's ok to mount it. Do not use this if you don't know what you're doing .TP .B -u, --user-password=[\fIUSER_PASSWORD\fB]\fR decrypt the volume using the user password method. If no user-password is provided, it will be asked afterward; this has the advantage not to leak the password on the commandline .TP .B -v, --verbosity increase verbosity (CRITICAL level by default), see also `\fB-q\fR' .TP .B -V, --volume \fIVOLUME\fR volume to get metadata and encrypted keys from .TP .B -- mark the end of program's options and the beginning of FUSE's ones (useful if you want to pass something like -d to FUSE) .PP .B ARGS are any arguments you want to pass to FUSE. Note that you need to pass at least the mount-point. .SH FVEK FILE .TP The FVEK file option expects a specific format from the file. The file is split into two major parts: - 2 bytes describing the encryption in use, from 0x8000 to 0x8003 for AES 128 or 256 bits, with or without diffuser. - 64 bytes (512 bits) which are the FVEK as in the FVEK key protector once decrypted. .PP The file is therefore 66 bytes long, not more nor less. Note that you may have to deal with endianness. .SH EXAMPLES These are examples you can run directly. First, you may want to copy the BitLocker volume: .IP .B % dd if=/dev/sda2 of=encrypted.bitlocker .IP This will copy the entire volume located into \fB/dev/sda2\fR to \fBencrypted.bitlocker\fR. You're not forced to do this step, but this will ensure no write whatsoever is performed on the BitLocker volume. .P Then dislock it: .IP .B % dislocker -V encrypted.bitlocker -f /path/to/usb/file.BEK -- /mnt/ntfs .IP This will create a file into \fB/mnt/ntfs\fR named dislocker-file. .TP To mount partitions once decrypted, use this sort of line: .B % mount -o loop /mnt/ntfs/dislocker-file /mnt/clear .P -- .TP It seems that you have to unmount the NTFS partition and the dislocker one before halting the system, or you will run into unexpected behaviour. In order to do so, you may run these commands (replacing your mount points): .B % umount /mnt/clear && umount /mnt/ntfs/dislocker-file .P -- .P Note that these are \fBexamples\fR and, as such, may need to be modified. For instance, you may want to change the decryption method used in them. .SH AUTHOR This tool is developed by Romain Coltel on behalf of HSC (\fBhttp://www.hsc.fr/\fR) .PP Feel free to send bugs report to dislocker-0.7.3/src/000077500000000000000000000000001375503125700142775ustar00rootroot00000000000000dislocker-0.7.3/src/CMakeLists.txt000066400000000000000000000235131375503125700170430ustar00rootroot00000000000000# 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. set(_Ruby_DEBUG_OUTPUT ON) if("${CMAKE_SOURCE_DIR}" MATCHES "src/?$") message(FATAL_ERROR "\nPlease execute cmake from the directory above, not the src/ directory.") return() endif() # On OSX, frameworks are found before installed libraries (cf. https://gitlab.kitware.com/cmake/cmake/-/issues/16427) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") set(CMAKE_FIND_FRAMEWORK Last) message(STATUS "CMAKE_FIND_FRAMEWORK='${CMAKE_FIND_FRAMEWORK}'") endif() add_definitions (-DPROGNAME="${PROJECT_NAME}") add_definitions (-DAUTHOR="${AUTHOR}") add_definitions (-DVERSION="${VERSION}") add_definitions (-D_FILE_OFFSET_BITS=64) add_definitions (-D__OS="${CMAKE_SYSTEM_NAME}") string (TOUPPER "${CMAKE_SYSTEM_NAME}" SYSNAME) add_definitions (-D__${SYSNAME}) if("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) add_definitions (-D__ARCH="x86_64") add_definitions (-D__ARCH_X86_64) else() add_definitions (-D__ARCH="x86") add_definitions (-D__ARCH_X86) endif() if( NOT CMAKE_CROSSCOMPILING ) include_directories (SYSTEM /usr/local/include) endif() include_directories (${PROJECT_SOURCE_DIR}/include) set (LIB pthread) set (SOURCES dislocker.c common.c config.c xstd/xstdio.c xstd/xstdlib.c metadata/datums.c metadata/metadata.c metadata/vmk.c metadata/fvek.c metadata/extended_info.c metadata/guid.c metadata/print_metadata.c accesses/stretch_key.c accesses/accesses.c accesses/rp/recovery_password.c accesses/user_pass/user_pass.c accesses/bek/bekfile.c encryption/encommon.c encryption/decrypt.c encryption/encrypt.c encryption/diffuser.c encryption/crc32.c encryption/aes-xts.c ntfs/clock.c ntfs/encoding.c inouts/inouts.c inouts/prepare.c inouts/sectors.c ) if(NOT DEFINED WARN_FLAGS) set (WARN_FLAGS "-Wall -Wextra" CACHE STRING "" FORCE) endif() if(NOT DEFINED HARDEN_FLAGS) set (HARDEN_FLAGS "-fstack-protector -fstrict-aliasing -D_FORTIFY_SOURCE=2 -O1" CACHE STRING "" FORCE) endif() set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARN_FLAGS}") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${HARDEN_FLAGS}") if(DEFINED CFLAGS) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CFLAGS}") endif() if(DEFINED RPM_OPT_FLAGS) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RPM_OPT_FLAGS}") endif() set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D DEBUG=${DEBUG} -D__DIS_CORE_DUMPS") if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") # Don't use `-read_only_relocs' here as it seems to only work for 32 bits # binaries set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-bind_at_load") set (FUSE_LIB osxfuse_i64) else() # Useless warnings when used within Darwin set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion") set (FUSE_LIB fuse) if("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") link_directories ( ${LINK_DIRECTORIES} /usr/local/lib ) endif() endif() if(${CMAKE_COMPILER_IS_GNUCC}) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,now -Wl,-z,relro") elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments") else() message ("*** WARNING *** You're compiling with an untested compiler (${CMAKE_C_COMPILER_ID}), this mays result in unwanted behaviours.\n") endif() if(DEFINED LDFLAGS) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LDFLAGS}") endif() if(DEFINED RPM_LD_FLAGS) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RPM_LD_FLAGS}") endif() # Libraries set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) find_package (PolarSSL REQUIRED) if(POLARSSL_FOUND AND POLARSSL_INCLUDE_DIRS AND POLARSSL_LIBRARIES) include_directories (${POLARSSL_INCLUDE_DIRS}) set (LIB ${LIB} ${POLARSSL_LIBRARIES}) configure_file (${PROJECT_SOURCE_DIR}/include/dislocker/ssl_bindings.h.in ${PROJECT_SOURCE_DIR}/include/dislocker/ssl_bindings.h ESCAPE_QUOTES @ONLY) else() return () endif() find_package (Ruby) if(RUBY_FOUND AND RUBY_INCLUDE_DIRS AND RUBY_LIBRARY) include_directories (${RUBY_INCLUDE_DIRS}) set (LIB ${LIB} ${RUBY_LIBRARY}) add_definitions (-D_HAVE_RUBY=${RUBY_VERSION_STRING}) set (SOURCES ${SOURCES} ruby.c) endif() find_package (FUSE) if(FUSE_FOUND AND FUSE_INCLUDE_DIRS AND FUSE_LIBRARIES) include_directories (${FUSE_INCLUDE_DIRS}) set (LIB ${LIB} ${FUSE_LIBRARIES}) endif() # Places if(NOT DEFINED sharedir) set(sharedir ${CMAKE_INSTALL_PREFIX}/share) endif() if(NOT DEFINED mandir) set(mandir ${sharedir}/man) endif() if(NOT DEFINED LIB_INSTALL_DIR) if(NOT DEFINED libdir) if(IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib64") set(libdir "${CMAKE_INSTALL_PREFIX}/lib64") else() set(libdir "${CMAKE_INSTALL_PREFIX}/lib") endif() endif() else() set(libdir ${LIB_INSTALL_DIR}) endif() if(NOT DEFINED bindir) set(bindir "${CMAKE_INSTALL_PREFIX}/bin") endif() string (TOLOWER "${CMAKE_SYSTEM_NAME}" SYSNAME) set (DIS_MAN ${PROJECT_SOURCE_DIR}/man/${SYSNAME}) # RPATH handling if(POLICY CMP0042) cmake_policy (SET CMP0042 NEW) endif() set (CMAKE_SKIP_BUILD_RPATH FALSE) set (CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) list (FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${libdir}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set (CMAKE_INSTALL_RPATH "${libdir}") endif() # Targets add_library (${PROJECT_NAME} SHARED ${SOURCES}) target_link_libraries (${PROJECT_NAME} ${LIB}) set_target_properties (${PROJECT_NAME} PROPERTIES VERSION "${VERSION}" SOVERSION "${VERSION_MAJOR}.${VERSION_MINOR}") install (TARGETS ${PROJECT_NAME} LIBRARY DESTINATION "${libdir}") if (${APPLE}) set (BUNDLE_NAME ${PROJECT_NAME}_bundle) add_library (${BUNDLE_NAME} MODULE ${SOURCES}) target_link_libraries (${BUNDLE_NAME} ${LIB}) set_target_properties (${BUNDLE_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME} SUFFIX .bundle) install (TARGETS ${BUNDLE_NAME} DESTINATION "${libdir}") endif() set (CLEAN_FILES "") set (BIN_FUSE ${PROJECT_NAME}-fuse) add_executable (${BIN_FUSE} ${BIN_FUSE}.c) target_link_libraries (${BIN_FUSE} ${FUSE_LIB} ${PROJECT_NAME}) set_target_properties (${BIN_FUSE} PROPERTIES COMPILE_DEFINITIONS FUSE_USE_VERSION=26) set_target_properties (${BIN_FUSE} PROPERTIES LINK_FLAGS "-pie -fPIE") add_custom_command (TARGET ${BIN_FUSE} POST_BUILD COMMAND mkdir -p ${CMAKE_BINARY_DIR}/man/ COMMAND gzip -c ${DIS_MAN}/${BIN_FUSE}.1 > ${CMAKE_BINARY_DIR}/man/${BIN_FUSE}.1.gz ) set (CLEAN_FILES ${CLEAN_FILES} ${CMAKE_BINARY_DIR}/man/${BIN_FUSE}.1.gz) install (TARGETS ${BIN_FUSE} RUNTIME DESTINATION "${bindir}") install (FILES ${CMAKE_BINARY_DIR}/man/${BIN_FUSE}.1.gz DESTINATION "${mandir}/man1") set (BIN_FILE ${PROJECT_NAME}-file) add_executable (${BIN_FILE} ${BIN_FILE}.c) target_link_libraries (${BIN_FILE} ${PROJECT_NAME}) set_target_properties (${BIN_FILE} PROPERTIES LINK_FLAGS "-pie -fPIE") add_custom_command (TARGET ${BIN_FILE} POST_BUILD COMMAND mkdir -p ${CMAKE_BINARY_DIR}/man/ COMMAND gzip -c ${DIS_MAN}/${BIN_FILE}.1 > ${CMAKE_BINARY_DIR}/man/${BIN_FILE}.1.gz ) set (CLEAN_FILES ${CLEAN_FILES} ${CMAKE_BINARY_DIR}/man/${BIN_FILE}.1.gz) install (TARGETS ${BIN_FILE} RUNTIME DESTINATION "${bindir}") install (FILES ${CMAKE_BINARY_DIR}/man/${BIN_FILE}.1.gz DESTINATION "${mandir}/man1") set (BIN_METADATA ${PROJECT_NAME}-metadata) add_executable (${BIN_METADATA} ${BIN_METADATA}.c) target_link_libraries (${BIN_METADATA} ${PROJECT_NAME}) set_target_properties (${BIN_METADATA} PROPERTIES LINK_FLAGS "-pie -fPIE") install (TARGETS ${BIN_METADATA} RUNTIME DESTINATION "${bindir}") set (BIN_BEK ${PROJECT_NAME}-bek) add_executable (${BIN_BEK} ${BIN_BEK}.c) target_link_libraries (${BIN_BEK} ${PROJECT_NAME}) set_target_properties (${BIN_BEK} PROPERTIES LINK_FLAGS "-pie -fPIE") install (TARGETS ${BIN_BEK} RUNTIME DESTINATION "${bindir}") if(RUBY_FOUND) set (BIN_FIND ${PROJECT_NAME}-find) configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/${BIN_FIND}.rb.in" "${CMAKE_CURRENT_SOURCE_DIR}/${BIN_FIND}.rb" ESCAPE_QUOTES @ONLY) add_custom_target(${BIN_FIND} ALL COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/${BIN_FIND}.rb" "${CMAKE_CURRENT_BINARY_DIR}/${BIN_FIND}" COMMAND chmod u+x "${CMAKE_CURRENT_BINARY_DIR}/${BIN_FIND}" SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${BIN_FIND}.rb" ) set (CLEAN_FILES ${CLEAN_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${BIN_FIND}) add_custom_command (TARGET ${BIN_FIND} POST_BUILD COMMAND mkdir -p ${CMAKE_BINARY_DIR}/man/ COMMAND gzip -c ${DIS_MAN}/${BIN_FIND}.1 > ${CMAKE_BINARY_DIR}/man/${BIN_FIND}.1.gz ) set (CLEAN_FILES ${CLEAN_FILES} ${CMAKE_BINARY_DIR}/man/${BIN_FIND}.1.gz) install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${BIN_FIND} DESTINATION "${bindir}") install (FILES ${CMAKE_BINARY_DIR}/man/${BIN_FIND}.1.gz DESTINATION "${mandir}/man1") else() set (BIN_FIND true) endif() install (CODE "execute_process (COMMAND ${CMAKE_COMMAND} -E create_symlink ${BIN_FUSE} \"\$ENV{DESTDIR}${bindir}/${PROJECT_NAME}\")") install (CODE "execute_process (COMMAND ${CMAKE_COMMAND} -E create_symlink ${BIN_FUSE}.1.gz \"\$ENV{DESTDIR}${mandir}/man1/${PROJECT_NAME}.1.gz\")") set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CLEAN_FILES}") # Travis' test target add_custom_target(travis-test COMMAND ${BIN_FUSE} -h COMMAND ${BIN_FILE} -h COMMAND ${BIN_METADATA} -h COMMAND ${BIN_BEK} -h COMMAND ${BIN_FIND} -h COMMAND man -w dislocker ) dislocker-0.7.3/src/accesses/000077500000000000000000000000001375503125700160705ustar00rootroot00000000000000dislocker-0.7.3/src/accesses/accesses.c000066400000000000000000000251411375503125700200300ustar00rootroot00000000000000/* -*- 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 "dislocker/dislocker.priv.h" #include "dislocker/accesses/accesses.h" #include "dislocker/accesses/bek/bekfile.h" #include "dislocker/accesses/rp/recovery_password.h" #include "dislocker/accesses/user_pass/user_pass.h" #include "dislocker/metadata/vmk.h" #include "dislocker/metadata/fvek.h" #include "dislocker/return_values.h" int dis_get_access(dis_context_t dis_ctx) { void* vmk_datum = NULL; void* fvek_datum = NULL; datum_key_t* fvek_typed_datum = NULL; /* * First, get the VMK datum using either any necessary mean */ while(dis_ctx->cfg.decryption_mean) { if(dis_ctx->cfg.decryption_mean & DIS_USE_CLEAR_KEY) { if(!get_vmk_from_clearkey(dis_ctx->metadata, &vmk_datum)) { dis_ctx->cfg.decryption_mean &= (unsigned) ~DIS_USE_CLEAR_KEY; } else { dis_printf(L_INFO, "Used clear key decryption method\n"); dis_ctx->cfg.decryption_mean = DIS_USE_CLEAR_KEY; break; } } else if(dis_ctx->cfg.decryption_mean & DIS_USE_USER_PASSWORD) { if(!get_vmk_from_user_pass(dis_ctx->metadata, &dis_ctx->cfg, &vmk_datum)) { dis_ctx->cfg.decryption_mean &= (unsigned) ~DIS_USE_USER_PASSWORD; } else { dis_printf(L_INFO, "Used user password decryption method\n"); dis_ctx->cfg.decryption_mean = DIS_USE_USER_PASSWORD; /* We don't need the user password anymore */ if(dis_ctx->cfg.user_password) { memclean( (char*) dis_ctx->cfg.user_password, strlen((char*) dis_ctx->cfg.user_password) ); dis_ctx->cfg.user_password = NULL; } break; } } else if(dis_ctx->cfg.decryption_mean & DIS_USE_RECOVERY_PASSWORD) { if(!get_vmk_from_rp(dis_ctx->metadata, &dis_ctx->cfg, &vmk_datum)) { dis_ctx->cfg.decryption_mean &= (unsigned) ~DIS_USE_RECOVERY_PASSWORD; } else { dis_printf(L_INFO, "Used recovery password decryption method\n"); dis_ctx->cfg.decryption_mean = DIS_USE_RECOVERY_PASSWORD; /* We don't need the recovery_password anymore */ if(dis_ctx->cfg.recovery_password) { memclean( (char*) dis_ctx->cfg.recovery_password, strlen((char*) dis_ctx->cfg.recovery_password) ); dis_ctx->cfg.recovery_password = NULL; } break; } } else if(dis_ctx->cfg.decryption_mean & DIS_USE_BEKFILE) { if(!get_vmk_from_bekfile(dis_ctx->metadata, &dis_ctx->cfg, &vmk_datum)) { dis_ctx->cfg.decryption_mean &= (unsigned) ~DIS_USE_BEKFILE; } else { dis_printf(L_INFO, "Used bek file decryption method\n"); dis_ctx->cfg.decryption_mean = DIS_USE_BEKFILE; break; } } else if(dis_ctx->cfg.decryption_mean & DIS_USE_FVEKFILE) { if(!build_fvek_from_file(&dis_ctx->cfg, &fvek_datum)) { dis_ctx->cfg.decryption_mean &= (unsigned) ~DIS_USE_FVEKFILE; } else { dis_printf(L_INFO, "Used FVEK file decryption method\n"); dis_ctx->cfg.decryption_mean = DIS_USE_FVEKFILE; break; } } else if(dis_ctx->cfg.decryption_mean & DIS_USE_VMKFILE) { if(!get_vmk_from_file(&dis_ctx->cfg, &vmk_datum)) { dis_ctx->cfg.decryption_mean &= (unsigned) ~DIS_USE_VMKFILE; } else { dis_printf(L_INFO, "Used VMK file decryption method\n"); dis_ctx->cfg.decryption_mean = DIS_USE_VMKFILE; break; } } else { dis_printf(L_CRITICAL, "Wtf!? Abort.\n"); return DIS_RET_ERROR_VMK_RETRIEVAL; } } if(!dis_ctx->cfg.decryption_mean) { dis_printf( L_CRITICAL, "None of the provided decryption mean is " "decrypting the keys. Abort.\n" ); return DIS_RET_ERROR_VMK_RETRIEVAL; } dis_ctx->io_data.vmk = vmk_datum; checkupdate_dis_state(dis_ctx, DIS_STATE_AFTER_VMK); /* * NOTE -- We could here validate the information buffer in a more precise * way using the VMK and the validations structure (the one after the * information one, see bitlocker_validations_t in metadata/metadata.h) * * NOTE -- We could here get all of the other key a user could use * using the VMK and the reverse encrypted data */ /* * And then, use the VMK to decrypt the FVEK */ if(dis_ctx->cfg.decryption_mean != DIS_USE_FVEKFILE) { if(!get_fvek(dis_ctx->metadata, vmk_datum, &fvek_datum)) return DIS_RET_ERROR_FVEK_RETRIEVAL; } /* Just a check of the algo used to crypt data here */ fvek_typed_datum = (datum_key_t*) fvek_datum; fvek_typed_datum->algo &= 0xffff; if(fvek_typed_datum->algo < DIS_CIPHER_LOWEST_SUPPORTED || fvek_typed_datum->algo > DIS_CIPHER_HIGHEST_SUPPORTED) { dis_printf( L_CRITICAL, "Can't recognize the encryption algorithm used: %#hx. Abort\n", fvek_typed_datum->algo ); return DIS_RET_ERROR_CRYPTO_ALGORITHM_UNSUPPORTED; } dis_ctx->io_data.fvek = fvek_typed_datum; checkupdate_dis_state(dis_ctx, DIS_STATE_AFTER_FVEK); return DIS_RET_SUCCESS; } #ifdef _HAVE_RUBY struct _rb_dis_access { dis_metadata_t metadata; datum_vmk_t* vmk; datum_aes_ccm_t* fvek; }; typedef struct _rb_dis_access* rb_dis_access_t; static inline VALUE save_ret_vmk(rb_dis_access_t dis_accesses, void* vmk_datum) { extern VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; datum_header_safe_t header; if(get_header_safe(vmk_datum, &header) != TRUE) rb_raise(rb_eRuntimeError, "Cannot get VMK header safely"); dis_accesses->vmk = vmk_datum; VALUE datum = rb_str_new((char*) vmk_datum, (long) header.datum_size); /* Transform the VMK in a VALUE to be returned */ return rb_cDislockerMetadataDatum_new( dis_rb_classes[DIS_RB_CLASS_DATUM], datum ); } static VALUE rb_get_vmk_from_clearkey(VALUE self) { void* vmk_datum = NULL; rb_dis_access_t dis_accesses = DATA_PTR(self); /* Get the VMK */ if(!get_vmk_from_clearkey(dis_accesses->metadata, &vmk_datum)) rb_raise(rb_eRuntimeError, "Couldn't retrieve the VMK"); /* Save it */ return save_ret_vmk(dis_accesses, vmk_datum); } static VALUE rb_get_vmk_from_userpass(VALUE self, VALUE rb_userpass) { void* vmk_datum = NULL; uint8_t* userpass = NULL; rb_dis_access_t dis_accesses = DATA_PTR(self); Check_Type(rb_userpass, T_STRING); userpass = (uint8_t*) StringValuePtr(rb_userpass); /* Get the VMK */ if(!get_vmk_from_user_pass2(dis_accesses->metadata, &userpass, &vmk_datum)) rb_raise(rb_eRuntimeError, "Couldn't retrieve the VMK"); /* Save it */ return save_ret_vmk(dis_accesses, vmk_datum); } static VALUE rb_get_vmk_from_rp(VALUE self, VALUE rb_rp) { void* vmk_datum = NULL; uint8_t* rp = NULL; rb_dis_access_t dis_accesses = DATA_PTR(self); Check_Type(rb_rp, T_STRING); rp = (uint8_t*) StringValuePtr(rb_rp); /* Get the VMK */ if(!get_vmk_from_rp2(dis_accesses->metadata, rp, &vmk_datum)) rb_raise(rb_eRuntimeError, "Couldn't retrieve the VMK"); /* Save it */ return save_ret_vmk(dis_accesses, vmk_datum); } static VALUE rb_get_vmk_from_bekfile(VALUE self, VALUE rb_bekfile_path) { void* vmk_datum = NULL; char* bekfile_path = NULL; rb_dis_access_t dis_accesses = DATA_PTR(self); Check_Type(rb_bekfile_path, T_STRING); bekfile_path = StringValuePtr(rb_bekfile_path); /* Get the VMK */ if(!get_vmk_from_bekfile2(dis_accesses->metadata, bekfile_path, &vmk_datum)) rb_raise(rb_eRuntimeError, "Couldn't retrieve the VMK"); /* Save it */ return save_ret_vmk(dis_accesses, vmk_datum); } static VALUE rb_get_fvek(int argc, VALUE *argv, VALUE self) { datum_vmk_t* vmk_datum = NULL; void* fvek_datum = NULL; rb_dis_access_t dis_accesses = DATA_PTR(self); datum_header_safe_t header; extern VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; if(argc == 0) { if(dis_accesses->vmk == NULL) rb_raise(rb_eRuntimeError, "Didn't retrieve the VMK and none given"); vmk_datum = dis_accesses->vmk; } else { Data_Get_Struct( argv[0], datum_vmk_t, vmk_datum ); } /* Get the FVEK */ if(!get_fvek(dis_accesses->metadata, vmk_datum, &fvek_datum)) rb_raise(rb_eRuntimeError, "Could not retrieve the FVEK"); /* Save it */ dis_accesses->fvek = fvek_datum; if(get_header_safe(vmk_datum, &header) != TRUE) rb_raise(rb_eRuntimeError, "Cannot get VMK header safely"); /* Transform the FVEK in a VALUE to be returned */ return rb_cDislockerMetadataDatum_new( dis_rb_classes[DIS_RB_CLASS_DATUM], rb_str_new(fvek_datum, header.datum_size) ); } static void rb_cDislockerAccesses_free(rb_dis_access_t dis_accesses) { if(dis_accesses) dis_free(dis_accesses); } static VALUE rb_cDislockerAccesses_alloc(VALUE klass) { rb_dis_access_t dis_accesses = NULL; return Data_Wrap_Struct( klass, NULL, rb_cDislockerAccesses_free, dis_accesses ); } static VALUE rb_cDislockerAccesses_init(VALUE self, VALUE rb_dis_meta) { rb_dis_access_t dis_accesses = dis_malloc(sizeof(struct _rb_dis_access)); Data_Get_Struct( rb_dis_meta, struct _dis_metadata, dis_accesses->metadata ); dis_accesses->vmk = NULL; dis_accesses->fvek = NULL; DATA_PTR(self) = dis_accesses; return Qnil; } void Init_accesses(VALUE rb_mDislocker) { VALUE rb_cDislockerAccesses = rb_define_class_under( rb_mDislocker, "Accesses", rb_cObject ); extern VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; dis_rb_classes[DIS_RB_CLASS_ACCESSES] = rb_cDislockerAccesses; rb_define_alloc_func(rb_cDislockerAccesses, rb_cDislockerAccesses_alloc); rb_define_method( rb_cDislockerAccesses, "initialize", rb_cDislockerAccesses_init, 1 ); rb_define_method( rb_cDislockerAccesses, "vmk_from_clearkey", rb_get_vmk_from_clearkey, 0 ); rb_define_method( rb_cDislockerAccesses, "vmk_from_userpass", rb_get_vmk_from_userpass, 1 ); rb_define_method( rb_cDislockerAccesses, "vmk_from_recoverypassword", rb_get_vmk_from_rp, 1 ); rb_define_method( rb_cDislockerAccesses, "vmk_from_bekfile", rb_get_vmk_from_bekfile, 1 ); rb_define_method( rb_cDislockerAccesses, "fvek", rb_get_fvek, -1 ); } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/accesses/bek/000077500000000000000000000000001375503125700166315ustar00rootroot00000000000000dislocker-0.7.3/src/accesses/bek/Makefile000066400000000000000000000025121375503125700202710ustar00rootroot00000000000000PROGNAME = read_bekfile AUTHOR = \"Romain Coltel\" ARCH = $(shell uname -m) OS = $(shell uname -s) # DEBUG = 1 ifeq ($(OS), FreeBSD) MAKE = gmake else MAKE = make endif CC = cc DEFINES = -DPROGNAME=\"$(PROGNAME)\" INC = -I/usr/include -I../.. CHARDEN = -fstack-protector -fPIC -D_FORTIFY_SOURCE=2 -O1 LHARDEN = -pie -fPIE -Wl,-z,relro -Wl,-z,now WFLAGS = -Wall -Werror -Wextra CFLAGS = $(WFLAGS) $(DEFINES) $(INC) $(CHARDEN) SOURCES = main.c read_bekfile.c OBJECTS = $(SOURCES:.c=.o) override LDFLAGS += $(LIB) $(LHARDEN) BIN = $(PROGNAME) EXT_OBJ = ../../common.o ../../metadata/datums.o ../../metadata/print_metadata.o \ ../../metadata/extended_info.o ../../metadata/vmk.o \ ../../ntfs/guid.o ../../ntfs/clock.o ../../ntfs/encoding.o \ ../../xstd/xstdio.o ../../xstd/xstdlib.o # For MacOSX users ifeq ($(OS), Darwin) DEFINES += -D__DARWIN else # Useless warnings when used within Darwin WFLAGS += -Wconversion endif ifdef DEBUG DBGFLAGS = -ggdb -D DEBUG=$(DEBUG) CFLAGS += $(DBGFLAGS) endif export .PHONY : all $(BIN) library clean .c.o : $(CC) $(CFLAGS) -c -o $@ $< all : $(BIN) $(BIN) : $(OBJECTS) @$(MAKE) DEBUG=$(DEBUG) -C ../../ common $(CC) $(CFLAGS) -o $@ $^ $(EXT_OBJ) $(LDFLAGS) library : read_bekfile.o clean : @$(MAKE) -C ../../ clean rm -rf -- $(BIN) *.o *~ *.swp *.gcno *.gcda *.gcov dislocker-0.7.3/src/accesses/bek/bekfile.c000066400000000000000000000172111375503125700204000ustar00rootroot00000000000000/* -*- 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. */ /* * BitLocker Encryption Key (BEK) structure reader. * * Ref: * - http://jessekornblum.com/publications/di09.pdf */ #include #include #include #include #include #include #include #include #include #include #include "dislocker/common.h" #include "dislocker/metadata/metadata.priv.h" #include "dislocker/metadata/vmk.h" #include "dislocker/accesses/bek/bekfile.h" /** * Get the VMK datum using a bek file (external key) * * @param dataset The dataset of BitLocker's metadata on the volume * @param cfg The configuration structure * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_bekfile(dis_metadata_t dis_meta, dis_config_t* cfg, void** vmk_datum) { return get_vmk_from_bekfile2(dis_meta, cfg->bek_file, vmk_datum); } /** * Get the VMK datum using a bek file (external key) * * @param dataset The dataset of BitLocker's metadata on the volume * @param bek_file The path to the .BEK file to use * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_bekfile2(dis_metadata_t dis_meta, char* bek_file, void** vmk_datum) { // Check parameters if(!dis_meta || !vmk_datum) return FALSE; guid_t key_guid = {0,}; char rec_id[37] = {0,}; bitlocker_dataset_t* bek_dataset = NULL; uint8_t* recovery_key = NULL; size_t rk_size = 0; int result = FALSE; int fd_bek = 0; if(bek_file) { /* Check if the bek file exists */ fd_bek = dis_open(bek_file, O_RDONLY); if(fd_bek < 0) { dis_printf(L_ERROR, "Cannot open FVEK file (%s)\n", bek_file); return FALSE; } } else { dis_printf( L_ERROR, "Using bekfile method (USB) but missing the bekfile name. Abort.\n" ); return FALSE; } dis_printf( L_INFO, "Using the bekfile '%s' to decrypt the VMK.\n", bek_file ); /* * We need the recovery key id which can be found in the bek file * to find its match in a datum of the volume's metadata */ if(!get_bek_dataset(fd_bek, (void**) &bek_dataset)) { dis_printf(L_ERROR, "Unable to retrieve the dataset. Abort.\n"); dis_close(fd_bek); return FALSE; } /* We have what we wanted, so close the file */ dis_close(fd_bek); /* Get the external datum */ void* dataset = dis_metadata_set_dataset(dis_meta, bek_dataset); get_next_datum( dis_meta, UINT16_MAX, DATUMS_VALUE_EXTERNAL_KEY, NULL, vmk_datum ); dis_metadata_set_dataset(dis_meta, dataset); /* Check the result datum */ if(!*vmk_datum || !datum_value_type_must_be(*vmk_datum, DATUMS_VALUE_EXTERNAL_KEY)) { dis_printf( L_ERROR, "Error processing the bekfile: datum of type %hd not found. " "Internal failure, abort.\n", DATUMS_VALUE_EXTERNAL_KEY ); *vmk_datum = NULL; memclean(bek_dataset, bek_dataset->size); return FALSE; } /* Now that we are sure of the type, take care of copying the recovery key id */ datum_external_t* datum_exte = (datum_external_t*) *vmk_datum; memcpy(key_guid, datum_exte->guid, 16); format_guid(key_guid, rec_id); dis_printf( L_INFO, "Bekfile GUID found: '%s', looking for the same in metadata...\n", rec_id ); /* Grab the datum nested in the last, we will need it to decrypt the VMK */ if(!get_nested_datumvaluetype(*vmk_datum, DATUMS_VALUE_KEY, vmk_datum) || !*vmk_datum) { dis_printf( L_ERROR, "Error processing the bekfile: no nested datum found. " "Internal failure, abort.\n" ); *vmk_datum = NULL; memclean(bek_dataset, bek_dataset->size); return FALSE; } if(!get_payload_safe(*vmk_datum, (void**) &recovery_key, &rk_size)) { dis_printf( L_ERROR, "Error getting the key to decrypt VMK from the bekfile. " "Internal failure, abort.\n" ); *vmk_datum = NULL; memclean(bek_dataset, bek_dataset->size); return FALSE; } memclean(bek_dataset, bek_dataset->size); /* * Now that we have the key to decrypt the VMK, we need to * find the VMK datum in the BitLocker metadata in order to * decrypt the VMK using this already found key in the bekfile */ if(!get_vmk_datum_from_guid(dis_meta, key_guid, vmk_datum)) { format_guid(key_guid, rec_id); dis_printf( L_ERROR, "\n\tError, can't find a valid and matching VMK datum.\n" "\tThe GUID researched was '%s', check if you have the right " "bek file for the right volume.\n" "\tAbort.\n", rec_id ); *vmk_datum = NULL; dis_free(recovery_key); return FALSE; } dis_printf( L_INFO, "VMK datum of id '%s' found. Trying to reach the Key datum...\n", rec_id ); /* * We have the datum containing other data, so get in there and take the * nested one with type 5 (aes-ccm) */ if(!get_nested_datumvaluetype(*vmk_datum, DATUMS_VALUE_AES_CCM, vmk_datum)) { dis_printf( L_ERROR, "Error looking for the nested datum in the VMK one. " "Internal failure, abort.\n" ); *vmk_datum = NULL; dis_free(recovery_key); return FALSE; } dis_printf(L_INFO, "Key datum found and payload extracted!\n"); result = get_vmk( (datum_aes_ccm_t*) *vmk_datum, recovery_key, rk_size, (datum_key_t**) vmk_datum ); dis_free(recovery_key); return result; } /** * Get the dataset present in a .BEK file * * @param fd The file descriptor to the .BEK file * @param bek_dataset The extracted dataset * @return TRUE if result can be trusted, FALSE otherwise */ int get_bek_dataset(int fd, void** bek_dataset) { if(!bek_dataset) { dis_printf(L_ERROR, "Invalid parameter given to get_bek_dataset().\n"); return FALSE; } bitlocker_dataset_t dataset; /* Read the dataset header */ ssize_t nb_read = dis_read(fd, &dataset, sizeof(bitlocker_dataset_t)); // Check if we read all we wanted if(nb_read != sizeof(bitlocker_dataset_t)) { dis_printf( L_ERROR, "get_bek_dataset::Error, not all byte read (bek dataset header).\n" ); return FALSE; } if(dataset.size <= sizeof(bitlocker_dataset_t)) { dis_printf( L_ERROR, "get_bek_dataset::Error, dataset size < dataset header size.\n" ); return FALSE; } *bek_dataset = dis_malloc(dataset.size); memset(*bek_dataset, 0, dataset.size); memcpy(*bek_dataset, &dataset, sizeof(bitlocker_dataset_t)); size_t rest = dataset.size - sizeof(bitlocker_dataset_t); /* Read the data included in the dataset */ nb_read = dis_read(fd, *bek_dataset + sizeof(bitlocker_dataset_t), rest); // Check if we read all we wanted if((size_t) nb_read != rest) { dis_printf( L_ERROR, "get_bek_dataset::Error, not all byte read (bek dataset content).\n" ); dis_free(*bek_dataset); return FALSE; } return TRUE; } dislocker-0.7.3/src/accesses/rp/000077500000000000000000000000001375503125700165115ustar00rootroot00000000000000dislocker-0.7.3/src/accesses/rp/main.c000066400000000000000000000046461375503125700176130ustar00rootroot00000000000000/* -*- 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 #include "common.h" #include "recovery_password.h" void usage(char **argv) { fprintf(stderr, "Usage: %s [-h] [-p RECOVERY_PASSWORD]\n" "\n" " -h print this help and exit\n" " -p RECOVERY_PASSWORD the recovery password to compute\n", argv[0]); } int main(int argc, char **argv) { // Check the parameters if(argc < 2) { usage(argv); return 1; } int optchar = 0; uint8_t *recovery_password = NULL; uint8_t *recovery_key = NULL; uint8_t salt[16] = { (uint8_t)'\x3b', (uint8_t)'\x36', (uint8_t)'\xd9', (uint8_t)'\x30', (uint8_t)'\x72', (uint8_t)'\xa2', (uint8_t)'\x2e', (uint8_t)'\x03', (uint8_t)'\xf2', (uint8_t)'\xed', (uint8_t)'\xfe', (uint8_t)'\x6f', (uint8_t)'\xcd', (uint8_t)'\x14', (uint8_t)'\xb4', (uint8_t)'\x58' }; while((optchar = getopt(argc, argv, "p:h")) != -1) { switch(optchar) { case 'h': usage(argv); return 0; case 'p': recovery_password = (uint8_t *) strdup(optarg); break; case '?': default: fprintf(stderr, "Unknown option encountered.\n"); usage(argv); exit(1); } } xstdio_init(L_DEBUG, NULL); dis_printf(L_INFO, "Recovery Password: %s\n", (char *)recovery_password); recovery_key = xmalloc(32 * sizeof(uint8_t)); if(!intermediate_key(recovery_password, salt, recovery_key)) { dis_free(recovery_key); return 1; } print_intermediate_key(recovery_key); dis_free(recovery_key); if(recovery_password) dis_free(recovery_password); xstdio_end(); return 0; } dislocker-0.7.3/src/accesses/rp/recovery_password.c000066400000000000000000000325221375503125700224410ustar00rootroot00000000000000/* -*- 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 #include "dislocker/accesses/rp/recovery_password.h" #include "dislocker/metadata/vmk.h" #include "dislocker/xstd/xsys_select.h" // Specifications of the recovery password #define NB_RP_BLOCS 8 #define NB_DIGIT_BLOC 6 #define INTERMEDIATE_KEY_LENGTH 32 /** * Get the VMK datum using a recovery password * * @param dis_metadata The metadata structure * @param cfg The configuration structure * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_rp(dis_metadata_t dis_meta, dis_config_t* cfg, void** vmk_datum) { return get_vmk_from_rp2(dis_meta, cfg->recovery_password, vmk_datum); } /** * Get the VMK datum using a recovery password * * @param dis_metadata The metadata structure * @param recovery_password The recovery password provided by the user * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_rp2(dis_metadata_t dis_meta, uint8_t* recovery_password, void** vmk_datum) { // Check parameters if(!dis_meta) return FALSE; uint8_t* recovery_key = NULL; uint8_t salt[16] = {0,}; int result = FALSE; /* If the recovery password wasn't provide, ask for it */ if(!recovery_password) if(!prompt_rp(&recovery_password)) { dis_printf(L_ERROR, "Cannot get valid recovery password. Abort.\n"); return FALSE; } dis_printf(L_DEBUG, "Using the recovery password: '%s'.\n", (char *)recovery_password); /* * We need a salt contained in the VMK datum associated to the recovery * password, so go get this salt and the VMK datum first * We use here the range which should be upper (or equal) than 0x800 */ if(!get_vmk_datum_from_range(dis_meta, 0x800, 0xfff, (void**) vmk_datum)) { dis_printf( L_ERROR, "Error, can't find a valid and matching VMK datum. Abort.\n" ); *vmk_datum = NULL; return FALSE; } /* * We have the datum containing other data, so get in there and take the * nested one with type 3 (stretch key) */ void* stretch_datum = NULL; if(!get_nested_datumvaluetype( *vmk_datum, DATUMS_VALUE_STRETCH_KEY, &stretch_datum ) || !stretch_datum) { char* type_str = datumvaluetypestr(DATUMS_VALUE_STRETCH_KEY); dis_printf( L_ERROR, "Error looking for the nested datum of type %hd (%s) in the VMK one" ". Internal failure, abort.\n", DATUMS_VALUE_STRETCH_KEY, type_str ); dis_free(type_str); *vmk_datum = NULL; return FALSE; } /* The salt is in here, don't forget to keep it somewhere! */ memcpy(salt, ((datum_stretch_key_t*) stretch_datum)->salt, 16); /* Get data which can be decrypted with this password */ void* aesccm_datum = NULL; if(!get_nested_datumvaluetype( *vmk_datum, DATUMS_VALUE_AES_CCM, &aesccm_datum ) || !aesccm_datum) { dis_printf( L_ERROR, "Error finding the AES_CCM datum including the VMK. " "Internal failure, abort.\n" ); *vmk_datum = NULL; return FALSE; } /* * We have all the things we need to compute the intermediate key from * the recovery password, so do it! */ recovery_key = dis_malloc(32 * sizeof(uint8_t)); if(!intermediate_key(recovery_password, salt, recovery_key)) { dis_printf( L_ERROR, "Error computing the recovery password to the recovery key. " "Abort.\n" ); *vmk_datum = NULL; dis_free(recovery_key); return FALSE; } /* As the computed key length is always the same, use a direct value */ result = get_vmk( (datum_aes_ccm_t*) aesccm_datum, recovery_key, 32, (datum_key_t**) vmk_datum ); dis_free(recovery_key); return result; } /** * Validating one block of the recovery password * * @param digits The entire block to validate * @param block_nb The block number * @param short_password The block divided by 11 and converted into uint16_t * @return TRUE if valid, FALSE otherwise */ int valid_block(uint8_t* digits, int block_nb, uint16_t* short_password) { // Check the parameters if(!digits) return FALSE; /* Convert chars into int */ errno = 0; long int block = strtol((char *) digits, (char **) NULL, 10); if(errno == ERANGE) { dis_printf( L_ERROR, "Error converting '%s' into a number: errno=ERANGE", digits ); return FALSE; } /* 1st check -- Checking if the bloc is divisible by eleven */ if((block % 11) != 0) { dis_printf( L_ERROR, "Error handling the recovery password: Bloc n°%d (%d) invalid. " "It has to be divisible by 11.\n", block_nb, block ); return FALSE; } /* 2nd check -- Checking if the bloc is less than 2**16 * 11 */ if(block >= 720896) { dis_printf( L_ERROR, "Error handling the recovery password: Bloc n°%d (%d) invalid. " "It has to be less than 2**16 * 11 (720896).\n", block_nb, block ); return FALSE; } /* 3rd check -- Checking if the checksum is correct */ int8_t check_digit = (int8_t)(digits[0] - digits[1] + digits[2] - digits[3] + digits[4] - 48) % 11; /* Convert chars into digits */ /* Some kind of bug the c modulo has: -2 % 11 yields -2 instead of 9 */ while(check_digit < 0) check_digit = (int8_t)(check_digit + 11); if(check_digit != (digits[5] - 48)) { dis_printf( L_ERROR, "Error handling the recovery password: Bloc n°%d (%d) has " "invalid checksum.\n", block_nb, block ); return FALSE; } /* * The bloc has a good look, store a short version of it * We already have checked the size (see 2nd check), a uint16_t can contain * the result */ if(short_password) *short_password = (uint16_t) (block / 11); return TRUE; } /** * Validating (or not) the recovery password. * If the password is valid, short_password contains the blocs divided by 11 in * uint16_t slot. * * @param recovery_password The recovery password the user typed (48+7 bytes) * @param short_password The recovery password converted in uint16_t (8 uint16_t) * @return TRUE if valid, FALSE otherwise */ int is_valid_key(const uint8_t *recovery_password, uint16_t *short_password) { // Check the parameters if(recovery_password == NULL) return FALSE; if(short_password == NULL) return FALSE; /* Begin by checking the length of the password */ if(strlen((char*)recovery_password) != 48+7) { dis_printf( L_ERROR, "Error handling the recovery password: " "Wrong length (has to be %d)\n", 48+7); return FALSE; } const uint8_t *rp = recovery_password; uint16_t *sp = short_password; uint8_t digits[NB_DIGIT_BLOC + 1]; int loop = 0; for(loop = 0; loop < NB_RP_BLOCS; ++loop) { memcpy(digits, rp, NB_DIGIT_BLOC); digits[NB_DIGIT_BLOC] = 0; /* Check block validity */ if(!valid_block(digits, loop+1, sp)) return FALSE; sp++; rp += 7; } // All of the recovery password seems to be good return TRUE; } // End is_valid_key /** * Calculate the intermediate key from a raw recovery password. * * @param recovery_password The raw recovery password given by the user (48+7 bytes) * @param result_key The intermediate key used to decrypt the associated VMK (32 bytes) * @return TRUE if result_key can be trusted, FALSE otherwise */ int intermediate_key(const uint8_t *recovery_password, const uint8_t *salt, uint8_t *result_key) { // Check the parameters if(recovery_password == NULL) { dis_printf( L_ERROR, "Error: No recovery password given, aborting calculation " "of the intermediate key.\n" ); return FALSE; } if(result_key == NULL) { dis_printf( L_ERROR, "Error: No space to store the intermediate recovery key, " "aborting operation.\n" ); return FALSE; } uint16_t passwd[NB_RP_BLOCS]; uint8_t *iresult = dis_malloc(INTERMEDIATE_KEY_LENGTH * sizeof(uint8_t)); uint8_t *iresult_save = iresult; int loop = 0; memset(passwd, 0, NB_RP_BLOCS * sizeof(uint16_t)); memset(iresult, 0, INTERMEDIATE_KEY_LENGTH * sizeof(uint8_t)); /* Check if the recovery_password has a good smile */ if(!is_valid_key(recovery_password, passwd)) { memclean(iresult, INTERMEDIATE_KEY_LENGTH * sizeof(uint8_t)); return FALSE; } // passwd now contains the blocs divided by 11 in a uint16_t tab // Convert each one of the blocs in little endian and make it one buffer for(loop = 0; loop < NB_RP_BLOCS; ++loop) { *iresult = (uint8_t)(passwd[loop] & 0x00ff); iresult++; *iresult = (uint8_t)((passwd[loop] & 0xff00) >> 8); iresult++; } iresult = iresult_save; /* Just print it */ char s[NB_RP_BLOCS*2 * 5 + 1] = {0,}; for (loop = 0; loop < NB_RP_BLOCS*2; ++loop) snprintf(&s[loop*5], 6, "0x%02hhx ", iresult[loop]); dis_printf(L_DEBUG, "Distilled password: '%s\b'\n", s); stretch_recovery_key(iresult, salt, result_key); memclean(iresult, INTERMEDIATE_KEY_LENGTH * sizeof(uint8_t)); /* We successfuly retrieve the key! */ return TRUE; } // End intermediate_key /** * Prompt for the recovery password to be entered * * @param rp The place where to put the entered recovery password * @return TRUE if rp can be trusted, FALSE otherwise */ int prompt_rp(uint8_t** rp) { // Check the parameter if(!rp) return FALSE; int in = get_input_fd(); char* prompt = "\rEnter the recovery password: "; int idx = 0; uint8_t c = 0; int block_nb = 1; uint8_t digits[NB_DIGIT_BLOC + 1] = {0,}; uint8_t* blah = NULL; fd_set rfds; int nfds = in + 1; if(in < 0) { fprintf(stderr, "Cannot open tty.\n"); return FALSE; } if(FD_SETSIZE < 0) { fprintf(stderr, "Cannot add fd in the set.\n"); return FALSE; } if((unsigned) in >= (unsigned) FD_SETSIZE) { fprintf(stderr, "Terminal file descriptor (%u) is equal to or larger than " "FD_SETSIZE (%u).\n", (unsigned) in, (unsigned) FD_SETSIZE); close_input_fd(); return FALSE; } /* 8 = 7 hyphens separating the blocks + 1 '\0' at the end of the string */ *rp = malloc(NB_RP_BLOCS * NB_DIGIT_BLOC + 8); memset(*rp, 0, NB_RP_BLOCS * NB_DIGIT_BLOC + 8); blah = *rp; printf("%s", prompt); fflush(NULL); FD_ZERO(&rfds); /** @see xstd/xsys_select.h for an explanation of this macro */ DIS_FD_SET(in, &rfds); while(1) { /* Wait for inputs */ int selret = select(nfds+1, &rfds, NULL, NULL, NULL); /* Look for errors */ if(selret == -1) { fprintf(stderr, "Error %d in select: %s\n", errno, strerror(errno)); break; } if(read(in, &c, 1) <= 0) { fprintf( stderr, "Something is available for reading but unable to " "read (%d): %s\n", errno, strerror(errno) ); break; } /* If this is an hyphen, just ignore it */ if(c == '-') continue; /* Place the character at the right place or erase the last character */ if(idx <= NB_DIGIT_BLOC) { /* If backspace was hit */ if(c == '\b' || c == '\x7f') { idx--; if(idx < 0 && block_nb > 1) { blah -= (NB_DIGIT_BLOC + 1); snprintf((char*)digits, NB_DIGIT_BLOC, "%s", blah); *blah = '\0'; idx = NB_DIGIT_BLOC - 1; block_nb--; } if(idx < 0) idx = 0; /* Yeah, I agree, this is kinda dirty */ digits[idx] = ' '; printf("%s%s%s", prompt, *rp, digits); digits[idx] = '\0'; idx--; } else if(c >= '0' && c <= '9') digits[idx] = (uint8_t)c; else continue; } printf("%s%s%s", prompt, *rp, digits); fflush(NULL); idx++; /* Now if we're at the end of a block, (in)validate it */ if(idx >= NB_DIGIT_BLOC) { if(valid_block(digits, block_nb, NULL)) { snprintf((char*)blah, NB_DIGIT_BLOC+1, "%s", digits); blah += NB_DIGIT_BLOC; if(block_nb >= NB_RP_BLOCS) { /* Hide the recovery password for sneaky eyes */ printf( "%1$s%2$s-%2$s-%2$s-%2$s-%2$s-%2$s-%2$s-%2$s\n", prompt, "XXXXXX" ); printf("Valid password format, continuing.\n"); close_input_fd(); return TRUE; } else { putchar('-'); *blah = '-'; blah++; } block_nb++; } else { fprintf(stderr, "\nInvalid block.\n"); printf("%s%s", prompt, *rp); } fflush(NULL); idx = 0; memset(digits, 0, NB_DIGIT_BLOC); } } close_input_fd(); return FALSE; } /** * Print the result key which can be used to decrypt the associated VMK * * @param result_key The key after passed to intermediate_key */ void print_intermediate_key(uint8_t *result_key) { if(result_key == NULL) return; int loop = 0; char s[32*3 + 1] = {0,}; for(loop = 0; loop < 32; ++loop) snprintf(&s[loop*3], 4, "%02hhx ", result_key[loop]); dis_printf(L_INFO, "Intermediate recovery key:\n\t%s\n", s); } dislocker-0.7.3/src/accesses/stretch_key.c000066400000000000000000000107071375503125700205650ustar00rootroot00000000000000/* -*- 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 "dislocker/accesses/stretch_key.h" #define SHA256_DIGEST_LENGTH 32 #define SALT_LENGTH 16 // Needed structure to 'stretch' a password typedef struct { uint8_t updated_hash[SHA256_DIGEST_LENGTH]; uint8_t password_hash[SHA256_DIGEST_LENGTH]; uint8_t salt[SALT_LENGTH]; uint64_t hash_count; } bitlocker_chain_hash_t; /* This prototype is for internal use only */ static int stretch_key(bitlocker_chain_hash_t* ch, uint8_t *result); /** * Function implementing the algorithm of the chain hash, described by Jesse D. * Kornblum. * Ref: http://jessekornblum.com/presentations/di09.pdf * @see stretch_key() * * @param recovery_key The 16-bytes recovery key previously distilled (16 bytes) * @param salt The salt used for crypto (16 bytes) * @param result Will contain the resulting hash key (32 bytes) * @return TRUE if result can be trusted, FALSE otherwise */ int stretch_recovery_key(const uint8_t *recovery_key, const uint8_t *salt, uint8_t *result) { if(!recovery_key || !salt || !result) { dis_printf(L_ERROR, "Invalid parameter given to stretch_recovery_key().\n"); return FALSE; } size_t size = sizeof(bitlocker_chain_hash_t); bitlocker_chain_hash_t * ch = NULL; ch = (bitlocker_chain_hash_t *) dis_malloc(size); memset(ch, 0, size); /* 16 is the size of the recovery_key, in bytes (see doc above) */ SHA256(recovery_key, 16, ch->password_hash); memcpy(ch->salt, salt, SALT_LENGTH); dis_printf(L_INFO, "Stretching the recovery password, it could take some time...\n"); if(!stretch_key(ch, result)) return FALSE; dis_printf(L_INFO, "Stretching of the recovery password is now ok!\n"); /* Wipe out with zeros and free it */ memclean(ch, size); return TRUE; } /** * Function implementing the stretching of a hashed user password. * @see stretch_key() * * @param user_hash The 32-bytes hash from SHA256(SHA256(UTF16(user_password))) * @param salt The salt used for crypto (16 bytes) * @param result Will contain the resulting hash key (32 bytes) * @return TRUE if result can be trusted, FALSE otherwise */ int stretch_user_key(const uint8_t *user_hash, const uint8_t *salt, uint8_t *result) { if(!user_hash || !salt || !result) { dis_printf(L_ERROR, "Invalid parameter given to stretch_user_key().\n"); return FALSE; } size_t size = sizeof(bitlocker_chain_hash_t); bitlocker_chain_hash_t ch; memset(&ch, 0, size); memcpy(ch.password_hash, user_hash, SHA256_DIGEST_LENGTH); memcpy(ch.salt, salt, SALT_LENGTH); dis_printf(L_INFO, "Stretching the user password, it could take some time...\n"); if(!stretch_key(&ch, result)) return FALSE; dis_printf(L_INFO, "Stretching of the user password is now ok!\n"); /* Wipe out with zeros */ memset(&ch, 0, size); return TRUE; } /** * Core function implementing the chain hash algorithm. * @see stretch_recovery_key() * * @param ch A pointer to a bitlocker_chain_hash_t structure * @param result Will contain the resulting hash key (32 bytes) * @return TRUE if result can be trusted, FALSE otherwise */ static int stretch_key(bitlocker_chain_hash_t* ch, uint8_t *result) { if(!ch || !result) { dis_printf(L_ERROR, "Invalid parameter given to stretch_key().\n"); return FALSE; } size_t size = sizeof(bitlocker_chain_hash_t); uint64_t loop = 0; for(loop = 0; loop < 0x100000; ++loop) { SHA256((unsigned char *)ch, size, ch->updated_hash); ch->hash_count++; } memcpy(result, ch->updated_hash, SHA256_DIGEST_LENGTH); return TRUE; } dislocker-0.7.3/src/accesses/user_pass/000077500000000000000000000000001375503125700200745ustar00rootroot00000000000000dislocker-0.7.3/src/accesses/user_pass/Makefile000066400000000000000000000030271375503125700215360ustar00rootroot00000000000000PROGNAME = user_pass AUTHOR = \"Romain Coltel\" ARCH = $(shell uname -m) OS = $(shell uname -s) # DEBUG = 1 ifeq ($(OS), FreeBSD) MAKE = gmake else MAKE = make endif CC = cc DEFINES = -DPROGNAME=\"$(PROGNAME)\" -D_FILE_OFFSET_BITS=64 INC = -I/usr/include -I../../ CHARDEN = -fstack-protector -fPIC -D_FORTIFY_SOURCE=2 -O1 LHARDEN = -pie -fPIE -Wl,-z,relro -Wl,-z,now WFLAGS = -Wall -Werror -Wextra CFLAGS = $(WFLAGS) $(DEFINES) $(INC) $(CHARDEN) override LDFLAGS += $(LIB) $(LHARDEN) -lpolarssl MAIN_OBJECT = SOURCES = user_pass.c ../stretch_key.c OBJECTS = $(SOURCES:.c=.o) ../stretch_key.o \ ../../xstd/xstdio.o ../../xstd/xstdlib.o \ ../../ntfs/encoding.o BIN = $(PROGNAME) # For MacOSX users ifeq ($(OS), Darwin) DEFINES += -D__DARWIN else # Useless warnings when used within Darwin WFLAGS += -Wconversion endif ifdef DEBUG DBGFLAGS = -ggdb -D DEBUG=$(DEBUG) CFLAGS += $(DBGFLAGS) endif export .PHONY : all library $(BIN) clean .c.o : $(CC) $(CFLAGS) -c -o $@ $< all : MAIN_OBJECT = main.o all : main.o all : $(BIN) check : clean check : MAIN_OBJECT = check_user_pass.o check : check_user_pass.o check : DEFINES += -D__CK_DOING_TESTS check : CFLAGS += -fprofile-arcs -ftest-coverage check : LDFLAGS += -lcheck check : do_check do_check : $(BIN) ./$(BIN) gcov $(BIN).c $(BIN) : $(OBJECTS) @$(MAKE) DEBUG=$(DEBUG) -C ../../ common $(CC) $(CFLAGS) -o $@ $(MAIN_OBJECT) $^ ../../common.o $(LDFLAGS) library : user_pass.o clean : @$(MAKE) -C ../../ clean rm -rf -- $(BIN) *.o *~ *.swp *.gcno *.gcda *.gcov dislocker-0.7.3/src/accesses/user_pass/check_user_pass.c000066400000000000000000000100101375503125700233710ustar00rootroot00000000000000#include #include #include #include #include #include "user_pass.h" static char* ck_password = "TestPassword123!"; /* * Core tests */ // int prompt_up(uint8_t** up); START_TEST (check_prompt_up) { int old_stdin = -1; int old_stdout = -1; int new_stdin[2] = {-1, -1}; int new_stdout[2] = {-1, -1}; uint8_t *up = NULL; int ret = FALSE; /* Prepare file descriptors for testing */ if(pipe(new_stdin) == -1) ck_abort_msg("pipe(2) failed [1]: ", strerror(errno)); if(pipe(new_stdout) == -1) ck_abort_msg("pipe(2) failed [2]: ", strerror(errno)); old_stdin = dup(STDIN_FILENO); old_stdout = dup(STDOUT_FILENO); close(STDIN_FILENO); close(STDOUT_FILENO); dup2(new_stdin[0], STDIN_FILENO); dup2(new_stdout[1], STDOUT_FILENO); /* Write the password as if it comes from a user input */ if(fork() == 0) { size_t ck_password_len = strlen(ck_password); ssize_t wret = 0; ret = 0; wret = write(new_stdin[1], ck_password, ck_password_len); if(wret != (ssize_t)ck_password_len) ret = errno; wret = write(new_stdin[1], "\n", 1); if(wret != 1) ret = errno; _exit(ret); } /* Tested unit */ ret = prompt_up(&up); /* Check unit outputs */ ck_assert_int_eq(ret, TRUE); ck_assert_str_eq(up, ck_password); /* Putting every file descriptors back to normal */ close(STDIN_FILENO); close(STDOUT_FILENO); close(new_stdin[0]); close(new_stdin[1]); close(new_stdout[0]); close(new_stdout[1]); dup2(old_stdin, STDIN_FILENO); dup2(old_stdout, STDOUT_FILENO); close(old_stdin); close(old_stdout); /* Check for child's status */ if(wait(&ret) == -1) ck_abort_msg("Waiting for child failed: %s", strerror(errno)); if(ret != 0) ck_abort_msg("Child failed: %s", strerror(ret)); } END_TEST // int user_key(const uint8_t *user_password, const uint8_t *salt, uint8_t *result_key); START_TEST (check_user_key) { uint8_t *user_password = NULL; uint8_t salt[16] = {0,}; uint8_t *result_key = NULL; char good_key[] = { '\x39', '\xf5', '\x3f', '\xaf', '\x64', '\x09', '\x97', '\x2b', '\xb1', '\x2b', '\x8e', '\xb2', '\x44', '\xcb', '\x04', '\x40', '\x63', '\x57', '\x5c', '\xe5', '\xca', '\x3f', '\xce', '\x7f', '\xac', '\xc6', '\x8c', '\x66', '\x96', '\x2d', '\x94', '\xb6' }; int ret = FALSE; user_password = (uint8_t*) ck_password; /* From function's documentation, size should be 32 */ result_key = dis_malloc(32 * sizeof(char)); memset(result_key, 0, 32 * sizeof(char)); /* Tested unit */ ret = user_key(user_password, salt, result_key); /* Check unit outputs */ ck_assert_int_eq(ret, TRUE); if(memcmp(result_key, good_key, 32) != 0) { dis_free(result_key); ck_abort_msg("Found result key doesn't match what it should"); } dis_free(result_key); } END_TEST /* * Limit tests */ START_TEST (check_user_key_nullargs) { uint8_t *uint8_notnull = malloc(4); ck_assert_int_eq(user_key(NULL, uint8_notnull, uint8_notnull), FALSE); ck_assert_int_eq(user_key(uint8_notnull, NULL, uint8_notnull), FALSE); ck_assert_int_eq(user_key(uint8_notnull, uint8_notnull, NULL), FALSE); free(uint8_notnull); } END_TEST START_TEST (check_prompt_up_nullargs) { ck_assert_int_eq(prompt_up(NULL), FALSE); } END_TEST /* * Testing suite */ Suite* user_pass_suite(void) { Suite *s = suite_create("User pass"); /* Core test case */ TCase *tc_core = tcase_create("Core"); tcase_add_test(tc_core, check_user_key); tcase_add_test(tc_core, check_prompt_up); suite_add_tcase(s, tc_core); /* Limits tests case */ TCase *tc_limits = tcase_create("Limits"); tcase_add_test(tc_limits, check_user_key_nullargs); tcase_add_test(tc_limits, check_prompt_up_nullargs); /* TODO add more limits for more code coverage */ suite_add_tcase(s, tc_limits); return s; } int main(void) { int number_failed; xstdio_init(L_ERROR, NULL); Suite *s = user_pass_suite(); SRunner *sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free (sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } dislocker-0.7.3/src/accesses/user_pass/main.c000066400000000000000000000044171375503125700211720ustar00rootroot00000000000000/* -*- 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 #include "common.h" #include "user_pass.h" #include "accesses/stretch_key.h" void usage(char **argv) { fprintf(stderr, "Usage: %s [-h] [-u USER_PASSWORD]\n" "\n" " -h print this help and exit\n" " -u USER_PASSWORD a user password to check on the volume\n", argv[0]); } int main(int argc, char **argv) { // Check the parameters if(argc < 2) { usage(argv); return 1; } int optchar = 0; uint8_t *user_password = NULL; uint8_t user_hash[32] = {0,}; uint8_t salt[16] = {0,}; // TODO while((optchar = getopt(argc, argv, "u:h")) != -1) { switch(optchar) { case 'h': usage(argv); return 0; case 'u': user_password = (uint8_t *) strdup(optarg); break; case '?': default: fprintf(stderr, "Unknown option encountered.\n"); usage(argv); exit(1); } } xstdio_init(L_DEBUG, NULL); if(user_password == NULL) { dis_printf(L_CRITICAL, "No user password given, aborting.\n"); goto error; } dis_printf(L_INFO, "User Password: %s\n", (char *)user_password); if(!user_key(user_password, salt, user_hash)) { dis_printf(L_CRITICAL, "Can't stretch the user password, aborting.\n"); goto error; } dis_printf(L_INFO, "User hash:\n"); hexdump(L_INFO, user_hash, 32); error: if(user_password) free(user_password); xstdio_end(); return 0; } dislocker-0.7.3/src/accesses/user_pass/user_pass.c000066400000000000000000000215631375503125700222530ustar00rootroot00000000000000/* -*- 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. */ #if defined(__FREEBSD) # define _WITH_GETLINE #endif /* __FREEBSD */ #include "dislocker/accesses/user_pass/user_pass.h" #include "dislocker/metadata/vmk.h" #include #include #include /** * Get the VMK datum using a user password * * @param dataset The dataset of BitLocker's metadata on the volume * @param cfg The configuration structure * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_user_pass(dis_metadata_t dis_meta, dis_config_t* cfg, void** vmk_datum) { return get_vmk_from_user_pass2(dis_meta, &cfg->user_password, vmk_datum); } /** * Get the VMK datum using a user password * * @param dataset The dataset of BitLocker's metadata on the volume * @param user_password The user password provided * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_user_pass2(dis_metadata_t dis_meta, uint8_t** user_password, void** vmk_datum) { // Check parameters if(!dis_meta || !user_password) return FALSE; uint8_t user_hash[32] = {0,}; uint8_t salt[16] = {0,}; /* If the user password wasn't provide, ask for it */ if(!*user_password) if(!prompt_up(user_password)) { dis_printf(L_ERROR, "Cannot get valid user password. Abort.\n"); return FALSE; } dis_printf( L_DEBUG, "Using the user password: '%s'.\n", (char *) *user_password ); /* * We need a salt contained in the VMK datum associated to the recovery * password, so go get this salt and the VMK datum first * We use here the range which should be equal to 0x2000 * There may be another mean to find the correct datum, but I don't see * another one here */ if(!get_vmk_datum_from_range(dis_meta, 0x2000, 0x2000, (void**) vmk_datum)) { dis_printf( L_ERROR, "Error, can't find a valid and matching VMK datum. Abort.\n" ); *vmk_datum = NULL; memclean((char*) *user_password, strlen((char*) *user_password)); *user_password = NULL; return FALSE; } /* * We have the datum containing other data, so get in there and take the * nested one with type 3 (stretch key) */ void* stretch_datum = NULL; if(!get_nested_datumvaluetype( *vmk_datum, DATUMS_VALUE_STRETCH_KEY, &stretch_datum ) || !stretch_datum) { char* type_str = datumvaluetypestr(DATUMS_VALUE_STRETCH_KEY); dis_printf( L_ERROR, "Error looking for the nested datum of type %hd (%s) in the VMK one" ". Internal failure, abort.\n", DATUMS_VALUE_STRETCH_KEY, type_str ); dis_free(type_str); *vmk_datum = NULL; memclean( (char*) *user_password, strlen((char*) *user_password)); *user_password = NULL; return FALSE; } /* The salt is in here, don't forget to keep it somewhere! */ memcpy(salt, ((datum_stretch_key_t*) stretch_datum)->salt, 16); /* Get data which can be decrypted with this password */ void* aesccm_datum = NULL; if(!get_nested_datumvaluetype( *vmk_datum, DATUMS_VALUE_AES_CCM, &aesccm_datum ) || !aesccm_datum) { dis_printf( L_ERROR, "Error finding the AES_CCM datum including the VMK. " "Internal failure, abort.\n" ); *vmk_datum = NULL; memclean((char*) *user_password, strlen((char*) *user_password)); *user_password = NULL; return FALSE; } /* * We have all the things we need to compute the intermediate key from * the user password, so do it! */ if(!user_key(*user_password, salt, user_hash)) { dis_printf(L_CRITICAL, "Can't stretch the user password, aborting.\n"); *vmk_datum = NULL; memclean((char*) *user_password, strlen((char*) *user_password)); *user_password = NULL; return FALSE; } /* As the computed key length is always the same, use a direct value */ return get_vmk( (datum_aes_ccm_t*) aesccm_datum, user_hash, 32, (datum_key_t**) vmk_datum ); } /** * Get the user's pass without displaying it. * * @param lineptr A pointer to a malloc()-able variable where the password will * be * @param stream The FILE* from which to get the password * @return The number of bytes read */ static ssize_t my_getpass(char **lineptr, FILE *stream) { if(!lineptr || !stream) return -1; size_t n = 0; ssize_t nread; /* * If we're running tests under check, disable echoing off: this doesn't * work on pipes */ #ifndef __CK_DOING_TESTS struct termios old, new; if(isatty(fileno(stream))) { /* Turn echoing off and fail if we can't. */ if(tcgetattr(fileno(stream), &old) != 0) return -1; new = old; new.c_lflag &= (tcflag_t)~ECHO; if(tcsetattr(fileno(stream), TCSAFLUSH, &new) != 0) return -1; } #endif /* __CK_DOING_TESTS */ /* Read the password. */ nread = getline(lineptr, &n, stream); #ifndef __CK_DOING_TESTS if(isatty(fileno(stream))) { /* Restore terminal. */ (void) tcsetattr(fileno(stream), TCSAFLUSH, &old); } printf("\n"); #endif /* __CK_DOING_TESTS */ dis_printf( L_DEBUG, "New memory allocation at %p (%#" F_SIZE_T " byte allocated)\n", (void*) *lineptr, n ); return nread; } /** * Compute the user hash from a user password using the stretch algorithm. * * @param user_password The raw user password that we have to calculate the hash * @param salt The salt used for crypto (16 bytes) * @param result_key Will contain the resulting hash key (32 bytes) * @return TRUE if result can be trusted, FALSE otherwise */ int user_key(const uint8_t *user_password, const uint8_t *salt, uint8_t *result_key) { if(!user_password || !salt || !result_key) { dis_printf(L_ERROR, "Invalid parameter given to user_key().\n"); return FALSE; } uint16_t* utf16_password = NULL; size_t utf16_length = 0; uint8_t user_hash[32] = {0,}; /* * We first get the SHA256(SHA256(to_UTF16(user_password))) */ utf16_length = (strlen((char*) user_password)+1) * sizeof(uint16_t); utf16_password = dis_malloc(utf16_length); if(!asciitoutf16(user_password, utf16_password)) { dis_printf( L_ERROR, "Can't convert user password to UTF-16, aborting.\n" ); memclean(utf16_password, utf16_length); return FALSE; } dis_printf(L_DEBUG, "UTF-16 user password:\n"); hexdump(L_DEBUG, (uint8_t*) utf16_password, utf16_length); /* We're not taking the '\0\0' end of the UTF-16 string */ SHA256((unsigned char *) utf16_password, utf16_length-2, user_hash); SHA256((unsigned char *) user_hash, 32, user_hash); /* * We then pass it to the key stretching manipulation */ if(!stretch_user_key(user_hash, (uint8_t *) salt, result_key)) { dis_printf(L_ERROR, "Can't stretch the user password, aborting.\n"); memclean(utf16_password, utf16_length); return FALSE; } memclean(utf16_password, utf16_length); return TRUE; } /** * Prompt for the user password to be entered * * @param up The place where to put the entered user password * @return TRUE if up can be trusted, FALSE otherwise */ int prompt_up(uint8_t** up) { // Check the parameter if(!up) return FALSE; *up = NULL; ssize_t nb_read; const char* env_pass = getenv("DISLOCKER_PASSWORD"); if(env_pass) { #ifndef __CK_DOING_TESTS printf("Reading user password from the environment\n"); fflush(NULL); #endif /* __CK_DOING_TESTS */ nb_read = (ssize_t)strlen(env_pass); uint8_t* tmp = malloc((size_t)nb_read+2); memcpy(tmp, env_pass, (size_t)nb_read); *(tmp + nb_read) = '\n'; *(tmp + nb_read + 1) = '\0'; *up = tmp; }else{ /* There's no need for a prompt if we're doing tests */ #ifndef __CK_DOING_TESTS printf("Enter the user password: "); fflush(NULL); #endif /* __CK_DOING_TESTS */ nb_read = my_getpass((char**) up, stdin); } if(nb_read <= 0) { if(*up) dis_free(*up); *up = NULL; dis_printf(L_ERROR, "Can't get a user password using getline()\n"); return FALSE; } // getline() gets the '\n' character, so we need to remove it chomp((char*) *up); return TRUE; } dislocker-0.7.3/src/common.c000066400000000000000000000200431375503125700157320ustar00rootroot00000000000000/* -*- 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 #include #include #include #include "dislocker/return_values.h" #include "dislocker/common.h" /** * Here are wrappers for low-level and common used functions * These check the return value and print debug info if needed */ /** * open syscall wrapper * * @param file The file (with its path) to open * @param flags The mode(s) along the opening (read/write/...) * @return The file descriptor returned by the actual open */ #define DIS_XOPEN_ARBITRARY_VALUE 42 #define DIS_XOPEN_FAIL_STR "Failed to open file" #define DIS_XOPEN_FAIL_LEN sizeof(DIS_XOPEN_FAIL_STR) int dis_open(const char* file, int flags) { int fd = -1; dis_printf(L_DEBUG, "Trying to open '%s'...\n", file); if((fd = open(file, flags)) < 0) { char err_string[DIS_XOPEN_FAIL_LEN + DIS_XOPEN_ARBITRARY_VALUE + 4] = {0,}; char file_truncated[DIS_XOPEN_ARBITRARY_VALUE] = {0,}; dis_errno = errno; snprintf(file_truncated, DIS_XOPEN_ARBITRARY_VALUE, "%s", file); if(DIS_XOPEN_ARBITRARY_VALUE < strlen(file)) { file_truncated[DIS_XOPEN_ARBITRARY_VALUE-4] = '.'; file_truncated[DIS_XOPEN_ARBITRARY_VALUE-3] = '.'; file_truncated[DIS_XOPEN_ARBITRARY_VALUE-2] = '.'; } snprintf( err_string, DIS_XOPEN_FAIL_LEN + DIS_XOPEN_ARBITRARY_VALUE + 4, DIS_XOPEN_FAIL_STR " '%s'", file_truncated ); dis_printf(L_ERROR, "%s: %s\n", err_string, strerror(dis_errno)); return -1; } dis_printf(L_DEBUG, "Opened (fd #%d).\n", fd); return fd; } /** * close syscall wrapper * * @param fd The result of an dis_open call * @return The result of the close call */ #define DIS_XCLOSE_FAIL_STR "Failed to close previously opened stream" #define DIS_XCLOSE_FAIL_LEN sizeof(DIS_XCLOSE_FAIL_STR) int dis_close(int fd) { int res = -1; dis_printf(L_DEBUG, "Trying to close fd #%d...\n", fd); if((res = close(fd)) < 0) { dis_errno = errno; dis_printf(L_ERROR, DIS_XCLOSE_FAIL_STR " #%d: %s\n", fd, strerror(errno)); } return res; } /** * read syscall wrapper * * @param fd The file to read from * @param buf The buffer where to put read data * @param count The number of bytes to read * @return The number of bytes read */ #define DIS_XREAD_FAIL_STR "Failed to read in" #define DIS_XREAD_FAIL_LEN sizeof(DIS_XREAD_FAIL_STR) ssize_t dis_read(int fd, void* buf, size_t count) { ssize_t res = -1; dis_printf(L_DEBUG, "Reading %# " F_SIZE_T " bytes from #%d into %p\n", count, fd, buf); #ifdef __FREEBSD /* * FreeBSD's devices are character devices which are to be accessed one * block at a time. Exactly what one block is remains a mystery atm, so we * assume it's a sector, and that a sector is 512-bytes long. * So we count the number of sectors the requested read is on, read them all * and copy to the user only the requested data. */ uint16_t sector_size = 512; off_t offset = lseek(fd, 0, SEEK_CUR); unsigned int sector_to_add = 0; off_t new_offset = -1; size_t old_count = count; void* old_buf = buf; if((offset % sector_size) != 0) sector_to_add += 1; if(((offset + (off_t)count) % sector_size) != 0) sector_to_add += 1; new_offset = (offset / sector_size) * sector_size; count = ((count / sector_size) + sector_to_add) * sector_size; if(lseek(fd, new_offset, SEEK_SET) != new_offset) { dis_printf( L_ERROR, "Cannot lseek(2) to boundary %#" F_OFF_T "\n", new_offset ); errno = EIO; return -1; } buf = dis_malloc(count * sizeof(char)); if(buf == NULL) { dis_printf( L_ERROR, "Cannot malloc %" F_SIZE_T " bytes\n", count * sizeof(char) ); errno = EIO; return -1; } #endif if((res = read(fd, buf, count)) < 0) { dis_errno = errno; dis_printf(L_ERROR, DIS_XREAD_FAIL_STR " #%d: %s\n", fd, strerror(errno)); } #ifdef __FREEBSD /* What is remaining is just to copy actual data */ memcpy(old_buf, (char*) buf + (offset - new_offset), old_count); dis_free(buf); if(lseek(fd, offset + (off_t)old_count, SEEK_SET) == -1) { dis_printf( L_ERROR, "Cannot lseek(2) for restore to %#" F_OFF_T "\n", offset + (off_t)old_count ); errno = EIO; return -1; } /* Fake the return value */ res = (ssize_t) old_count; #endif return res; } /** * write syscall wrapper * * @param fd The file to write to * @param buf The buffer where to put data * @param count The number of bytes to write * @return The number of bytes written */ #define DIS_XWRITE_FAIL_STR "Failed to write in" #define DIS_XWRITE_FAIL_LEN sizeof(DIS_XWRITE_FAIL_STR) ssize_t dis_write(int fd, void* buf, size_t count) { ssize_t res = -1; dis_printf(L_DEBUG, "Writing %#" F_SIZE_T " bytes to #%d from %p\n", count, fd, buf); if((res = write(fd, buf, count)) < 0) { dis_errno = errno; dis_printf(L_ERROR, DIS_XWRITE_FAIL_STR " #%d: %s\n", fd, strerror(errno)); } return res; } /** * lseek syscall wrapper * * @param fd Move cursor of this file descriptor * @param offset To this offset * @param whence According to this whence * @return The result of the lseek call */ #define DIS_XSEEK_FAIL_STR "Failed to seek in" #define DIS_XSEEK_FAIL_LEN sizeof(DIS_XSEEK_FAIL_STR) off_t dis_lseek(int fd, off_t offset, int whence) { off_t res = -1; dis_printf(L_DEBUG, "Positioning #%d at offset %lld from %d\n", fd, offset, whence); if((res = lseek(fd, offset, whence)) < 0) { dis_errno = errno; dis_printf(L_ERROR, DIS_XSEEK_FAIL_STR " #%d: %s\n", fd, strerror(errno)); } return res; } /** * Print data in hexa * * @param data Data to print * @param data_len Length of the data to print */ void hexdump(DIS_LOGS level, uint8_t* data, size_t data_len) { size_t i, j, max = 0; size_t offset = 16; for(i = 0; i < data_len; i += offset) { char s[512] = {0,}; snprintf(s, 12, "0x%.8zx ", i); max = (i+offset > data_len ? data_len : i + offset); for(j = i; j < max; j++) snprintf(&s[11 + 3*(j-i)], 4, "%.2x%s", data[j], (j-i == offset/2-1 && j+1 != max) ? "-" : " "); dis_printf(level, "%s\n", s); } } /** * Apply a bitwise-xor on two buffers * * @param buf1 The first buffer to xor * @param buf2 The second buffer to xor * @param size The size of the two buffers * @param output The resulted xored output (the result is put into buf1 if no output buffer is given) */ void xor_buffer(unsigned char* buf1, const unsigned char* buf2, unsigned char* output, size_t size) { size_t loop; unsigned char* tmp = NULL; if(output) tmp = output; else tmp = buf1; for(loop = 0; loop < size; ++loop, ++buf1, ++buf2, ++tmp) *tmp = *buf1 ^ *buf2; } /** * Clean memory before freeing * * @param ptr A pointeur to the memory region * @param size The size of the region */ void memclean(void* ptr, size_t size) { memset(ptr, 0, size); dis_free(ptr); } #ifdef _HAVE_RUBY VALUE rb_hexdump(uint8_t* data, size_t data_len) { VALUE rb_str = rb_str_new("", 0); size_t i, j, max = 0; size_t offset = 16; for(i = 0; i < data_len; i += offset) { char s[512] = {0,}; snprintf(s, 12, "0x%.8zx ", i); max = (i+offset > data_len ? data_len : i + offset); for(j = i; j < max; j++) snprintf(&s[11 + 3*(j-i)], 4, "%.2x%s", data[j], (j-i == offset/2-1 && j+1 != max) ? "-" : " "); rb_str_catf(rb_str, "%s\n", s); } return rb_str; } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/config.c000066400000000000000000000525041375503125700157160ustar00rootroot00000000000000/* -*- 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 #include #include "dislocker/common.h" #include "dislocker/config.priv.h" #include "dislocker/dislocker.priv.h" /** * Hide a commandline option, replacing the actual optarg by 'X's. * * @param opt The option to hide */ static void hide_opt(char* opt) { if(!opt) return; size_t len = strlen(opt); while(len) { opt[--len] = 'X'; } } /* These functions are wrappers around the appropriate dis_setopt call */ static void setclearkey(dis_context_t dis_ctx, char* optarg) { (void) optarg; int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_USE_CLEAR_KEY, &true); } static void setbekfile(dis_context_t dis_ctx, char* optarg) { int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_USE_BEK_FILE, &true); dis_setopt(dis_ctx, DIS_OPT_SET_BEK_FILE_PATH, optarg); } static void setforceblock(dis_context_t dis_ctx, char* optarg) { off_t force; if(optarg) force = (unsigned char) strtol(optarg, NULL, 10); else force = 1; dis_setopt(dis_ctx, DIS_OPT_FORCE_BLOCK, &force); } static void setfvek(dis_context_t dis_ctx, char* optarg) { int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_USE_FVEK_FILE, &true); dis_setopt(dis_ctx, DIS_OPT_SET_FVEK_FILE_PATH, optarg); } static void setvmk(dis_context_t dis_ctx, char* optarg) { int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_USE_VMK_FILE, &true); dis_setopt(dis_ctx, DIS_OPT_SET_VMK_FILE_PATH, optarg); } static void setlogfile(dis_context_t dis_ctx, char* optarg) { dis_setopt(dis_ctx, DIS_OPT_LOG_FILE_PATH, optarg); } static void setoffset(dis_context_t dis_ctx, char* optarg) { off_t offset = (off_t) strtoll(optarg, NULL, 10); dis_setopt(dis_ctx, DIS_OPT_VOLUME_OFFSET, &offset); } static void setrecoverypwd(dis_context_t dis_ctx, char* optarg) { int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_USE_RECOVERY_PASSWORD, &true); dis_setopt(dis_ctx, DIS_OPT_SET_RECOVERY_PASSWORD, optarg); hide_opt(optarg); } static void setquiet(dis_context_t dis_ctx, char* optarg) { (void) optarg; DIS_LOGS l = L_QUIET; dis_setopt(dis_ctx, DIS_OPT_VERBOSITY, &l); } static void setro(dis_context_t dis_ctx, char* optarg) { (void) optarg; int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_READ_ONLY, &true); } static void setstateok(dis_context_t dis_ctx, char* optarg) { (void) optarg; int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_DONT_CHECK_VOLUME_STATE, &true); } static void setuserpassword(dis_context_t dis_ctx, char* optarg) { int true = TRUE; dis_setopt(dis_ctx, DIS_OPT_USE_USER_PASSWORD, &true); dis_setopt(dis_ctx, DIS_OPT_SET_USER_PASSWORD, optarg); hide_opt(optarg); } static void setverbosity(dis_context_t dis_ctx, char* optarg) { dis_ctx->cfg.verbosity = (DIS_LOGS)strtol(optarg, NULL, 10); } /* Structure used to define dislocker's options */ struct _dis_options { struct option opt; void (*fn)(dis_context_t dis_ctx, char* optarg); }; static struct _dis_options dis_opt[] = { { {"clearkey", no_argument, NULL, 'c'}, setclearkey }, { {"bekfile", required_argument, NULL, 'f'}, setbekfile }, { {"force-block", optional_argument, NULL, 'F'}, setforceblock }, { {"help", no_argument, NULL, 'h'}, NULL }, { {"fvek", required_argument, NULL, 'k'}, setfvek }, { {"vmk", required_argument, NULL, 'K'}, setvmk }, { {"logfile", required_argument, NULL, 'l'}, setlogfile }, { {"offset", required_argument, NULL, 'O'}, setoffset }, { {"options", required_argument, NULL, 'o'}, NULL }, { {"recovery-password", optional_argument, NULL, 'p'}, setrecoverypwd }, { {"quiet", no_argument, NULL, 'q'}, setquiet }, { {"readonly", no_argument, NULL, 'r'}, setro }, { {"ro", no_argument, NULL, 'r'}, setro }, { {"stateok", no_argument, NULL, 's'}, setstateok }, { {"user-password", optional_argument, NULL, 'u'}, setuserpassword }, { {"verbosity", no_argument, NULL, 'v'}, setverbosity }, { {"volume", required_argument, NULL, 'V'}, NULL } }; /** * Print program's usage */ void dis_usage() { fprintf(stderr, PROGNAME " by " AUTHOR ", v" VERSION " (compiled for " __OS "/" __ARCH ")\n" #ifdef VERSION_DBG "Compiled version: " VERSION_DBG "\n" #endif "\n" "Usage: " PROGNAME " [-hqrsv] [-l LOG_FILE] [-O OFFSET] [-V VOLUME DECRYPTMETHOD -F[N]] [-- ARGS...]\n" " with DECRYPTMETHOD = -p[RECOVERY_PASSWORD]|-f BEK_FILE|-u[USER_PASSWORD]|-k FVEK_FILE|-K VMK_FILE|-c\n" "\n" "Options:\n" " -c, --clearkey decrypt volume using a clear key (default)\n" " -f, --bekfile BEKFILE\n" " decrypt volume using the bek file (on USB key)\n" " -F, --force-block=[N] force use of metadata block number N (1, 2 or 3)\n" " -h, --help print this help and exit\n" " -k, --fvek FVEK_FILE decrypt volume using the FVEK directly\n" " -K, --vmk VMK_FILE decrypt volume using the VMK directly\n" " -l, --logfile LOG_FILE\n" " put messages into this file (stdout by default)\n" " -O, --offset OFFSET BitLocker partition offset, in bytes (default is 0)\n" " -p, --recovery-password=[RECOVERY_PASSWORD]\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\n" " -u, --user-password=[USER_PASSWORD]\n" " 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" "\n" " -- end of program options, beginning of FUSE's ones\n" "\n" " ARGS are any arguments you want to pass to FUSE. You need to pass at least\n" "the mount-point.\n" "\n" ); } /** * Parse the --options parameter's value * * @param dis_ctx Dislocker's context * @param optstr The value passed with the --options parameter */ static void parse_options(dis_context_t dis_ctx, char* optstr) { char* tok = NULL; size_t nb_options = sizeof(dis_opt)/sizeof(struct _dis_options); size_t i; size_t opt_len; tok = strtok(optstr, ","); while(tok != NULL) { for(i = 0; i < nb_options; i++) { opt_len = strlen(dis_opt[i].opt.name); if(strncmp(dis_opt[i].opt.name, tok, opt_len) == 0) { if(tok[opt_len] == '=' && tok[opt_len] != '\0') dis_opt[i].fn(dis_ctx, &tok[opt_len + 1]); else dis_opt[i].fn(dis_ctx, NULL); } } tok = strtok(NULL, ","); } } /** * Parse arguments strings * * @warning If -h/--help is encountered, the help is printed and the program * exits (using exit(EXIT_SUCCESS)). * * @param dis_ctx Dislocker's context * @param argc Number of arguments given to the program * @param argv Arguments given to the program * @return Return the number of arguments which are still waiting to be studied. * If -1 is returned, then an error occurred and the configuration isn't set. */ int dis_getopts(dis_context_t dis_ctx, int argc, char** argv) { /** See man getopt_long(3) */ extern int optind; int optchar = 0; size_t nb_options = sizeof(dis_opt)/sizeof(struct _dis_options); /* Options which could be passed as argument */ const char short_opts[] = "cf:F::hk:K:l:O:o:p::qrsu::vV:"; struct option* long_opts; if(!dis_ctx || !argv) return -1; dis_config_t* cfg = &dis_ctx->cfg; int true = TRUE; long_opts = malloc(nb_options * sizeof(struct option)); while(nb_options--) { long_opts[nb_options].name = dis_opt[nb_options].opt.name; long_opts[nb_options].has_arg = dis_opt[nb_options].opt.has_arg; long_opts[nb_options].flag = dis_opt[nb_options].opt.flag; long_opts[nb_options].val = dis_opt[nb_options].opt.val; } while((optchar = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch(optchar) { case 'c': { dis_setopt(dis_ctx, DIS_OPT_USE_CLEAR_KEY, &true); break; } case 'f': { dis_setopt(dis_ctx, DIS_OPT_USE_BEK_FILE, &true); dis_setopt(dis_ctx, DIS_OPT_SET_BEK_FILE_PATH, optarg); break; } case 'F': { off_t force; if(optarg) force = (unsigned char) strtol(optarg, NULL, 10); else force = 1; dis_setopt(dis_ctx, DIS_OPT_FORCE_BLOCK, &force); break; } case 'h': { dis_usage(); dis_free_args(dis_ctx); exit(EXIT_SUCCESS); } case 'k': { dis_setopt(dis_ctx, DIS_OPT_USE_FVEK_FILE, &true); dis_setopt(dis_ctx, DIS_OPT_SET_FVEK_FILE_PATH, optarg); break; } case 'K': { dis_setopt(dis_ctx, DIS_OPT_USE_VMK_FILE, &true); dis_setopt(dis_ctx, DIS_OPT_SET_VMK_FILE_PATH, optarg); break; } case 'l': { dis_setopt(dis_ctx, DIS_OPT_LOG_FILE_PATH, optarg); break; } case 'O': { off_t offset = (off_t) strtoll(optarg, NULL, 10); dis_setopt(dis_ctx, DIS_OPT_VOLUME_OFFSET, &offset); break; } case 'o': { parse_options(dis_ctx, optarg); break; } case 'p': { dis_setopt(dis_ctx, DIS_OPT_USE_RECOVERY_PASSWORD, &true); dis_setopt(dis_ctx, DIS_OPT_SET_RECOVERY_PASSWORD, optarg); hide_opt(optarg); break; } case 'q': { DIS_LOGS l = L_QUIET; dis_setopt(dis_ctx, DIS_OPT_VERBOSITY, &l); break; } case 'r': { dis_setopt(dis_ctx, DIS_OPT_READ_ONLY, &true); break; } case 's': { dis_setopt(dis_ctx, DIS_OPT_DONT_CHECK_VOLUME_STATE, &true); break; } case 'u': { dis_setopt(dis_ctx, DIS_OPT_USE_USER_PASSWORD, &true); dis_setopt(dis_ctx, DIS_OPT_SET_USER_PASSWORD, optarg); hide_opt(optarg); break; } case 'v': { if(cfg->verbosity != L_QUIET) cfg->verbosity++; break; } case 'V': { dis_setopt(dis_ctx, DIS_OPT_VOLUME_PATH, optarg); break; } case '?': default: { dis_usage(); free(long_opts); dis_free_args(dis_ctx); return -1; } } } /* Check verbosity */ if(cfg->verbosity > L_DEBUG) cfg->verbosity = L_DEBUG; if(cfg->verbosity < L_CRITICAL) cfg->verbosity = L_CRITICAL; /* Check decryption method */ if(!cfg->decryption_mean) cfg->decryption_mean |= DIS_USE_CLEAR_KEY; /* Check if a block is forced */ if(cfg->force_block != 1 && cfg->force_block != 2 && cfg->force_block != 3) cfg->force_block = 0; free(long_opts); return optind; } /** * Get dislocker's option * * @param dis_ctx Dislocker's context * @param opt_name The option's name to get * @param opt_value The retrieved value of the option. This is stored in *opt_value. */ int dis_getopt(dis_context_t dis_ctx, dis_opt_e opt_name, void** opt_value) { if (!dis_ctx || !opt_value) return FALSE; dis_config_t* cfg = &dis_ctx->cfg; switch(opt_name) { case DIS_OPT_VOLUME_PATH: *opt_value = cfg->volume_path; break; case DIS_OPT_USE_CLEAR_KEY: if(cfg->decryption_mean & DIS_USE_CLEAR_KEY) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_USE_BEK_FILE: if(cfg->decryption_mean & DIS_USE_BEKFILE) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_SET_BEK_FILE_PATH: *opt_value = cfg->bek_file; break; case DIS_OPT_USE_RECOVERY_PASSWORD: if(cfg->decryption_mean & DIS_USE_RECOVERY_PASSWORD) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_SET_RECOVERY_PASSWORD: *opt_value = cfg->recovery_password; break; case DIS_OPT_USE_USER_PASSWORD: if(cfg->decryption_mean & DIS_USE_USER_PASSWORD) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_SET_USER_PASSWORD: *opt_value = cfg->user_password; break; case DIS_OPT_USE_FVEK_FILE: if(cfg->decryption_mean & DIS_USE_FVEKFILE) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_SET_FVEK_FILE_PATH: *opt_value = cfg->fvek_file; break; case DIS_OPT_USE_VMK_FILE: if(cfg->decryption_mean & DIS_USE_VMKFILE) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_SET_VMK_FILE_PATH: *opt_value = cfg->vmk_file; break; case DIS_OPT_VERBOSITY: *opt_value = (void*) cfg->verbosity; break; case DIS_OPT_LOG_FILE_PATH: *opt_value = cfg->log_file; break; case DIS_OPT_FORCE_BLOCK: *opt_value = (void*) ((long) cfg->force_block); break; case DIS_OPT_VOLUME_OFFSET: *opt_value = (void*) cfg->offset; break; case DIS_OPT_READ_ONLY: if(cfg->flags & DIS_FLAG_READ_ONLY) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_DONT_CHECK_VOLUME_STATE: if(cfg->flags & DIS_FLAG_DONT_CHECK_VOLUME_STATE) *opt_value = (void*) TRUE; else *opt_value = (void*) FALSE; break; case DIS_OPT_INITIALIZE_STATE: *opt_value = (void*) cfg->init_stop_at; break; } return TRUE; } static void set_decryption_mean(dis_config_t* cfg, int set, unsigned value) { if(set == TRUE) cfg->decryption_mean |= value; else cfg->decryption_mean &= (unsigned) ~value; } /** * Modify dislocker's options one-by-one * * @param dis_ctx Dislocker's context * @param opt_name The option's name to change * @param opt_value The new value of the option. Note that this is a pointer. If * NULL, the default value -which is not necessarily usable- will be set. */ int dis_setopt(dis_context_t dis_ctx, dis_opt_e opt_name, const void* opt_value) { if (!dis_ctx) return FALSE; dis_config_t* cfg = &dis_ctx->cfg; switch(opt_name) { case DIS_OPT_VOLUME_PATH: if(cfg->volume_path != NULL) free(cfg->volume_path); if(opt_value == NULL) cfg->volume_path = NULL; else cfg->volume_path = strdup((const char*) opt_value); break; case DIS_OPT_USE_CLEAR_KEY: if(opt_value == NULL) cfg->decryption_mean &= (unsigned) ~DIS_USE_CLEAR_KEY; else set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_CLEAR_KEY); break; case DIS_OPT_USE_BEK_FILE: if(opt_value == NULL) cfg->decryption_mean &= (unsigned) ~DIS_USE_BEKFILE; else set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_BEKFILE); break; case DIS_OPT_SET_BEK_FILE_PATH: if(cfg->bek_file != NULL) free(cfg->bek_file); if(opt_value == NULL) cfg->bek_file = NULL; else cfg->bek_file = strdup((const char*) opt_value); break; case DIS_OPT_USE_RECOVERY_PASSWORD: if(opt_value == NULL) cfg->decryption_mean &= (unsigned) ~DIS_USE_RECOVERY_PASSWORD; else set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_RECOVERY_PASSWORD); break; case DIS_OPT_SET_RECOVERY_PASSWORD: if(cfg->recovery_password != NULL) free(cfg->recovery_password); if(opt_value == NULL) cfg->recovery_password = NULL; else { const char* v = (const char*) opt_value; cfg->recovery_password = (uint8_t *) strdup(v); } break; case DIS_OPT_USE_USER_PASSWORD: if(opt_value == NULL) cfg->decryption_mean &= (unsigned) ~DIS_USE_USER_PASSWORD; else set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_USER_PASSWORD); break; case DIS_OPT_SET_USER_PASSWORD: if(cfg->user_password != NULL) free(cfg->user_password); if(opt_value == NULL) cfg->user_password = NULL; else { const char* v = (const char*) opt_value; cfg->user_password = (uint8_t *) strdup(v); } break; case DIS_OPT_USE_FVEK_FILE: if(opt_value == NULL) cfg->decryption_mean &= (unsigned) ~DIS_USE_FVEKFILE; else set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_FVEKFILE); break; case DIS_OPT_SET_FVEK_FILE_PATH: if(cfg->fvek_file != NULL) free(cfg->fvek_file); if(opt_value == NULL) cfg->fvek_file = NULL; else cfg->fvek_file = strdup((const char*) opt_value); break; case DIS_OPT_USE_VMK_FILE: if(opt_value == NULL) cfg->decryption_mean &= (unsigned) ~DIS_USE_VMKFILE; else set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_VMKFILE); break; case DIS_OPT_SET_VMK_FILE_PATH: if(cfg->vmk_file != NULL) free(cfg->vmk_file); if(opt_value == NULL) cfg->vmk_file = NULL; else cfg->vmk_file = strdup((const char*) opt_value); break; case DIS_OPT_VERBOSITY: if(opt_value == NULL) cfg->verbosity = 0; else { DIS_LOGS l = *(DIS_LOGS*) opt_value; if(l >= L_QUIET && l <= L_DEBUG) cfg->verbosity = l; else cfg->verbosity = 0; } break; case DIS_OPT_LOG_FILE_PATH: if(cfg->log_file != NULL) free(cfg->log_file); if(opt_value == NULL) cfg->log_file = NULL; else cfg->log_file = strdup((const char*) opt_value); break; case DIS_OPT_FORCE_BLOCK: if(opt_value == NULL) cfg->force_block = 0; else { int uc = *(int*) opt_value; if(uc >= 1 && uc <= 3) cfg->force_block = (unsigned char) uc; else cfg->force_block = 0; } break; case DIS_OPT_VOLUME_OFFSET: if(opt_value == NULL) cfg->offset = 0; else cfg->offset = *(off_t*) opt_value; break; case DIS_OPT_READ_ONLY: if(opt_value == NULL) cfg->flags &= (unsigned) ~DIS_FLAG_READ_ONLY; else { int flag = *(int*) opt_value; if(flag == TRUE) cfg->flags |= DIS_FLAG_READ_ONLY; else cfg->flags &= (unsigned) ~DIS_FLAG_READ_ONLY; } break; case DIS_OPT_DONT_CHECK_VOLUME_STATE: if(opt_value == NULL) cfg->flags &= (unsigned) ~DIS_FLAG_DONT_CHECK_VOLUME_STATE; else { int flag = *(int*) opt_value; if(flag == TRUE) cfg->flags |= DIS_FLAG_DONT_CHECK_VOLUME_STATE; else cfg->flags &= (unsigned) ~DIS_FLAG_DONT_CHECK_VOLUME_STATE; } break; case DIS_OPT_INITIALIZE_STATE: if(opt_value == NULL) cfg->init_stop_at = DIS_STATE_COMPLETE_EVERYTHING; else { dis_state_e state = *(dis_state_e*) opt_value; cfg->init_stop_at = state; } break; } return TRUE; } /** * Free dis_config_t members * * @param cfg Dislocker's config */ void dis_free_args(dis_context_t dis_ctx) { if (!dis_ctx) return; dis_config_t* cfg = &dis_ctx->cfg; if(cfg->recovery_password) memclean(cfg->recovery_password, strlen((char*)cfg->recovery_password) + sizeof(char)); if(cfg->user_password) memclean(cfg->user_password, strlen((char*)cfg->user_password) + sizeof(char)); if(cfg->bek_file) memclean(cfg->bek_file, strlen(cfg->bek_file) + sizeof(char)); if(cfg->fvek_file) memclean(cfg->fvek_file, strlen(cfg->fvek_file) + sizeof(char)); if(cfg->vmk_file) memclean(cfg->vmk_file, strlen(cfg->vmk_file) + sizeof(char)); if(cfg->volume_path) dis_free(cfg->volume_path); if(cfg->log_file) dis_free(cfg->log_file); } /** * Print read configuration */ void dis_print_args(dis_context_t dis_ctx) { if(!dis_ctx) return; dis_config_t* cfg = &dis_ctx->cfg; dis_printf(L_DEBUG, "--- Config...\n"); dis_printf(L_DEBUG, " Verbosity: %d\n", cfg->verbosity); dis_printf(L_DEBUG, " Trying to decrypt '%s'\n", cfg->volume_path); if(cfg->decryption_mean & DIS_USE_CLEAR_KEY) { dis_printf(L_DEBUG, " \tusing a clear key on the volume\n"); } else if(cfg->decryption_mean & DIS_USE_USER_PASSWORD) { dis_printf(L_DEBUG, " \tusing the user's password method\n"); dis_printf(L_DEBUG, " \t\t-> '%s'\n", cfg->user_password); } else if(cfg->decryption_mean & DIS_USE_RECOVERY_PASSWORD) { dis_printf(L_DEBUG, " \tusing the recovery password method\n"); dis_printf(L_DEBUG, " \t\t-> '%s'\n", cfg->recovery_password); } else if(cfg->decryption_mean & DIS_USE_BEKFILE) { dis_printf(L_DEBUG, " \tusing the bek file at '%s'\n", cfg->bek_file); } else if(cfg->decryption_mean & DIS_USE_FVEKFILE) { dis_printf(L_DEBUG, " \tusing the FVEK file at '%s'\n", cfg->fvek_file); } else if(cfg->decryption_mean & DIS_USE_VMKFILE) { dis_printf(L_DEBUG, " \tusing the VMK file at '%s'\n", cfg->vmk_file); } else { dis_printf(L_DEBUG, " \tnot using any decryption mean\n"); } if(cfg->force_block) dis_printf( L_DEBUG, " Forced to be using metadata block n°%d\n", cfg->force_block ); else dis_printf(L_DEBUG, " Using the first valid metadata block\n"); if(cfg->flags & DIS_FLAG_READ_ONLY) dis_printf( L_DEBUG, " Not allowing any write on the BitLocker volume " "(read only mode)\n" ); dis_printf(L_DEBUG, "... End config ---\n"); } /** * Getters for the flags */ int dis_is_read_only(dis_context_t dis_ctx) { if(!dis_ctx) return -1; return (dis_ctx->cfg.flags & DIS_FLAG_READ_ONLY); } int dis_is_volume_state_checked(dis_context_t dis_ctx) { if(!dis_ctx) return -1; return !(dis_ctx->cfg.flags & DIS_FLAG_DONT_CHECK_VOLUME_STATE); } dislocker-0.7.3/src/dislocker-bek.c000066400000000000000000000064571375503125700171750ustar00rootroot00000000000000/* -*- 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. */ /* * Testing BEK files reading and parsing */ #include #include #include #include #include #include "dislocker/common.h" #include "dislocker/metadata/print_metadata.h" #include "dislocker/metadata/metadata.h" #include "dislocker/metadata/metadata_config.h" #include "dislocker/accesses/bek/bekfile.h" #define USAGE "Usage: %1$s [-h] [-f file.bek]\n" \ " Reads .BEK files and prints information about them\n" void usage(char* prog) { fprintf(stderr, USAGE, prog); } int main (int argc, char **argv) { char *filename = NULL; int c = 0; int fd = 0; void* bek_dataset = NULL; dis_metadata_config_t dis_meta_cfg = NULL; opterr = 0; while((c = getopt (argc, argv, "hf:")) != -1) { switch(c) { case 'h': usage(argv[0]); return EXIT_SUCCESS; case 'f': filename = optarg; break; case '?': if (optopt == 'f') fprintf (stderr, "Option -%c requires a filename.\n", optopt); else fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt); return EXIT_FAILURE; default: usage(argv[0]); return EXIT_FAILURE; } } dis_stdio_init(L_INFO, NULL); if(filename == NULL) { dis_printf(L_CRITICAL, "Filename must be provided\n"); usage(argv[0]); return EXIT_FAILURE; } if(( fd = dis_open(filename, O_RDONLY) ) < 0) { dis_printf(L_CRITICAL, "Failed to open file %s\n", filename); return EXIT_FAILURE; } if(!get_bek_dataset(fd, &bek_dataset)) { dis_printf(L_CRITICAL, "Unable to get the dataset from the BEK file\n"); return EXIT_FAILURE; } dis_close(fd); /* display infos */ dis_printf(L_INFO, "BEK File Information: %s\n", filename); /* bek header */ dis_context_t dis_ctx = dis_new(); /* * The metadata configuration is freed when calling dis_metadata_destroy() */ dis_meta_cfg = dis_metadata_config_new(); dis_meta_cfg->fve_fd = get_fvevol_fd(dis_ctx); dis_meta_cfg->force_block = 0; dis_meta_cfg->offset = 0; dis_meta_cfg->init_stop_at = 0; dis_metadata_t dis_metadata = dis_metadata_new(dis_meta_cfg); dis_metadata_set_dataset(dis_metadata, bek_dataset); print_dataset(L_INFO, dis_metadata); /* external datum, which contains the decryption key */ print_one_datum(L_INFO, bek_dataset + 0x30); dis_free(bek_dataset); dis_metadata_destroy(dis_metadata); dis_destroy(dis_ctx); dis_stdio_end(); return EXIT_SUCCESS; } dislocker-0.7.3/src/dislocker-file.c000066400000000000000000000120671375503125700173450ustar00rootroot00000000000000/* -*- 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. */ /* This define is for the O_LARGEFILE definition */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include "dislocker/xstd/xstdio.h" #include "dislocker/xstd/xstdlib.h" #include "dislocker/inouts/inouts.h" #include "dislocker/config.h" #include "dislocker/common.h" #include "dislocker/dislocker.h" #if defined(__DARWIN) || defined(__FREEBSD) # define O_LARGEFILE 0 #endif /* __DARWIN || __FREEBSD */ /* Number of sectors we're reading at a time */ #define NB_READ_SECTOR 16 /** * open(2) syscall wrapper (for the one with mode) * * @param file The file (with its path) to open * @param flags The mode(s) along the opening (read/write/...) * @param mode The mode(s) a file will have if created * @return The file descriptor returned by the actual open */ static int dis_open_file(const char* file, int flags, mode_t mode) { int fd = -1; dis_printf(L_DEBUG, "Trying to open '%s'... ", file); if((fd = open(file, flags, mode)) < 0) { #define DIS_FILE_OPEN_FAIL_STR "Failed to open file" #define DIS_FILE_OPEN_FAIL_LEN sizeof(DIS_FILE_OPEN_FAIL_STR) size_t len = DIS_FILE_OPEN_FAIL_LEN + strlen(file) + 4; char* err_string = dis_malloc(len); snprintf(err_string, len , "%s '%s'", DIS_FILE_OPEN_FAIL_STR, file); perror(err_string); dis_free(err_string); exit(2); } dis_printf(L_DEBUG, "Opened (fd #%d).\n", fd); return fd; } static int file_main(char* ntfs_file, dis_context_t dis_ctx) { // Check parameter if(!ntfs_file) { dis_printf(L_ERROR, "Error, empty string file. Abort.\n"); return EXIT_FAILURE; } if(!dis_ctx) { dis_printf(L_ERROR, "Error, no context given. Abort.\n"); return EXIT_FAILURE; } size_t buf_size = (size_t)(NB_READ_SECTOR * dis_inouts_sector_size(dis_ctx)); uint8_t* buffer = dis_malloc(buf_size); mode_t mode = S_IRUSR|S_IWUSR; if(dis_is_read_only(dis_ctx)) mode = S_IRUSR; int fd_ntfs = dis_open_file(ntfs_file, O_CREAT|O_RDWR|O_LARGEFILE, mode); off_t offset = 0; long long int percent = 0; off_t decrypting_size = (off_t)dis_inouts_volume_size(dis_ctx); dis_printf(L_INFO, "File size: %" PRIu64 " bytes\n", decrypting_size); /* Read all sectors and decrypt them if necessary */ dis_printf(L_INFO, "\rDecrypting... 0%%"); fflush(stdout); while(offset < decrypting_size) { /* Read and decrypt an entire region of the disk */ dislock(dis_ctx, buffer, offset, buf_size); offset += (off_t) buf_size; /* Now copy the required amount of data to the user file */ dis_write(fd_ntfs, buffer, buf_size); /* Screen update */ if(percent != (offset*100)/decrypting_size) { percent = (offset*100)/decrypting_size; dis_printf(L_INFO, "\rDecrypting... %lld%%", percent); fflush(stdout); } } dis_printf(L_INFO, "\rDecrypting... Done.\n"); dis_free(buffer); dis_close(fd_ntfs); return EXIT_SUCCESS; } /** * Main function ran initially */ int main(int argc, char** argv) { // Check parameters number if(argc < 2) { dis_usage(); exit(EXIT_FAILURE); } int param_idx = 0; int ret = 0; dis_context_t dis_ctx = dis_new(); /* Get command line options */ param_idx = dis_getopts(dis_ctx, argc, argv); /* Initialize dislocker */ if(dis_initialize(dis_ctx) == EXIT_FAILURE) { dis_printf(L_CRITICAL, "Can't initialize dislocker. Abort.\n"); return EXIT_FAILURE; } /* Check that we have the file where to put NTFS data */ if(param_idx >= argc || param_idx <= 0) { dis_printf(L_CRITICAL, "Error, no file given. Abort.\n"); return EXIT_FAILURE; } /* * Create a NTFS file which could be mounted using `mount -o loop...` */ char* ntfs_file = argv[param_idx]; // Check if the file exists, we don't want to overwrite it if(access(ntfs_file, F_OK) == 0) { dis_printf(L_CRITICAL, "'%s' already exists, can't override. Abort.\n", ntfs_file); dis_destroy(dis_ctx); return EXIT_FAILURE; } dis_printf(L_INFO, "Putting NTFS data into '%s'...\n", ntfs_file); // TODO before running the encryption, check if the NTFS file will fit into the free space /* Run the decryption */ ret = file_main(ntfs_file, dis_ctx); dis_destroy(dis_ctx); return ret; } dislocker-0.7.3/src/dislocker-find.rb.in000066400000000000000000000070241375503125700201310ustar00rootroot00000000000000#!/usr/bin/env ruby # # 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. # # This placeholder is replaced during `make' for the script to find libdislocker # once installed $LOAD_PATH.unshift '@libdir@' require 'libdislocker' $signatures = Dislocker::Signatures::BitLocker $guids = Dislocker::Metadata::GUID::INFORMATION_OFFSETS def get_partitions uname = nil reps = %w(/bin/ /usr/bin/ /sbin/ /usr/sbin/) reps.each do |rep| uname = "#{rep}uname" if File.exists?("#{rep}uname") end if uname.nil? $stderr.puts 'Cannot find uname binary.' return [] end os = `#{uname} -s` os.chomp! os.downcase! if Symbol.all_symbols.any? { |sym| sym.to_s == "get_#{os}_partitions" } return send "get_#{os}_partitions" else $stderr.puts 'OS not supported.' end return [] end def get_freebsd_partitions return Dir['/dev/diskid/*'] end def get_linux_partitions fd = File.open('/proc/partitions', 'r') lines = fd.readlines fd.close if lines.count <= 2 $stderr.puts 'Wrong file format.' exit -1 end # Remove header and empty line lines = lines.last(lines.count - 2) lines = lines.map do |line| line.split /\s+/ end return lines.map do |line| "/dev/#{line[4]}" end end def get_darwin_partitions return Dir['/dev/disk*'] end # Check if a device is BitLocker-encrypted def is_bitlocker_encrypted?(device) begin fd = File.open(device, 'rb') rescue Errno::ENOMEDIUM # This doesn't concern us, it's for cdrom media return false rescue Errno::EBUSY # This means in OSX that the device is mounted, we can't figure if it's # a BitLocker partition or not return false end begin volume_header = fd.read_nonblock(512) rescue # If we can't read 512 bytes, then it's not a BitLocker volume return false else volume_signature = volume_header[3, 8] end fd.close $signatures.each do |sig| # First check is the volume's signature if sig == volume_signature $guids.each do |guid| # Second one is the volume's GUID return true if volume_header[guid] end end end return false end # # Begin here # if ARGV.empty? devices = get_partitions elsif ARGV[0] =~ /^--help|-h$/ puts "Usage: #{$0} [-h] [files...]" puts ' Try to find partitions which are BitLocker-encrypted. Each found is' puts ' printed on stdout.' puts " If one or more file is passed as argument, #{$0} will print each" puts ' file which is a BitLocker-encrypted volume.' puts ' The number of partition found is returned (in $? in sh).' exit 0 else devices = ARGV end encrypted_devices = [] devices.each do |dev| next unless File.exists? dev encrypted_devices << dev if is_bitlocker_encrypted? dev end if encrypted_devices.empty? $stderr.puts 'No BitLocker volume found.' else puts encrypted_devices end exit encrypted_devices.count dislocker-0.7.3/src/dislocker-fuse.c000066400000000000000000000145511375503125700173700ustar00rootroot00000000000000/* -*- 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 #include #include "dislocker/xstd/xstdio.h" #include "dislocker/xstd/xstdlib.h" #include "dislocker/return_values.h" #include "dislocker/config.h" #include "dislocker/dislocker.h" #ifdef __DARWIN # include #else # include #endif /* __DARWIN */ /** NTFS virtual partition's name */ #define NTFS_FILENAME "dislocker-file" #define NTFS_FILERELATIVEPATH "/" NTFS_FILENAME #include "dislocker/inouts/inouts.h" #include "dislocker/dislocker.h" #include "dislocker/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_FILERELATIVEPATH) == 0) { mode_t m = dis_is_read_only(dis_ctx) ? 0444 : 0666; stbuf->st_mode = S_IFREG | m; stbuf->st_nlink = 1; stbuf->st_size = (off_t)dis_inouts_volume_size(dis_ctx); } 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, 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_FILERELATIVEPATH) != 0) return -ENOENT; if(dis_is_read_only(dis_ctx)) { if((fi->flags & O_ACCMODE) != O_RDONLY) return -EACCES; } else { /* Authorize read/write, readonly and writeonly operations */ if((fi->flags & O_ACCMODE) != O_RDWR && (fi->flags & O_ACCMODE) != O_RDONLY && (fi->flags & O_ACCMODE) != 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_FILERELATIVEPATH) != 0) { dis_printf(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_FILERELATIVEPATH) != 0) { dis_printf(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) { char* volume_path = NULL; // Check parameters number if(argc < 2) { dis_usage(); exit(EXIT_FAILURE); } int param_idx = 0; int ret = EXIT_SUCCESS; /* Get command line options */ dis_ctx = dis_new(); param_idx = dis_getopts(dis_ctx, argc, argv); /* * Check we have a volume path given and if not, take the first non-argument * as the volume path */ dis_getopt(dis_ctx, DIS_OPT_VOLUME_PATH, (void**) &volume_path); if(volume_path == NULL) { if(param_idx >= argc || param_idx <= 0) { dis_printf(L_CRITICAL, "Error, no volume path given. Abort.\n"); return EXIT_FAILURE; } dis_printf(L_DEBUG, "Setting the volume path to %s.\n", argv[param_idx]); dis_setopt(dis_ctx, DIS_OPT_VOLUME_PATH, argv[param_idx]); param_idx++; } /* Initialize dislocker */ if(dis_initialize(dis_ctx) != DIS_RET_SUCCESS) { dis_printf(L_CRITICAL, "Can't initialize dislocker. Abort.\n"); return EXIT_FAILURE; } /* Check we got enough arguments for at least one more, the mount point */ if(param_idx >= argc || param_idx <= 0) { dis_printf(L_CRITICAL, "Error, no mount point given. 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); dis_printf(L_DEBUG, "New value for argc: %d\n", new_argc); char** new_argv = dis_malloc(new_argc * sizeof(char*)); /* Get argv[0] */ size_t lg = strlen(argv[0]) + 1; *new_argv = dis_malloc(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) = dis_malloc(lg); memcpy(*(new_argv + loop), argv[(size_t)param_idx + loop - 1], lg); } dis_printf(L_INFO, "Running FUSE with these arguments: \n"); for(loop = 0; loop < new_argc; ++loop) dis_printf(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) dis_free(new_argv[loop]); dis_free(new_argv); /* Destroy dislocker structures */ dis_destroy(dis_ctx); return ret; } dislocker-0.7.3/src/dislocker-metadata.c000066400000000000000000000101101375503125700201710ustar00rootroot00000000000000/* -*- 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. */ /* * Get and display BitLocker's metadata */ #define _GNU_SOURCE 1 #include #include #include #include #include #include "dislocker/return_values.h" #include "dislocker/config.h" #include "dislocker/dislocker.h" #include "dislocker/metadata/datums.h" #include "dislocker/metadata/metadata.h" #include "dislocker/metadata/print_metadata.h" /* * On Darwin and FreeBSD, files are opened using 64 bits offsets/variables * and O_LARGEFILE isn't defined */ #if defined(__DARWIN) || defined(__FREEBSD) # define O_LARGEFILE 0 #endif /* __DARWIN || __FREEBSD */ void usage() { fprintf(stderr, "Usage: " PROGNAME " [-hov] [-V VOLUME]\n" "\n" " -h print this help and exit\n" " -o partition offset\n" " -v increase verbosity to debug level\n" " -V VOLUME volume to get metadata from\n" ); } int main(int argc, char **argv) { if(argc < 2) { usage(); exit(EXIT_FAILURE); } int optchar = 0; char *volume_path = NULL; dis_metadata_config_t dis_meta_cfg = NULL; dis_metadata_t dis_metadata = NULL; int fve_fd = -1; void* vmk_clear_key_datum = NULL; off_t offset = 0; DIS_LOGS verbosity = L_INFO; while((optchar = getopt(argc, argv, "o:V:hv")) != -1) { switch(optchar) { case 'h': usage(); return EXIT_SUCCESS; case 'o': offset = (off_t) strtoll(optarg, NULL, 10); break; case 'v': verbosity = L_DEBUG; break; case 'V': volume_path = optarg; break; case '?': default: fprintf(stderr, "Unknown option encountered.\n"); usage(); exit(EXIT_FAILURE); } } if(!volume_path) { usage(); exit(EXIT_FAILURE); } /* Initialize outputs */ dis_stdio_init(verbosity, NULL); dis_printf(L_INFO, PROGNAME " by " AUTHOR ", v" VERSION " (compiled for " __OS "/" __ARCH ")\n"); #ifdef VERSION_DBG dis_printf(L_INFO, "Compiled version: " VERSION_DBG "\n"); #endif /* Open the volume as a (big) normal file */ dis_printf(L_DEBUG, "Trying to open '%s'...\n", volume_path); fve_fd = dis_open(volume_path, O_RDONLY|O_LARGEFILE); /* * Initialize dislocker's configuration * */ dis_meta_cfg = dis_metadata_config_new(); dis_meta_cfg->fve_fd = fve_fd; dis_meta_cfg->offset = offset; dis_metadata = dis_metadata_new(dis_meta_cfg); if(dis_metadata_initialize(dis_metadata) != DIS_RET_SUCCESS) { dis_printf(L_CRITICAL, "Can't initialize dislocker. Abort.\n"); return EXIT_FAILURE; } // Printing volume header print_volume_header(L_INFO, dis_metadata); dis_printf(L_INFO, "\n"); // Printing BitLocker information metadata print_information(L_INFO, dis_metadata); dis_printf(L_INFO, "\n"); // Now we're looking at the data themselves print_data(L_INFO, dis_metadata); // Search for a clear key if(dis_metadata_has_clear_key(dis_metadata, &vmk_clear_key_datum)) { dis_printf(L_INFO, "=======[ There's a clear key here ]========\n"); print_one_datum(L_INFO, vmk_clear_key_datum); dis_printf(L_INFO, "=============[ Clear key end ]=============\n"); } else dis_printf(L_INFO, "No clear key found.\n"); dis_close(fve_fd); dis_metadata_destroy(dis_metadata); return EXIT_SUCCESS; } dislocker-0.7.3/src/dislocker.bb000066400000000000000000000021721375503125700165650ustar00rootroot00000000000000FILESEXTRAPATHS_prepend := "${THISDIR}/dislocker:" SUMMARY = "Read BitLocker encrypted partitions under a Linux system" DESCRIPTION = " \ This software has been designed to read BitLocker encrypted partitions under a \ Linux system. The driver has the capability to read/write on: \ - Windows Vista, 7, 8, 8.1 and 10 encrypted partitions - that's AES-CBC, \ AES-XTS, 128 or 256 bits, with or without the Elephant diffuser, encrypted \ partitions; \ - BitLocker-To-Go encrypted partitions - that's USB/FAT32 partitions. \ " HOMEPAGE = "https://github.com/Aorimn/dislocker" BUGTRACKER = "https://github.com/Aorimn/dislocker/issues" LICENSE = "GPLv2" LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=6aa0d8e41ad2e57bef0712adf0cf5cb5" SECTION = "e/utils" SRC_URI = "https://github.com/Aorimn/dislocker/archive/v${PV}.tar.gz" SRC_URI[md5sum] = "2685fba76693420677c2b9f8e3fd8c83" SRC_URI[sha256sum] = "c3173dab96545a7a9b210d11dd7317b63662025c4f78bf820d3fe41017f49f68" DEPENDS = "mbedtls fuse" RDEPENDS_${PN} += "mbedtls fuse" PROVIDES += "dislocker" RPROVIDES_${PN} = "dislocker" EXTRA_OECMAKE = " -DLIB_INSTALL_DIR=${baselib}" inherit cmake dislocker-0.7.3/src/dislocker.c000066400000000000000000000462731375503125700164360ustar00rootroot00000000000000/* -*- 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. */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include "dislocker/accesses/accesses.h" #include "dislocker/metadata/datums.h" #include "dislocker/metadata/metadata.h" #include "dislocker/metadata/print_metadata.h" #include "dislocker/metadata/fvek.h" #include "dislocker/metadata/vmk.h" #include "dislocker/inouts/prepare.h" #include "dislocker/inouts/sectors.h" #include "dislocker/xstd/xstdio.h" #include "dislocker/return_values.h" #include "dislocker/config.priv.h" #include "dislocker/dislocker.priv.h" #include #ifndef __DIS_CORE_DUMPS #include #include #endif /* * On Darwin and FreeBSD, files are opened using 64 bits offsets/variables * and O_LARGEFILE isn't defined */ #if defined(__DARWIN) || defined(__FREEBSD) # define O_LARGEFILE 0 #endif /* __DARWIN || __FREEBSD */ /* Get low-level errors the library encoutered by looking at this variable */ int dis_errno; dis_context_t dis_new() { /* Allocate dislocker's context */ dis_context_t dis_ctx = dis_malloc(sizeof(struct _dis_ctx)); memset(dis_ctx, 0, sizeof(struct _dis_ctx)); #ifndef __DIS_CORE_DUMPS /* As we manage passwords and secrets, do not authorize core dumps */ struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &limit) != 0) { fprintf(stderr, "Cannot disable core dumps.\n"); dis_free(dis_ctx); return NULL; } #endif dis_ctx->fve_fd = -1; return dis_ctx; } int dis_initialize(dis_context_t dis_ctx) { int ret = DIS_RET_SUCCESS; dis_metadata_config_t dis_meta_cfg = NULL; /* Initialize outputs */ dis_stdio_init(dis_ctx->cfg.verbosity, dis_ctx->cfg.log_file); dis_printf(L_INFO, PROGNAME " by " AUTHOR ", v" VERSION " (compiled for " __OS "/" __ARCH ")\n"); #ifdef VERSION_DBG dis_printf(L_INFO, "Compiled version: " VERSION_DBG "\n"); #endif if(dis_ctx->cfg.verbosity >= L_DEBUG) dis_print_args(dis_ctx); /* * Check parameters given */ if(!dis_ctx->cfg.volume_path) { dis_printf(L_CRITICAL, "No BitLocker volume path given. Abort.\n"); dis_destroy(dis_ctx); return DIS_RET_ERROR_VOLUME_NOT_GIVEN; } /* Open the volume as a (big) normal file */ dis_printf(L_DEBUG, "Trying to open '%s'...\n", dis_ctx->cfg.volume_path); dis_ctx->fve_fd = dis_open(dis_ctx->cfg.volume_path, O_RDWR|O_LARGEFILE); if(dis_ctx->fve_fd < 0) { /* Trying to open it in read-only if O_RDWR doesn't work */ dis_ctx->fve_fd = dis_open( dis_ctx->cfg.volume_path, O_RDONLY|O_LARGEFILE ); if(dis_ctx->fve_fd < 0) { dis_printf( L_CRITICAL, "Failed to open %s: %s\n", dis_ctx->cfg.volume_path, strerror(errno) ); dis_destroy(dis_ctx); return DIS_RET_ERROR_FILE_OPEN; } dis_ctx->cfg.flags |= DIS_FLAG_READ_ONLY; dis_printf( L_WARNING, "Failed to open %s for writing. Falling back to read-only.\n", dis_ctx->cfg.volume_path ); } dis_printf(L_DEBUG, "Opened (fd #%d).\n", dis_ctx->fve_fd); dis_ctx->io_data.volume_fd = dis_ctx->fve_fd; checkupdate_dis_state(dis_ctx, DIS_STATE_AFTER_OPEN_VOLUME); /* To print UTF-32 strings */ setlocale(LC_ALL, ""); /* * The metadata configuration is freed when calling dis_metadata_destroy() */ dis_meta_cfg = dis_metadata_config_new(); dis_meta_cfg->fve_fd = dis_ctx->fve_fd; dis_meta_cfg->force_block = dis_ctx->cfg.force_block; dis_meta_cfg->offset = dis_ctx->cfg.offset; dis_meta_cfg->init_stop_at = dis_ctx->cfg.init_stop_at; dis_ctx->metadata = dis_metadata_new(dis_meta_cfg); if(dis_ctx->metadata == NULL) { dis_printf(L_CRITICAL, "Can't allocate metadata object. Abort.\n"); dis_destroy(dis_ctx); return DIS_RET_ERROR_ALLOC; } ret = dis_metadata_initialize(dis_ctx->metadata); dis_ctx->curr_state = dis_meta_cfg->curr_state; if(ret != DIS_RET_SUCCESS) { /* * If it's less than 0, then it's an error, if not, it's an early * return of this function. */ if(ret < 0) dis_destroy(dis_ctx); return ret; } /* * If the state of the volume is currently decrypted, there's no key to grab */ if(dis_ctx->metadata->information->curr_state != METADATA_STATE_DECRYPTED) { /* * Get the keys -- VMK & FVEK -- for dec/encryption operations */ if((ret = dis_get_access(dis_ctx)) != DIS_RET_SUCCESS) { /* * If it's less than 0, then it's an error, if not, it's an early * return of this function. */ if(ret < 0) { dis_printf(L_CRITICAL, "Unable to grab VMK or FVEK. Abort.\n"); dis_destroy(dis_ctx); } return ret; } /* * Init the crypto structure */ dis_ctx->io_data.crypt = dis_crypt_new( dis_metadata_sector_size(dis_ctx->metadata), dis_ctx->metadata->dataset->algorithm ); /* * Init the decrypt keys' contexts */ if(init_keys( dis_metadata_set_dataset(dis_ctx->metadata, NULL), dis_ctx->io_data.fvek, dis_ctx->io_data.crypt) != DIS_RET_SUCCESS) { dis_printf(L_CRITICAL, "Can't initialize keys. Abort.\n"); dis_destroy(dis_ctx); return DIS_RET_ERROR_CRYPTO_INIT; } } /* * Fill the dis_iodata_t structure which will be used for encryption & * decryption afterward */ if((ret = prepare_crypt(dis_ctx)) != DIS_RET_SUCCESS) dis_printf(L_CRITICAL, "Can't prepare the crypt structure. Abort.\n"); // TODO add the DIS_STATE_BEFORE_DECRYPTION_CHECKING event here, so add the check here too /* Don't do the check for each and every enc/decryption operation */ dis_ctx->io_data.volume_state = TRUE; int look_state = dis_ctx->cfg.flags & DIS_FLAG_DONT_CHECK_VOLUME_STATE; if(look_state == 0 && !check_state(dis_ctx->metadata)) { dis_ctx->io_data.volume_state = FALSE; ret = DIS_RET_ERROR_VOLUME_STATE_NOT_SAFE; } /* Clean everything before returning if there's an error */ if(ret != DIS_RET_SUCCESS) dis_destroy(dis_ctx); else dis_ctx->curr_state = DIS_STATE_COMPLETE_EVERYTHING; return ret; } int dislock(dis_context_t dis_ctx, uint8_t* buffer, off_t offset, size_t size) { uint8_t* buf = NULL; size_t sector_count; off_t sector_start; size_t sector_to_add = 0; uint16_t sector_size; if(!dis_ctx || !buffer) return -EINVAL; /* Check the initialization's state */ if(dis_ctx->curr_state != DIS_STATE_COMPLETE_EVERYTHING) { dis_printf(L_ERROR, "Initialization not completed. Abort.\n"); return -EFAULT; } /* Check the state the BitLocker volume is in */ if(dis_ctx->io_data.volume_state == FALSE) { dis_printf(L_ERROR, "Invalid volume state, can't run safely. Abort.\n"); return -EFAULT; } /* Check requested size */ if(size == 0) { dis_printf(L_DEBUG, "Received a request with a null size\n"); return 0; } if(size > INT_MAX) { dis_printf(L_ERROR, "Received size which will overflow: %#" F_SIZE_T "\n", size ); return -EOVERFLOW; } /* Check requested offset */ if(offset < 0) { dis_printf(L_ERROR, "Offset under 0: %#" F_OFF_T "\n", offset); return -EFAULT; } if(offset >= (off_t)dis_ctx->io_data.volume_size) { dis_printf( L_ERROR, "Offset (%#" F_OFF_T ") exceeds volume's size (%#" F_OFF_T ")\n", offset, (off_t)dis_ctx->io_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 */ sector_size = dis_ctx->io_data.sector_size; if((offset % sector_size) != 0) sector_to_add += 1; if(((offset + (off_t)size) % sector_size) != 0) sector_to_add += 1; sector_count = ( size / sector_size ) + sector_to_add; sector_start = offset / sector_size; dis_printf(L_DEBUG, "--------------------{ Fuse reading }-----------------------\n"); dis_printf(L_DEBUG, " Offset and size needed: %#" F_OFF_T " and %#" F_SIZE_T "\n", offset, size); dis_printf(L_DEBUG, " Start sector number: %#" F_OFF_T " || Number of sectors: %#" F_SIZE_T "\n", sector_start, sector_count); /* * NOTE: DO NOT use dis_malloc() here, we don't want to mess everything up! * In general, do not use xfunctions() but dis_printf() here. */ size_t to_allocate = size + sector_to_add*sector_size; dis_printf(L_DEBUG, " Trying to allocate %#" F_SIZE_T " bytes\n",to_allocate); buf = malloc(to_allocate); /* If buffer could not be allocated, return an error */ if(!buf) { dis_printf(L_ERROR, "Cannot allocate buffer for reading, abort.\n"); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); if(errno < 0) return errno; else return -ENOMEM; } if(!dis_ctx->io_data.decrypt_region( &dis_ctx->io_data, sector_count, sector_size, sector_start * sector_size, buf)) { free(buf); dis_printf(L_ERROR, "Cannot decrypt sectors, abort.\n"); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); return -EIO; } /* Now copy the required amount of data to the user buffer */ memcpy(buffer, buf + (offset % sector_size), size); free(buf); dis_printf(L_DEBUG, " Outsize which will be returned: %d\n", (int)size); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); return (int)size; } int enlock(dis_context_t dis_ctx, uint8_t* buffer, off_t offset, size_t size) { uint8_t* buf = NULL; int ret = 0; uint16_t sector_size; size_t sector_count; off_t sector_start; size_t sector_to_add = 0; if(!dis_ctx || !buffer) return -EINVAL; /* Check the initialization's state */ if(dis_ctx->curr_state != DIS_STATE_COMPLETE_EVERYTHING) { dis_printf(L_ERROR, "Initialization not completed. Abort.\n"); return -EFAULT; } /* Check the state the BitLocker volume is in */ if(dis_ctx->io_data.volume_state == FALSE) { dis_printf(L_ERROR, "Invalid volume state, can't run safely. Abort.\n"); return -EFAULT; } /* Perform basic checks */ if(dis_ctx->cfg.flags & DIS_FLAG_READ_ONLY) { dis_printf(L_DEBUG, "Only decrypting (-r or --read-only option passed)\n"); return -EACCES; } if(size == 0) { dis_printf(L_DEBUG, "Received a request with a null size\n"); return 0; } if(size > INT_MAX) { dis_printf(L_ERROR, "Received size which will overflow: %#" F_SIZE_T "\n", size ); return -EOVERFLOW; } if(offset < 0) { dis_printf(L_ERROR, "Offset under 0: %#" F_OFF_T "\n", offset); return -EFAULT; } if(offset >= (off_t)dis_ctx->io_data.volume_size) { dis_printf(L_ERROR, "Offset (%#" F_OFF_T ") exceeds volume's size (%#" F_OFF_T ")\n", offset, (off_t)dis_ctx->io_data.volume_size); return -EFAULT; } if(offset + (off_t)size >= (off_t)dis_ctx->io_data.volume_size) { size_t nsize = (size_t)dis_ctx->io_data.volume_size - (size_t)offset; dis_printf( L_WARNING, "Size modified as exceeding volume's end (offset=%#" F_OFF_T " + size=%#" F_OFF_T " >= volume_size=%#" F_OFF_T ") ; new size: %#" F_SIZE_T "\n", offset, (off_t)size, dis_ctx->io_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). */ if(dis_metadata_is_overwritten(dis_ctx->metadata, offset, size) != DIS_RET_SUCCESS) return -EFAULT; /* * For BitLocker 7's volume, redirect writes to firsts sectors to the backed * up ones */ if(dis_ctx->metadata->information->version == V_SEVEN && offset < dis_ctx->metadata->virtualized_size) { dis_printf(L_DEBUG, " Entering virtualized area\n"); if(offset + (off_t)size <= dis_ctx->metadata->virtualized_size) { /* * If all the request is within the virtualized area, just change * the offset */ offset = offset + (off_t)dis_ctx->metadata->information->boot_sectors_backup; dis_printf(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 */ dis_printf(L_DEBUG, " `-> Splitting the request in two, recursing\n"); size_t nsize = (size_t)(dis_ctx->metadata->virtualized_size - offset); ret = enlock(dis_ctx, buffer, offset, nsize); if(ret < 0) return ret; offset = dis_ctx->metadata->virtualized_size; size -= nsize; buffer += 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 */ sector_size = dis_ctx->io_data.sector_size; if((offset % sector_size) != 0) sector_to_add += 1; if(((offset + (off_t)size) % sector_size) != 0) sector_to_add += 1; sector_count = ( size / sector_size ) + sector_to_add; sector_start = offset / sector_size; dis_printf(L_DEBUG, "--------------------{ Fuse writing }-----------------------\n"); dis_printf(L_DEBUG, " Offset and size requested: %#" F_OFF_T " and %#" F_SIZE_T "\n", offset, size); dis_printf(L_DEBUG, " Start sector number: %#" F_OFF_T " || Number of sectors: %#" F_SIZE_T "\n", sector_start, sector_count); /* * NOTE: DO NOT use dis_malloc() here, we don't want to mess everything up! * In general, do not use xfunctions() but dis_printf() here. */ buf = malloc(size + sector_to_add * (size_t)sector_size); /* If buffer could not be allocated */ if(!buf) { dis_printf(L_ERROR, "Cannot allocate buffer for writing, abort.\n"); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); return -ENOMEM; } if(!dis_ctx->io_data.decrypt_region( &dis_ctx->io_data, sector_count, sector_size, sector_start * sector_size, buf )) { free(buf); dis_printf(L_ERROR, "Cannot decrypt sectors, abort.\n"); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); return -EIO; } /* Now copy the user's buffer to the received data */ memcpy(buf + (offset % sector_size), buffer, size); /* Finally, encrypt the buffer and write it to the disk */ if(!dis_ctx->io_data.encrypt_region( &dis_ctx->io_data, sector_count, sector_size, sector_start * sector_size, buf )) { free(buf); dis_printf(L_ERROR, "Cannot encrypt sectors, abort.\n"); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); return -EIO; } free(buf); /* Note that ret is zero when no recursion occurs */ int outsize = (int)size + ret; dis_printf(L_DEBUG, " Outsize which will be returned: %d\n", outsize); dis_printf(L_DEBUG, "-----------------------------------------------------------\n"); return outsize; } int dis_destroy(dis_context_t dis_ctx) { /* Finish cleaning things */ if(dis_ctx->io_data.vmk) dis_free(dis_ctx->io_data.vmk); if(dis_ctx->io_data.fvek) dis_free(dis_ctx->io_data.fvek); dis_crypt_destroy(dis_ctx->io_data.crypt); dis_metadata_destroy(dis_ctx->metadata); dis_free_args(dis_ctx); dis_close(dis_ctx->io_data.volume_fd); dis_stdio_end(); dis_free(dis_ctx); return EXIT_SUCCESS; } int get_fvevol_fd(dis_context_t dis_ctx) { return dis_ctx->fve_fd; } /** * This part below is for Ruby bindings */ #ifdef _HAVE_RUBY #include VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; static VALUE rb_init_dislocker(VALUE self, VALUE rb_vdis_ctx) { rb_iv_set(self, "@context", rb_vdis_ctx); // TODO dis_initialize(dis_context_t* dis_ctx); return Qtrue; } static VALUE rb_dislock(VALUE self, VALUE rb_vbuffer, VALUE rb_voffset, VALUE rb_vsize) { // TODO implement the function (void) self; (void) rb_vbuffer; (void) rb_voffset; (void) rb_vsize; return Qtrue; } static VALUE rb_enlock(VALUE self, VALUE rb_vbuffer, VALUE rb_voffset, VALUE rb_vsize) { // TODO implement the function (void) self; (void) rb_vbuffer; (void) rb_voffset; (void) rb_vsize; return Qtrue; } static VALUE rb_destroy_dislocker(VALUE self) { // TODO implement the function (void) self; return Qtrue; } void Init_libdislocker() { VALUE rb_mDislocker = rb_define_module("Dislocker"); dis_rb_classes[DIS_RB_CLASS_DISLOCKER] = rb_mDislocker; Init_metadata(rb_mDislocker); Init_accesses(rb_mDislocker); rb_define_method(rb_mDislocker, "initialize", rb_init_dislocker, 1); rb_define_method(rb_mDislocker, "dislock", rb_dislock, 3); rb_define_method(rb_mDislocker, "enlock", rb_enlock, 3); rb_define_method(rb_mDislocker, "destroy", rb_destroy_dislocker, 0); VALUE rb_mDisSignatures = rb_define_module_under(rb_mDislocker, "Signatures"); VALUE signatures = rb_ary_new3( 2, rb_str_new(BITLOCKER_SIGNATURE, BITLOCKER_SIGNATURE_SIZE), rb_str_new(BITLOCKER_TO_GO_SIGNATURE, BITLOCKER_TO_GO_SIGNATURE_SIZE) ); rb_define_const(rb_mDisSignatures, "BitLocker", signatures); } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/dislocker.rb000066400000000000000000000011141375503125700166000ustar00rootroot00000000000000# # this brew file *must* be called 'dislocker.rb' to match the Formula # require 'formula' class Dislocker < Formula homepage 'https://github.com/Aorimn/dislocker' url 'https://github.com/Aorimn/dislocker/archive/v0.7.2.zip' sha256 '9c7cbc44193f560bbe4c23bc2568485d8a77a9f598c86ba41465cd0eb0cf4441' version '0.7.2' depends_on 'mbedtls' depends_on 'cmake' # This dependency is seperately installed, as a cask # depends_on :osxfuse def install system 'cmake', *std_cmake_args system 'make' system 'make', 'install' end end dislocker-0.7.3/src/encryption/000077500000000000000000000000001375503125700164715ustar00rootroot00000000000000dislocker-0.7.3/src/encryption/aes-xts.c000066400000000000000000000234351375503125700202300ustar00rootroot00000000000000/* -*- 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 #include #include "dislocker/ssl_bindings.h" #ifndef GET_UINT64_LE #define GET_UINT64_LE(n,b,i) \ { \ (n) = ( (uint64_t) (b)[(i) + 7] << 56 ) \ | ( (uint64_t) (b)[(i) + 6] << 48 ) \ | ( (uint64_t) (b)[(i) + 5] << 40 ) \ | ( (uint64_t) (b)[(i) + 4] << 32 ) \ | ( (uint64_t) (b)[(i) + 3] << 24 ) \ | ( (uint64_t) (b)[(i) + 2] << 16 ) \ | ( (uint64_t) (b)[(i) + 1] << 8 ) \ | ( (uint64_t) (b)[(i) ] ); \ } #endif #ifndef PUT_UINT64_LE #define PUT_UINT64_LE(n,b,i) \ { \ (b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \ (b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \ (b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \ (b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \ (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) ] = (unsigned char) ( (n) ); \ } #endif #define gf128mul_dat(q) { \ q(0x00), q(0x01), q(0x02), q(0x03), q(0x04), q(0x05), q(0x06), q(0x07),\ q(0x08), q(0x09), q(0x0a), q(0x0b), q(0x0c), q(0x0d), q(0x0e), q(0x0f),\ q(0x10), q(0x11), q(0x12), q(0x13), q(0x14), q(0x15), q(0x16), q(0x17),\ q(0x18), q(0x19), q(0x1a), q(0x1b), q(0x1c), q(0x1d), q(0x1e), q(0x1f),\ q(0x20), q(0x21), q(0x22), q(0x23), q(0x24), q(0x25), q(0x26), q(0x27),\ q(0x28), q(0x29), q(0x2a), q(0x2b), q(0x2c), q(0x2d), q(0x2e), q(0x2f),\ q(0x30), q(0x31), q(0x32), q(0x33), q(0x34), q(0x35), q(0x36), q(0x37),\ q(0x38), q(0x39), q(0x3a), q(0x3b), q(0x3c), q(0x3d), q(0x3e), q(0x3f),\ q(0x40), q(0x41), q(0x42), q(0x43), q(0x44), q(0x45), q(0x46), q(0x47),\ q(0x48), q(0x49), q(0x4a), q(0x4b), q(0x4c), q(0x4d), q(0x4e), q(0x4f),\ q(0x50), q(0x51), q(0x52), q(0x53), q(0x54), q(0x55), q(0x56), q(0x57),\ q(0x58), q(0x59), q(0x5a), q(0x5b), q(0x5c), q(0x5d), q(0x5e), q(0x5f),\ q(0x60), q(0x61), q(0x62), q(0x63), q(0x64), q(0x65), q(0x66), q(0x67),\ q(0x68), q(0x69), q(0x6a), q(0x6b), q(0x6c), q(0x6d), q(0x6e), q(0x6f),\ q(0x70), q(0x71), q(0x72), q(0x73), q(0x74), q(0x75), q(0x76), q(0x77),\ q(0x78), q(0x79), q(0x7a), q(0x7b), q(0x7c), q(0x7d), q(0x7e), q(0x7f),\ q(0x80), q(0x81), q(0x82), q(0x83), q(0x84), q(0x85), q(0x86), q(0x87),\ q(0x88), q(0x89), q(0x8a), q(0x8b), q(0x8c), q(0x8d), q(0x8e), q(0x8f),\ q(0x90), q(0x91), q(0x92), q(0x93), q(0x94), q(0x95), q(0x96), q(0x97),\ q(0x98), q(0x99), q(0x9a), q(0x9b), q(0x9c), q(0x9d), q(0x9e), q(0x9f),\ q(0xa0), q(0xa1), q(0xa2), q(0xa3), q(0xa4), q(0xa5), q(0xa6), q(0xa7),\ q(0xa8), q(0xa9), q(0xaa), q(0xab), q(0xac), q(0xad), q(0xae), q(0xaf),\ q(0xb0), q(0xb1), q(0xb2), q(0xb3), q(0xb4), q(0xb5), q(0xb6), q(0xb7),\ q(0xb8), q(0xb9), q(0xba), q(0xbb), q(0xbc), q(0xbd), q(0xbe), q(0xbf),\ q(0xc0), q(0xc1), q(0xc2), q(0xc3), q(0xc4), q(0xc5), q(0xc6), q(0xc7),\ q(0xc8), q(0xc9), q(0xca), q(0xcb), q(0xcc), q(0xcd), q(0xce), q(0xcf),\ q(0xd0), q(0xd1), q(0xd2), q(0xd3), q(0xd4), q(0xd5), q(0xd6), q(0xd7),\ q(0xd8), q(0xd9), q(0xda), q(0xdb), q(0xdc), q(0xdd), q(0xde), q(0xdf),\ q(0xe0), q(0xe1), q(0xe2), q(0xe3), q(0xe4), q(0xe5), q(0xe6), q(0xe7),\ q(0xe8), q(0xe9), q(0xea), q(0xeb), q(0xec), q(0xed), q(0xee), q(0xef),\ q(0xf0), q(0xf1), q(0xf2), q(0xf3), q(0xf4), q(0xf5), q(0xf6), q(0xf7),\ q(0xf8), q(0xf9), q(0xfa), q(0xfb), q(0xfc), q(0xfd), q(0xfe), q(0xff) \ } #define xx(p, q) 0x##p##q #define xda_bbe(i) ( \ (i & 0x80 ? xx(43, 80) : 0) ^ (i & 0x40 ? xx(21, c0) : 0) ^ \ (i & 0x20 ? xx(10, e0) : 0) ^ (i & 0x10 ? xx(08, 70) : 0) ^ \ (i & 0x08 ? xx(04, 38) : 0) ^ (i & 0x04 ? xx(02, 1c) : 0) ^ \ (i & 0x02 ? xx(01, 0e) : 0) ^ (i & 0x01 ? xx(00, 87) : 0) \ ) static const uint16_t gf128mul_table_bbe[256] = gf128mul_dat(xda_bbe); typedef unsigned char be128[16]; static void gf128mul_x_ble(be128 r, const be128 x) { uint64_t a, b, ra, rb; uint64_t _tt; GET_UINT64_LE(a, x, 0); GET_UINT64_LE(b, x, 8); _tt = gf128mul_table_bbe[b >> 63]; ra = (a << 1) ^ _tt; rb = (b << 1) | (a >> 63); PUT_UINT64_LE(ra, r, 0); PUT_UINT64_LE(rb, r, 8); } /* * AES-XEX buffer encryption/decryption */ int dis_aes_crypt_xex( AES_CONTEXT *crypt_ctx, AES_CONTEXT *tweak_ctx, int mode, size_t length, unsigned char *iv, const unsigned char *input, unsigned char *output ) { union xex_buf128 { uint8_t u8[16]; uint64_t u64[2]; }; union xex_buf128 scratch; union xex_buf128 t_buf; union xex_buf128 *inbuf; union xex_buf128 *outbuf; inbuf = (union xex_buf128*)input; outbuf = (union xex_buf128*)output; if( length % 16 ) return( -1 ); AES_ECB_ENC( tweak_ctx, AES_ENCRYPT, iv, t_buf.u8 ); goto first; do { gf128mul_x_ble( t_buf.u8, t_buf.u8 ); first: /* PP <- T xor P */ scratch.u64[0] = (uint64_t)( inbuf->u64[0] ^ t_buf.u64[0] ); scratch.u64[1] = (uint64_t)( inbuf->u64[1] ^ t_buf.u64[1] ); /* CC <- E(Key2,PP) */ AES_ECB_ENC( crypt_ctx, mode, scratch.u8, outbuf->u8 ); /* C <- T xor CC */ outbuf->u64[0] = (uint64_t)( outbuf->u64[0] ^ t_buf.u64[0] ); outbuf->u64[1] = (uint64_t)( outbuf->u64[1] ^ t_buf.u64[1] ); inbuf += 1; outbuf += 1; length -= 16; } while( length > 0 ); return( 0 ); } /* * AES-XTS buffer encryption/decryption */ int dis_aes_crypt_xts( AES_CONTEXT *crypt_ctx, AES_CONTEXT *tweak_ctx, int mode, size_t length, unsigned char *iv, const unsigned char *input, unsigned char *output ) { union xts_buf128 { uint8_t u8[16]; uint64_t u64[2]; }; union xts_buf128 scratch; union xts_buf128 cts_scratch; union xts_buf128 t_buf; union xts_buf128 cts_t_buf; union xts_buf128 *inbuf; union xts_buf128 *outbuf; size_t nb_blocks = length / 16; size_t remaining = length % 16; inbuf = (union xts_buf128*)input; outbuf = (union xts_buf128*)output; /* For performing the ciphertext-stealing operation, we have to get at least * one complete block */ if( length < 16 ) return( -1 ); AES_ECB_ENC( tweak_ctx, AES_ENCRYPT, iv, t_buf.u8 ); goto first; do { gf128mul_x_ble( t_buf.u8, t_buf.u8 ); first: /* PP <- T xor P */ scratch.u64[0] = (uint64_t)( inbuf->u64[0] ^ t_buf.u64[0] ); scratch.u64[1] = (uint64_t)( inbuf->u64[1] ^ t_buf.u64[1] ); /* CC <- E(Key2,PP) */ AES_ECB_ENC( crypt_ctx, mode, scratch.u8, outbuf->u8 ); /* C <- T xor CC */ outbuf->u64[0] = (uint64_t)( outbuf->u64[0] ^ t_buf.u64[0] ); outbuf->u64[1] = (uint64_t)( outbuf->u64[1] ^ t_buf.u64[1] ); inbuf += 1; outbuf += 1; nb_blocks -= 1; } while( nb_blocks > 0 ); /* Ciphertext stealing, if necessary */ if( remaining != 0 ) { outbuf = (union xts_buf128*)output; nb_blocks = length / 16; if( mode == AES_ENCRYPT ) { memcpy( cts_scratch.u8, (uint8_t*)&outbuf[nb_blocks], remaining ); memcpy( cts_scratch.u8 + remaining, ((uint8_t*)&outbuf[nb_blocks - 1]) + remaining, 16 - remaining ); memcpy( (uint8_t*)&outbuf[nb_blocks], (uint8_t*)&outbuf[nb_blocks - 1], remaining ); gf128mul_x_ble( t_buf.u8, t_buf.u8 ); /* PP <- T xor P */ scratch.u64[0] = (uint64_t)( cts_scratch.u64[0] ^ t_buf.u64[0] ); scratch.u64[1] = (uint64_t)( cts_scratch.u64[1] ^ t_buf.u64[1] ); /* CC <- E(Key2,PP) */ AES_ECB_ENC( crypt_ctx, mode, scratch.u8, scratch.u8 ); /* C <- T xor CC */ ( &outbuf[nb_blocks - 1] )->u64[0] = (uint64_t)( scratch.u64[0] ^ t_buf.u64[0] ); ( &outbuf[nb_blocks - 1] )->u64[1] = (uint64_t)( scratch.u64[1] ^ t_buf.u64[1] ); } else /* AES_DECRYPT */ { cts_t_buf.u64[0] = t_buf.u64[0]; cts_t_buf.u64[1] = t_buf.u64[1]; gf128mul_x_ble( t_buf.u8, t_buf.u8 ); /* PP <- T xor P */ scratch.u64[0] = (uint64_t)( outbuf[nb_blocks - 1].u64[0] ^ t_buf.u64[0] ); scratch.u64[1] = (uint64_t)( outbuf[nb_blocks - 1].u64[1] ^ t_buf.u64[1] ); /* CC <- E(Key2,PP) */ AES_ECB_ENC( crypt_ctx, mode, scratch.u8, scratch.u8 ); /* C <- T xor CC */ cts_scratch.u64[0] = (uint64_t)( scratch.u64[0] ^ t_buf.u64[0] ); cts_scratch.u64[1] = (uint64_t)( scratch.u64[1] ^ t_buf.u64[1] ); memcpy( (uint8_t*)&outbuf[nb_blocks - 1], (uint8_t*)&outbuf[nb_blocks], remaining ); memcpy( (uint8_t*)&outbuf[nb_blocks - 1] + remaining, cts_scratch.u8, 16 - remaining ); memcpy( (uint8_t*)&outbuf[nb_blocks], cts_scratch.u8, remaining ); /* PP <- T xor P */ scratch.u64[0] = (uint64_t)( ( &outbuf[nb_blocks - 1] )->u64[0] ^ cts_t_buf.u64[0] ); scratch.u64[1] = (uint64_t)( ( &outbuf[nb_blocks - 1] )->u64[1] ^ cts_t_buf.u64[1] ); /* CC <- E(Key2,PP) */ AES_ECB_ENC( crypt_ctx, mode, scratch.u8, scratch.u8 ); /* C <- T xor CC */ ( &outbuf[nb_blocks - 1] )->u64[0] = (uint64_t)( scratch.u64[0] ^ cts_t_buf.u64[0] ); ( &outbuf[nb_blocks - 1] )->u64[1] = (uint64_t)( scratch.u64[1] ^ cts_t_buf.u64[1] ); } } return( 0 ); } dislocker-0.7.3/src/encryption/crc32.c000066400000000000000000000165061375503125700175610ustar00rootroot00000000000000/* -*- 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. */ /* ============================================================= */ /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ /* code or tables extracted from it, as desired without restriction. */ /* */ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ /* polynomial $edb88320 */ /* */ /* -------------------------------------------------------------------- */ static unsigned int crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; /* * Return a 32-bit CRC of the contents of the buffer. */ unsigned int crc32(const unsigned char *s, const unsigned int len) { unsigned int loop; unsigned int result; result = ~ (unsigned) 0; for(loop = 0; loop < len; loop++) result = crc32_tab[(result ^ s[loop]) & 0xff] ^ (result >> 8); return ~result; } dislocker-0.7.3/src/encryption/decrypt.c000066400000000000000000000303611375503125700203120ustar00rootroot00000000000000/* -*- 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 "dislocker/common.h" #include "dislocker/encryption/diffuser.h" #include "dislocker/encryption/decrypt.h" #include "dislocker/encryption/encommon.priv.h" /* * Two functions used by decrypt_key */ static int aes_ccm_encrypt_decrypt( AES_CONTEXT* ctx, unsigned char* iv, unsigned char iv_length, unsigned char* input, unsigned int input_length, unsigned char* mac, unsigned int mac_size, unsigned char* output ); static int aes_ccm_compute_unencrypted_tag( AES_CONTEXT* ctx, unsigned char* iv, unsigned char iv_length, unsigned char* buffer, unsigned int buffer_length, unsigned char* mac ); /** * In order to decrypt keys as VMK or FVEK, use this function * * @param input The AES encrypted buffer to decrypt * @param key The key to decrypt the input buffer (already extracted from a datum_key_t structure) * @param output The decrypted result * @param output_size The size of the decrypted result * @return TRUE if result can be trusted, FALSE otherwise */ int decrypt_key( unsigned char* input, unsigned int input_size, unsigned char* mac, unsigned char* nonce, unsigned char* key, unsigned int keybits, void** output) { // Check parameters if(!input || !mac || !nonce || !key || !output) return FALSE; AES_CONTEXT ctx; uint8_t mac_first [AUTHENTICATOR_LENGTH]; uint8_t mac_second[AUTHENTICATOR_LENGTH]; /* * Allocate output buffer */ *output = dis_malloc(input_size); memset(*output, 0, input_size); /* * Get the MAC */ memcpy(mac_first, mac, AUTHENTICATOR_LENGTH); /* * Set key which is used to decrypt (already extracted from a datum_key_t structure) */ AES_SETENC_KEY(&ctx, key, keybits); /* * Decrypt the input buffer now * NOTE: The 0xc is the nonce length (hardcoded) */ dis_printf(L_DEBUG, "}--------[ Data passed to aes_ccm_encrypt_decrypt ]--------{\n"); dis_printf(L_DEBUG, "-- Nonce:\n"); hexdump(L_DEBUG, nonce, 0xc); dis_printf(L_DEBUG, "-- Input buffer:\n"); hexdump(L_DEBUG, input, input_size); dis_printf(L_DEBUG, "-- MAC:\n"); hexdump(L_DEBUG, mac_first, AUTHENTICATOR_LENGTH); dis_printf(L_DEBUG, "}----------------------------------------------------------{\n"); aes_ccm_encrypt_decrypt( &ctx, nonce, 0xc, input, input_size, mac_first, AUTHENTICATOR_LENGTH, (unsigned char*) *output ); /* * Compute to check decryption */ memset(mac_second, 0, AUTHENTICATOR_LENGTH); aes_ccm_compute_unencrypted_tag( &ctx, nonce, 0xc, (unsigned char*) *output, input_size, mac_second ); memset(&ctx, 0, sizeof(AES_CONTEXT)); /* * Check if the MACs correspond, if not, * we didn't decrypt correctly the input buffer */ dis_printf(L_DEBUG, "Looking if MACs match...\n"); dis_printf(L_DEBUG, "They are just below:\n"); hexdump(L_DEBUG, mac_first, AUTHENTICATOR_LENGTH); hexdump(L_DEBUG, mac_second, AUTHENTICATOR_LENGTH); if(memcmp(mac_first, mac_second, AUTHENTICATOR_LENGTH) != 0) { dis_printf(L_ERROR, "The MACs don't match.\n"); return FALSE; } dis_printf(L_DEBUG, "Ok, they match!\n"); memset(mac_first, 0, AUTHENTICATOR_LENGTH); memset(mac_second, 0, AUTHENTICATOR_LENGTH); return TRUE; } /** * Internal function to decrypt keys * * @param ctx AES context * @param iv Initializing Vector * @param iv_length Length of the Initializing Vector * @param input Crypted input buffer * @param input_length Input buffer length * @param output Decrypted result * @return TRUE if result can be trusted, FALSE otherwise */ static int aes_ccm_encrypt_decrypt( AES_CONTEXT* ctx, unsigned char* nonce, unsigned char nonce_length, unsigned char* input, unsigned int input_length, unsigned char* mac, unsigned int mac_length, unsigned char* output) { // Check parameters if(!ctx || !input || !mac || !output) return FALSE; dis_printf(L_DEBUG, "Entering aes_ccm_encrypt_decrypt...\n"); unsigned char iv[16]; unsigned int loop = 0; unsigned char tmp_buf[16] = {0,}; unsigned char* failsafe = NULL; /* * Here is how the counter works in microsoft compatible ccm implementation: * * - User supplies a less than 16 bytes and more than 12 bytes iv * * - Copy it in order to form this format: * 15-iv_length-1 (1 byte) | iv (max 14 bytes) | counter counting from zero (from 1 to 3 byte) * * - Apply counter mode of aes * * (thanks to Kumar and Kumar for these explanations) */ memset(iv, 0, sizeof(iv)); memcpy(iv + 1, nonce, (nonce_length % sizeof(iv))); if(15 - nonce_length - 1 < 0) return FALSE; *iv = (unsigned char)(15 - nonce_length - 1); AES_ECB_ENC(ctx, AES_ENCRYPT, iv, tmp_buf); dis_printf(L_DEBUG, "\tTmp buffer:\n"); hexdump(L_DEBUG, tmp_buf, 16); dis_printf(L_DEBUG, "\tInput:\n"); hexdump(L_DEBUG, mac, mac_length); xor_buffer(mac, tmp_buf, NULL, mac_length); dis_printf(L_DEBUG, "\tOutput:\n"); hexdump(L_DEBUG, mac, mac_length); /* Increment the internal iv counter */ iv[15] = 1; if(input_length > sizeof(iv)) { loop = input_length >> 4; dis_printf(L_DEBUG, "Input length: %d, loop: %d\n", input_length, loop); do { AES_ECB_ENC(ctx, AES_ENCRYPT, iv, tmp_buf); xor_buffer(input, tmp_buf, output, sizeof(iv)); iv[15]++; /* A failsafe to not have the same iv twice */ if(!iv[15]) { failsafe = &iv[15]; do { failsafe--; (*failsafe)++; } while(*failsafe == 0 && failsafe >= &iv[0]); } input += sizeof(iv); output += sizeof(iv); input_length = (unsigned int)(input_length - sizeof(iv)); } while(--loop); } dis_printf(L_DEBUG, "Input length remain: %d\n", input_length); /* * Last block */ if(input_length) { AES_ECB_ENC(ctx, AES_ENCRYPT, iv, tmp_buf); xor_buffer(input, tmp_buf, output, input_length); } /* Cleanup */ memset(iv, 0, sizeof(iv)); memset(tmp_buf, 0, sizeof(tmp_buf)); dis_printf(L_DEBUG, "Ending aes_ccm_encrypt_decrypt successfully!\n"); return TRUE; } /** * Function to validate decryption * * @param ctx AES context * @param iv Initializing Vector * @param iv_length Length of the Initializing Vector * @param buffer Data buffer * @param buffer_length Data buffer length * @param mac MAC result to use to validate decryption * @return TRUE if result can be trusted, FALSE otherwise */ static int aes_ccm_compute_unencrypted_tag( AES_CONTEXT* ctx, unsigned char* nonce, unsigned char nonce_length, unsigned char* buffer, unsigned int buffer_length, unsigned char* mac) { // Check parameters if(!ctx || !buffer || !mac || nonce_length > 0xe) return FALSE; dis_printf(L_DEBUG, "Entering aes_ccm_compute_unencrypted_tag...\n"); unsigned char iv[AUTHENTICATOR_LENGTH]; unsigned int loop = 0; unsigned int tmp_size = buffer_length; /* * Construct the IV */ memset(iv, 0, AUTHENTICATOR_LENGTH); iv[0] = ((unsigned char)(0xe - nonce_length)) | ((AUTHENTICATOR_LENGTH - 2) & 0xfe) << 2; memcpy(iv + 1, nonce, (nonce_length % AUTHENTICATOR_LENGTH)); for(loop = 15; loop > nonce_length; --loop) { *(iv + loop) = tmp_size & 0xff; tmp_size = tmp_size >> 8; } /* * Compute algorithm */ AES_ECB_ENC(ctx, AES_ENCRYPT, iv, iv); if(buffer_length > 16) { loop = buffer_length >> 4; do { dis_printf(L_DEBUG, "\tBuffer:\n"); hexdump(L_DEBUG, buffer, 16); dis_printf(L_DEBUG, "\tInternal IV:\n"); hexdump(L_DEBUG, iv, 16); xor_buffer(iv, buffer, NULL, AUTHENTICATOR_LENGTH); AES_ECB_ENC(ctx, AES_ENCRYPT, iv, iv); buffer += AUTHENTICATOR_LENGTH; buffer_length -= AUTHENTICATOR_LENGTH; } while(--loop); } /* * Last block */ if(buffer_length) { xor_buffer(iv, buffer, NULL, buffer_length); AES_ECB_ENC(ctx, AES_ENCRYPT, iv, iv); } memcpy(mac, iv, AUTHENTICATOR_LENGTH); memset(iv, 0, AUTHENTICATOR_LENGTH); dis_printf(L_DEBUG, "Ending aes_ccm_compute_unencrypted_tag successfully!\n"); return TRUE; } /** * Interface to decrypt a sector * * @param crypt Data needed by the decryption to deal with encrypted data * @param sector The sector to decrypt * @param sector_address Address of the sector to decrypt * @param buffer The place where we have to put decrypted data * @return TRUE if result can be trusted, FALSE otherwise */ int decrypt_sector(dis_crypt_t crypt, uint8_t* sector, off_t sector_address, uint8_t* buffer) { // Check parameters if(!crypt || !sector || !buffer) return FALSE; crypt->decrypt_fn( &crypt->ctx, crypt->sector_size, sector, sector_address, buffer ); return TRUE; } /** * Decrypt a sector which was not encrypted with the diffuser * * @param ctx AES's contexts * @param sector_size Size of a sector (in bytes) * @param sector The sector to decrypt * @param sector_address Address of the sector to decrypt * @param buffer The place where we have to put decrypted data */ void decrypt_cbc_without_diffuser(dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer) { /* Parameters are assumed to be correctly checked already */ union { unsigned char multi[16]; off_t single; } iv; memset(iv.multi, 0, 16); /* Create the iv */ iv.single = sector_address; AES_ECB_ENC(&ctx->FVEK_E_ctx, AES_ENCRYPT, iv.multi, iv.multi); /* Actually decrypt data */ AES_CBC(&ctx->FVEK_D_ctx, AES_DECRYPT, sector_size, iv.multi, sector, buffer); } /** * Decrypt a sector which was encrypted with the diffuser enabled * * @param ctx AES's contexts * @param sector_size Size of a sector (in bytes) * @param sector The sector to decrypt * @param sector_address Address of the sector to decrypt * @param buffer The place where we have to put decrypted data */ void decrypt_cbc_with_diffuser(dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer) { /* Parameters are assumed to be correctly checked already */ union { uint8_t multi[16]; off_t single; } iv; memset(iv.multi, 0, 16); uint8_t sector_key[32] = {0,}; int loop = 0; /* First, create the sector key */ iv.single = sector_address; AES_ECB_ENC(&ctx->TWEAK_E_ctx, AES_ENCRYPT, iv.multi, sector_key); /* For iv unicity reason... */ iv.multi[15] = 0x80; AES_ECB_ENC(&ctx->TWEAK_E_ctx, AES_ENCRYPT, iv.multi, §or_key[16]); /* Then actually decrypt the buffer */ decrypt_cbc_without_diffuser(ctx, sector_size, sector, sector_address, buffer); /* Call diffuser B */ diffuserB_decrypt(buffer, sector_size, (uint32_t*)buffer); /* Afterward, call diffuser A */ diffuserA_decrypt(buffer, sector_size, (uint32_t*)buffer); /* And finally, apply the sector key */ for(loop = 0; loop < sector_size; ++loop) buffer[loop] ^= sector_key[loop % 32]; memset(sector_key, 0, 32); } /** * Decrypt a sector which was encrypted with AES-XTS * * @param ctx AES's contexts * @param sector_size Size of a sector (in bytes) * @param sector The sector to decrypt * @param sector_address Address of the sector to decrypt * @param buffer The place where we have to put decrypted data */ void decrypt_xts( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer) { /* Parameters are assumed to be correctly checked already */ union { unsigned char multi[16]; off_t single; } iv; /* Create the iv */ memset(iv.multi, 0, 16); iv.single = sector_address / sector_size; AES_XTS( &ctx->FVEK_D_ctx, &ctx->TWEAK_E_ctx, AES_DECRYPT, sector_size, iv.multi, sector, buffer ); } dislocker-0.7.3/src/encryption/diffuser.c000066400000000000000000000121721375503125700204470ustar00rootroot00000000000000/* -*- 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 #include "dislocker/encryption/diffuser.h" #define ROTATE_LEFT(a,n) (((a) << (n)) | ((a) >> ((sizeof(a) * 8)-(n)))) #define ROTATE_RIGHT(a,n) (((a) >> (n)) | ((a) << ((sizeof(a) * 8)-(n)))) /** * Implement diffuser A's decryption algorithm as explained by Niels Ferguson * @warning sector and buffer should not overlap * * @param sector The sector to de-diffuse * @param sector_size The size of the sector (in bytes) * @param buffer The resulted de-diffused data */ void diffuserA_decrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer) { int i = 0; int Acycles = 5; uint16_t Ra[] = {9, 0, 13, 0}; /* buffer is a pointer on a 4 bytes object */ uint16_t int_size = sector_size / 4; /* Use buffer for the algorithm */ if((uint8_t*)buffer != sector) memcpy(buffer, sector, sector_size); while(Acycles) { for(i = 0; i < int_size; ++i) { *(buffer + i) = *(buffer + i) + // d[i] + ( /* Remember that, for instance, -5 % 2 yields -1, not 1 as expected */ *(buffer + ((i-2 + int_size) % int_size)) ^ // d[i-2] xor ROTATE_LEFT(*(buffer + ((i-5 + int_size) % int_size)), Ra[i % 4]) // ROTATE_LEFT(d[i-5], Ra[i mod 4]) ); } Acycles--; } } /** * Implement diffuser B's decryption algorithm as explained by Niels Ferguson * @warning sector and buffer should not overlap * * @param sector The sector to de-diffuse * @param sector_size The size of the sector (in bytes) * @param buffer The resulted de-diffused data */ void diffuserB_decrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer) { int i = 0; int Bcycles = 3; uint16_t Rb[] = {0, 10, 0, 25}; /* buffer is a pointer on a 4 bytes object */ uint16_t int_size = sector_size / 4; /* Use buffer for the algorithm */ if((uint8_t*)buffer != sector) memcpy(buffer, sector, sector_size); while(Bcycles) { for(i = 0; i < int_size; ++i) { *(buffer+i) = *(buffer + i) + // d[i] + ( *(buffer + ((i+2) % int_size)) ^ // d[i+2] xor ROTATE_LEFT(*(buffer + ((i+5) % int_size)), Rb[i % 4]) // ROTATE_LEFT(d[i+5], Rb[i mod 4]) ); } Bcycles--; } } /** * Implement diffuser A's encryption algorithm as explained by Niels Ferguson * @warning sector and buffer should not overlap * * @param sector The sector to diffuse * @param sector_size The size of the sector (in bytes) * @param buffer The resulted diffused data */ void diffuserA_encrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer) { int i = 0; int Acycles = 5; uint16_t Ra[] = {9, 0, 13, 0}; /* buffer is a pointer on a 4 bytes object */ uint16_t int_size = sector_size / 4; /* Use buffer for the algorithm */ if((uint8_t*)buffer != sector) memcpy(buffer, sector, sector_size); while(Acycles) { for(i = int_size - 1; i >= 0; --i) { *(buffer + i) = *(buffer + i) - // d[i] - ( /* Remember that, for instance, -5 % 2 yields -1, not 1 as expected */ *(buffer + ((i-2 + int_size) % int_size)) ^ // d[i-2] xor ROTATE_LEFT(*(buffer + ((i-5 + int_size) % int_size)), Ra[i % 4]) // ROTATE_LEFT(d[i-5], Ra[i mod 4]) ); } Acycles--; } } /** * Implement diffuser B's encryption algorithm as explained by Niels Ferguson * @warning sector and buffer should not overlap * * @param sector The sector to diffuse * @param sector_size The size of the sector (in bytes) * @param buffer The resulted diffused data */ void diffuserB_encrypt(uint8_t* sector, uint16_t sector_size, uint32_t* buffer) { int i = 0; int Bcycles = 3; uint16_t Rb[] = {0, 10, 0, 25}; /* buffer is a pointer on a 4 bytes object */ uint16_t int_size = sector_size >> 2; /* Use buffer for the algorithm */ if((uint8_t*)buffer != sector) memcpy(buffer, sector, sector_size); while(Bcycles) { for(i = int_size - 1; i >= 0; --i) { *(buffer+i) = *(buffer + i) - // d[i] - ( *(buffer + ((i+2) % int_size)) ^ // d[i+2] xor ROTATE_LEFT(*(buffer + ((i+5) % int_size)), Rb[i % 4]) // ROTATE_LEFT(d[i+5], Rb[i mod 4]) ); } Bcycles--; } } dislocker-0.7.3/src/encryption/encommon.c000066400000000000000000000075231375503125700204570ustar00rootroot00000000000000/* -*- 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 #include "dislocker/return_values.h" #include "dislocker/xstd/xstdio.h" #include "dislocker/xstd/xstdlib.h" #include "dislocker/encryption/encrypt.h" #include "dislocker/encryption/decrypt.h" #include "dislocker/encryption/encommon.priv.h" #include /** * Create "an object" of type dis_crypt_t * * @param sector_size The sector size is needed for various operations. It's the * size to be used for decrypting the disc as it's encrypted sector by sector. * @param disk_cipher Indicate the encryption used on the disk for data. * @return The newly allocated dis_crypt_t "object". */ dis_crypt_t dis_crypt_new(uint16_t sector_size, cipher_t disk_cipher) { dis_crypt_t crypt = dis_malloc(sizeof(struct _dis_crypt)); memset(crypt, 0, sizeof(struct _dis_crypt)); crypt->sector_size = sector_size; if(disk_cipher == AES_128_DIFFUSER || disk_cipher == AES_256_DIFFUSER) { crypt->flags |= DIS_ENC_FLAG_USE_DIFFUSER; crypt->encrypt_fn = encrypt_cbc_with_diffuser; crypt->decrypt_fn = decrypt_cbc_with_diffuser; } else if(disk_cipher == AES_XTS_128 || disk_cipher == AES_XTS_256) { crypt->encrypt_fn = encrypt_xts; crypt->decrypt_fn = decrypt_xts; } else { crypt->encrypt_fn = encrypt_cbc_without_diffuser; crypt->decrypt_fn = decrypt_cbc_without_diffuser; } return crypt; } int dis_crypt_set_fvekey(dis_crypt_t crypt, uint16_t algorithm, uint8_t* fvekey) { if(!crypt || !fvekey) return DIS_RET_ERROR_DISLOCKER_INVAL; switch(algorithm) { case AES_128_DIFFUSER: AES_SETENC_KEY(&crypt->ctx.TWEAK_E_ctx, fvekey + 0x20, 128); AES_SETDEC_KEY(&crypt->ctx.TWEAK_D_ctx, fvekey + 0x20, 128); // fall through case AES_128_NO_DIFFUSER: AES_SETENC_KEY(&crypt->ctx.FVEK_E_ctx, fvekey, 128); AES_SETDEC_KEY(&crypt->ctx.FVEK_D_ctx, fvekey, 128); return DIS_RET_SUCCESS; case AES_256_DIFFUSER: AES_SETENC_KEY(&crypt->ctx.TWEAK_E_ctx, fvekey + 0x20, 256); AES_SETDEC_KEY(&crypt->ctx.TWEAK_D_ctx, fvekey + 0x20, 256); // fall through case AES_256_NO_DIFFUSER: AES_SETENC_KEY(&crypt->ctx.FVEK_E_ctx, fvekey, 256); AES_SETDEC_KEY(&crypt->ctx.FVEK_D_ctx, fvekey, 256); return DIS_RET_SUCCESS; case AES_XTS_128: AES_SETENC_KEY(&crypt->ctx.FVEK_E_ctx, fvekey, 128); AES_SETDEC_KEY(&crypt->ctx.FVEK_D_ctx, fvekey, 128); AES_SETENC_KEY(&crypt->ctx.TWEAK_E_ctx, fvekey + 0x10, 128); AES_SETDEC_KEY(&crypt->ctx.TWEAK_D_ctx, fvekey + 0x10, 128); return DIS_RET_SUCCESS; case AES_XTS_256: AES_SETENC_KEY(&crypt->ctx.FVEK_E_ctx, fvekey, 256); AES_SETDEC_KEY(&crypt->ctx.FVEK_D_ctx, fvekey, 256); AES_SETENC_KEY(&crypt->ctx.TWEAK_E_ctx, fvekey + 0x20, 256); AES_SETDEC_KEY(&crypt->ctx.TWEAK_D_ctx, fvekey + 0x20, 256); return DIS_RET_SUCCESS; default: dis_printf(L_WARNING, "Algo not supported: %#hx\n", algorithm); break; } return DIS_RET_ERROR_CRYPTO_ALGORITHM_UNSUPPORTED; } void dis_crypt_destroy(dis_crypt_t crypt) { if(crypt) dis_free(crypt); } dislocker-0.7.3/src/encryption/encrypt.c000066400000000000000000000111241375503125700203200ustar00rootroot00000000000000/* -*- 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 "dislocker/common.h" #include "dislocker/encryption/diffuser.h" #include "dislocker/encryption/encrypt.h" #include "dislocker/encryption/encommon.priv.h" /** * Interface to encrypt a sector * * @param crypt Data needed by the encryption to deal with encrypted data * @param sector The sector to encrypt * @param sector_address The address of the sector to encrypt * @param buffer The place where we have to put encrypted data * @return TRUE if result can be trusted, FALSE otherwise */ int encrypt_sector(dis_crypt_t crypt, uint8_t* sector, off_t sector_address, uint8_t* buffer) { // Check parameters if(!crypt || !sector || !buffer) return FALSE; crypt->encrypt_fn( &crypt->ctx, crypt->sector_size, sector, sector_address, buffer ); return TRUE; } /** * Encrypt a sector whithout the diffuser * * @param ctx AES's contexts * @param sector_size Size of a sector (in bytes) * @param sector The sector to encrypt * @param sector_address Address of the sector to encrypt * @param buffer The place where we have to put encrypted data */ void encrypt_cbc_without_diffuser(dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer) { /* Parameters are assumed to be correctly checked already */ union { unsigned char multi[16]; off_t single; } iv; memset(iv.multi, 0, 16); /* Create the iv */ iv.single = sector_address; AES_ECB_ENC(&ctx->FVEK_E_ctx, AES_ENCRYPT, iv.multi, iv.multi); /* Actually encrypt data */ AES_CBC(&ctx->FVEK_E_ctx, AES_ENCRYPT, sector_size, iv.multi, sector, buffer); } /** * Encrypt a sector when the diffuser is enabled * * @param ctx AES's contexts * @param sector_size Size of a sector (in bytes) * @param sector The sector to encrypt * @param sector_address Address of the sector to encrypt * @param buffer The place where we have to put encrypted data */ void encrypt_cbc_with_diffuser(dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer) { /* Parameters are assumed to be correctly checked already */ union { uint8_t multi[16]; off_t single; } iv; memset(iv.multi, 0, 16); uint8_t sector_key[32] = {0,}; int loop = 0; /* First, create the sector key */ iv.single = sector_address; AES_ECB_ENC(&ctx->TWEAK_E_ctx, AES_ENCRYPT, iv.multi, sector_key); /* For iv unicity reason... */ iv.multi[15] = 0x80; AES_ECB_ENC(&ctx->TWEAK_E_ctx, AES_ENCRYPT, iv.multi, §or_key[16]); memcpy(buffer, sector, sector_size); /* Then apply the sector key */ for(loop = 0; loop < sector_size; ++loop) buffer[loop] ^= sector_key[loop % 32]; /* Afterward, call diffuser A */ diffuserA_encrypt(buffer, sector_size, (uint32_t*)buffer); /* Call diffuser B */ diffuserB_encrypt(buffer, sector_size, (uint32_t*)buffer); /* And finally, actually encrypt the buffer */ encrypt_cbc_without_diffuser(ctx, sector_size, buffer, sector_address, buffer); memset(sector_key, 0, 32); } /** * Encrypt a sector when the diffuser is enabled * * @param ctx AES's contexts * @param sector_size Size of a sector (in bytes) * @param sector The sector to encrypt * @param sector_address Address of the sector to encrypt * @param buffer The place where we have to put encrypted data */ void encrypt_xts( dis_aes_contexts_t* ctx, uint16_t sector_size, uint8_t* sector, off_t sector_address, uint8_t* buffer) { /* Parameters are assumed to be correctly checked already */ union { unsigned char multi[16]; off_t single; } iv; /* Create the iv */ memset(iv.multi, 0, 16); iv.single = sector_address / sector_size; AES_XTS( &ctx->FVEK_E_ctx, &ctx->TWEAK_E_ctx, AES_ENCRYPT, sector_size, iv.multi, sector, buffer ); } dislocker-0.7.3/src/inouts/000077500000000000000000000000001375503125700156205ustar00rootroot00000000000000dislocker-0.7.3/src/inouts/inouts.c000066400000000000000000000056031375503125700173110ustar00rootroot00000000000000/* -*- 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 "dislocker/inouts/sectors.h" #include "dislocker/inouts/inouts.priv.h" #include "dislocker/dislocker.priv.h" #include "dislocker/config.priv.h" /** * Getting the real volume size is proving to be quite difficult. */ static uint64_t get_volume_size(dis_context_t dis_ctx); /** * Get the volume's size. It's retrieved from the FVE volume's boot record or * the NTFS volume's boot record. */ uint64_t dis_inouts_volume_size(dis_context_t dis_ctx) { if(!dis_ctx) return 0; if(dis_ctx->io_data.volume_size) return dis_ctx->io_data.volume_size; return get_volume_size(dis_ctx); } /** * Compute the real volume's size. * * @param dis_ctx The dislocker structure * @return The volume size or 0 if it can't be determined */ static uint64_t get_volume_size(dis_context_t dis_ctx) { uint64_t volume_size = 0; void* old_vbr = NULL; uint16_t sector_size = dis_inouts_sector_size(dis_ctx); volume_size = dis_metadata_volume_size_from_vbr(dis_ctx->metadata); if(!volume_size && dis_metadata_information_version(dis_ctx->metadata) == 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 = dis_malloc(sector_size); memset(input, 0, sector_size); if(!read_decrypt_sectors(&dis_ctx->io_data, 1, sector_size, 0, input)) { dis_printf(L_ERROR, "Unable to read the NTFS header to get the volume's size\n"); return 0; } old_vbr = dis_metadata_set_volume_header(dis_ctx->metadata, input); volume_size = dis_metadata_volume_size_from_vbr(dis_ctx->metadata); dis_metadata_set_volume_header(dis_ctx->metadata, old_vbr); dis_free(input); } return volume_size; } uint16_t dis_inouts_sector_size(dis_context_t dis_ctx) { if(!dis_ctx) return 0; if(dis_ctx->io_data.sector_size) return dis_ctx->io_data.sector_size; dis_ctx->io_data.sector_size = dis_metadata_sector_size(dis_ctx->metadata); return dis_ctx->io_data.sector_size; } dislocker-0.7.3/src/inouts/prepare.c000066400000000000000000000100431375503125700174200ustar00rootroot00000000000000/* -*- 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 #include #include "dislocker/inouts/prepare.h" #include "dislocker/inouts/sectors.h" #include "dislocker/inouts/inouts.priv.h" #include "dislocker/dislocker.priv.h" #include "dislocker/return_values.h" /** * Initialize data decryption keys * * @param dataset BitLocker dataset * @param fvek The entire 32 bytes FVEK, without the KEY structure * @param crypt Crypto structure to decrypt sectors * @return TRUE if result can be trusted, FALSE otherwise */ int init_keys(bitlocker_dataset_t* dataset, datum_key_t* fvek_datum, dis_crypt_t crypt) { // Check parameters if(!dataset || !fvek_datum || !crypt) return DIS_RET_ERROR_DISLOCKER_INVAL; uint8_t* fvek = NULL; size_t size_fvek = 0; if(!get_payload_safe(fvek_datum, (void**)&fvek, &size_fvek)) { dis_printf(L_ERROR, "Can't get the FVEK datum payload. Abort.\n"); return DIS_RET_ERROR_DISLOCKER_INVAL; } dis_printf(L_DEBUG, "FVEK -----------------------------------------------------\n"); hexdump(L_DEBUG, fvek, size_fvek); dis_printf(L_DEBUG, "----------------------------------------------------------\n"); /* * It shouldn't be necessary as the algorithms should be the same, but * still, we have a choice, so we do both */ uint16_t algo[3] = {dataset->algorithm, fvek_datum->algo, 0}; uint16_t* palgo = algo; while(*palgo != 0) { if(dis_crypt_set_fvekey(crypt, *palgo, fvek) == DIS_RET_SUCCESS) { memclean(fvek, size_fvek); return DIS_RET_SUCCESS; } palgo++; } dis_printf(L_ERROR, "Dataset's and FVEK's algorithms not supported: %#hx and %#hx\n", dataset->algorithm, fvek_datum->algo); memclean(fvek, size_fvek); return DIS_RET_ERROR_CRYPTO_ALGORITHM_UNSUPPORTED; } /** * Prepare a structure which hold data used for decryption/encryption * * @param dis_ctx The dislocker context used everywhere. * @return TRUE if result can be trusted, FALSE otherwise */ int prepare_crypt(dis_context_t dis_ctx) { dis_iodata_t* io_data; if(!dis_ctx) return DIS_RET_ERROR_DISLOCKER_INVAL; io_data = &dis_ctx->io_data; io_data->metadata = dis_ctx->metadata; io_data->part_off = dis_ctx->cfg.offset; io_data->sector_size = dis_inouts_sector_size(dis_ctx); io_data->decrypt_region = read_decrypt_sectors; io_data->encrypt_region = encrypt_write_sectors; io_data->encrypted_volume_size = dis_metadata_encrypted_volume_size(io_data->metadata); io_data->backup_sectors_addr = dis_metadata_ntfs_sectors_address(io_data->metadata); io_data->nb_backup_sectors = dis_metadata_backup_sectors_count(io_data->metadata); /* * Get volume size directly from dis_metadata_t, which is more accurate. */ io_data->volume_size = io_data->encrypted_volume_size; if(io_data->volume_size == 0) { dis_printf(L_ERROR, "Can't initialize the volume's size\n"); return DIS_RET_ERROR_VOLUME_SIZE_NOT_FOUND; } dis_printf( L_INFO, "Found volume's size: 0x%1$" PRIx64 " (%1$" PRIu64 ") bytes\n", io_data->volume_size ); /* * Don't initialize the mftmirror_backup field for it's the same as the * backup_sectors_addr one. */ return DIS_RET_SUCCESS; } dislocker-0.7.3/src/inouts/sectors.c000066400000000000000000000353721375503125700174600ustar00rootroot00000000000000/* -*- 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. */ #define _GNU_SOURCE 1 #include #include #include "dislocker/common.h" #include "dislocker/return_values.h" #include "dislocker/encryption/decrypt.h" #include "dislocker/encryption/encrypt.h" #include "dislocker/metadata/metadata.h" #include "dislocker/inouts/inouts.priv.h" /* * Number of thread you want to run for enc/decryption * NOTE: FUSE uses its own threads so the FUSE's functions can be called in * parallel. Use the environment variable FUSE_MAX_WORKERS to change the * FUSE's threads number. */ #define NB_THREAD 0 // Have a look at sysconf(_SC_NPROCESSORS_ONLN) // Note: 512*NB_THREAD shouldn't be more than 2^16 (due to used types) /* Struct we pass to a thread for buffer enc/decryption */ typedef struct _thread_arg { size_t nb_loop; uint16_t nb_threads; unsigned int thread_begin; uint16_t sector_size; off_t sector_start; uint8_t* input; uint8_t* output; dis_iodata_t* io_data; } thread_arg_t; /** 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* io_data, off_t sector_address, uint8_t *input, 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 ); /** * Read and decrypt one or more sectors * @warning The sector_start has to be correctly aligned * * @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 * above * @param output The output buffer where to put decrypted data * @return TRUE if result can be trusted, FALSE otherwise */ 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(!io_data || !output) return FALSE; size_t nb_loop = 0; size_t size = nb_read_sector * sector_size; uint8_t* input = malloc(size); off_t off = sector_start + io_data->part_off; memset(input , 0, size); memset(output, 0, size); /* Read the sectors we need */ ssize_t read_size = pread(io_data->volume_fd, input, size, off); if(read_size <= 0) { free(input); dis_printf( L_ERROR, "Unable to read %#" F_SIZE_T " bytes from %#" F_OFF_T "\n", size, off ); return FALSE; } /* * We are assuming that we always have a "sector size" multiple disk length * Can this assumption be wrong? I don't think so :) */ nb_loop = (size_t) read_size / sector_size; /* Run threads if compiled with */ #if NB_THREAD > 0 { /* Threads preparations */ pthread_t thread[NB_THREAD]; thread_arg_t args[NB_THREAD]; unsigned int loop = 0; for(loop = 0; loop < NB_THREAD; ++loop) { args[loop].nb_loop = nb_loop; args[loop].nb_threads = NB_THREAD; args[loop].thread_begin = loop; args[loop].sector_size = sector_size; args[loop].sector_start = sector_start; args[loop].input = input; args[loop].output = output; args[loop].io_data = io_data; pthread_create( &thread[loop], NULL, thread_decrypt, (void*) &args[loop] ); } /* Wait for threads to end */ for(loop = 0; loop < NB_THREAD; ++loop) pthread_join(thread[loop], NULL); } #else { thread_arg_t arg; arg.nb_loop = nb_loop; arg.nb_threads = 1; arg.thread_begin = 0; arg.sector_size = sector_size; arg.sector_start = sector_start; arg.input = input; arg.output = output; arg.io_data = io_data; thread_decrypt(&arg); } #endif free(input); return TRUE; } /** * Encrypt and write one or more sectors * @warning The sector_start has to be correctly aligned * * @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 * above * @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( dis_iodata_t* io_data, size_t nb_write_sector, uint16_t sector_size, off_t sector_start, uint8_t* input) { // Check parameter if(!io_data || !input) return FALSE; uint8_t* output = malloc(nb_write_sector * sector_size); memset(output , 0, nb_write_sector * sector_size); /* Run threads if compiled with */ #if NB_THREAD > 0 { /* Threads preparations */ pthread_t thread[NB_THREAD]; thread_arg_t args[NB_THREAD]; unsigned int loop = 0; for(loop = 0; loop < NB_THREAD; ++loop) { args[loop].nb_loop = nb_write_sector; args[loop].nb_threads = NB_THREAD; args[loop].thread_begin = loop; args[loop].sector_size = sector_size; args[loop].sector_start = sector_start; args[loop].input = input; args[loop].output = output; args[loop].io_data = io_data; pthread_create( &thread[loop], NULL, thread_encrypt, (void*) &args[loop] ); } /* Wait for threads to end */ for(loop = 0; loop < NB_THREAD; ++loop) pthread_join(thread[loop], NULL); } #else { thread_arg_t arg; arg.nb_loop = nb_write_sector; arg.nb_threads = 1; arg.thread_begin = 0; arg.sector_size = sector_size; arg.sector_start = sector_start; arg.input = input; arg.output = output; arg.io_data = io_data; thread_encrypt(&arg); } #endif /* Write the sectors we want */ ssize_t write_size = pwrite( io_data->volume_fd, output, nb_write_sector * sector_size, sector_start + io_data->part_off ); free(output); if(write_size <= 0) return FALSE; return TRUE; } /** * Decrypt a sector region according to one or more thread * * @param params The structure used for thread parameters storage */ static void* thread_decrypt(void* params) { if(!params) return NULL; thread_arg_t* args = (thread_arg_t*) params; dis_iodata_t* io_data = args->io_data; off_t loop = args->thread_begin; uint16_t step_unit = args->nb_threads; int hover = 0; uint16_t version = dis_metadata_information_version(io_data->metadata); uint16_t sector_size = args->sector_size; uint16_t step_size = (uint16_t) (sector_size * step_unit); off_t offset = args->sector_start + sector_size * loop; uint8_t* loop_input = args->input + sector_size * loop; uint8_t* loop_output = args->output + sector_size * loop; for( ; loop < (off_t)args->nb_loop; loop += step_unit, offset += step_size, loop_input += step_size, loop_output += step_size) { /* * For BitLocker-encrypted volume with W$ 7/8: * - Don't decrypt the firsts sectors whatever might be the case, they * are saved elsewhere anyway. * For these encrypted with W$ Vista: * - Change the first sector. * For both of them: * - Zero out the metadata area returned to the user (not the one on * the disk, obviously). * - Don't decrypt sectors if we're outside the encrypted-volume's * size (but still in the volume's size obv). This is needed when the * encryption was paused during BitLocker's turn on. */ off_t sector_offset = args->sector_start / sector_size + loop; /* Check for zero out areas */ hover = dis_metadata_is_overwritten( io_data->metadata, offset, sector_size); if(hover == DIS_RET_ERROR_METADATA_FILE_OVERWRITE) { memset(loop_output, 0, sector_size); continue; } /* Check for sectors fixing and non-encrypted sectors */ if(version == V_SEVEN && (uint64_t)sector_offset < io_data->nb_backup_sectors) { /* * The firsts sectors are encrypted in a different place on a * Windows 7 volume */ fix_read_sector_seven( io_data, offset, loop_input, loop_output ); } else if(version == V_SEVEN && (uint64_t)offset >= io_data->encrypted_volume_size) { /* Do not decrypt when there's nothing to */ dis_printf(L_DEBUG, " > Copying sector from 0x%" F_OFF_T " (%" F_SIZE_T " bytes)\n", offset, sector_size ); memcpy(loop_output, loop_input, sector_size); } else if(version == V_VISTA && sector_offset < 16) { /* * The firsts sectors are not really encrypted on a Vista volume */ if(sector_offset < 1) fix_read_sector_vista( io_data, loop_input, loop_output ); else { dis_printf(L_DEBUG, " > Copying sector from 0x%" F_OFF_T " (%" F_SIZE_T " bytes)\n", offset, sector_size ); memcpy(loop_output, loop_input, sector_size); } } else { /* Decrypt the sector */ if(!decrypt_sector( io_data->crypt, loop_input, offset, loop_output )) dis_printf(L_CRITICAL, "Decryption of sector %#" F_OFF_T " failed!\n", offset); } } return args->output; } /** * Encrypt a sector region according to one or more thread * * @param params The structure used for thread parameters storage */ static void* thread_encrypt(void* params) { if(!params) return NULL; thread_arg_t* args = (thread_arg_t*)params; dis_iodata_t* io_data = args->io_data; off_t loop = args->thread_begin; uint16_t step_unit = args->nb_threads; uint16_t version = dis_metadata_information_version(io_data->metadata); uint16_t sector_size = args->sector_size; uint16_t step_size = (uint16_t) (sector_size * step_unit); uint8_t* loop_input = args->input + sector_size * loop; uint8_t* loop_output = args->output + sector_size * loop; off_t offset = args->sector_start + sector_size * loop; for( ; loop < (off_t)args->nb_loop; loop += step_unit, offset += step_size, loop_input += step_size, loop_output += step_size) { /* * Just encrypt this sector * Exception: don't encrypt it if the sector wasn't (as in the * "BitLocker's-volume-encryption-was-paused case decribed in the * decryption function above") */ off_t sector_offset = args->sector_start / sector_size + loop; /* * NOTE: Seven specificities are dealt with earlier in the process * see dislocker.c:enlock() */ if(version == V_VISTA && sector_offset < 16) { /* * The firsts sectors are not really encrypted on a Vista volume */ if(sector_offset < 1) fix_write_sector_vista( io_data, loop_input, loop_output ); else memcpy(loop_output, loop_input, sector_size); } else if(version == V_SEVEN && (uint64_t)offset >= io_data->encrypted_volume_size) { memcpy(loop_output, loop_input, sector_size); } else { if(!encrypt_sector( io_data->crypt, loop_input, offset, loop_output )) dis_printf(L_CRITICAL, "Encryption of sector %#" F_OFF_T " failed!\n", offset); } } return args->input; } /** * "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Seven for * read operation * * @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* io_data, off_t sector_address, uint8_t* input, uint8_t* output) { // Check parameter if(!output) return; ssize_t read_size; /* * NTFS's boot sectors are saved into the field "boot_sectors_backup" into * metadata's header: the information structure. This field should have been * reported into the "backup_sectors_addr" field of the dis_iodata_t * structure. * 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)io_data->backup_sectors_addr; dis_printf(L_DEBUG, " Fixing sector (7): from %#" F_OFF_T " to %#" F_OFF_T "\n", from, to); to += io_data->part_off; /* Read the real sector we need, at the offset we need it */ read_size = pread(io_data->volume_fd, input, io_data->sector_size, to); if(read_size <= 0) { dis_printf( L_ERROR, "Unable to read %#" F_SIZE_T " bytes from %#" F_OFF_T "\n", io_data->sector_size, to ); return; } to -= io_data->part_off; /* If the sector wasn't yet encrypted, don't decrypt it */ if((uint64_t)to >= io_data->encrypted_volume_size) { memcpy(output, input, io_data->sector_size); } else { decrypt_sector( io_data->crypt, input, to, output ); } } /** * "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Vista for * read operation * * @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* io_data, uint8_t* input, uint8_t* output) { // Check parameter if(!input || !output) return; /* * Only two fields need to be changed: the NTFS signature and the MFT mirror */ memcpy(output, input, io_data->sector_size); dis_metadata_vista_vbr_fve2ntfs(io_data->metadata, output); } /** * "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Vista for * write operation * * @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* io_data, uint8_t* input, uint8_t* output) { // Check parameter if(!input || !output) return; /* * Only two fields need to be changed: the NTFS signature and the MFT mirror */ memcpy(output, input, io_data->sector_size); dis_metadata_vista_vbr_ntfs2fve(io_data->metadata, output); } dislocker-0.7.3/src/logs/000077500000000000000000000000001375503125700152435ustar00rootroot00000000000000dislocker-0.7.3/src/logs/event_descriptors.c000066400000000000000000000220411375503125700211500ustar00rootroot00000000000000/* -*- 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 "event_descriptors.h" void init_events() { FVE_ENCRYPT_START = { .id = 0x6001 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_ENCRYPT_STOP = { .id = 0x6002 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_ENCRYPT_COMPLETE = { .id = 0x6003 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_DECRYPT_START = { .id = 0x6004 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_DECRYPT_STOP = { .id = 0x6005 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_DECRYPT_COMPLETE = { .id = 0x6006 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_RESUME = { .id = 0x6007 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_PAUSE = { .id = 0x6008 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_AUTOUNLOCK_ENABLE_OK = { .id = 0x6009 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_ERROR = { .id = 0x600a .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_AUTOUNLOCK_DISABLE_OK = { .id = 0x600b .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_SECTOR_ERROR = { .id = 0x600c .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_AUTOUNLOCK_ENABLE_ERROR = { .id = 0x600d .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_AUTOUNLOCK_DISABLE_ERROR = { .id = 0x600e .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_AUTOUNLOCK_ERROR = { .id = 0x600f .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_AUTO_START_FAILURE = { .id = 0x6010 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_DISK_FAILED_WRITE_ERROR = { .id = 0x6011 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_REBUILD_DATA_LOSS_ERROR = { .id = 0x6012 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_BAD_CLUSTERS_SKIPPED = { .id = 0x6013 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_INVALID_CONFIG = { .id = 0x601c .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_KEY_UNAVAILABLE = { .id = 0x6021 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_PARTIAL_COMMIT = { .id = 0x6022 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_FAILED_COMMIT = { .id = 0x6023 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_DISK_FAILED_FLUSH_ERROR = { .id = 0x6024 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_DISK_FAILED_READBACK_ERROR = { .id = 0x6025 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_DISK_FAILED_VERIFY_ERROR = { .id = 0x6026 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_CORRUPT_ERROR = { .id = 0x6027 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_FAILOVER_ERROR = { .id = 0x6028 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_FAILOVER = { .id = 0x6029 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_SUBSET = { .id = 0x602a .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_METADATA_REBUILD_DROP = { .id = 0x602b .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_INIT_FAILED_ERROR = { .id = 0x602c .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_CONV_RECOVERING = { .id = 0x602d .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_MOR_BIT_RUN_INIT_ERROR = { .id = 0x602f .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_MOR_BIT_SET_ERROR = { .id = 0x6030 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_KEY_OBTAINED = { .id = 0x6031 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_AUTOUNLOCK_NO_MASTER_KEY = { .id = 0x6032 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_DEBUGGER_ENABLED = { .id = 0x6033 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_BAD_PARTITION_SIZE = { .id = 0x6034 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_MOR_FAILED = { .id = 0x6035 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_KEYFILE_NOT_FOUND = { .id = 0x6036 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_KEYFILE_CORRUPT = { .id = 0x6037 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_KEYFILE_NO_VMK = { .id = 0x6038 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_TPM_DISABLED = { .id = 0x6039 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_TPM_INVALID_SRK = { .id = 0x603a .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_TPM_INVALID_PCR = { .id = 0x603b .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_TPM_NO_VMK = { .id = 0x603c .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_INVALID_APPLICATION = { .id = 0x603d .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_PIN_INVALID = { .id = 0x603e .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_PASSWORD_INVALID = { .id = 0x603f .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_GOT_KEY = { .id = 0x6040 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_UNEXPECTED = { .id = 0x6041 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; FVE_KEYRING_ENH_PIN_INVALID = { .id = 0x6043 .version = 0, .channel = 8, .level = 4, .opcode = 0, .task = 0, .keyword = 0x8000000000000000 }; } dislocker-0.7.3/src/logs/event_descriptors.h000066400000000000000000000100221375503125700211510ustar00rootroot00000000000000/* -*- 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 EVENT_DESCRIPTORS_H #define EVENT_DESCRIPTORS_H #define UNUSED __attribute__ ((unused)) typedef struct { uint16_t id; uint8_t version; uint8_t channel; uint8_t level; uint8_t opcode; uint16_t task; uint64_t keyword; } event_description_t; /** * Available events */ UNUSED event_description_t FVE_ENCRYPT_START; UNUSED event_description_t FVE_ENCRYPT_STOP; UNUSED event_description_t FVE_ENCRYPT_COMPLETE; UNUSED event_description_t FVE_DECRYPT_START; UNUSED event_description_t FVE_DECRYPT_STOP; UNUSED event_description_t FVE_DECRYPT_COMPLETE; UNUSED event_description_t FVE_CONV_RESUME; UNUSED event_description_t FVE_CONV_PAUSE; UNUSED event_description_t FVE_AUTOUNLOCK_ENABLE_OK; UNUSED event_description_t FVE_CONV_ERROR; UNUSED event_description_t FVE_AUTOUNLOCK_DISABLE_OK; UNUSED event_description_t FVE_CONV_SECTOR_ERROR; UNUSED event_description_t FVE_AUTOUNLOCK_ENABLE_ERROR; UNUSED event_description_t FVE_AUTOUNLOCK_DISABLE_ERROR; UNUSED event_description_t FVE_AUTOUNLOCK_ERROR; UNUSED event_description_t FVE_CONV_AUTO_START_FAILURE; UNUSED event_description_t FVE_METADATA_DISK_FAILED_WRITE_ERROR; UNUSED event_description_t FVE_METADATA_REBUILD_DATA_LOSS_ERROR; UNUSED event_description_t FVE_CONV_BAD_CLUSTERS_SKIPPED; UNUSED event_description_t FVE_KEYRING_INVALID_CONFIG; UNUSED event_description_t FVE_KEYRING_KEY_UNAVAILABLE; UNUSED event_description_t FVE_METADATA_PARTIAL_COMMIT; UNUSED event_description_t FVE_METADATA_FAILED_COMMIT; UNUSED event_description_t FVE_METADATA_DISK_FAILED_FLUSH_ERROR; UNUSED event_description_t FVE_METADATA_DISK_FAILED_READBACK_ERROR; UNUSED event_description_t FVE_METADATA_DISK_FAILED_VERIFY_ERROR; UNUSED event_description_t FVE_METADATA_CORRUPT_ERROR; UNUSED event_description_t FVE_METADATA_FAILOVER_ERROR; UNUSED event_description_t FVE_METADATA_FAILOVER; UNUSED event_description_t FVE_METADATA_SUBSET; UNUSED event_description_t FVE_METADATA_REBUILD_DROP; UNUSED event_description_t FVE_INIT_FAILED_ERROR; UNUSED event_description_t FVE_CONV_RECOVERING; UNUSED event_description_t FVE_MOR_BIT_RUN_INIT_ERROR; UNUSED event_description_t FVE_MOR_BIT_SET_ERROR; UNUSED event_description_t FVE_KEYRING_KEY_OBTAINED; UNUSED event_description_t FVE_AUTOUNLOCK_NO_MASTER_KEY; UNUSED event_description_t FVE_KEYRING_DEBUGGER_ENABLED; UNUSED event_description_t FVE_KEYRING_BAD_PARTITION_SIZE; UNUSED event_description_t FVE_KEYRING_MOR_FAILED; UNUSED event_description_t FVE_KEYRING_KEYFILE_NOT_FOUND; UNUSED event_description_t FVE_KEYRING_KEYFILE_CORRUPT; UNUSED event_description_t FVE_KEYRING_KEYFILE_NO_VMK; UNUSED event_description_t FVE_KEYRING_TPM_DISABLED; UNUSED event_description_t FVE_KEYRING_TPM_INVALID_SRK; UNUSED event_description_t FVE_KEYRING_TPM_INVALID_PCR; UNUSED event_description_t FVE_KEYRING_TPM_NO_VMK; UNUSED event_description_t FVE_KEYRING_INVALID_APPLICATION; UNUSED event_description_t FVE_KEYRING_PIN_INVALID; UNUSED event_description_t FVE_KEYRING_PASSWORD_INVALID; UNUSED event_description_t FVE_KEYRING_GOT_KEY; UNUSED event_description_t FVE_KEYRING_UNEXPECTED; UNUSED event_description_t FVE_KEYRING_ENH_PIN_INVALID; #endif /* EVENT_DESCRIPTORS_H */ dislocker-0.7.3/src/mbed_install.sh000077500000000000000000000006361375503125700173000ustar00rootroot00000000000000#!/bin/bash MBEDTLS_FOLDER=mbedtls-for-dislocker if brew info mbedtls |head -1 |grep -q 2.0.0 then git clone https://github.com/ARMmbed/mbedtls.git ${MBEDTLS_FOLDER} cd ${MBEDTLS_FOLDER} git checkout mbedtls-2.0.0 git cherry-pick -n --strategy=recursive -Xours 6f42417ba8dd28fa77fd08d42d73c87a0253f93e cmake . make VERBOSE=1 make install cd .. rm -fr ${MBEDTLS_FOLDER} else brew install -v polarssl fi dislocker-0.7.3/src/metadata/000077500000000000000000000000001375503125700160575ustar00rootroot00000000000000dislocker-0.7.3/src/metadata/datums.c000066400000000000000000000775521375503125700175400ustar00rootroot00000000000000/* -*- 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 #include #include "dislocker/metadata/datums.h" #include "dislocker/metadata/vmk.h" #include "dislocker/metadata/metadata.priv.h" /** Datums value types into string */ static const char* value_type_str[] = { "ERASED", "KEY", "UNICODE", "STRETCH KEY", "USE", "AES-CCM", "TPM_ENCODED", "VALIDATION", "VMK", "EXTERNAL KEY", "UPDATE", "ERROR", "ASYM ENC", "EXPORTED KEY", "PUBLIC KEY", "VIRTUALIZATION INFO", "SIMPLE 1", "SIMPLE 2", "CONCAT HASH KEY", "SIMPLE 3" }; /** Datums entry types into string */ static const char* entry_type_str[] = { "ENTRY TYPE UNKNOWN 1", "ENTRY TYPE UNKNOWN 2", "ENTRY TYPE VMK", "ENTRY TYPE FVEK (FveDatasetVmkGetFvek)", "ENTRY TYPE UNKNOWN", "ENTRY TYPE UNKNOWN", "ENTRY TYPE UNKNOWN", "ENTRY TYPE UNKNOWN", "ENTRY TYPE UNKNOWN", "ENTRY TYPE UNKNOWN", "ENTRY TYPE UNKNOWN", "ENTRY TYPE FVEK (TryObtainKey)" // also from "FveSynchronizeDatasetUpdate" }; /** * Transform an algorithm code into its significant string * @warning This returned string has to be free()d * * @param enc The code of the algorithm * @return The string decoded */ char* cipherstr(cipher_t enc) { size_t len; const char* value; char* data; switch (enc) { case 0: value = "NULL"; break; case STRETCH_KEY : value = "STRETCH KEY"; break; case AES_CCM_256_0 : case AES_CCM_256_1 : case AES_CCM_256_2 : value = "AES-CCM-256"; break; case EXTERN_KEY : value = "EXTERN KEY"; break; case VMK : value = "VMK"; break; case HASH_256 : value = "VALIDATION HASH 256"; break; case AES_128_DIFFUSER : value = "AES-128-DIFFUSER"; break; case AES_256_DIFFUSER : value = "AES-256-DIFFUSER"; break; case AES_128_NO_DIFFUSER : value = "AES-128-NODIFFUSER"; break; case AES_256_NO_DIFFUSER : value = "AES-256-NODIFFUSER"; break; case AES_XTS_128: value = "AES-XTS-128"; break; case AES_XTS_256: value = "AES-XTS-256"; break; default: value = "UNKNOWN CIPHER!"; break; } len = strlen(value) + 1; data = (char*) dis_malloc(len * sizeof(char)); memset(data, 0, len); memcpy(data, value, len); return data; } /** * Given a datum type code, it returns the corresponding signification in * string format * @warning This returned string has to be free()d * * @param value_type The datum's value type to tranform * @return The decoded string or NULL if there's no signification (index out of * bound) */ char* datumvaluetypestr(dis_datums_value_type_t value_type) { if(value_type >= NB_DATUMS_VALUE_TYPES) return NULL; size_t len = strlen(value_type_str[value_type]) + 1; char* data = (char*) dis_malloc(len * sizeof(char)); memset(data, 0, len); memcpy(data, value_type_str[value_type], len); return data; } /** * Get a datum minimal header * * @param data Where to pick the datum header * @param header A datum header to retrieve * @return TRUE if result can be trusted, FALSE otherwise */ int get_header_safe(void* data, datum_header_safe_t* header) { // Check parameters if(!data) return FALSE; /* Too easy, boring */ memcpy(header, data, sizeof(datum_header_safe_t)); dis_printf(L_DEBUG, "Header safe: %#x, %#x, %#x, %#x\n", header->datum_size, header->entry_type, header->value_type, header->error_status); /* Now check if the header is good */ if(header->datum_size < sizeof(datum_header_safe_t) || header->value_type > NB_DATUMS_VALUE_TYPES) return FALSE; return TRUE; } /** * Get the payload based on the datum's size and value type * * @param data The data to take the payload from * @param payload The extracted payload (need to be free()d if return is TRUE) * @param size_payload The malloc()ed payload size * @return TRUE if result can be trusted, FALSE otherwise */ int get_payload_safe(void* data, void** payload, size_t* size_payload) { // Check parameters if(!data) return FALSE; datum_header_safe_t header; uint16_t size_header = 0; if(!get_header_safe(data, &header)) return FALSE; size_header = datum_value_types_prop[header.value_type].size_header; if(header.datum_size <= size_header) return FALSE; *size_payload = (size_t)(header.datum_size - size_header); *payload = dis_malloc(*size_payload); memset(*payload, 0, *size_payload); memcpy(*payload, data + size_header, *size_payload); return TRUE; } /** * Print only one datum * * @param level The level to print the message * @param datum The datum to print */ void print_one_datum(DIS_LOGS level, void* datum) { datum_header_safe_t* header = (datum_header_safe_t*) datum; print_header(level, header); dis_datums_value_type_t value_type = header->value_type; if (value_type < NB_DATUMS_VALUE_TYPES) print_datum_tab[value_type](level, datum); } /** * Print the header all data have * * @param level The level to print the message * @param header The header to print */ void print_header(DIS_LOGS level, datum_header_safe_t* header) { dis_printf(level, "Total datum size: 0x%1$04hx (%1$hd) bytes\n", header->datum_size); dis_printf(level, "Datum entry type: %hu\n", header->entry_type); if(header->entry_type < NB_DATUMS_ENTRY_TYPES) dis_printf(level, " `--> %s\n", entry_type_str[header->entry_type]); dis_printf(level, "Datum value type: %hu\n", header->value_type); if(header->value_type < NB_DATUMS_VALUE_TYPES) { dis_printf(level, " `--> %s -- Total size header: %hu -- Nested datum: %s\n", value_type_str[header->value_type], datum_value_types_prop[header->value_type].size_header, (datum_value_types_prop[header->value_type].has_nested_datum ? "yes" : "no") ); } dis_printf(level, "Status: %#x\n", header->error_status); } /** * Print information of a generic datum (one whose type is unknown) * * @param level The level to print the message * @param vdatum The datum to print */ void print_datum_generic(DIS_LOGS level, void* vdatum) { datum_generic_type_t* datum = (datum_generic_type_t*) vdatum; dis_printf(level, "Generic datum:\n"); hexdump(level, (void*)((char*)datum + sizeof(datum_generic_type_t)), datum->header.datum_size - sizeof(datum_generic_type_t)); } /** * All the other specifics print functions * * @param level The level to print the message * @param datum The datum to print */ void print_datum_erased(DIS_LOGS level, void* vdatum) { dis_printf(level, "This datum is of ERASED type and should thus be nullified"); hexdump(level, vdatum, sizeof(datum_erased_t)); } void print_datum_key(DIS_LOGS level, void* vdatum) { datum_key_t* datum = (datum_key_t*) vdatum; char* cipher_str = cipherstr((cipher_t) datum->algo); dis_printf(level, "Unkown: \n"); hexdump(level, (void*) &datum->padd, 2); dis_printf(level, "Algo: %s (%#hx)\n", cipher_str, datum->algo); dis_printf(level, "Key:\n"); hexdump( level, (void*) ((char*) datum + sizeof(datum_key_t)), datum->header.datum_size - sizeof(datum_key_t) ); dis_free(cipher_str); } void print_datum_unicode(DIS_LOGS level, void* vdatum) { datum_unicode_t* datum = (datum_unicode_t*) vdatum; size_t utf16_length = (datum->header.datum_size - sizeof(datum_unicode_t)); wchar_t* wchar_s = dis_malloc( ((datum->header.datum_size - sizeof(datum_unicode_t)) / 2) * sizeof(wchar_t) ); /* * This datum's payload is an UTF-16 string finished by \0 * We convert it in wchar_t so we can print it */ utf16towchars( (uint16_t*) ((char*) datum + sizeof(datum_unicode_t)), utf16_length, wchar_s ); dis_printf(level, "UTF-16 string: '%ls'\n", wchar_s); dis_free(wchar_s); } void print_datum_stretch_key(DIS_LOGS level, void* vdatum) { datum_stretch_key_t* datum = (datum_stretch_key_t*) vdatum; dis_printf(level, "Unkown: \n"); hexdump(level, (void*) &datum->padd, 2); dis_printf(level, "Algo: %#x\n", datum->algo); dis_printf(level, "Salt: \n"); print_mac(level, datum->salt); /* This datum's payload seems to be another datum, so print it */ dis_printf(level, " ------ Nested datum ------\n"); print_one_datum(level, (char*) datum + sizeof(datum_stretch_key_t)); dis_printf(level, " ---------------------------\n"); } void print_datum_use_key(DIS_LOGS level, void* vdatum) { datum_use_key_t* datum = (datum_use_key_t*) vdatum; dis_printf(level, "Algo: %#hx\n", datum->algo); dis_printf(level, "Unknown: \n"); hexdump(level, (void*) &datum->padd, 2); /* This datum's payload seems to be another datum, so print it */ dis_printf(level, " ------ Nested datum ------\n"); print_one_datum(level, (char*) datum + sizeof(datum_use_key_t)); dis_printf(level, " ---------------------------\n"); } void print_datum_aes_ccm(DIS_LOGS level, void* vdatum) { datum_aes_ccm_t* datum = (datum_aes_ccm_t*) vdatum; dis_printf(level, "Nonce: \n"); print_nonce(level, datum->nonce); dis_printf(level, "MAC: \n"); print_mac(level, datum->mac); dis_printf(level, "Payload:\n"); hexdump( level, (void*) ((char*) datum + sizeof(datum_aes_ccm_t)), datum->header.datum_size - sizeof(datum_aes_ccm_t) ); } void print_datum_tpmenc(DIS_LOGS level, void* vdatum) { datum_tpm_enc_t* datum = (datum_tpm_enc_t*) vdatum; dis_printf(level, "Unknown: %#x\n", datum->unknown); dis_printf(level, "Payload:\n"); hexdump( level, (void*) ((char*) datum + sizeof(datum_tpm_enc_t)), datum->header.datum_size - sizeof(datum_tpm_enc_t) ); } void print_datum_vmk(DIS_LOGS level, void* vdatum) { datum_vmk_t* datum = (datum_vmk_t*) vdatum; char extkey_id[37]; int computed_size = 0; format_guid(datum->guid, extkey_id); dis_printf(level, "Recovery Key GUID: '%.39s'\n", extkey_id); dis_printf(level, "Nonce: \n"); print_nonce(level, datum->nonce); computed_size = sizeof(datum_vmk_t); /* This datum's payload seems to be another datum, so print it */ dis_printf(level, " ------ Nested datum(s) ------\n"); while(computed_size < datum->header.datum_size) { dis_printf(level, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); print_one_datum(level, (char*) datum + computed_size); datum_header_safe_t header; memset(&header, 0, sizeof(datum_header_safe_t)); get_header_safe((char*) datum + computed_size, &header); computed_size += header.datum_size; dis_printf(level, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); } dis_printf(level, " ------------------------------\n"); } void print_datum_external(DIS_LOGS level, void* vdatum) { datum_external_t* datum = (datum_external_t*) vdatum; char extkey_id[37]; time_t ts; char* date = NULL; int computed_size = 0; format_guid(datum->guid, extkey_id); ntfs2utc(datum->timestamp, &ts); date = strdup(asctime(gmtime(&ts))); chomp(date); dis_printf(level, "Recovery Key GUID: '%.39s'\n", extkey_id); dis_printf( level, "Epoch Timestamp: %u sec, being %s\n", (unsigned int) ts, date ); computed_size = sizeof(datum_external_t); /* This datum's payload seems to be another datum, so print it */ dis_printf(level, " ------ Nested datum ------\n"); while(computed_size < datum->header.datum_size) { dis_printf(level, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); print_one_datum(level, (char*) datum + computed_size); datum_header_safe_t header; memset(&header, 0, sizeof(datum_header_safe_t)); get_header_safe((char*) datum + computed_size, &header); computed_size += header.datum_size; dis_printf(level, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); } dis_printf(level, " ---------------------------\n"); free(date); } void print_datum_virtualization(DIS_LOGS level, void* vdatum) { datum_virtualization_t* datum = (datum_virtualization_t*) vdatum; uint16_t value_type = datum->header.value_type; dis_printf( level, "NTFS boot sectors address: %#" PRIx64 "\n", datum->ntfs_boot_sectors ); dis_printf( level, "Number of backuped bytes: %1$#" PRIx64 " (%1$" PRIu64 ")\n", datum->nb_bytes ); /* For Windows 8 encrypted volumes */ size_t win7_size = datum_value_types_prop[value_type].size_header; size_t actual_size = ((size_t)datum->header.datum_size) & 0xffff; if(actual_size > win7_size) { print_extended_info(level, &datum->xinfo); } } /** * Print a nonce * * @param level The level to print the message * @param nonce The nonce to print */ void print_nonce(DIS_LOGS level, uint8_t* nonce) { int i = 0; char s[12*3 + 1] = {0,}; for(i = 0; i < 12; ++i) snprintf(&s[i*3], 4, "%02hhx ", nonce[i]); dis_printf(level, "%s\n", s); } /** * Print MAC * * @param level The level to print the message * @param mac The MAC to print */ void print_mac(DIS_LOGS level, uint8_t* mac) { int i = 0; char s[16*3 + 1] = {0,}; for(i = 0; i < 16; ++i) snprintf(&s[i*3], 4, "%02hhx ", mac[i]); dis_printf(level, "%s\n", s); } /** * Get the next specified datum * * @param dis_metadata The metadata structure * @param entry_type The second uint16_t of any datum header struct * @param value_type The third uint16_t of any datum header struct * @param datum_begin The beginning of the search, begins after this given datum * @param datum_result The found datum * @return TRUE if result can be trusted, FALSE otherwise */ int get_next_datum( dis_metadata_t dis_meta, dis_datums_entry_type_t entry_type, dis_datums_value_type_t value_type, void* datum_begin, void** datum_result) { // Check parameters if(!dis_meta || value_type > NB_DATUMS_VALUE_TYPES) return FALSE; dis_printf(L_DEBUG, "Entering get_next_datum...\n"); bitlocker_dataset_t* dataset = dis_meta->dataset; void* datum = NULL; void* limit = (char*)dataset + dataset->size; datum_header_safe_t header; *datum_result = NULL; memset(&header, 0, sizeof(datum_header_safe_t)); if(datum_begin) datum = datum_begin + *(uint16_t*)datum_begin; else datum = (char*)dataset + dataset->header_size; while(1) { if(datum + 8 >= limit) { dis_printf(L_DEBUG, "Hit limit, search failed.\n"); break; } if(!get_header_safe(datum, &header)) break; if(value_type == UINT16_MAX && entry_type == UINT16_MAX) { /* * If the datum types are not in range, assume the caller want each * datum */ *datum_result = datum; break; } else if((entry_type == header.entry_type || entry_type == UINT16_MAX) && (value_type == header.value_type || value_type == UINT16_MAX)) { /* * If the entry type and the value type searched match, * then return this datum */ *datum_result = datum; break; } datum += header.datum_size; memset(&header, 0, sizeof(datum_header_safe_t)); } dis_printf(L_DEBUG, "Going out of get_next_datum\n"); if(!*datum_result) return FALSE; return TRUE; } /** * Retrieve a datum nested into another one * * @param datum Where to find a nested datum * @param datum_nested The datum resulted * @return TRUE if result can be trusted, FALSE otherwise */ int get_nested_datum(void* datum, void** datum_nested) { // Check parameters if(!datum) return FALSE; datum_header_safe_t header; if(!get_header_safe(datum, &header)) return FALSE; if(!datum_value_types_prop[header.value_type].has_nested_datum) return FALSE; uint16_t size = datum_value_types_prop[header.value_type].size_header; *datum_nested = (char*)datum + size; return TRUE; } /** * Retrieve a datum nested into another one with a specific value type * * @param datum Where to find a nested datum * @param value_type The datum of the searched datum * @param datum_nested The datum resulted * @return TRUE if result can be trusted, FALSE otherwise */ int get_nested_datumvaluetype(void* datum, dis_datums_value_type_t value_type, void** datum_nested) { // Check parameters if(!datum) return FALSE; /* Get the first nested datum */ if(!get_nested_datum(datum, datum_nested)) return FALSE; datum_header_safe_t header; datum_header_safe_t nested_header; if(!get_header_safe(datum, &header)) return FALSE; if(!get_header_safe(*datum_nested, &nested_header)) return FALSE; /* While we don't have the type we're looking for */ while(nested_header.value_type != value_type) { /* Just go to the next datum */ *datum_nested += nested_header.datum_size; /* If we're not into the datum anymore */ if((char*)datum + header.datum_size <= (char*)*datum_nested) return FALSE; if(!get_header_safe(*datum_nested, &nested_header)) return FALSE; } return TRUE; } /** * Safely check of the datum's value type * * @param datum The datum to validate * @param value_type The datum's value type to find * @return TRUE if result can be trusted, FALSE otherwise */ int datum_value_type_must_be(void* datum, dis_datums_value_type_t value_type) { // Check parameters if(!datum) return FALSE; datum_header_safe_t header; if(!get_header_safe(datum, &header)) return FALSE; if(header.value_type == value_type) return TRUE; else return FALSE; } /** * Check if a clear key is stored in data * * @param dataset The metadata's dataset * @param vmk_datum The VMK datum of the clear key if found * @return TRUE if result can be trusted, FALSE otherwise */ int dis_metadata_has_clear_key(dis_metadata_t dis_meta, void** vmk_datum) { if(!dis_meta) return FALSE; *vmk_datum = NULL; dis_printf(L_DEBUG, "Entering has_clear_key. Returning result of get_vmk_datum_from_range with range between 0x00 and 0xff\n"); return get_vmk_datum_from_range(dis_meta, 0x00, 0xff, vmk_datum); } #ifdef _HAVE_RUBY #include "dislocker/dislocker.priv.h" struct _rb_dis_datum { /* The actual datum's data */ datum_generic_type_t* datum; /* If the datum was malloc()-ed, then it needs to be free()-d */ char need_free; }; typedef struct _rb_dis_datum* rb_dis_datum_t; /* Declare this function for recursive to_s datums */ static VALUE rb_cDislockerMetadataDatum_to_s(VALUE self); static VALUE rb_cDislockerMetadataDatum_get_datum_size(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); return INT2NUM(rb_datum->datum->header.datum_size); } static VALUE rb_cDislockerMetadataDatum_get_entry_type(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); return INT2NUM(rb_datum->datum->header.entry_type); } static VALUE rb_cDislockerMetadataDatum_get_value_type(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); return INT2NUM(rb_datum->datum->header.value_type); } static VALUE rb_cDislockerMetadataDatum_get_error_status(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); return INT2NUM(rb_datum->datum->header.error_status); } static VALUE rb_cDislockerMetadataDatum_get_payload(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); void* payload = NULL; size_t size = 0; extern VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; if(get_payload_safe(rb_datum->datum, &payload, &size)) { if(size > LONG_MAX) { rb_raise( rb_eRuntimeError, "Wtf with this datum's payload size (%" F_SIZE_T ")?", size ); } VALUE new_rb_datum = rb_cDislockerMetadataDatum_new( dis_rb_classes[DIS_RB_CLASS_DATUM], rb_str_new(payload, (long int) size) ); return new_rb_datum; } return Qnil; } static VALUE rb_format_mac(uint8_t* mac) { VALUE rb_str = rb_str_new("", 0); int i = 0; char s[16*3 + 1] = {0,}; for(i = 0; i < 16; ++i) snprintf(&s[i*3], 4, "%02hhx ", mac[i]); rb_str_catf(rb_str, "%s\n", s); return rb_str; } static VALUE rb_format_nonce(uint8_t* nonce) { VALUE rb_str = rb_str_new("", 0); int i = 0; char s[12*3 + 1] = {0,}; for(i = 0; i < 12; ++i) snprintf(&s[i*3], 4, "%02hhx ", nonce[i]); rb_str_catf(rb_str, "%s\n", s); return rb_str; } static VALUE rb_cDislockerMetadataDatumHeader_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_generic_type_t* gt = rb_datum->datum; char* entry_type = "UNKNOWN"; char* value_type = "UNKNOWN"; VALUE rb_str = rb_str_new("", 0); if(gt == NULL) return rb_str; if(gt->header.entry_type < NB_DATUMS_ENTRY_TYPES) entry_type = (char*) entry_type_str[gt->header.entry_type]; if(gt->header.value_type < NB_DATUMS_VALUE_TYPES) value_type = (char*) value_type_str[gt->header.value_type]; rb_str_catf( rb_str, "Total size: 0x%04hx (%hd) bytes\n", gt->header.datum_size, gt->header.datum_size ); rb_str_catf( rb_str, "Entry type: %s (%hu)\n", entry_type, gt->header.entry_type ); rb_str_catf( rb_str, "Value type: %s (%hu)\n", value_type, gt->header.value_type ); rb_str_catf( rb_str, "Status : %#x\n", gt->header.error_status ); return rb_str; } VALUE rb_datum_generic_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_generic_type_t* datum = rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; rb_str_cat2(rb_str, "Generic datum: "); rb_str_concat(rb_str, rb_hexdump( (uint8_t*) datum + sizeof(datum_generic_type_t), datum->header.datum_size - sizeof(datum_generic_type_t) )); return rb_str; } VALUE rb_datum_erased_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_generic_type_t* datum = rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; rb_str_cat2(rb_str, "This datum is of ERASED type and should thus be nullified"); return rb_str; } VALUE rb_datum_key_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_key_t* datum = (datum_key_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; char* cipher_str = cipherstr((cipher_t) datum->algo); rb_str_catf(rb_str, "Unknown: 0x%04hx\n", datum->padd); rb_str_catf(rb_str, "Algo: %s (%#hx)\n", cipher_str, datum->algo); rb_str_cat2(rb_str, "Key:\n"); rb_str_concat(rb_str, rb_hexdump( (uint8_t*) datum + sizeof(datum_key_t), datum->header.datum_size - sizeof(datum_key_t) )); dis_free(cipher_str); return rb_str; } VALUE rb_datum_unicode_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_unicode_t* datum = (datum_unicode_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; size_t utf16_length = (datum->header.datum_size - sizeof(datum_unicode_t)); wchar_t* wchar_s = dis_malloc( ((datum->header.datum_size - sizeof(datum_unicode_t)) / 2) * sizeof(wchar_t) ); /* * This datum's payload is an UTF-16 string finished by \0 * We convert it in wchar_t so we can print it */ utf16towchars( (uint16_t*)((char*) datum + sizeof(datum_unicode_t)), utf16_length, wchar_s ); rb_str_catf(rb_str, "UTF-16 string: '%ls'\n", wchar_s); dis_free(wchar_s); return rb_str; } VALUE rb_datum_stretch_key_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_stretch_key_t* datum = (datum_stretch_key_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; rb_str_catf(rb_str, "Unknown: 0x%04hx\n", datum->padd); rb_str_catf(rb_str, "Algo: %#x\n", datum->algo); rb_str_cat2(rb_str, "Salt: \n"); rb_str_concat(rb_str, rb_format_mac(datum->salt)); /* This datum's payload seems to be another datum, so print it */ rb_str_cat2(rb_str, " ------ Nested datum ------\n"); rb_datum->datum = (datum_generic_type_t*) datum + sizeof(datum_stretch_key_t); rb_str_concat(rb_str, rb_cDislockerMetadataDatum_to_s(self)); rb_str_cat2(rb_str, " ---------------------------\n"); rb_datum->datum = (datum_generic_type_t*) datum; return rb_str; } VALUE rb_datum_use_key_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_use_key_t* datum = (datum_use_key_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; rb_str_catf(rb_str, "Algo: %#hx\n", datum->algo); rb_str_catf(rb_str, "Unknown: 0x%04hx\n", datum->padd); /* This datum's payload seems to be another datum, so print it */ rb_str_cat2(rb_str, " ------ Nested datum ------\n"); rb_datum->datum = (datum_generic_type_t*) datum + sizeof(datum_use_key_t); rb_str_concat(rb_str, rb_cDislockerMetadataDatum_to_s(self)); rb_str_cat2(rb_str, " ---------------------------\n"); rb_datum->datum = (datum_generic_type_t*) datum; return rb_str; } VALUE rb_datum_aes_ccm_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_aes_ccm_t* datum = (datum_aes_ccm_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; rb_str_cat2(rb_str, "Nonce:\n"); rb_str_concat(rb_str, rb_format_nonce(datum->nonce)); rb_str_cat2(rb_str, "MAC:\n"); rb_str_concat(rb_str, rb_format_mac(datum->mac)); rb_str_cat2(rb_str, "Payload:\n"); rb_str_concat(rb_str, rb_hexdump( (uint8_t*) ((char*) datum + sizeof(datum_aes_ccm_t)), datum->header.datum_size - sizeof(datum_aes_ccm_t) )); return rb_str; } VALUE rb_datum_tpmenc_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_tpm_enc_t* datum = (datum_tpm_enc_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; rb_str_catf(rb_str, "Unknown: %#x\n", datum->unknown); rb_str_cat2(rb_str, "Payload:\n"); rb_str_concat(rb_str, rb_hexdump( (uint8_t*) ((char*) datum + sizeof(datum_tpm_enc_t)), datum->header.datum_size - sizeof(datum_tpm_enc_t) )); return rb_str; } VALUE rb_datum_vmk_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_vmk_t* datum = (datum_vmk_t*) rb_datum->datum; char extkey_id[37]; int computed_size = 0; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; format_guid(datum->guid, extkey_id); rb_str_catf(rb_str, "Recovery Key GUID: '%.39s'\n", extkey_id); rb_str_cat2(rb_str, "Nonce: \n"); rb_str_concat(rb_str, rb_format_nonce(datum->nonce)); computed_size = sizeof(datum_vmk_t); /* This datum's payload seems to be another datum, so print it */ while(computed_size < datum->header.datum_size) { rb_str_cat2(rb_str, " ------ Nested datum(s) ------\n"); rb_datum->datum = (datum_generic_type_t*) datum + computed_size; rb_str_concat(rb_str, rb_cDislockerMetadataDatum_to_s(self)); datum_header_safe_t header; memset(&header, 0, sizeof(datum_header_safe_t)); get_header_safe((char*) datum + computed_size, &header); computed_size += header.datum_size; rb_str_cat2(rb_str, " ------------------------------\n"); } rb_datum->datum = (datum_generic_type_t*) datum; return rb_str; } VALUE rb_datum_external_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_external_t* datum = (datum_external_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; char extkey_id[37]; time_t ts; char* date = NULL; int computed_size = 0; format_guid(datum->guid, extkey_id); ntfs2utc(datum->timestamp, &ts); date = strdup(asctime(gmtime(&ts))); chomp(date); rb_str_catf(rb_str, "Recovery Key GUID: '%.39s'\n", extkey_id); rb_str_catf( rb_str, "Epoch Timestamp: %u sec, being %s\n", (unsigned int) ts, date ); computed_size = sizeof(datum_external_t); /* This datum's payload seems to be another datum, so print it */ while(computed_size < datum->header.datum_size) { rb_str_cat2(rb_str, " ------ Nested datum ------\n"); rb_datum->datum = (datum_generic_type_t*) datum + computed_size; rb_str_concat(rb_str, rb_cDislockerMetadataDatum_to_s(self)); datum_header_safe_t header; memset(&header, 0, sizeof(datum_header_safe_t)); get_header_safe((char*) datum + computed_size, &header); computed_size += header.datum_size; rb_str_cat2(rb_str, " ---------------------------\n"); } free(date); rb_datum->datum = (datum_generic_type_t*) datum; return rb_str; } VALUE rb_datum_virtualization_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_virtualization_t* datum = (datum_virtualization_t*) rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(datum == NULL) return rb_str; uint16_t value_type = datum->header.value_type; rb_str_catf( rb_str, "NTFS boot sectors address: %#" PRIx64 "\n", datum->ntfs_boot_sectors ); rb_str_catf( rb_str, "Number of backuped bytes: %1$#" PRIx64 " (%1$" PRIu64 ")\n", datum->nb_bytes ); /* For Windows 8 encrypted volumes */ size_t win7_size = datum_value_types_prop[value_type].size_header; size_t actual_size = ((size_t)datum->header.datum_size) & 0xffff; if(actual_size > win7_size) { rb_str_concat( rb_str, rb_datum_virtualization_extinfo_to_s(&datum->xinfo) ); } return rb_str; } typedef VALUE (*rb_datum_to_s_f)(VALUE self); static const rb_datum_to_s_f rb_datum_to_s_tab[NB_DATUMS_VALUE_TYPES] = { rb_datum_erased_to_s, rb_datum_key_to_s, rb_datum_unicode_to_s, rb_datum_stretch_key_to_s, rb_datum_use_key_to_s, rb_datum_aes_ccm_to_s, rb_datum_tpmenc_to_s, rb_datum_generic_to_s, rb_datum_vmk_to_s, rb_datum_external_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, rb_datum_virtualization_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, rb_datum_generic_to_s, }; VALUE rb_cDislockerMetadataDatumPayload_to_s(VALUE self) { rb_dis_datum_t rb_datum = DATA_PTR(self); datum_generic_type_t* gt = rb_datum->datum; VALUE rb_str = rb_str_new("", 0); if(gt == NULL) return rb_str; if(gt->header.value_type < NB_DATUMS_VALUE_TYPES) return rb_datum_to_s_tab[gt->header.value_type](self); return rb_str; } static VALUE rb_cDislockerMetadataDatum_to_s(VALUE self) { VALUE rb_str = rb_cDislockerMetadataDatumHeader_to_s(self); rb_str_concat(rb_str, rb_cDislockerMetadataDatumPayload_to_s(self)); return rb_str; } static void rb_cDislockerMetadataDatum_free(rb_dis_datum_t rb_datum) { if(rb_datum) { if(rb_datum->need_free) dis_free(rb_datum->datum); dis_free(rb_datum); } } static VALUE rb_cDislockerMetadataDatum_alloc(VALUE klass) { rb_dis_datum_t datum = NULL; return Data_Wrap_Struct( klass, NULL, rb_cDislockerMetadataDatum_free, datum ); } static VALUE rb_cDislockerMetadataDatum_init(VALUE self, VALUE datum) { rb_dis_datum_t rb_datum = dis_malloc(sizeof(struct _rb_dis_datum)); if(rb_datum == NULL) rb_raise(rb_eRuntimeError, "Cannot allocate more memory"); memset(rb_datum, 0, sizeof(struct _rb_dis_datum)); DATA_PTR(self) = rb_datum; Check_Type(datum, T_STRING); rb_datum->datum = (datum_generic_type_t*) StringValuePtr(datum); return Qnil; } VALUE rb_cDislockerMetadataDatum_new(VALUE klass, VALUE datum) { VALUE rb_datum = rb_cDislockerMetadataDatum_alloc(klass); rb_cDislockerMetadataDatum_init(rb_datum, datum); return rb_datum; } void Init_datum(VALUE rb_cDislockerMetadata) { VALUE rb_cDislockerMetadataDatum = rb_define_class_under( rb_cDislockerMetadata, "Datum", rb_cObject ); extern VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; dis_rb_classes[DIS_RB_CLASS_DATUM] = rb_cDislockerMetadataDatum; rb_define_alloc_func( rb_cDislockerMetadataDatum, rb_cDislockerMetadataDatum_alloc ); rb_define_method( rb_cDislockerMetadataDatum, "initialize", rb_cDislockerMetadataDatum_init, 1 ); rb_define_method( rb_cDislockerMetadataDatum, "size", rb_cDislockerMetadataDatum_get_datum_size, 0 ); rb_define_method( rb_cDislockerMetadataDatum, "entry_type", rb_cDislockerMetadataDatum_get_entry_type, 0 ); rb_define_method( rb_cDislockerMetadataDatum, "value_type", rb_cDislockerMetadataDatum_get_value_type, 0 ); rb_define_method( rb_cDislockerMetadataDatum, "error_status", rb_cDislockerMetadataDatum_get_error_status, 0 ); rb_define_method( rb_cDislockerMetadataDatum, "payload", rb_cDislockerMetadataDatum_get_payload, 0 ); rb_define_method( rb_cDislockerMetadataDatum, "to_s", rb_cDislockerMetadataDatum_to_s, 0 ); } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/metadata/extended_info.c000066400000000000000000000050621375503125700210410ustar00rootroot00000000000000/* -*- 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 "dislocker/metadata/extended_info.h" /** * Print the extended info structure * * @param level The level to print the message * @param xinfo The extended_info_t structure to print */ void print_extended_info(DIS_LOGS level, extended_info_t* xinfo) { dis_printf(level, "Unknown:\n"); hexdump(level, (uint8_t*)&xinfo->unknown1, 2); dis_printf(level, "Size: 0x%1$04x (%1$hu)\n", xinfo->size); dis_printf(level, "Unknown:\n"); hexdump(level, (uint8_t*)&xinfo->unknown2, 4); dis_printf(level, "Flags: 0x%1$" PRIx64 " (%1$" PRIu64 ")\n", xinfo->flags); dis_printf(level, "Convert Log offset: 0x%016" PRIx64 "\n", xinfo->convertlog_addr); dis_printf(level, "Convert Log size: 0x%1$08x (%1$u)\n", xinfo->convertlog_size); dis_printf(level, "Sector size (1): 0x%1$x (%1$d)\n", xinfo->sector_size1); dis_printf(level, "Sector size (2): 0x%1$x (%1$d)\n", xinfo->sector_size2); } #ifdef _HAVE_RUBY VALUE rb_datum_virtualization_extinfo_to_s(extended_info_t* xinfo) { VALUE rb_str = rb_str_new("", 0); rb_str_catf(rb_str, "Unknown: 0x%04hx\n", xinfo->unknown1); rb_str_catf(rb_str, "Size: 0x%1$04x (%1$hu)\n", xinfo->size); rb_str_catf(rb_str, "Unknown: 0x%08x\n", xinfo->unknown2); rb_str_catf(rb_str, "Flags: 0x%1$" PRIx64 " (%1$" PRIu64 ")\n", xinfo->flags); rb_str_catf(rb_str, "Convert Log offset: 0x%016" PRIx64 "\n", xinfo->convertlog_addr); rb_str_catf(rb_str, "Convert Log size: 0x%1$08x (%1$u)\n", xinfo->convertlog_size); rb_str_catf(rb_str, "Sector size (1): 0x%1$x (%1$d)\n", xinfo->sector_size1); rb_str_catf(rb_str, "Sector size (2): 0x%1$x (%1$d)\n", xinfo->sector_size2); return rb_str; } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/metadata/fvek.c000066400000000000000000000133551375503125700171650ustar00rootroot00000000000000/* -*- 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 #include #include #include #include "dislocker/metadata/datums.h" #include "dislocker/encryption/decrypt.h" #include "dislocker/metadata/fvek.h" #include "dislocker/metadata/metadata.priv.h" /** * Get the FVEK from the VMK * * @param dis_metadata The metadata structure * @param vmk_datum The datum of type 1 containing the VMK * @param fvek_datum The FVEK datum KEY structure * @return TRUE if result can be trusted, FALSE otherwise */ int get_fvek(dis_metadata_t dis_meta, void* vmk_datum, void** fvek_datum) { // Check parameters if(!dis_meta) return FALSE; void* vmk_key = NULL; size_t vmk_key_size = 0; datum_aes_ccm_t* fvek = NULL; unsigned int fvek_size = 0; unsigned int header_size = 0; /* First get the AES-CCM datum where the FVEK is */ if(!get_next_datum( dis_meta, DATUMS_ENTRY_FVEK, DATUMS_VALUE_AES_CCM, 0, fvek_datum )) { dis_printf( L_CRITICAL, "Error in finding the AES_CCM datum including the VMK. " "Internal failure, abort.\n" ); return FALSE; } /* Check if the VMK datum is of type KEY (1) */ if(!datum_value_type_must_be(vmk_datum, DATUMS_VALUE_KEY)) { dis_printf( L_CRITICAL, "Error, the provided VMK datum's type is incorrect. Abort.\n" ); return FALSE; } /* Then extract the real key in the VMK key structure */ if(!get_payload_safe(vmk_datum, &vmk_key, &vmk_key_size)) { dis_printf( L_CRITICAL, "Error getting the key included into the VMK key structure. " "Internal failure, abort.\n" ); return FALSE; } fvek = (datum_aes_ccm_t*)*fvek_datum; header_size = datum_value_types_prop[fvek->header.value_type].size_header; fvek_size = fvek->header.datum_size - header_size; if(vmk_key_size > (size_t) (UINT_MAX / 8)) { dis_printf( L_ERROR, "VMK size too big, unsupported: %#" F_SIZE_T "\n", vmk_key_size ); return FALSE; } /* Finally decrypt the FVEK with the VMK */ if(!decrypt_key( (unsigned char*) fvek + header_size, fvek_size, fvek->mac, fvek->nonce, vmk_key, (unsigned int)vmk_key_size * 8, fvek_datum )) { if(*fvek_datum) { dis_printf(L_ERROR, "FVEK found (but not good it seems):\n"); hexdump(L_ERROR, *fvek_datum, fvek_size); } dis_printf(L_CRITICAL, "Can't decrypt correctly the FVEK. Abort.\n"); dis_free(*fvek_datum); return FALSE; } dis_free(vmk_key); dis_printf(L_DEBUG, "=========================[ FVEK ]=========================\n"); print_one_datum(L_DEBUG, *fvek_datum); dis_printf(L_DEBUG, "==========================================================\n"); return TRUE; } /** * Build the FVEK datum using the FVEK file. * The expected format is: * - 2 bytes for the encryption method used (AES 128/256 bits, with or without * diffuser). These two bytes are between 0x8000 -> 0x8003 included, {@see * cipher_types@datums.h}. * - 512 bytes that are usable directly in init_keys()@outputs/prepare.c * * @param cfg The configuration structure, therefore having the FVEK file * @param fvek_datum The FVEK datum KEY structure * @return TRUE if result can be trusted, FALSE otherwise */ int build_fvek_from_file(dis_config_t* cfg, void** fvek_datum) { if(!cfg) return FALSE; off_t actual_size = -1; int file_fd = -1; datum_key_t* datum_key = NULL; ssize_t rs; union { cipher_t single; char multi[2]; } enc_method; memset(enc_method.multi, 0, 2); char fvek_keys[64] = {0,}; off_t expected_size = sizeof(enc_method) + sizeof(fvek_keys); file_fd = dis_open(cfg->fvek_file, O_RDONLY); if(file_fd == -1) { dis_printf(L_ERROR, "Cannot open FVEK file (%s)\n", cfg->fvek_file); return FALSE; } /* Check the file's size */ actual_size = dis_lseek(file_fd, 0, SEEK_END); if(actual_size != expected_size) { dis_printf( L_ERROR, "Wrong FVEK file size, expected %d but has %d\n", expected_size, actual_size ); return FALSE; } /* Read everything */ dis_lseek(file_fd, 0, SEEK_SET); rs = dis_read(file_fd, enc_method.multi, sizeof(enc_method)); if(rs != sizeof(enc_method)) { dis_printf( L_ERROR, "Cannot read whole encryption method in the FVEK file\n" ); return FALSE; } rs = dis_read(file_fd, fvek_keys, sizeof(fvek_keys)); if(rs != sizeof(fvek_keys)) { dis_printf(L_ERROR, "Cannot read whole FVEK keys in the FVEK file\n"); return FALSE; } /* Create the FVEK datum */ *fvek_datum = dis_malloc(sizeof(datum_key_t) + sizeof(fvek_keys)); /* ... create the header */ datum_key = *fvek_datum; datum_key->header.datum_size = sizeof(datum_key_t) + sizeof(fvek_keys); datum_key->header.entry_type = 3; datum_key->header.value_type = DATUMS_VALUE_KEY; datum_key->header.error_status = 1; datum_key->algo = enc_method.single; datum_key->padd = 0; /* ... copy the keys */ memcpy((char*) *fvek_datum + sizeof(datum_key_t), fvek_keys, sizeof(fvek_keys)); return TRUE; } dislocker-0.7.3/src/metadata/guid.c000066400000000000000000000071031375503125700171540ustar00rootroot00000000000000/* -*- 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 "dislocker/metadata/guid.h" /** * Some GUIDs found in BitLocker */ const guid_t INFORMATION_OFFSET_GUID = { 0x3b, 0xd6, 0x67, 0x49, 0x29, 0x2e, 0xd8, 0x4a, 0x83, 0x99, 0xf6, 0xa3, 0x39, 0xe3, 0xd0, 0x01 }; const guid_t EOW_INFORMATION_OFFSET_GUID = { 0x3b, 0x4d, 0xa8, 0x92, 0x80, 0xdd, 0x0e, 0x4d, 0x9e, 0x4e, 0xb1, 0xe3, 0x28, 0x4e, 0xae, 0xd8 }; /** * Get raw GUID data and format it in a formated GUID * * @param raw_guid GUID directly extracted * @param formated_guid (out) A GUID ready to be printed (needs 37 bytes) */ void format_guid(uint8_t *raw_guid, char* formated_guid) { int i, j; memset(formated_guid, 0, 37); for(i = 3, j = 0; i >= 0; i--, j += 2) sprintf(&formated_guid[j], "%.2X", raw_guid[i]); // 4*2 = 8 sprintf(&formated_guid[j], "-"); j++; for(i = 5; i > 3; i--, j += 2) sprintf(&formated_guid[j], "%.2X", raw_guid[i]); // 13 sprintf(&formated_guid[j], "-"); j++; for(i = 7; i > 5; i--, j += 2) sprintf(&formated_guid[j], "%.2X", raw_guid[i]); // 18 sprintf(&formated_guid[j], "-"); j++; for(i = 8; i < 10; i++, j += 2) sprintf(&formated_guid[j], "%.2X", raw_guid[i]); // 23 sprintf(&formated_guid[j], "-"); j++; for(i = 10; i < 16; i++, j += 2) sprintf(&formated_guid[j], "%.2X", raw_guid[i]); // 36... + 1 = 37 } /** * Check if two guids match * * @param guid_1 The first guid to compare * @param guid_2 The second guid to compare * @return TRUE if match, FALSE otherwise */ int check_match_guid(guid_t guid_1, guid_t guid_2) { return ( guid_1[0] == guid_2[0] && guid_1[1] == guid_2[1] && guid_1[2] == guid_2[2] && guid_1[3] == guid_2[3] && guid_1[4] == guid_2[4] && guid_1[5] == guid_2[5] && guid_1[6] == guid_2[6] && guid_1[7] == guid_2[7] && guid_1[8] == guid_2[8] && guid_1[9] == guid_2[9] && guid_1[10] == guid_2[10] && guid_1[11] == guid_2[11] && guid_1[12] == guid_2[12] && guid_1[13] == guid_2[13] && guid_1[14] == guid_2[14] && guid_1[15] == guid_2[15] ); } #ifdef _HAVE_RUBY static VALUE rb_format_guid(VALUE self, VALUE rb_vGuid) { (void) self; char* guid = StringValuePtr(rb_vGuid); char formated_guid[37]; format_guid((uint8_t*) guid, formated_guid); return rb_str_new(formated_guid, 37); } void Init_guid(VALUE rb_cDislockerMetadata) { VALUE rb_mDisMetadataGuid = rb_define_module_under(rb_cDislockerMetadata, "GUID"); VALUE offset_guids = rb_ary_new3( 2, rb_str_new((const char*)INFORMATION_OFFSET_GUID, 16), rb_str_new((const char*)EOW_INFORMATION_OFFSET_GUID, 16) ); rb_define_const(rb_mDisMetadataGuid, "INFORMATION_OFFSETS", offset_guids); rb_define_singleton_method(rb_mDisMetadataGuid, "pretty", rb_format_guid, 1); } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/metadata/metadata.c000066400000000000000000001100631375503125700200040ustar00rootroot00000000000000/* -*- 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. */ #define _GNU_SOURCE 1 #include "dislocker/encryption/crc32.h" #include "dislocker/metadata/metadata.priv.h" #include "dislocker/metadata/metadata_config.h" #include "dislocker/metadata/print_metadata.h" #include "dislocker/dislocker.priv.h" #include #define BLKSSZGET _IO(0x12,104)/* get block device sector size */ /* * On Darwin and FreeBSD, files are opened using 64 bits offsets/variables * and O_LARGEFILE isn't defined */ #if defined(__DARWIN) || defined(__FREEBSD) # define O_LARGEFILE 0 #endif /* __DARWIN || __FREEBSD */ static int get_volume_header( volume_header_t *volume_header, int fd, off_t partition_offset ); static int check_volume_header( dis_metadata_t dis_metadata, int volume_fd, off_t disk_offset ); static int begin_compute_regions( volume_header_t* vh, int fd, off_t disk_offset, dis_regions_t* regions ); static int end_compute_regions(dis_metadata_t dis_meta); static int get_metadata(off_t source, void **metadata, int fd); static int get_dataset(void* metadata, bitlocker_dataset_t** dataset); static int get_eow_information(off_t source, void** eow_infos, int fd); static int get_metadata_lazy_checked( volume_header_t* volume_header, int fd, void** metadata, off_t disk_offset, unsigned char force_block, dis_regions_t *regions ); static int get_eow_check_valid( volume_header_t *volume_header, int fd, void **eow_infos, off_t disk_offset ); dis_metadata_config_t dis_metadata_config_new() { size_t len = sizeof(struct _dis_metadata_config); dis_metadata_config_t dis_meta_cfg = dis_malloc(len); if(dis_meta_cfg == NULL) return NULL; memset(dis_meta_cfg, 0, len); return dis_meta_cfg; } void dis_metadata_config_destroy(dis_metadata_config_t dis_meta_cfg) { if(dis_meta_cfg) dis_free(dis_meta_cfg); } dis_metadata_t dis_metadata_new(dis_metadata_config_t dis_metadata_cfg) { if(!dis_metadata_cfg) return NULL; dis_metadata_t dis_meta = dis_malloc(sizeof(struct _dis_metadata)); memset(dis_meta, 0, sizeof(struct _dis_metadata)); dis_meta->volume_header = dis_malloc(sizeof(volume_header_t)); memset(dis_meta->volume_header, 0, sizeof(volume_header_t)); dis_meta->cfg = dis_metadata_cfg; return dis_meta; } dis_metadata_t dis_metadata_get(dis_context_t dis_ctx) { if(!dis_ctx) return NULL; return dis_ctx->metadata; } int dis_metadata_initialize(dis_metadata_t dis_meta) { if(!dis_meta) return DIS_RET_ERROR_DISLOCKER_INVAL; dis_metadata_config_t dis_meta_cfg = dis_meta->cfg; int ret = DIS_RET_SUCCESS; void* metadata = NULL; bitlocker_information_t* information = NULL; bitlocker_dataset_t* dataset = NULL; /* Getting volume infos */ if(!get_volume_header( dis_meta->volume_header, dis_meta_cfg->fve_fd, dis_meta_cfg->offset)) { dis_printf( L_CRITICAL, "Error during reading the volume: not enough byte read.\n" ); return DIS_RET_ERROR_VOLUME_HEADER_READ; } //Windows 10 1903 exFAT if (!dis_meta->volume_header->sector_size) { uint64_t nSectorSize = 0; ioctl(dis_meta_cfg->fve_fd, BLKSSZGET, &nSectorSize); if(!nSectorSize) nSectorSize = 512; dis_meta->volume_header->sector_size = (uint16_t)nSectorSize; } //Windows 10 1903 exFAT /* For debug purpose, print the volume header retrieved */ print_volume_header(L_DEBUG, dis_meta); checkupdate_dis_meta_state(dis_meta_cfg, DIS_STATE_AFTER_VOLUME_HEADER); /* Checking the volume header */ if(!check_volume_header(dis_meta, dis_meta_cfg->fve_fd, dis_meta_cfg->offset)) { dis_printf(L_CRITICAL, "Cannot parse volume header. Abort.\n"); return DIS_RET_ERROR_VOLUME_HEADER_CHECK; } checkupdate_dis_meta_state(dis_meta_cfg, DIS_STATE_AFTER_VOLUME_CHECK); /* Fill the regions the metadata occupy on disk */ if(!begin_compute_regions( dis_meta->volume_header, dis_meta_cfg->fve_fd, dis_meta_cfg->offset, dis_meta->virt_region)) { dis_printf( L_CRITICAL, "Can't compute regions from volume header. Abort.\n" ); return DIS_RET_ERROR_METADATA_OFFSET; } /* Getting BitLocker metadata and validate them */ if(!get_metadata_lazy_checked( dis_meta->volume_header, dis_meta_cfg->fve_fd, &metadata, dis_meta_cfg->offset, dis_meta_cfg->force_block, dis_meta->virt_region)) { dis_printf( L_CRITICAL, "A problem occured during the retrieving of metadata. Abort.\n" ); return DIS_RET_ERROR_METADATA_CHECK; } if(!metadata) { dis_printf( L_CRITICAL, "Can't find a valid set of metadata on the disk. Abort.\n" ); return DIS_RET_ERROR_METADATA_CHECK; } /* Don't use dis_meta->information here as metadata are not validated yet */ information = metadata; /* Checking BitLocker version */ if(information->version > V_SEVEN) { dis_printf( L_CRITICAL, "Program designed only for BitLocker version 2 and less, " "the version here is %hd. Abort.\n", information->version ); return DIS_RET_ERROR_METADATA_VERSION_UNSUPPORTED; } dis_printf(L_INFO, "BitLocker metadata found and parsed.\n"); dis_meta->information = information; /* Now that we have the information, get the dataset within it */ if(get_dataset(metadata, &dataset) != TRUE) { dis_printf(L_CRITICAL, "Unable to find a valid dataset. Abort.\n"); return DIS_RET_ERROR_DATASET_CHECK; } dis_meta->dataset = dataset; /* For debug purpose, print the metadata */ print_information(L_DEBUG, dis_meta); print_data(L_DEBUG, dis_meta); checkupdate_dis_meta_state(dis_meta_cfg, DIS_STATE_AFTER_BITLOCKER_INFORMATION_CHECK); /* * Initialize region to report as filled with zeroes, if asked from the NTFS * layer. This is to mimic BitLocker's behaviour. */ if((ret = end_compute_regions(dis_meta)) != DIS_RET_SUCCESS) { dis_printf(L_CRITICAL, "Unable to compute regions. Abort.\n"); return ret; } return ret; } int dis_metadata_destroy(dis_metadata_t dis_meta) { if(!dis_meta) return DIS_RET_ERROR_DISLOCKER_INVAL; if(dis_meta->volume_header) dis_free(dis_meta->volume_header); if(dis_meta->information) dis_free(dis_meta->information); dis_metadata_config_destroy(dis_meta->cfg); dis_free(dis_meta); return DIS_RET_SUCCESS; } /** * Read the beginning of a volume and put it in a volume_header_t structure * * @param volume_header A volume header structure to complete * @param fd A file descriptor to the volume * @param offset The initial partition offset * @return TRUE if result can be trusted, FALSE otherwise */ static int get_volume_header(volume_header_t *volume_header, int fd, off_t offset) { if(!volume_header || fd < 0) return FALSE; // Go to the beginning dis_lseek(fd, offset, SEEK_SET); dis_printf(L_DEBUG, "Reading volume header...\n"); // Read and place data into the volume_header_t structure ssize_t nb_read = dis_read(fd, volume_header, sizeof(volume_header_t)); // Check if we read all we wanted if(nb_read != sizeof(volume_header_t)) return FALSE; dis_printf(L_DEBUG, "Volume header read\n"); return TRUE; } /** * Get BitLocker's version from the volume header * * @param volume_header A volume header structure to check * @return V_VISTA or V_SEVEN according to the version found, or -1 if not * recognized */ static inline int get_version_from_volume_header(volume_header_t *volume_header) { if(memcmp(BITLOCKER_SIGNATURE, volume_header->signature, BITLOCKER_SIGNATURE_SIZE) == 0) { if(volume_header->metadata_lcn == 0) return V_SEVEN; return V_VISTA; } return -1; } /** * Check the volume header * * @param volume_header A volume header structure to check * @param volume_fd The opened file descriptor of the BitLocker volume * @param disk_offset The offset of the beginning of the volume * @return TRUE if result can be trusted, FALSE otherwise */ static int check_volume_header(dis_metadata_t dis_meta, int volume_fd, off_t disk_offset) { if(!dis_meta || volume_fd < 0) return FALSE; volume_header_t* volume_header = dis_meta->volume_header; guid_t volume_guid; /* Checking sector size */ if(volume_header->sector_size == 0) { dis_printf(L_ERROR, "The sector size found is null.\n"); return FALSE; } /* Check the signature */ if(memcmp(BITLOCKER_SIGNATURE, volume_header->signature, BITLOCKER_SIGNATURE_SIZE) == 0) { memcpy(volume_guid, volume_header->guid, sizeof(guid_t)); } else if(memcmp(BITLOCKER_TO_GO_SIGNATURE, volume_header->signature, BITLOCKER_TO_GO_SIGNATURE_SIZE) == 0) { memcpy(volume_guid, volume_header->bltg_guid, sizeof(guid_t)); } else { dis_printf( L_ERROR, "The signature of the volume (%.8s) doesn't match the " "BitLocker's ones (" BITLOCKER_SIGNATURE " or " BITLOCKER_TO_GO_SIGNATURE "). Abort.\n", volume_header->signature ); return FALSE; } /* * There's no BitLocker GUID in the volume header for volumes encrypted by * Vista */ if(get_version_from_volume_header(volume_header) == V_VISTA) return TRUE; /* Check if we're running under EOW mode */ extern guid_t INFORMATION_OFFSET_GUID, EOW_INFORMATION_OFFSET_GUID; if(check_match_guid(volume_guid, INFORMATION_OFFSET_GUID)) { dis_printf(L_INFO, "Volume GUID (INFORMATION OFFSET) supported\n"); } else if(check_match_guid(volume_guid, EOW_INFORMATION_OFFSET_GUID)) { dis_printf(L_INFO, "Volume has EOW_INFORMATION_OFFSET_GUID.\n"); // First: get the EOW informations no matter what off_t source = (off_t) volume_header->eow_information_off[0]; void* eow_infos = NULL; if(get_eow_information(source, &eow_infos, volume_fd)) { dis_meta->eow_information = eow_infos; // Second: print them print_eow_infos(L_DEBUG, dis_meta); dis_free(eow_infos); dis_meta->eow_information = NULL; // Third: check if this struct passes checks if(get_eow_check_valid(volume_header, volume_fd, &eow_infos, disk_offset)) { dis_printf(L_INFO, "EOW information at offset % " F_OFF_T " passed the tests\n", source); dis_free(eow_infos); } else { dis_printf(L_ERROR, "EOW information at offset % " F_OFF_T " failed to pass the tests\n", source); } } else { dis_printf(L_ERROR, "Getting EOW information at offset % " F_OFF_T " failed\n", source); } dis_printf(L_ERROR, "EOW volume GUID not supported.\n"); return FALSE; } else { dis_printf(L_ERROR, "Unknown volume GUID, not supported.\n"); return FALSE; } return TRUE; } /** * This function compute the real offsets when the metadata_lcn doesn't equal 0 * This is because of Vista which compute offsets differently than Seven * This also takes into account BitLocker-to-go's volume header structure * difference in the offsets * * @param vh The volume header structure already taken * @param fd The opened file descriptor of the BitLocker volume * @param disk_offset Initial partition offset * @param regions The 3 offsets of the BitLocker INFORMATION structure (which * corresponds to our bitlocker_information_t structure) will be put in the 3 * first addr member of this array * @return TRUE if result can be trusted, FALSE otherwise */ static int begin_compute_regions(volume_header_t* vh, int fd, off_t disk_offset, dis_regions_t* regions) { // Check parameters if(!vh || fd < 0) return FALSE; if(memcmp(BITLOCKER_SIGNATURE, vh->signature, BITLOCKER_SIGNATURE_SIZE) == 0) { /* This is when the volume has been encrypted with W$ 7 or 8 */ if(get_version_from_volume_header(vh) == V_SEVEN) { regions[0].addr = vh->information_off[0]; regions[1].addr = vh->information_off[1]; regions[2].addr = vh->information_off[2]; return TRUE; } /* And when encrypted with W$ Vista: */ dis_printf( L_DEBUG, "MetadataLcn = %" PRIu64 " | SectorsPerCluster = %" PRIu64 " | SectorSize = %" PRIu64 "\n", vh->metadata_lcn, vh->sectors_per_cluster, vh->sector_size ); uint64_t new_offset = vh->metadata_lcn * vh->sectors_per_cluster * vh->sector_size; dis_printf( L_DEBUG, "Changing first metadata offset from %#" PRIx64 " to %#" PRIx64 "\n", vh->information_off[0], new_offset ); regions[0].addr = new_offset; /* Now that we have the first offset, go get the others */ bitlocker_information_t* information = NULL; if(!get_metadata( (off_t) new_offset + disk_offset, (void**) &information, fd )) return FALSE; regions[1].addr = information->information_off[1]; regions[2].addr = information->information_off[2]; dis_free(information); } else if(memcmp(BITLOCKER_TO_GO_SIGNATURE, vh->signature, BITLOCKER_TO_GO_SIGNATURE_SIZE) == 0) { regions[0].addr = vh->bltg_header[0]; regions[1].addr = vh->bltg_header[1]; regions[2].addr = vh->bltg_header[2]; } else { dis_printf(L_ERROR, "Wtf!? Unknown volume signature not supported."); return FALSE; } return TRUE; } /** * This finalizes the initialization of the regions informations, putting the * metadata file sizes in the right place. * * @param dis_metadata The metadata structure * @return DIS_RET_SUCCESS on success, other value on failure */ static int end_compute_regions(dis_metadata_t dis_meta) { if(!dis_meta) return DIS_RET_ERROR_DISLOCKER_INVAL; dis_regions_t* regions = dis_meta->virt_region; volume_header_t* volume_header = dis_meta->volume_header; bitlocker_information_t* information = dis_meta->information; uint16_t sector_size = volume_header->sector_size; uint8_t sectors_per_cluster = volume_header->sectors_per_cluster; uint32_t cluster_size = 0; uint64_t metafiles_size = 0; /* * Alignment isn't the same for W$ Vista (size-of-a-cluster aligned on * 0x4000) and 7&8 (size-of-a-sector aligned on 0x10000). * This gives the metadata files' sizes in the NTFS layer. */ if(information->version == V_VISTA) { cluster_size = (uint32_t)sector_size * sectors_per_cluster; metafiles_size = (uint64_t)(cluster_size+0x3fff) & ~(cluster_size-1); } else if(information->version == V_SEVEN) { metafiles_size = (uint64_t)(~(sector_size-1) & (sector_size+0xffff)); } dis_printf(L_DEBUG, "Metadata files size: %#" PRIx64 "\n", metafiles_size); /* * The first 3 regions are for INFORMATION metadata, they have the same size */ regions[0].size = metafiles_size; regions[1].size = metafiles_size; regions[2].size = metafiles_size; dis_meta->nb_virt_region = 3; if(information->version == V_VISTA) { // Nothing special to do } else if(information->version == V_SEVEN) { /* * On BitLocker 7's volumes, there's a virtualized space used to store * firsts NTFS sectors. BitLocker creates a NTFS file to not write on * the area and displays a zeroes-filled file. * A second part, new from Windows 8, follows... */ datum_virtualization_t* datum = NULL; if(!get_next_datum(dis_meta, UINT16_MAX, DATUMS_VALUE_VIRTUALIZATION_INFO, NULL, (void**)&datum)) { char* type_str = datumvaluetypestr(DATUMS_VALUE_VIRTUALIZATION_INFO); dis_printf( L_ERROR, "Error looking for the VIRTUALIZATION datum type" " %hd (%s). Internal failure, abort.\n", DATUMS_VALUE_VIRTUALIZATION_INFO, type_str ); dis_free(type_str); datum = NULL; return DIS_RET_ERROR_VIRTUALIZATION_INFO_DATUM_NOT_FOUND; } dis_meta->nb_virt_region++; regions[3].addr = information->boot_sectors_backup; regions[3].size = datum->nb_bytes; /* Another area to report as filled with zeroes, new to W8 as well */ if(information->curr_state == METADATA_STATE_SWITCHING_ENCRYPTION) { dis_meta->nb_virt_region++; regions[4].addr = information->encrypted_volume_size; regions[4].size = information->convert_size; } dis_meta->virtualized_size = (off_t)datum->nb_bytes; dis_printf( L_DEBUG, "Virtualized info size: %#" F_OFF_T "\n", dis_meta->virtualized_size ); /* Extended info is new to Windows 8 */ size_t win7_size = datum_value_types_prop[datum->header.value_type].size_header; size_t actual_size = ((size_t)datum->header.datum_size) & 0xffff; if(actual_size > win7_size) { dis_meta->xinfo = &datum->xinfo; dis_printf(L_DEBUG, "Got extended info\n"); } } else { /* Explicitly mark a BitLocker version as unsupported */ dis_printf(L_ERROR, "Unsupported BitLocker version (%hu)\n", information->version); return DIS_RET_ERROR_METADATA_VERSION_UNSUPPORTED; } return DIS_RET_SUCCESS; } /** * Read the beginning of one of the BitLocker metadata area and put data in a * bitlocker_information_t structure. * This also take the dataset header as it's in the bitlocker_information_t. * Then includes datums in the read. * * @param source The beginning address of the header * @param metadata One of the BitLocker metadata, beginning at source * @param fd A file descriptor to the volume * @return TRUE if result can be trusted, FALSE otherwise */ static int get_metadata(off_t source, void **metadata, int fd) { if(!source || fd < 0 || !metadata) return FALSE; // Go to the beginning of the BitLocker header dis_lseek(fd, source, SEEK_SET); dis_printf(L_DEBUG, "Reading bitlocker header at %#" F_OFF_T "...\n", source); bitlocker_information_t information; /* * Read and place data into the bitlocker_information_t structure, * this is the metadata's header */ ssize_t nb_read = dis_read(fd, &information, sizeof(bitlocker_information_t)); // Check if we read all we wanted if(nb_read != sizeof(bitlocker_information_t)) { dis_printf(L_ERROR, "get_metadata::Error, not all bytes read: %d, %d" " expected (1).\n", nb_read, sizeof(bitlocker_information_t)); return FALSE; } /* * Now that we now the size of the metadata, allocate a buffer and read data * to complete it */ size_t size = (size_t)(information.version == V_SEVEN ? information.size << 4 : information.size); if(size <= sizeof(bitlocker_information_t)) { dis_printf(L_ERROR, "get_metadata::Error, metadata size is lesser than the" " size of the metadata header\n"); return FALSE; } size_t rest_size = size - sizeof(bitlocker_information_t); *metadata = dis_malloc(size); // Copy the header at the begining of the metadata memcpy(*metadata, &information, sizeof(bitlocker_information_t)); dis_printf(L_DEBUG, "Reading data...\n"); // Read the rest, the real data nb_read = dis_read(fd, *metadata + sizeof(bitlocker_information_t), rest_size); // Check if we read all we wanted if((size_t) nb_read != rest_size) { dis_printf(L_ERROR, "get_metadata::Error, not all bytes read: %d, %d" " expected (2).\n", nb_read, rest_size); return FALSE; } dis_printf(L_DEBUG, "End get_metadata.\n"); return TRUE; } /** * Get the dataset in the metadata * No allocation is performed * * @param metadata The one to check for a dataset * @param dataset The resulting dataset * @return TRUE if result can be trusted, FALSE otherwise */ static int get_dataset(void* metadata, bitlocker_dataset_t** dataset) { // Check parameters if(!metadata) return FALSE; bitlocker_information_t* information = metadata; *dataset = &information->dataset; /* Check this dataset validity */ if( (*dataset)->copy_size < (*dataset)->header_size || (*dataset)->size > (*dataset)->copy_size || (*dataset)->copy_size - (*dataset)->header_size < 8 ) { dis_printf(L_DEBUG, "size=%#x, copy_size=%#x, header_size=%#x\n"); return FALSE; } return TRUE; } /** * This function reads the EOW information in two phases: first the header, then * the payload. * * @param source The beginning address of the EOW information * @param eow_infos One of the EOW information, beginning at source * @param fd A file descriptor to the volume * @return TRUE if result can be trusted, FALSE otherwise */ static int get_eow_information(off_t source, void** eow_infos, int fd) { if(!source || fd < 0 || !eow_infos) return FALSE; /* Go to the beginning of the EOW Information header */ dis_lseek(fd, source, SEEK_SET); dis_printf(L_DEBUG, "Reading EOW Information header at %#" F_OFF_T "...\n", source); bitlocker_eow_infos_t eow_infos_hdr; /* * Read and place data into the bitlocker_eow_infos_t structure, * this is the EOW information header */ ssize_t nb_read = dis_read(fd, &eow_infos_hdr, sizeof(bitlocker_eow_infos_t)); // Check if we read all we wanted if(nb_read != sizeof(bitlocker_eow_infos_t)) { dis_printf(L_ERROR, "get_eow_information::Error, not all bytes read: %d," " %d expected (1).\n", nb_read, sizeof(bitlocker_eow_infos_t)); return FALSE; } size_t size = eow_infos_hdr.infos_size; if(size <= sizeof(bitlocker_eow_infos_t)) { dis_printf(L_ERROR, "get_eow_information::Error, EOW information size is" " lesser than the size of the header\n"); return FALSE; } size_t rest_size = size - sizeof(bitlocker_information_t); *eow_infos = dis_malloc(size); // Copy the header at the begining of the EOW information memcpy(*eow_infos, &eow_infos_hdr, sizeof(bitlocker_eow_infos_t)); dis_printf(L_DEBUG, "Reading EOW information's payload...\n"); // Read the rest, the payload nb_read = dis_read(fd, *eow_infos + sizeof(bitlocker_eow_infos_t), rest_size); // Check if we read all we wanted if((size_t) nb_read != rest_size) { dis_printf(L_ERROR, "get_eow_information::Error, not all bytes read: %d, " "%d expected (2).\n", nb_read, rest_size); return FALSE; } dis_printf(L_DEBUG, "End get_eow_information.\n"); return TRUE; } /** * Get metadata/validations one by one, stop at the first valid * If a metadata block is forced to be taken, use this one without validation * * @param volume_header The volume header structure already taken * @param fd The opened file descriptor of the volume * @param metadata A validated metadata resulting of this function * @param disk_offset The offset to the beginning of the volume * @param force_block The metadata block to use (0 if any) * @param regions Regions used by metadata, mostly the metadata's offsets for * use in this function * @return TRUE if result can be trusted, FALSE otherwise */ static int get_metadata_lazy_checked( volume_header_t *volume_header, int fd, void **metadata, off_t disk_offset, unsigned char force_block, dis_regions_t *regions) { // Check parameters if(!volume_header || fd < 0 || !metadata) return FALSE; dis_printf(L_DEBUG, "Entering get_metadata_lazy_checked\n"); bitlocker_information_t* information = NULL; unsigned int metadata_size = 0; unsigned char current = 0; unsigned int metadata_crc32 = 0; off_t validations_offset = 0; bitlocker_validations_t validations; /* If the user wants a specific metadata block */ if(force_block != 0) { dis_printf(L_INFO, "Obtaining block n°%d, forced by user...\n", force_block); // Get the metadata if(!get_metadata((off_t)regions[force_block-1].addr + disk_offset, metadata, fd)) { dis_printf(L_ERROR, "Can't get metadata (n°%d, forced by user)\n", force_block); return FALSE; } dis_printf(L_DEBUG, "Block n°%d obtained\n", force_block); return TRUE; } while(current < 3) { /* Get the metadata */ if(!get_metadata((off_t)regions[current].addr + disk_offset, metadata, fd)) { /* dis_printf(L_ERROR, "Can't get metadata (n°%d)\n", current+1); return FALSE; */ if (++current >= 3) //Consider metadata corruption return FALSE; continue; } /* Check some small things */ /* Calculate validations offset */ validations_offset = 0; information = *metadata; metadata_size = (unsigned int)(information->version == V_SEVEN ? ((unsigned int)information->size) << 4 : information->size); validations_offset = (off_t)regions[current].addr + metadata_size; dis_printf( L_DEBUG, "Reading validations data at offset %#" PRIx64 ".\n", validations_offset ); /* Go to the beginning of the BitLocker validation header */ dis_lseek(fd, validations_offset + disk_offset, SEEK_SET); /* Get the validations metadata */ memset(&validations, 0, sizeof(bitlocker_validations_t)); ssize_t nb_read = dis_read(fd, &validations, sizeof(bitlocker_validations_t)); if(nb_read != sizeof(bitlocker_validations_t)) { /* dis_printf(L_ERROR, "Error, can't read all validations data.\n"); return FALSE; */ if (++current >= 3) //Consider bad sectors return FALSE; continue; } /* Check the validity */ metadata_crc32 = crc32((unsigned char*)*metadata, metadata_size); /* * TODO add the thing with the datum contained in this validation metadata * this provides a better checksum (sha256 hash) * => This needs the VMK (decrypted) */ dis_printf(L_DEBUG, "Looking if %#x == %#x for metadata validation\n", metadata_crc32, validations.crc32); ++current; if(metadata_crc32 == validations.crc32) { dis_printf(L_DEBUG, "We have a winner (n°%d)!\n", current); break; } else dis_free(*metadata); } if(current > 3) return FALSE; return TRUE; } /** * Get the EOW information structure one by one, stop at the first valid * * @param volume_header The volume header structure already taken * @param fd The opened file descriptor of the volume * @param eow_infos The EOW information resulting of this function * @param disk_offset The offset to the beginning of the volume * @return TRUE if result can be trusted, FALSE otherwise */ static int get_eow_check_valid( volume_header_t *volume_header, int fd, void **eow_infos, off_t disk_offset) { // Check parameters if(!volume_header || fd < 0 || !eow_infos) return FALSE; dis_printf(L_DEBUG, "Entering get_eow_check_valid\n"); bitlocker_eow_infos_t *eow_infos_hdr = NULL; unsigned char current = 0; unsigned int eow_infos_size = 0; unsigned int computed_crc32 = 0; off_t curr_offset = 0; int payload_size = 0; while(current < 2) { /* Compute the on-disk offset */ curr_offset = (off_t)volume_header->eow_information_off[current] + disk_offset; ++current; /* Get the EOW information */ if(!get_eow_information(curr_offset, eow_infos, fd)) { dis_printf(L_ERROR, "Can't get EOW information (n°%d)\n", current); return FALSE; } eow_infos_hdr = (bitlocker_eow_infos_t*) *eow_infos; /* Check some small things */ /* Check sizes */ if(eow_infos_hdr->infos_size <= eow_infos_hdr->header_size) { dis_free(*eow_infos); continue; } /* Check size & number of regions */ payload_size = eow_infos_hdr->infos_size - eow_infos_hdr->header_size; if((payload_size & 7) || eow_infos_hdr->nb_regions != (uint32_t)(payload_size >> 3)) { dis_free(*eow_infos); continue; } /* Check the crc32 validity */ eow_infos_size = eow_infos_hdr->infos_size; computed_crc32 = crc32((unsigned char*)*eow_infos, eow_infos_size); dis_printf(L_DEBUG, "Looking if %#x == %#x for EOW information validation\n", computed_crc32, eow_infos_hdr->crc32); if(computed_crc32 == eow_infos_hdr->crc32) { dis_printf(L_DEBUG, "We have a winner (n°%d)!\n", current); break; } else { dis_free(*eow_infos); } } if(current == 2) return FALSE; return TRUE; } /** * Check for dangerous state the BitLocker volume can be in. * * @param dis_metadata The metadata structure * @return TRUE if it's safe to use the volume, FALSE otherwise */ int check_state(dis_metadata_t dis_metadata) { // Check parameter if(!dis_metadata) return FALSE; bitlocker_information_t* information = dis_metadata->information; char* enc = "enc"; char* dec = "dec"; char* unknown = "unknown-"; char* next_state = NULL; if(information->next_state == METADATA_STATE_DECRYPTED) next_state = dec; else if(information->next_state == METADATA_STATE_ENCRYPTED) next_state = enc; else { next_state = unknown; dis_printf(L_WARNING, "The next state of the volume is currently unknown of " PROGNAME ", but it would be awesome if you could spare some time to report " "this state (%d) to the author and how did you do to have this. " "Many thanks.\n", information->next_state ); } switch(information->curr_state) { case METADATA_STATE_SWITCHING_ENCRYPTION: dis_printf(L_ERROR, "The volume is currently being %srypted, which is an unstable " "state. If you know what you're doing, pass `-s' to the command" " line, but be aware it may result in data corruption.\n", next_state ); return FALSE; case METADATA_STATE_SWITCH_ENCRYPTION_PAUSED: dis_printf(L_WARNING, "The volume is currently in a secure state, " "but don't resume the %sryption while using " PROGNAME " for " "the volume would become instable, resulting in data " "corruption.\n", next_state ); break; case METADATA_STATE_DECRYPTED: dis_printf(L_WARNING, "The disk is about to get encrypted. Using " PROGNAME " while " "encrypting the disk in parallel, this may corrupt your data.\n" ); } return TRUE; } void dis_metadata_vista_vbr_fve2ntfs(dis_metadata_t dis_meta, void* vbr) { if(!dis_meta || !vbr) return; volume_header_t* volume_header = (volume_header_t*) vbr; dis_printf( L_DEBUG, " Fixing sector (Vista): replacing signature " "and MFTMirror field by: %#" PRIx64 "\n", dis_meta->volume_header->mft_mirror ); /* This is for the NTFS signature */ memcpy(volume_header->signature, NTFS_SIGNATURE, NTFS_SIGNATURE_SIZE); /* And this is for the MFT Mirror field */ volume_header->mft_mirror = dis_meta->volume_header->mft_mirror; } void dis_metadata_vista_vbr_ntfs2fve(dis_metadata_t dis_meta, void* vbr) { if(!dis_meta || !vbr) return; volume_header_t* volume_header = (volume_header_t*) vbr; /* This is for the BitLocker signature */ memcpy( volume_header->signature, BITLOCKER_SIGNATURE, BITLOCKER_SIGNATURE_SIZE ); /* And this is for the metadata LCN */ volume_header->metadata_lcn = dis_meta->information->information_off[0] / (uint64_t)( volume_header->sectors_per_cluster * volume_header->sector_size ); dis_printf( L_DEBUG, " Fixing sector (Vista): replacing signature " "and MFTMirror field by: %#" PRIx64 "\n", volume_header->metadata_lcn ); } int dis_metadata_is_overwritten( dis_metadata_t dis_meta, off_t offset, size_t size) { if(!dis_meta) return DIS_RET_ERROR_DISLOCKER_INVAL; off_t metadata_offset = 0; off_t metadata_size = 0; size_t virt_loop = 0; for(virt_loop = 0; virt_loop < dis_meta->nb_virt_region; virt_loop++) { metadata_size = (off_t)dis_meta->virt_region[virt_loop].size; if(metadata_size == 0) continue; metadata_offset = (off_t)dis_meta->virt_region[virt_loop].addr; if(offset >= metadata_offset && offset < metadata_offset + metadata_size) { dis_printf(L_DEBUG, "In metadata file (1:%#" F_OFF_T ")\n", offset); return DIS_RET_ERROR_METADATA_FILE_OVERWRITE; } if(offset < metadata_offset && offset + (off_t)size > metadata_offset) { dis_printf(L_DEBUG, "In metadata file (2:%#" F_OFF_T "+ %#" F_SIZE_T ")\n", offset, size); return DIS_RET_ERROR_METADATA_FILE_OVERWRITE; } } return DIS_RET_SUCCESS; } /** * Retrieve the volume size from the first sector. * * @param volume_header The partition MBR to look at. NTFS or FVE, np * @return The volume size or 0, which indicates the size couldn't be retrieved */ uint64_t dis_metadata_volume_size_from_vbr(dis_metadata_t dis_meta) { if(!dis_meta) return 0; volume_header_t* volume_header = dis_meta->volume_header; uint64_t volume_size = 0; if(volume_header->nb_sectors_16b) { volume_size = (uint64_t)volume_header->sector_size * volume_header->nb_sectors_16b; } else if(volume_header->nb_sectors_32b) { volume_size = (uint64_t)volume_header->sector_size * volume_header->nb_sectors_32b; } else if(volume_header->nb_sectors_64b) { volume_size = (uint64_t)volume_header->sector_size * volume_header->nb_sectors_64b; } return volume_size; } void* dis_metadata_set_dataset(dis_metadata_t dis_meta, void* new_dataset) { if(!dis_meta) return NULL; if(!new_dataset) return dis_meta->dataset; void* old_dataset = dis_meta->dataset; dis_meta->dataset = new_dataset; return old_dataset; } void* dis_metadata_set_volume_header(dis_metadata_t dis_meta, void* new_volume_header) { if(!dis_meta) return NULL; if(!new_volume_header) return dis_meta->volume_header; void* old_volume_header = dis_meta->volume_header; dis_meta->volume_header = new_volume_header; return old_volume_header; } uint16_t dis_metadata_sector_size(dis_metadata_t dis_meta) { return dis_meta->volume_header->sector_size; } version_t dis_metadata_information_version(dis_metadata_t dis_meta) { return dis_meta->information->version; } uint64_t dis_metadata_encrypted_volume_size(dis_metadata_t dis_meta) { return dis_meta->information->encrypted_volume_size; } uint64_t dis_metadata_ntfs_sectors_address(dis_metadata_t dis_meta) { return dis_meta->information->boot_sectors_backup; } uint64_t dis_metadata_mftmirror(dis_metadata_t dis_meta) { return dis_meta->information->mftmirror_backup; } uint32_t dis_metadata_backup_sectors_count(dis_metadata_t dis_meta) { return dis_meta->information->nb_backup_sectors; } #ifdef _HAVE_RUBY #include #include #include static VALUE rb_cDislockerMetadata_has_clearkey(VALUE self) { void* vmk_datum = NULL; dis_metadata_t dis_meta = DATA_PTR(self); if(dis_metadata_has_clear_key(dis_meta, &vmk_datum) == TRUE && vmk_datum != NULL) { return Qtrue; } return Qfalse; } static void rb_cDislockerMetadata_free(dis_metadata_t dis_meta) { dis_close(dis_meta->cfg->fve_fd); if(dis_metadata_destroy(dis_meta) != DIS_RET_SUCCESS) { rb_raise( rb_eRuntimeError, "Wrong metadata, object cannot be cleanly freed." ); } } static VALUE rb_cDislockerMetadata_alloc(VALUE klass) { dis_metadata_t dis_meta = NULL; return Data_Wrap_Struct( klass, NULL, rb_cDislockerMetadata_free, dis_meta ); } static VALUE rb_cDislockerMetadata_init(int argc, VALUE *argv, VALUE self) { int fd = -1; char cForceBlock = 0; dis_metadata_config_t dis_meta_cfg = NULL; if(argc < 1) { rb_raise( rb_eArgError, "initialize: fvevol_path [offset] [force_block]" ); } Check_Type(argv[0], T_STRING); fd = open(StringValuePtr(argv[0]), O_RDWR|O_LARGEFILE); dis_meta_cfg = dis_metadata_config_new(); dis_meta_cfg->fve_fd = fd; if(argc > 1) { Check_Type(argv[1], T_FIXNUM); dis_meta_cfg->offset = NUM2OFFT(argv[1]); } if(argc > 2) { Check_Type(argv[2], T_FIXNUM); cForceBlock = (char) NUM2CHR(argv[2]); if(cForceBlock >= 1 && cForceBlock <= 3) dis_meta_cfg->force_block = (unsigned char) cForceBlock; else dis_meta_cfg->force_block = 0; } DATA_PTR(self) = dis_metadata_new(dis_meta_cfg); if(dis_metadata_initialize(DATA_PTR(self)) != DIS_RET_SUCCESS) rb_raise(rb_eRuntimeError, "Couldn't retrieve metadata"); return Qnil; } void Init_metadata(VALUE rb_mDislocker) { VALUE rb_cDislockerMetadata = rb_define_class_under( rb_mDislocker, "Metadata", rb_cObject ); extern VALUE dis_rb_classes[DIS_RB_CLASS_MAX]; dis_rb_classes[DIS_RB_CLASS_METADATA] = rb_cDislockerMetadata; rb_define_alloc_func(rb_cDislockerMetadata, rb_cDislockerMetadata_alloc); rb_define_method( rb_cDislockerMetadata, "initialize", rb_cDislockerMetadata_init, -1 ); rb_define_method( rb_cDislockerMetadata, "has_clearkey?", rb_cDislockerMetadata_has_clearkey, 0 ); Init_datum(rb_cDislockerMetadata); Init_guid(rb_cDislockerMetadata); } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/metadata/print_metadata.c000066400000000000000000000234161375503125700212250ustar00rootroot00000000000000/* -*- 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 #include "dislocker/metadata/metadata.priv.h" #include "dislocker/metadata/datums.h" #include "dislocker/metadata/print_metadata.h" /** BitLocker's states into string */ static const char* states_str[] = { "NULL", "DECRYPTED", "SWITCHING ENCRYPTION", "EOW ACTIVATED", "ENCRYPTED", "SWITCHING ENCRYPTION PAUSED", "UNKNOWN STATE (too big)" }; /** * Print a volume header structure into a human-readable format * * @param level The level above which we're gonna print * @param dis_metadata The metadata structure */ void print_volume_header(DIS_LOGS level, dis_metadata_t dis_meta) { if(!dis_meta) return; volume_header_t *volume_header = dis_meta->volume_header; char rec_id[37]; format_guid(volume_header->guid, rec_id); dis_printf(level, "=====[ Volume header informations ]=====\n"); dis_printf(level, " Signature: '%.8s'\n", volume_header->signature); dis_printf(level, " Sector size: 0x%1$04x (%1$hu) bytes\n", volume_header->sector_size); dis_printf(level, " Sector per cluster: 0x%1$02x (%1$hhu) bytes\n", volume_header->sectors_per_cluster); dis_printf(level, " Reserved clusters: 0x%1$04x (%1$hu) bytes\n", volume_header->reserved_clusters); dis_printf(level, " Fat count: 0x%1$02x (%1$hhu) bytes\n", volume_header->fat_count); dis_printf(level, " Root entries: 0x%1$04x (%1$hu) bytes\n", volume_header->root_entries); dis_printf(level, " Number of sectors (16 bits): 0x%1$04x (%1$hu) bytes\n", volume_header->nb_sectors_16b); dis_printf(level, " Media descriptor: 0x%1$02x (%1$hhu) bytes\n", volume_header->media_descriptor); dis_printf(level, " Sectors per fat: 0x%1$04x (%1$hu) bytes\n", volume_header->sectors_per_fat); dis_printf(level, " Hidden sectors: 0x%1$08x (%1$u) bytes\n", volume_header->hidden_sectors); dis_printf(level, " Number of sectors (32 bits): 0x%1$08x (%1$u) bytes\n", volume_header->nb_sectors_32b); dis_printf(level, " Number of sectors (64 bits): 0x%1$016" PRIx64 " (%1$" PRIu64 ") bytes\n", volume_header->nb_sectors_64b); dis_printf(level, " MFT start cluster: 0x%1$016" PRIx64 " (%1$" PRIu64 ") bytes\n", volume_header->mft_start_cluster); dis_printf(level, " Metadata Lcn: 0x%1$016" PRIx64 " (%1$" PRIu64 ") bytes\n", volume_header->metadata_lcn); dis_printf(level, " Volume GUID: '%.37s'\n", rec_id); dis_printf(level, " First metadata header offset: 0x%016" PRIx64 "\n", volume_header->information_off[0]); dis_printf(level, " Second metadata header offset: 0x%016" PRIx64 "\n", volume_header->information_off[1]); dis_printf(level, " Third metadata header offset: 0x%016" PRIx64 "\n", volume_header->information_off[2]); dis_printf(level, " Boot Partition Identifier: '0x%04hx'\n", volume_header->boot_partition_identifier); dis_printf(level, "========================================\n"); } /** * Return the state in which BitLocker is in as a (constant) string * * @param state The state to translate * @return The state as a constant string */ static const char* get_state_str(dis_metadata_state_t state) { if(state >= sizeof(states_str) / sizeof(char*)) return states_str[sizeof(states_str) / sizeof(char*) - 1]; return states_str[state]; } /** * Print a BitLocker header structure into a human-readable format * * @param level The level above which we're gonna print * @param dis_meta The metadata structure */ void print_information(DIS_LOGS level, dis_metadata_t dis_meta) { if(!dis_meta) return; bitlocker_information_t *information = dis_meta->information; int metadata_size = information->version == V_SEVEN ? information->size << 4 : information->size; dis_printf(level, "=====================[ BitLocker information structure ]=====================\n"); dis_printf(level, " Signature: '%.8s'\n", information->signature); dis_printf(level, " Total Size: 0x%1$04x (%1$u) bytes (including signature and data)\n", metadata_size); dis_printf(level, " Version: %hu\n", information->version); dis_printf(level, " Current state: %s (%hu)\n", get_state_str(information->curr_state), information->curr_state); dis_printf(level, " Next state: %s (%hu)\n", get_state_str(information->next_state), information->next_state); dis_printf(level, " Encrypted volume size: %1$" PRIu64 " bytes (%1$#" PRIx64 "), ~%2$" PRIu64 " MB\n", information->encrypted_volume_size, information->encrypted_volume_size / (1024*1024)); dis_printf(level, " Size of convertion region: %1$#x (%1$u)\n", information->convert_size); dis_printf(level, " Number of boot sectors backuped: %1$u sectors (%1$#x)\n", information->nb_backup_sectors); dis_printf(level, " First metadata header offset: %#" PRIx64 "\n", information->information_off[0]); dis_printf(level, " Second metadata header offset: %#" PRIx64 "\n", information->information_off[1]); dis_printf(level, " Third metadata header offset: %#" PRIx64 "\n", information->information_off[2]); if(information->version == V_SEVEN) dis_printf(level, " Boot sectors backup address: %#" PRIx64 "\n", information->boot_sectors_backup); else dis_printf(level, " NTFS MftMirror field: %#" PRIx64 "\n", information->mftmirror_backup); print_dataset(level, dis_meta); dis_printf(level, "=============================================================================\n"); } /** * Print a BitLocker dataset structure into human-readable format * * @param level The level above which we're gonna print * @param dis_metadata The metadata structure */ void print_dataset(DIS_LOGS level, dis_metadata_t dis_meta) { if(!dis_meta) return; bitlocker_dataset_t* dataset = dis_meta->dataset; time_t ts; char* date = NULL; char* cipher = cipherstr(dataset->algorithm); char formated_guid[37]; format_guid(dataset->guid, formated_guid); ntfs2utc(dataset->timestamp, &ts); date = strdup(asctime(gmtime(&ts))); chomp(date); dis_printf(level, " ----------------------------{ Dataset header }----------------------------\n"); dis_printf(level, " Dataset size: 0x%1$08x (%1$d) bytes (including data)\n", dataset->size); dis_printf(level, " Unknown data: 0x%08x (always 0x00000001)\n", dataset->unknown1); dis_printf(level, " Dataset header size: 0x%08x (always 0x00000030)\n", dataset->header_size); dis_printf(level, " Dataset copy size: 0x%1$08x (%1$d) bytes\n", dataset->copy_size); dis_printf(level, " Dataset GUID: '%.39s'\n", formated_guid); dis_printf(level, " Next counter: %u\n", dataset->next_counter); dis_printf(level, " Encryption Type: %s (%#hx)\n", cipher, dataset->algorithm); dis_printf(level, " Epoch Timestamp: %u sec, that to say %s\n", (unsigned int)ts, date); dis_printf(level, " --------------------------------------------------------------------------\n"); dis_free(cipher); free(date); } /** * Print a BitLocker EOW information structure into human-readable format * * @param dis_metadata The metadata structure */ void print_eow_infos(DIS_LOGS level, dis_metadata_t dis_meta) { if(!dis_meta) return; bitlocker_eow_infos_t* eow_infos = dis_meta->eow_information; dis_printf(level, "=======================[ BitLocker EOW informations ]========================\n"); dis_printf(level, " Signature: '%.8s'\n", eow_infos->signature); dis_printf(level, " Structure size: 0x%1$04x (%1$hu)\n", eow_infos->header_size); dis_printf(level, " On-disk size: 0x%1$04x (%1$hu)\n", eow_infos->infos_size); dis_printf(level, " Sector size (1): 0x%1$04x (%1$hu)\n", eow_infos->sector_size1); dis_printf(level, " Sector size (2): 0x%1$04x (%1$hu)\n", eow_infos->sector_size2); dis_printf(level, " Unknown (0x14): 0x%1$08x (%1$u)\n", eow_infos->unknown_14); dis_printf(level, " Convlog size: 0x%1$08x (%1$u)\n", eow_infos->convlog_size); dis_printf(level, " Unknown (0x1c): 0x%1$08x (%1$u)\n", eow_infos->unknown_1c); dis_printf(level, " Number of regions: %u\n", eow_infos->nb_regions); dis_printf(level, " Crc32: %x\n", eow_infos->crc32); dis_printf(level, " On-disk offsets: %#" PRIx64 "\n", eow_infos->disk_offsets); dis_printf(level, "=============================================================================\n"); } /** * Print data of a given metadata * * @param level The level above which we're gonna print * @param dis_metadata The metadata structure */ void print_data(DIS_LOGS level, dis_metadata_t dis_meta) { // Check parameters if(!dis_meta) return; bitlocker_dataset_t* dataset = dis_meta->dataset; void* data = NULL; void* end_dataset = 0; int loop = 0; data = (char*)dataset + dataset->header_size; end_dataset = (char*)dataset + dataset->size; while(1) { /* Begin with reading the header */ datum_header_safe_t header; if(data >= end_dataset) break; if(!get_header_safe(data, &header)) break; if(data + header.datum_size > end_dataset) break; dis_printf(level, "\n"); dis_printf(level, "=======[ Datum n°%d informations ]=======\n", ++loop); print_one_datum(level, data); dis_printf(level, "=========================================\n"); data += header.datum_size; } } dislocker-0.7.3/src/metadata/vmk.c000066400000000000000000000210741375503125700170240ustar00rootroot00000000000000/* -*- 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 #include #include #include #include "dislocker/encryption/decrypt.h" #include "dislocker/metadata/vmk.h" /** * Get the VMK datum using a clear key * * @param dis_metadata The metadata structure * @param vmk_datum The datum_key_t found, containing the unencrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_clearkey(dis_metadata_t dis_meta, void** vmk_datum) { // Check parameters if(!dis_meta) return FALSE; uint8_t* recovery_key = NULL; size_t rk_size = 0; int result = FALSE; char* type_str = datumvaluetypestr(DATUMS_VALUE_KEY); /* Search for a clear key */ if(!dis_metadata_has_clear_key(dis_meta, vmk_datum)) { dis_printf(L_ERROR, "No clear key found. Use a different method.\n"); dis_free(type_str); *vmk_datum = NULL; return FALSE; } dis_printf(L_DEBUG, "============[ There's a clear key here! ]============\n"); print_one_datum(L_DEBUG, *vmk_datum); dis_printf(L_DEBUG, "==================[ Clear key end ]==================\n"); /* Get the clear key */ void* key_datum = NULL; if(!get_nested_datumvaluetype(*vmk_datum, DATUMS_VALUE_KEY, &key_datum) || !key_datum) { dis_printf( L_ERROR, "Error looking for the nested datum type %hd (%s) in the VMK one. " "Internal failure, abort.\n", DATUMS_VALUE_KEY, type_str ); dis_free(type_str); *vmk_datum = NULL; return FALSE; } if(!get_payload_safe(key_datum, (void**)&recovery_key, &rk_size)) { dis_printf( L_ERROR, "Error getting the key to decrypt VMK from the datum %s. " "Internal failure, abort.\n", type_str ); dis_free(type_str); *vmk_datum = NULL; return FALSE; } dis_free(type_str); /* Get the encrypted VMK which will be decrypted with the previously found clear key */ void* aesccm_datum = NULL; if(!get_nested_datumvaluetype( *vmk_datum, DATUMS_VALUE_AES_CCM, &aesccm_datum )) { type_str = datumvaluetypestr(DATUMS_VALUE_AES_CCM); dis_printf( L_ERROR, "Error in finding the %s including the VMK. " "Internal failure, abort.\n", type_str ); dis_free(type_str); dis_free(recovery_key); *vmk_datum = NULL; return FALSE; } /* Run the decryption */ result = get_vmk( (datum_aes_ccm_t*) aesccm_datum, recovery_key, rk_size, (datum_key_t**) vmk_datum ); dis_free(recovery_key); return result; } /** * Final stage to decrypt the VMK, other functions should pass here * * @param vmk_datum The encrypted VMK datum to decrypt * @param recovery_key The key to use to decrypt the encrypted VMK datum * @param key_size The key size * @param vmk The found datum_key_t containing the decrypted VMK * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk(datum_aes_ccm_t* vmk_datum, uint8_t* recovery_key, size_t key_size, datum_key_t** vmk) { // Check parameters if(!vmk_datum || !recovery_key || key_size == 0) return FALSE; unsigned int vmk_size = 0; unsigned int header_size = 0; dis_printf(L_DEBUG, "=====================[ ENCRYPTED VMK ]====================\n"); print_one_datum(L_DEBUG, *vmk); dis_printf(L_DEBUG, "==========================================================\n"); dis_printf(L_DEBUG, "=====================[ RECOVERY KEY ]=====================\n"); hexdump(L_DEBUG, recovery_key, key_size); dis_printf(L_DEBUG, "==========================================================\n"); header_size = datum_value_types_prop[vmk_datum->header.value_type].size_header; vmk_size = vmk_datum->header.datum_size - header_size; if(key_size > (size_t) (UINT_MAX / 8)) { dis_printf( L_ERROR, "Recovery key size too big, unsupported: %#" F_SIZE_T "\n", key_size ); return FALSE; } if(!decrypt_key( (unsigned char*) vmk_datum + header_size, vmk_size, vmk_datum->mac, vmk_datum->nonce, recovery_key, (unsigned int)key_size * 8, (void**) vmk )) { if(*vmk) { dis_printf(L_INFO, "VMK found (but not good it seems):\n"); hexdump(L_INFO, (void*)*vmk, vmk_size); dis_free(*vmk); *vmk = NULL; } dis_printf(L_ERROR, "Can't decrypt correctly the VMK. Abort.\n"); return FALSE; } if(!*vmk) { dis_printf(L_ERROR, "Can't decrypt VMK, abort.\n"); return FALSE; } dis_printf(L_DEBUG, "==========================[ VMK ]=========================\n"); print_one_datum(L_DEBUG, *vmk); dis_printf(L_DEBUG, "==========================================================\n"); return TRUE; } /** * Retrieve the VMK datum associated to a known GUID * * @param dis_metadata The metadata structure * @param guid The GUID of the VMK datum to find * @param vmk_datum The found datum * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_datum_from_guid(dis_metadata_t dis_meta, guid_t guid, void** vmk_datum) { // Check parameters if(!dis_meta || !guid) return FALSE; *vmk_datum = NULL; while(1) { if(!get_next_datum( dis_meta, DATUMS_ENTRY_VMK, DATUMS_VALUE_VMK, *vmk_datum, vmk_datum )) { *vmk_datum = NULL; return FALSE; } if(check_match_guid((*(datum_vmk_t**) vmk_datum)->guid, guid)) return TRUE; } } /** * Retrieve the VMK datum associated to priority range * The priority is determined with the last two bytes of a VMK datum's nonce * * @param dis_metadata The metadata structure * @param min_range The minimal range to search for * @param max_range The maximal range to search for * @param vmk_datum The found datum * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_datum_from_range(dis_metadata_t dis_meta, uint16_t min_range, uint16_t max_range, void** vmk_datum) { // Check parameters if(!dis_meta) return FALSE; uint16_t datum_range = 0; *vmk_datum = NULL; while(1) { if(!get_next_datum( dis_meta, DATUMS_ENTRY_VMK, DATUMS_VALUE_VMK, *vmk_datum, vmk_datum )) { *vmk_datum = NULL; return FALSE; } /* The last two bytes of the nonce is used as a priority range */ memcpy(&datum_range, &((*(datum_vmk_t**)vmk_datum)->nonce[10]), 2); if(min_range <= datum_range && datum_range <= max_range) return TRUE; } } /** * Retrieve the VMK using the VMK file. * * @param cfg The configuration structure, therefore having the VMK file * @param vmk_datum The VMK datum * @return TRUE if result can be trusted, FALSE otherwise */ int get_vmk_from_file(dis_config_t* cfg, void** vmk_datum) { if(!cfg) return FALSE; off_t actual_size = -1; int file_fd = -1; datum_key_t* datum_key = NULL; ssize_t rs; char vmk_keys[32] = {0,}; off_t expected_size = sizeof(vmk_keys); file_fd = dis_open(cfg->vmk_file, O_RDONLY); if(file_fd == -1) { dis_printf(L_ERROR, "Cannot open VMK file (%s)\n", cfg->vmk_file); return FALSE; } /* Check the file's size */ actual_size = dis_lseek(file_fd, 0, SEEK_END); if(actual_size != expected_size) { dis_printf( L_ERROR, "Wrong VMK file size, expected %d but has %d\n", expected_size, actual_size ); return FALSE; } /* Read everything */ dis_lseek(file_fd, 0, SEEK_SET); rs = dis_read(file_fd, vmk_keys, sizeof(vmk_keys)); if(rs != sizeof(vmk_keys)) { dis_printf(L_ERROR, "Cannot read whole VMK key in the VMK file\n"); return FALSE; } /* Create the VMK datum */ *vmk_datum = dis_malloc(sizeof(datum_key_t) + sizeof(vmk_keys)); /* ... create the header */ datum_key = *vmk_datum; datum_key->header.datum_size = sizeof(datum_key_t) + sizeof(vmk_keys); datum_key->header.entry_type = 3; datum_key->header.value_type = DATUMS_VALUE_KEY; datum_key->header.error_status = 1; datum_key->algo = AES_256_DIFFUSER; datum_key->padd = 0; /* ... copy the keys */ memcpy((char*) *vmk_datum + sizeof(datum_key_t), vmk_keys, sizeof(vmk_keys)); return TRUE; } dislocker-0.7.3/src/ntfs/000077500000000000000000000000001375503125700152515ustar00rootroot00000000000000dislocker-0.7.3/src/ntfs/clock.c000066400000000000000000000025341375503125700165140ustar00rootroot00000000000000/* -*- 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 "dislocker/ntfs/clock.h" // Constant used to convert NTFS timestamp into a UTC one #define NTFS_TIME_OFFSET ((ntfs_time_t)(369 * 365 + 89) *24 * 3600 * 10000000) /** * Convert a ntfs timestamp into a utc one * * @param t NTFS timestamp * @param ts UTC timestamp */ void ntfs2utc(ntfs_time_t t, time_t *ts) { if (ts == NULL) return; *ts = (time_t) ((t - (uint64_t)(NTFS_TIME_OFFSET)) / (uint64_t)10000000 ); } dislocker-0.7.3/src/ntfs/encoding.c000066400000000000000000000043511375503125700172060ustar00rootroot00000000000000/* -*- 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 "dislocker/ntfs/encoding.h" /** * Convert an UTF-16 string into a wchar_t string. wchar_t may be defined as * UTF-16 or UTF-32, this function doesn't care. * The UTF-32 string is supposed to be, at least, utf16_length*2 long. * * @param utf16 An UTF-16 string * @param utf16_length The UTF-16 string length * @param utf32 The wchar_t string resulted from the conversion * @return TRUE if result can be trusted, FALSE otherwise */ int utf16towchars(uint16_t* utf16, size_t utf16_length, wchar_t* utf32) { if(!utf16 || !utf32) return FALSE; memset(utf32, 0, utf16_length*2); size_t loop = 0; size_t nb_iter = utf16_length/2; for(loop = 0; loop < nb_iter; ++loop) utf32[loop] = utf16[loop]; return TRUE; } /** * Convert an ascii null-terminated string into an UTF-16 null-terminated * string. * The UTF-16 string is supposed to be, at least, (strlen(ascii)+1)*2 long. * * @param ascii A null-terminated ascii string * @param utf16 The UTF-16 string resulted from the conversion * @return TRUE if result can be trusted, FALSE otherwise */ int asciitoutf16(const uint8_t* ascii, uint16_t* utf16) { if(!ascii || !utf16) return FALSE; size_t len = strlen((char*)ascii); memset(utf16, 0, (len+1)*2); size_t loop = 0; for(loop = 0; loop < len; loop++) utf16[loop] = ascii[loop]; return TRUE; } dislocker-0.7.3/src/ruby.c000066400000000000000000000030101375503125700154160ustar00rootroot00000000000000/* -*- 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. */ #ifdef _HAVE_RUBY #include "dislocker/ruby.h" VALUE dis_rb_str_vcatf(VALUE str, const char *fmt, va_list ap) { int written = -1; size_t len = 1024; do { char cstr[len]; written = vsnprintf(cstr, len, fmt, ap); if(written < 0) rb_raise(rb_eRuntimeError, "vsnprintf error"); if((size_t) written >= len) len *= 2; else { rb_str_cat2(str, cstr); break; } } while(1); return str; } VALUE dis_rb_str_catf(VALUE str, const char *format, ...) { va_list ap; va_start(ap, format); str = rb_str_vcatf(str, format, ap); va_end(ap); return str; } #endif /* _HAVE_RUBY */ dislocker-0.7.3/src/samples/000077500000000000000000000000001375503125700157435ustar00rootroot00000000000000dislocker-0.7.3/src/samples/metadata_from_bekfile.rb000066400000000000000000000026041375503125700225560ustar00rootroot00000000000000#!/usr/bin/env ruby # # 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. # # $LOAD_PATH.unshift '@libdir@' require '../libdislocker' if ARGV.empty? or ARGV.length < 2 puts "Usage: #{$0} [ []]" exit 1 end volume = ARGV[0] bekfile = ARGV[1] offset = 0 block = 0 if ARGV.length > 2 offset = ARGV[2].to_i end if ARGV.length > 3 block = ARGV[3] end dismeta = Dislocker::Metadata.new volume, offset, block disaccess = Dislocker::Accesses.new(dismeta) disaccess.vmk_from_bekfile bekfile fvek = disaccess.get_fvek puts ". FVEK found:" puts fvek dislocker-0.7.3/src/samples/metadata_from_clearkey.rb000066400000000000000000000026721375503125700227610ustar00rootroot00000000000000#!/usr/bin/env ruby # # 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. # # $LOAD_PATH.unshift '@libdir@' require '../libdislocker' if ARGV.empty? or ARGV.length < 1 puts "Usage: #{$0} [ []]" exit 1 end volume = ARGV[0] offset = 0 block = 0 if ARGV.length > 1 offset = ARGV[1].to_i end if ARGV.length > 2 block = ARGV[2] end dismeta = Dislocker::Metadata.new volume, offset, block disaccess = Dislocker::Accesses.new(dismeta) if dismeta.has_clearkey? disaccess.vmk_from_clearkey fvek = disaccess.fvek puts ". FVEK found:" puts fvek else puts "No clear key found, use another decryption mean." end dislocker-0.7.3/src/samples/metadata_from_userpass.rb000066400000000000000000000026041375503125700230220ustar00rootroot00000000000000#!/usr/bin/env ruby # # 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. # # $LOAD_PATH.unshift '@libdir@' require '../libdislocker' if ARGV.empty? or ARGV.length < 2 puts "Usage: #{$0} [ []]" exit 1 end volume = ARGV[0] userpass = ARGV[1] offset = 0 block = 0 if ARGV.length > 2 offset = ARGV[2].to_i end if ARGV.length > 3 block = ARGV[3] end dismeta = Dislocker::Metadata.new volume, offset, block disaccess = Dislocker::Accesses.new(dismeta) disaccess.vmk_from_userpass userpass fvek = disaccess.fvek puts ". FVEK found:" puts fvek dislocker-0.7.3/src/xstd/000077500000000000000000000000001375503125700152615ustar00rootroot00000000000000dislocker-0.7.3/src/xstd/xstdio.c000066400000000000000000000116371375503125700167470ustar00rootroot00000000000000/* -*- 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 #include #include #include #include #include #include #include "dislocker/xstd/xstdio.h" #include "dislocker/xstd/xstdlib.h" /* Files descriptors to know where to put logs */ static FILE* fds[DIS_LOGS_NB] = {0,}; /* Keep track of the verbosity level */ static int verbosity = L_QUIET; /* Levels transcription into strings */ static char* msg_tab[DIS_LOGS_NB] = { "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG" }; /** Saving STDIN parameters before unbufferisation */ static struct termios ti_save; static int tty_fd = -1; /** * Initialize outputs for display messages * * @param v Application verbosity * @param file File where putting logs (stdout if NULL) */ void dis_stdio_init(DIS_LOGS v, const char* file) { verbosity = v; FILE* log = NULL; if(file) { log = fopen(file, LOG_MODE); if(!log) { perror("Error opening log file (falling back to stdout)"); log = stdout; } } else log = stdout; switch(v) { default: verbosity = L_DEBUG; // fall through case L_DEBUG: fds[L_DEBUG] = log; // fall through case L_INFO: fds[L_INFO] = log; // fall through case L_WARNING: fds[L_WARNING] = log; // fall through case L_ERROR: fds[L_ERROR] = log; // fall through case L_CRITICAL: fds[L_CRITICAL] = log; break; case L_QUIET: if (log != stdout) fclose(log); break; } dis_printf(L_DEBUG, "Verbosity level to %s (%d) into '%s'\n", msg_tab[verbosity], verbosity, file == NULL ? "stdout" : file); } /** * Create and return an unbuffered stdin * * @return The file descriptor of the unbuffered input tty */ int get_input_fd() { if(tty_fd > -1) return tty_fd; struct termios ti; if ((tty_fd = open("/dev/tty", O_RDONLY | O_NONBLOCK)) < 0) return -1; tcgetattr(tty_fd, &ti); ti_save = ti; ti.c_lflag &= (typeof(tcflag_t)) ~(ICANON | ECHO); ti.c_cc[VMIN] = 1; ti.c_cc[VTIME] = 0; tcsetattr(tty_fd, TCSANOW, &ti); return tty_fd; } /** * Close the unbuffered stdin if opened */ void close_input_fd() { if(tty_fd > -1) { tcsetattr(tty_fd, TCSANOW, &ti_save); close(tty_fd); } } /** * Endify in/outputs */ void dis_stdio_end() { close_input_fd(); if(verbosity > L_QUIET) fclose(fds[L_CRITICAL]); } /** * Remove the '\n', '\r' or '\r\n' before the first '\0' if present * * @param string String where the '\n', '\r' or '\r\n' is removed */ void chomp(char* string) { size_t len = strlen(string); if(len == 0) return; if(string[len - 1] == '\n' || string[len - 1] == '\r') string[len - 1] = '\0'; if(len == 1) return; if(string[len - 2] == '\r') string[len - 2] = '\0'; } /** * Do as printf(3) but displaying nothing if verbosity is not high enough * Messages are redirected to the log file if specified into xstdio_init() * * @param level Level of the message to print * @param format String to display (cf printf(3)) * @param ... Cf printf(3) * @return The number of characters printed */ int dis_printf(DIS_LOGS level, const char* format, ...) { int ret = -1; if(verbosity < level || verbosity <= L_QUIET) return 0; if(level >= DIS_LOGS_NB) level = L_DEBUG; va_list arg; va_start(arg, format); ret = dis_vprintf(level, format, arg); va_end(arg); fflush(fds[level]); return ret; } /** * Do as vprintf(3) but displaying nothing if verbosity is not high enough * Messages are redirected to the log file if specified into xstdio_init() * * @param level Level of the message to print * @param format String to display (cf vprintf(3)) * @param ap Cf vprintf(3) */ int dis_vprintf(DIS_LOGS level, const char* format, va_list ap) { if(verbosity < level || verbosity <= L_QUIET) return 0; if(level >= DIS_LOGS_NB) level = L_DEBUG; if(!fds[level]) return 0; time_t current_time = time(NULL); char* time2string = ctime(¤t_time); chomp(time2string); fprintf(fds[level], "%s [%s] ", time2string, msg_tab[level]); return vfprintf(fds[level], format, ap); } dislocker-0.7.3/src/xstd/xstdlib.c000066400000000000000000000032301375503125700170740ustar00rootroot00000000000000/* -*- 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 "dislocker/xstd/xstdlib.h" #include "dislocker/xstd/xstdio.h" /** * malloc wrapper * * @param size The size of the memory to allocate * @return A pointer to the memory */ void* dis_malloc(size_t size) { if(size == 0) { dis_printf(L_CRITICAL, "malloc(0) is not accepted, aborting\n"); exit(2); } void* p = malloc(size); dis_printf(L_DEBUG, "New memory allocation at %p (%#zx bytes allocated)\n", p, size); if(p == NULL) { dis_printf(L_CRITICAL, "Cannot allocate more memory, aborting\n"); exit(2); } return p; } /** * free wrapper * * @param pointer The pointer to the memory to free */ void dis_free(void *pointer) { dis_printf(L_DEBUG, "Freeing pointer at address %p\n", pointer); free(pointer); }