From 3b32f754a417f5ec4d723958073b4cfba690a68a Mon Sep 17 00:00:00 2001 From: Anton Date: Sat, 30 Nov 2024 18:30:29 +0400 Subject: [PATCH] Add PIV smart card keyfile encryption --- .github/workflows/build-macos.yml | 124 +++ .github/workflows/main.yml | 128 +++ .gitignore | 10 + README.md | 2 + doc/html/Bluekeys.html | 42 + doc/html/Keyfiles.html | 9 + doc/html/Security Tokens & Smart Cards.html | 7 +- src/Build/Include/Makefile.inc | 36 +- src/Common/EMVCard.h | 4 +- src/Common/EMVToken.h | 2 +- src/Common/Language.xml | 12 +- src/Common/MockSecurityToken.cpp | 69 ++ src/Common/MockSecurityToken.h | 49 + src/Common/SecurityToken.cpp | 383 +++++++- src/Common/SecurityToken.h | 160 +++- src/Core/Core.h | 24 +- src/Core/Core.make | 12 +- src/Core/CoreBase.cpp | 18 +- src/Core/CoreBase.h | 8 +- src/Core/CoreTest.cpp | 955 ++++++++++++++++++++ src/Core/MountOptions.cpp | 7 + src/Core/MountOptions.h | 6 +- src/Core/Unix/CoreServiceProxy.h | 7 +- src/Core/Unix/CoreUnix.cpp | 2 + src/Core/VolumeCreator.cpp | 2 +- src/Core/VolumeCreator.h | 1 + src/Driver/Fuse/FuseService.h | 5 +- src/Main/CommandLineInterface.cpp | 11 + src/Main/CommandLineInterface.h | 1 + src/Main/Forms/ChangePasswordDialog.cpp | 24 +- src/Main/Forms/ChangePasswordDialog.h | 2 +- src/Main/Forms/Forms.cpp | 92 +- src/Main/Forms/Forms.h | 32 +- src/Main/Forms/KeyfileGeneratorDialog.cpp | 35 +- src/Main/Forms/KeyfileGeneratorDialog.h | 1 + src/Main/Forms/MainFrame.cpp | 12 + src/Main/Forms/MainFrame.h | 1 + src/Main/Forms/MountOptionsDialog.cpp | 6 +- src/Main/Forms/SecurityTokenKeysDialog.cpp | 105 +++ src/Main/Forms/SecurityTokenKeysDialog.h | 54 ++ src/Main/Forms/VolumeCreationWizard.cpp | 12 +- src/Main/Forms/VolumeCreationWizard.h | 1 + src/Main/Forms/VolumePasswordPanel.cpp | 44 +- src/Main/Forms/VolumePasswordPanel.h | 6 +- src/Main/Forms/VolumePasswordWizardPage.cpp | 4 +- src/Main/Forms/VolumePasswordWizardPage.h | 4 +- src/Main/GraphicUserInterface.cpp | 59 +- src/Main/GraphicUserInterface.h | 3 +- src/Main/Main.make | 7 +- src/Main/TextUserInterface.cpp | 46 +- src/Main/TextUserInterface.h | 3 +- src/Main/Unix/Main.cpp | 2 + src/Main/UserInterface.cpp | 5 +- src/Main/UserInterface.h | 2 +- src/Makefile | 27 +- src/Platform/Buffer.cpp | 4 + src/Platform/Buffer.h | 2 +- src/Platform/FilesystemPath.h | 1 + src/Platform/Finally.h | 11 + src/Platform/PipelineStream.cpp | 62 ++ src/Platform/PipelineStream.h | 40 + src/Platform/PipelineStreamTest.cpp | 173 ++++ src/Platform/Platform.make | 4 + src/Platform/Unix/FilesystemPath.cpp | 9 + src/Testing/SampleTest.cpp | 46 + src/Testing/SampleTest.h | 15 + src/Testing/Testing.cpp | 94 ++ src/Testing/Testing.h | 130 +++ src/Testing/Testing.make | 6 + src/Volume/Keyfile.cpp | 205 ++++- src/Volume/Keyfile.h | 14 +- src/Volume/Volume.cpp | 14 +- src/Volume/Volume.h | 4 +- src/Volume/Volume.make | 5 +- 74 files changed, 3303 insertions(+), 221 deletions(-) create mode 100644 .github/workflows/build-macos.yml create mode 100644 .github/workflows/main.yml create mode 100644 doc/html/Bluekeys.html create mode 100644 src/Common/MockSecurityToken.cpp create mode 100644 src/Common/MockSecurityToken.h create mode 100644 src/Core/CoreTest.cpp create mode 100644 src/Main/Forms/SecurityTokenKeysDialog.cpp create mode 100644 src/Main/Forms/SecurityTokenKeysDialog.h create mode 100644 src/Platform/PipelineStream.cpp create mode 100644 src/Platform/PipelineStream.h create mode 100644 src/Platform/PipelineStreamTest.cpp create mode 100644 src/Testing/SampleTest.cpp create mode 100644 src/Testing/SampleTest.h create mode 100644 src/Testing/Testing.cpp create mode 100644 src/Testing/Testing.h create mode 100644 src/Testing/Testing.make diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml new file mode 100644 index 0000000000..d7b9570329 --- /dev/null +++ b/.github/workflows/build-macos.yml @@ -0,0 +1,124 @@ +name: Build and test macOS + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + create: + tags: + - '*' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + WX_BUILD_DIR: ${{ github.workspace }}/wxbuild + WX_ROOT: ${{ github.workspace }}/wxsrc + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ${{matrix.runner}} + strategy: + matrix: + runner: [macos-13] + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Download Packages + uses: carlosperate/download-file-action@v1.0.3 + id: download-packages + with: + file-url: 'http://s.sudre.free.fr/Software/files/Packages.dmg' + file-name: 'Packages.dmg' + location: '.' + + - name: Download macFUSE + uses: carlosperate/download-file-action@v1.0.3 + id: download-macfuse + with: + file-url: 'https://github.com/osxfuse/osxfuse/releases/download/macfuse-4.5.0/macfuse-4.5.0.dmg' + file-name: 'macfuse.dmg' + location: '.' + + - name: Download pkg-config + uses: carlosperate/download-file-action@v1.0.3 + id: download-pkg-config + with: + file-url: 'https://pkgconfig.freedesktop.org/releases/pkg-config-0.28.tar.gz' + file-name: pkg-config-0.28.tar.gz + location: '.' + + - name: Mount Packages + run: sudo hdiutil attach Packages.dmg + + - name: Mount macFUSE + run: sudo hdiutil attach macfuse.dmg + + - name: List Volumes directory context + run: ls -latr /Volumes || true + + - name: Install Packages + run: sudo installer -pkg "/Volumes/Packages 1.2.10/Install Packages.pkg" -target / + + - name: Install macFUSE + run: sudo installer -pkg "/Volumes/macFUSE/Install macFUSE.pkg" -target / + + - name: Build and install pkg-config + run: tar xvf pkg-config-0.28.tar.gz && cd pkg-config-0.28 && ./configure && make && sudo make install + + - name: Install yasm + run: brew install yasm + + - uses: actions/cache@v2 + name: Cache/restore wxWidgets + id: cache-wxwidgets + with: + path: | + ${{ env.WX_ROOT }} + ${{ env.WX_BUILD_DIR }} + key: wxwidgets + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - uses: actions/checkout@v2 + name: Checkout wxWidgets + with: + repository: 'wxWidgets/wxWidgets' + ref: 'v3.2.5' + path: ${{ env.WX_ROOT }} + submodules: 'recursive' + + - name: Show Xcode used + run: | + SDK_VERSION=$(xcrun --show-sdk-version); xcrun --show-sdk-path; xcrun --sdk macosx${SDK_VERSION} --show-sdk-path + + - name: Build wxWidgets + if: steps.cache-wxwidgets.outputs.cache-hit != 'true' + run: | + ls -l ${{env.WX_ROOT}} + (cd src && make WXSTATIC=FULL WX_ROOT=${{env.WX_ROOT}} WX_BUILD_DIR=${{env.WX_BUILD_DIR}} wxbuild); cat ${{ env.WX_BUILD_DIR }}/config.log + + - name: Build Veracrypt + run: cd src && make LOCAL_DEVELOPMENT_BUILD=true WXSTATIC=FULL WX_ROOT=${{env.WX_ROOT}} WX_BUILD_DIR=${{env.WX_BUILD_DIR}} && make LOCAL_DEVELOPMENT_BUILD=true WXSTATIC=1 package + + - name: Show directory structure + run: | + ls -R . + ls -l src || true + + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: '**/VeraCrypt*.dmg' + + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..c906c367bf --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,128 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master ] + pull_request: + branches: [ master ] + create: + tags: + - '*' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + WX_BUILD_DIR: ${{ github.workspace }}/wxbuild + WX_ROOT: ${{ github.workspace }}/wxsrc + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ${{matrix.runner}} + strategy: + matrix: + runner: [macos-13] + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Download Packages + uses: carlosperate/download-file-action@v1.0.3 + id: download-packages + with: + file-url: 'http://s.sudre.free.fr/Software/files/Packages.dmg' + file-name: 'Packages.dmg' + location: '.' + + - name: Download macFUSE + uses: carlosperate/download-file-action@v1.0.3 + id: download-macfuse + with: + file-url: 'https://github.com/osxfuse/osxfuse/releases/download/macfuse-4.5.0/macfuse-4.5.0.dmg' + file-name: 'macfuse.dmg' + location: '.' + + - name: Download pkg-config + uses: carlosperate/download-file-action@v1.0.3 + id: download-pkg-config + with: + file-url: 'https://pkgconfig.freedesktop.org/releases/pkg-config-0.28.tar.gz' + file-name: pkg-config-0.28.tar.gz + location: '.' + + - name: Mount Packages + run: sudo hdiutil attach Packages.dmg + + - name: Mount macFUSE + run: sudo hdiutil attach macfuse.dmg + + - name: List Volumes directory context + run: ls -latr /Volumes || true + + - name: Install Packages + run: sudo installer -pkg "/Volumes/Packages 1.2.10/Install Packages.pkg" -target / + + - name: Install macFUSE + run: sudo installer -pkg "/Volumes/macFUSE/Install macFUSE.pkg" -target / + + - name: Build and install pkg-config + run: tar xvf pkg-config-0.28.tar.gz && cd pkg-config-0.28 && ./configure && make && sudo make install + + - name: Install yasm + run: brew install yasm + + - uses: actions/cache@v2 + name: Cache/restore wxWidgets + id: cache-wxwidgets + with: + path: | + ${{ env.WX_ROOT }} + ${{ env.WX_BUILD_DIR }} + key: wxwidgets + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - uses: actions/checkout@v2 + name: Checkout wxWidgets + with: + repository: 'wxWidgets/wxWidgets' + ref: 'v3.2.5' + path: ${{ env.WX_ROOT }} + submodules: 'recursive' + + - name: Show Xcode used + run: | + SDK_VERSION=$(xcrun --show-sdk-version); xcrun --show-sdk-path; xcrun --sdk macosx${SDK_VERSION} --show-sdk-path + + - name: Build wxWidgets + if: steps.cache-wxwidgets.outputs.cache-hit != 'true' + run: | + ls -l ${{env.WX_ROOT}} + (cd src && make WXSTATIC=FULL WX_ROOT=${{env.WX_ROOT}} WX_BUILD_DIR=${{env.WX_BUILD_DIR}} wxbuild); cat ${{ env.WX_BUILD_DIR }}/config.log + + - name: Build Veracrypt + run: cd src && make LOCAL_DEVELOPMENT_BUILD=true WXSTATIC=FULL WX_ROOT=${{env.WX_ROOT}} WX_BUILD_DIR=${{env.WX_BUILD_DIR}} && make LOCAL_DEVELOPMENT_BUILD=true WXSTATIC=1 package + + - name: Show directory structure + run: | + ls -R . + ls -l src || true + + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: '**/VeraCrypt*.dmg' + + diff --git a/.gitignore b/.gitignore index 412edcca9d..80f85c7e51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,16 @@ # For those using Visual Studio Code for development .vscode/ +# Testing artifacts +Tests/**/*.raw +Tests/**/*.vol +Tests/**/*.bin +Tests/**/*.dmg +Tests/**/*.vc +Tests/**/*.key +**/*Testing +!src/Testing + # CLion .idea/ diff --git a/README.md b/README.md index 21f46ca757..dd00947aa9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![build](./actions/workflows/build-macos.yml/badge.svg) + This archive contains the source code of VeraCrypt. It is based on the original TrueCrypt 7.1a with security enhancements and modifications. diff --git a/doc/html/Bluekeys.html b/doc/html/Bluekeys.html new file mode 100644 index 0000000000..e0ba6c9a2e --- /dev/null +++ b/doc/html/Bluekeys.html @@ -0,0 +1,42 @@ + + + + +VeraCrypt - Free Open source disk encryption with strong security for the Paranoid + + + + + + +
+VeraCrypt +
+ + + +
+

+Documentation +>> +Bluekeys +

+ +
+

Bluekeys

+
+Security Tokens and Smart Cards, which support encryption (e.g. there are assymetric cryptography key on the card), can be used to issue blue key. +Blue key is just an ordinary keyfile encrypted using key stored on the smart card. Because usually it is not possible to extract the key from the smart card, +such a file could not be used independently from the card to decrypt the volume.

Please note that security tokens and smart cards are currently not +supported for Pre-Boot authentication of system encryption.

+
\ No newline at end of file diff --git a/doc/html/Keyfiles.html b/doc/html/Keyfiles.html index 04dd3463a4..f5d8c823c6 100644 --- a/doc/html/Keyfiles.html +++ b/doc/html/Keyfiles.html @@ -80,6 +80,15 @@

Keyfiles

smart cards protected by multiple PIN codes (which can be entered either using a hardware PIN pad or via the VeraCrypt GUI).

+

Optionally, keyfiles can be encrypted using PKCS-11 compliant security + tokens and smart cards. This provides additional level of security: + knowing the keyfile content is not enough, you also need a + security token or smart card. See chapter + Bluekeys. +

EMV-compliant smart cards' data can be used as keyfile, see chapter

Security Tokens & Smart Cards

-VeraCrypt supports security (or cryptographic) tokens and smart cards that can be accessed using the PKCS #11 (2.0 or later) protocol [23]. For more information, please see the section +VeraCrypt supports security (or cryptographic) tokens and smart cards that can be accessed using the PKCS #11 (2.0 or later) protocol [23]. There are two way these devices can be used with VeraCrypt. +
+Keyfiles +
  • As an additional encryption layer. For more infromation, please see Bluekeys
  • +.

    Please note that security tokens and smart cards are currently not supported for Pre-Boot authentication of system encryption.

    diff --git a/src/Build/Include/Makefile.inc b/src/Build/Include/Makefile.inc index 11ab12c24d..0ba95048ae 100644 --- a/src/Build/Include/Makefile.inc +++ b/src/Build/Include/Makefile.inc @@ -10,11 +10,21 @@ # code distribution packages. # -$(NAME): $(NAME).a +.PHONY: test-only lib $(NAME) + +ifeq "$(OBJS)" "" +$(NAME): test-only +else +$(NAME): lib +endif + +test-only: $(NAME)Testing $(NAME)Test.a +lib: $(NAME).a $(NAME)Test.a $(NAME)Testing clean: @echo Cleaning $(NAME) rm -f $(APPNAME) $(NAME).a $(OBJS) $(OBJSEX) $(OBJSNOOPT) $(OBJSHANI) $(OBJSSSE41) $(OBJSSSSE3) $(OBJS:.o=.d) $(OBJSEX:.oo=.d) $(OBJSNOOPT:.o0=.d) $(OBJSHANI:.oshani=.d) $(OBJSSSE41:.osse41=.d) $(OBJSSSSE3:.ossse3=.d) *.gch + rm -f $(NAME)Testing.a $(NAME)Test.a $(TEST_OBJS) %.o: %.c @echo Compiling $( m_aid; - vector> m_supportedAids; + vector > m_supportedAids; vector m_iccCert; vector m_issuerCert; vector m_cplcData; @@ -44,7 +44,7 @@ namespace VeraCrypt const static uint8 AMEX_AID[7]; const static uint8 MASTERCARD_AID[7]; const static uint8 VISA_AID[7]; - const static map> SUPPORTED_AIDS; + const static map > SUPPORTED_AIDS; EMVCard(); EMVCard(size_t slotId); diff --git a/src/Common/EMVToken.h b/src/Common/EMVToken.h index d82ea54224..8fd7496f27 100644 --- a/src/Common/EMVToken.h +++ b/src/Common/EMVToken.h @@ -35,7 +35,7 @@ namespace VeraCrypt friend void EMVTokenKeyfile::GetKeyfileData(vector & keyfileData) const; - static map > EMVCards; + static map > EMVCards; }; } diff --git a/src/Common/Language.xml b/src/Common/Language.xml index 9821bbe9c3..539fe80ef0 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -1,4 +1,4 @@ - + @@ -203,6 +203,10 @@ Add Mounted Volume to System Favorites... Analyze a System Crash... Backup Volume Header... + Reveal Red Key... + This will produce decrypted keyfile which can be used without using the smart card, thus reducing security to two factors. This keyfile should be stored securely. Are you sure to continue? + Red key is saved + Choose file to save red key to Benchmark... Set Header Key Derivation Algorithm... Change Volume Password... @@ -367,6 +371,12 @@ IMPORTANT: Move your mouse as randomly as possible within this window. The longer you move it, the better. This significantly increases security. When done, click 'Continue'. Secondary key (hexadecimal) Security token: + Security token key + Security Tokens... + Slot ID + Select token keys + Token name + Key label Sort Method: Please wait. This process may take a long time... Please wait...\nThis process may take a long time and VeraCrypt may seem unresponsive. diff --git a/src/Common/MockSecurityToken.cpp b/src/Common/MockSecurityToken.cpp new file mode 100644 index 0000000000..6af9c776ad --- /dev/null +++ b/src/Common/MockSecurityToken.cpp @@ -0,0 +1,69 @@ +#include "MockSecurityToken.h" + + +using namespace std; + +namespace VeraCrypt +{ +#ifdef TC_WINDOWS + void MockSecurityTokenImpl::InitLibrary (const wstring &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) +#else + void MockSecurityTokenImpl::InitLibrary (const string &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) +#endif + { + if (Initialized) + CloseLibrary(); + + PinCallback = pinCallback; + WarningCallback = warningCallback; + + Initialized = true; + } + + vector MockSecurityTokenImpl::GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter, const wstring keyfileIdFilter) + { + return vector(); + } + + vector MockSecurityTokenImpl::GetAvailablePrivateKeys(CK_SLOT_ID *slotIdFilter, const wstring keyIdFilter) + { + return vector(); + } + + vector MockSecurityTokenImpl::GetAvailablePublicKeys(CK_SLOT_ID *slotIdFilterm, const wstring keyIdFilter) + { + return vector(); + } + + void MockSecurityTokenImpl::GetSecurityTokenKey(wstring tokenKeyDescriptor, SecurityTokenKey &key, SecurityTokenKeyOperation mode) + { + shared_ptr testKey(new SecurityTokenKey()); + testKey->maxDecryptBufferSize = 128; + testKey->maxEncryptBufferSize = 128; + testKey->Id = L"Mock key"; + testKey->SlotId = 1; + testKey->Token = SecurityTokenInfo(); + testKey->Token.Label = L"Mock security token"; + key = *testKey; + } + void MockSecurityTokenImpl::GetDecryptedData(SecurityTokenKey key, vector tokenDataToDecrypt, vector &decryptedData) + { + decryptedData = tokenDataToDecrypt; + } + + void MockSecurityTokenImpl::GetEncryptedData(SecurityTokenKey key, vector plaintext, vector &ciphertext) + { + ciphertext = plaintext; + } + list MockSecurityTokenImpl::GetAvailableTokens () + { + return list(); + } + SecurityTokenInfo MockSecurityTokenImpl::GetTokenInfo (CK_SLOT_ID slotId) + { + return SecurityTokenInfo(); + } + bool MockSecurityTokenImpl::IsKeyfilePathValid (const wstring &securityTokenKeyfilePath) { + return false; + } +} \ No newline at end of file diff --git a/src/Common/MockSecurityToken.h b/src/Common/MockSecurityToken.h new file mode 100644 index 0000000000..88405ba7b7 --- /dev/null +++ b/src/Common/MockSecurityToken.h @@ -0,0 +1,49 @@ +#ifndef TC_HEADER_Common_MockSecurityToken +#define TC_HEADER_Common_MockSecurityToken + +#include "Platform/PlatformBase.h" +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) +# include "Exception.h" +#else +# include "Platform/Exception.h" +#endif + +#include "SecurityToken.h" +namespace VeraCrypt +{ + + class MockSecurityTokenImpl : public SecurityTokenIface { + public: + MockSecurityTokenImpl() {}; + virtual ~MockSecurityTokenImpl() {}; + void CloseAllSessions () throw () {}; + void CloseLibrary () {}; + void CreateKeyfile (CK_SLOT_ID slotId, vector &keyfileData, const string &name) {}; + void DeleteKeyfile (const SecurityTokenKeyfile &keyfile) {}; + vector GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); + + vector GetAvailablePrivateKeys(CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()); + vector GetAvailablePublicKeys(CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()); + void GetSecurityTokenKey(wstring tokenKeyDescriptor, SecurityTokenKey &key, SecurityTokenKeyOperation mode); + void GetDecryptedData(SecurityTokenKey key, vector tokenDataToDecrypt, vector &decryptedData); + void GetEncryptedData(SecurityTokenKey key, vector plaintext, vector &ciphertext); + + + void GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector &keyfileData) {}; + list GetAvailableTokens (); + SecurityTokenInfo GetTokenInfo (CK_SLOT_ID slotId); + #ifdef TC_WINDOWS + void InitLibrary (const wstring &pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback) {}; + #else + virtual void InitLibrary (const string &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback); + #endif + bool IsInitialized () { return Initialized; } + bool IsKeyfilePathValid (const wstring &securityTokenKeyfilePath); + + protected: + bool Initialized; + shared_ptr PinCallback; + shared_ptr WarningCallback; + }; +} +#endif // TC_HEADER_Common_MockSecurityToken \ No newline at end of file diff --git a/src/Common/SecurityToken.cpp b/src/Common/SecurityToken.cpp index cd4926a0d2..8288faf56b 100644 --- a/src/Common/SecurityToken.cpp +++ b/src/Common/SecurityToken.cpp @@ -22,6 +22,10 @@ # include "Language.h" #endif + #include + #include + #include + #ifdef TC_UNIX # include #endif @@ -75,13 +79,13 @@ namespace VeraCrypt return path.str(); } - void SecurityToken::CheckLibraryStatus() + void SecurityTokenImpl::CheckLibraryStatus () { if (!Initialized) throw SecurityTokenLibraryNotInitialized(); } - void SecurityToken::CloseLibrary() + void SecurityTokenImpl::CloseLibrary () { if (Initialized) { @@ -97,7 +101,7 @@ namespace VeraCrypt } } - void SecurityToken::CloseAllSessions() throw () + void SecurityTokenImpl::CloseAllSessions () throw () { if (!Initialized) return; @@ -114,7 +118,7 @@ namespace VeraCrypt } } - void SecurityToken::CloseSession(CK_SLOT_ID slotId) + void SecurityTokenImpl::CloseSession (CK_SLOT_ID slotId) { if (Sessions.find(slotId) == Sessions.end()) throw ParameterIncorrect(SRC_POS); @@ -123,7 +127,7 @@ namespace VeraCrypt Sessions.erase(Sessions.find(slotId)); } - void SecurityToken::CreateKeyfile(CK_SLOT_ID slotId, vector & keyfileData, const string& name) + void SecurityTokenImpl::CreateKeyfile (CK_SLOT_ID slotId, vector &keyfileData, const string &name) { if (name.empty()) throw ParameterIncorrect(SRC_POS); @@ -179,7 +183,7 @@ namespace VeraCrypt } } - void SecurityToken::DeleteKeyfile(const SecurityTokenKeyfile& keyfile) + void SecurityTokenImpl::DeleteKeyfile (const SecurityTokenKeyfile &keyfile) { LoginUserIfRequired(keyfile.Token->SlotId); @@ -188,7 +192,212 @@ namespace VeraCrypt throw Pkcs11Exception(status); } - vector SecurityToken::GetAvailableKeyfiles(CK_SLOT_ID* slotIdFilter, const wstring keyfileIdFilter) + + void SecurityTokenImpl::GetSecurityTokenKey(wstring tokenKeyDescriptor, SecurityTokenKey &key, SecurityTokenKeyOperation mode) + { + + CK_SLOT_ID slotId; + + if (swscanf (tokenKeyDescriptor.c_str(), L"%lu", &slotId) != 1) + throw InvalidSecurityTokenKeyfilePath(); + + size_t n = tokenKeyDescriptor.find(L":"); + if (n == std::string::npos) { + throw InvalidSecurityTokenKeyfilePath(); + } + + wstring keyId = tokenKeyDescriptor.substr(n+1); + + vector keys; + if (mode == SecurityTokenKeyOperation::ENCRYPT) { + keys = SecurityToken::GetAvailablePublicKeys(&slotId, keyId); + } else if (mode == SecurityTokenKeyOperation::DECRYPT) { + keys = SecurityToken::GetAvailablePrivateKeys(&slotId, keyId); + } else { + throw ParameterIncorrect(SRC_POS); + } + if (keys.size() > 1 || keys.size() == 0) { + throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + } + key = keys[0]; + } + + vector SecurityTokenImpl::GetAvailablePrivateKeys(CK_SLOT_ID *slotIdFilter, const wstring keyIdFilter) + { + bool unrecognizedTokenPresent = false; + vector keys; + + foreach (const CK_SLOT_ID &slotId, GetTokenSlots()) + { + SecurityTokenInfo token; + + if (slotIdFilter && *slotIdFilter != slotId) + continue; + + try + { + LoginUserIfRequired (slotId); + token = GetTokenInfo (slotId); + } + catch (UserAbort &) + { + continue; + } + catch (Pkcs11Exception &e) + { + if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED) + { + unrecognizedTokenPresent = true; + continue; + } + throw; + } + + foreach (const CK_OBJECT_HANDLE &dataHandle, GetObjects (slotId, CKO_PRIVATE_KEY)) + { + SecurityTokenKey key; + key.Handle = dataHandle; + key.SlotId = slotId; + key.Token = token; + + vector privateAttrib; + GetObjectAttribute (slotId, dataHandle, CKA_PRIVATE, privateAttrib); + + if (privateAttrib.size() == sizeof (CK_BBOOL) && *(CK_BBOOL *) &privateAttrib.front() != CK_TRUE) + continue; + + GetObjectAttribute (slotId, dataHandle, CKA_MODULUS_BITS, privateAttrib); + if (privateAttrib.size() == sizeof (CK_ULONG)) { + CK_ULONG modulus = *(CK_ULONG *) &privateAttrib.front(); + key.maxDecryptBufferSize = modulus / 8 - 11; + key.maxEncryptBufferSize = modulus / 8; + } + + + // check if CKA_DECRYPT is present + GetObjectAttribute (slotId, dataHandle, CKA_DECRYPT, privateAttrib); + if (privateAttrib.size() == sizeof(CK_BBOOL) && *(CK_BBOOL *) &privateAttrib.front() != CK_TRUE) { + continue; + } + + vector label; + GetObjectAttribute (slotId, dataHandle, CKA_LABEL, label); + label.push_back (0); + + key.IdUtf8 = (char *) &label.front(); + +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) + key.Id = Utf8StringToWide ((const char *) &label.front()); +#else + key.Id = StringConverter::ToWide ((const char *) &label.front()); +#endif + + if (key.Id.empty() || (!keyIdFilter.empty() && keyIdFilter != key.Id)) { + continue; + } + + keys.push_back (key); + + if (!keyIdFilter.empty()) + break; + } + } + + if (keys.empty() && unrecognizedTokenPresent) + throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + + return keys; + } + + + vector SecurityTokenImpl::GetAvailablePublicKeys(CK_SLOT_ID *slotIdFilter, const wstring keyIdFilter) + { + bool unrecognizedTokenPresent = false; + vector keys; + + foreach (const CK_SLOT_ID &slotId, GetTokenSlots()) + { + SecurityTokenInfo token; + + if (slotIdFilter && *slotIdFilter != slotId) + continue; + + try + { + LoginUserIfRequired (slotId); + token = GetTokenInfo (slotId); + } + catch (UserAbort &) + { + continue; + } + catch (Pkcs11Exception &e) + { + if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED) + { + unrecognizedTokenPresent = true; + continue; + } + throw; + } + + foreach (const CK_OBJECT_HANDLE &dataHandle, GetObjects (slotId, CKO_PUBLIC_KEY)) + { + SecurityTokenKey key; + key.Handle = dataHandle; + key.SlotId = slotId; + key.Token = token; + + vector publicAttrib; + GetObjectAttribute (slotId, dataHandle, CKA_PRIVATE, publicAttrib); + + if (publicAttrib.size() == sizeof (CK_BBOOL) && *(CK_BBOOL *) &publicAttrib.front() != CK_FALSE) + continue; + + + GetObjectAttribute (slotId, dataHandle, CKA_MODULUS_BITS, publicAttrib); + if (publicAttrib.size() == sizeof (CK_ULONG)) { + CK_ULONG modulus = *(CK_ULONG *) &publicAttrib.front(); + key.maxDecryptBufferSize = modulus / 8 - 11; + key.maxEncryptBufferSize = modulus / 8; + } + + // check if CKA_ENCRYPT attribute present + GetObjectAttribute (slotId, dataHandle, CKA_ENCRYPT, publicAttrib); + if (publicAttrib.size() == sizeof (CK_BBOOL) && *(CK_BBOOL *) &publicAttrib.front() != CK_TRUE) { + continue; + } + + vector label; + GetObjectAttribute (slotId, dataHandle, CKA_LABEL, label); + label.push_back (0); + + key.IdUtf8 = (char *) &label.front(); + +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) + key.Id = Utf8StringToWide ((const char *) &label.front()); +#else + key.Id = StringConverter::ToWide ((const char *) &label.front()); +#endif + + if (key.Id.empty() || (!keyIdFilter.empty() && keyIdFilter != key.Id)) { + continue; + } + + keys.push_back (key); + + if (!keyIdFilter.empty()) + break; + } + } + + if (keys.empty() && unrecognizedTokenPresent) + throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + + return keys; + } + + vector SecurityTokenImpl::GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter, const wstring keyfileIdFilter) { bool unrecognizedTokenPresent = false; vector keyfiles; @@ -260,7 +469,7 @@ namespace VeraCrypt return keyfiles; } - list SecurityToken::GetAvailableTokens() + list SecurityTokenImpl::GetAvailableTokens () { bool unrecognizedTokenPresent = false; list tokens; @@ -289,7 +498,7 @@ namespace VeraCrypt return tokens; } - SecurityTokenInfo SecurityToken::GetTokenInfo(CK_SLOT_ID slotId) + SecurityTokenInfo SecurityTokenImpl::GetTokenInfo (CK_SLOT_ID slotId) { CK_TOKEN_INFO info; CK_RV status = Pkcs11Functions->C_GetTokenInfo(slotId, &info); @@ -322,11 +531,16 @@ namespace VeraCrypt void SecurityTokenKeyfile::GetKeyfileData(vector & keyfileData) const { - SecurityToken::LoginUserIfRequired(Token->SlotId); - SecurityToken::GetObjectAttribute(Token->SlotId, Handle, CKA_VALUE, keyfileData); + SecurityToken::GetKeyfileData(*this, keyfileData); + } + + void SecurityTokenImpl::GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector &keyfileData) + { + LoginUserIfRequired (keyfile.Token->SlotId); + GetObjectAttribute (keyfile.Token->SlotId, keyfile.Handle, CKA_VALUE, keyfileData); } - vector SecurityToken::GetObjects(CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass) + vector SecurityTokenImpl::GetObjects (CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass) { if (Sessions.find(slotId) == Sessions.end()) throw ParameterIncorrect(SRC_POS); @@ -340,7 +554,8 @@ namespace VeraCrypt if (status != CKR_OK) throw Pkcs11Exception(status); - finally_do_arg(CK_SLOT_ID, slotId, { Pkcs11Functions->C_FindObjectsFinal(Sessions[finally_arg].Handle); }); + finally_do_member (SecurityTokenImpl, CK_SLOT_ID, slotId, { finally_obj->Pkcs11Functions->C_FindObjectsFinal (finally_obj->Sessions[finally_arg].Handle); }); + CK_ULONG objectCount; vector objects; @@ -361,7 +576,115 @@ namespace VeraCrypt return objects; } - void SecurityToken::GetObjectAttribute(CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector & attributeValue) + + CK_RV SecurityTokenImpl::PKCS11Encrypt( + CK_SESSION_HANDLE hSession, + vector plaintext, + vector &ciphertext + ) + { + CK_RV rv; + if (!plaintext.size()) + return CKR_ARGUMENTS_BAD; + + CK_ULONG ulInDataLen = plaintext.size(); + CK_BYTE* pInData = plaintext.data(); + CK_ULONG ulOutDataLen = ciphertext.size(); + CK_BYTE* pOutData = ciphertext.data(); + + rv = Pkcs11Functions->C_Encrypt(hSession, pInData, ulInDataLen, pOutData, + &ulOutDataLen); + + if (CKR_OK == rv) { + ciphertext = vector(pOutData, pOutData + ulOutDataLen); + } else { + throw Pkcs11Exception(rv); + } + return rv; + } + + CK_RV SecurityTokenImpl::PKCS11Decrypt( + CK_SESSION_HANDLE hSession, + vector inEncryptedData, + vector &outData + ) + { + CK_RV rv; + if (!inEncryptedData.size()) + return CKR_ARGUMENTS_BAD; + + CK_ULONG ulInDataLen = inEncryptedData.size(); + CK_BYTE* pInData = inEncryptedData.data(); + CK_ULONG ulOutDataLen = outData.size(); + CK_BYTE* pOutData = outData.data(); + + rv = Pkcs11Functions->C_Decrypt(hSession, pInData, ulInDataLen, pOutData, + &ulOutDataLen); + + if (CKR_OK == rv) { + outData = vector(pOutData, pOutData + ulOutDataLen); + } else { + throw Pkcs11Exception(rv); + } + return rv; + } + + void SecurityTokenImpl::GetEncryptedData(SecurityTokenKey key, vector plaintext, vector &ciphertext) { + GetEncryptedData(key.SlotId, key.Handle, plaintext, ciphertext); + } + + void SecurityTokenImpl::GetEncryptedData (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, vector plaintext, vector &ciphertext) + { + LoginUserIfRequired (slotId); + + if (Sessions.find (slotId) == Sessions.end()) + throw ParameterIncorrect (SRC_POS); + + CK_MECHANISM m = { CKM_RSA_PKCS, 0, 0 }; + CK_RV status = Pkcs11Functions->C_EncryptInit (Sessions[slotId].Handle, &m, tokenObject); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + status = PKCS11Encrypt( + Sessions[slotId].Handle, + plaintext, + ciphertext + ); + + if (status != CKR_OK) + throw Pkcs11Exception (status); + + } + + void SecurityTokenImpl::GetDecryptedData(SecurityTokenKey key, vector tokenDataToDecrypt, vector &decryptedData) + { + GetDecryptedData(key.SlotId, key.Handle, tokenDataToDecrypt, decryptedData); + } + + void SecurityTokenImpl::GetDecryptedData (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, vector edata, vector &decryptedData) + { + LoginUserIfRequired (slotId); + + if (Sessions.find (slotId) == Sessions.end()) + throw ParameterIncorrect (SRC_POS); + + CK_MECHANISM m = { CKM_RSA_PKCS, 0, 0 }; + CK_RV status = Pkcs11Functions->C_DecryptInit (Sessions[slotId].Handle, &m, tokenObject); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + status = PKCS11Decrypt( + Sessions[slotId].Handle, + edata, + decryptedData + ); + + if (status != CKR_OK) + throw Pkcs11Exception (status); + + } + + void SecurityTokenImpl::GetObjectAttribute (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector &attributeValue) { attributeValue.clear(); @@ -387,7 +710,7 @@ namespace VeraCrypt throw Pkcs11Exception(status); } - list SecurityToken::GetTokenSlots() + list SecurityTokenImpl::GetTokenSlots () { CheckLibraryStatus(); @@ -420,12 +743,12 @@ namespace VeraCrypt return slots; } - bool SecurityToken::IsKeyfilePathValid(const wstring& securityTokenKeyfilePath) + bool SecurityTokenImpl::IsKeyfilePathValid (const wstring &securityTokenKeyfilePath) { return securityTokenKeyfilePath.find(TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX) == 0; } - void SecurityToken::Login(CK_SLOT_ID slotId, const char* pin) + void SecurityTokenImpl::Login (CK_SLOT_ID slotId, const char* pin) { if (Sessions.find(slotId) == Sessions.end()) OpenSession(slotId); @@ -441,9 +764,10 @@ namespace VeraCrypt Sessions[slotId].UserLoggedIn = true; } - void SecurityToken::LoginUserIfRequired(CK_SLOT_ID slotId) + void SecurityTokenImpl::LoginUserIfRequired (CK_SLOT_ID slotId) { CheckLibraryStatus(); + CK_RV status; if (Sessions.find(slotId) == Sessions.end()) @@ -521,9 +845,9 @@ namespace VeraCrypt } #ifdef TC_WINDOWS - void SecurityToken::InitLibrary(const wstring& pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback) + void SecurityTokenImpl::InitLibrary (const wstring &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) #else - void SecurityToken::InitLibrary(const string& pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback) + void SecurityTokenImpl::InitLibrary (const string &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) #endif { if (Initialized) @@ -556,13 +880,13 @@ namespace VeraCrypt if (status != CKR_OK) throw Pkcs11Exception(status); - PinCallback = move_ptr(pinCallback); - WarningCallback = move_ptr(warningCallback); + PinCallback = pinCallback; + WarningCallback = warningCallback; Initialized = true; } - void SecurityToken::OpenSession(CK_SLOT_ID slotId) + void SecurityTokenImpl::OpenSession (CK_SLOT_ID slotId) { if (Sessions.find(slotId) != Sessions.end()) return; @@ -736,18 +1060,7 @@ namespace VeraCrypt } #endif // TC_HEADER_Common_Exception - unique_ptr SecurityToken::PinCallback; - unique_ptr SecurityToken::WarningCallback; - - bool SecurityToken::Initialized; - CK_FUNCTION_LIST_PTR SecurityToken::Pkcs11Functions; - map SecurityToken::Sessions; - -#ifdef TC_WINDOWS - HMODULE SecurityToken::Pkcs11LibraryHandle; -#else - void* SecurityToken::Pkcs11LibraryHandle; -#endif + shared_ptr SecurityToken::impl; #ifdef TC_HEADER_Platform_Exception diff --git a/src/Common/SecurityToken.h b/src/Common/SecurityToken.h index 6c454def6d..a4d30c0930 100644 --- a/src/Common/SecurityToken.h +++ b/src/Common/SecurityToken.h @@ -57,6 +57,12 @@ namespace VeraCrypt { + + enum SecurityTokenKeyOperation { + ENCRYPT, + DECRYPT + }; + struct SecurityTokenInfo: TokenInfo { virtual ~SecurityTokenInfo() {}; @@ -82,7 +88,20 @@ namespace VeraCrypt CK_OBJECT_HANDLE Handle; }; - struct Pkcs11Exception: public Exception + struct SecurityTokenKey + { + SecurityTokenKey () : Handle(CK_INVALID_HANDLE), SlotId(CK_UNAVAILABLE_INFORMATION) { Token.SlotId = CK_UNAVAILABLE_INFORMATION; Token.Flags = 0; } + + CK_OBJECT_HANDLE Handle; + wstring Id; + string IdUtf8; + CK_SLOT_ID SlotId; + SecurityTokenInfo Token; + size_t maxDecryptBufferSize; + size_t maxEncryptBufferSize; + }; + + struct Pkcs11Exception : public Exception { Pkcs11Exception(CK_RV errorCode = (CK_RV)-1) : ErrorCode(errorCode), @@ -176,48 +195,131 @@ namespace VeraCrypt virtual void operator() (const Exception& e) = 0; }; + class SecurityTokenIface { + public: + virtual void CloseAllSessions () throw () = 0; + virtual void CloseLibrary () = 0; + virtual void CreateKeyfile (CK_SLOT_ID slotId, vector &keyfileData, const string &name) =0; + virtual void DeleteKeyfile (const SecurityTokenKeyfile &keyfile) =0; + virtual vector GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()) =0; + + virtual vector GetAvailablePrivateKeys(CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()) =0; + virtual vector GetAvailablePublicKeys(CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()) =0; + virtual void GetSecurityTokenKey(wstring tokenKeyDescriptor, SecurityTokenKey &key, SecurityTokenKeyOperation mode) =0; + virtual void GetDecryptedData(SecurityTokenKey key, vector tokenDataToDecrypt, vector &decryptedData) =0; + virtual void GetEncryptedData(SecurityTokenKey key, vector plaintext, vector &ciphertext) =0; + + + virtual void GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector &keyfileData) =0; + virtual list GetAvailableTokens () =0; + virtual SecurityTokenInfo GetTokenInfo (CK_SLOT_ID slotId) =0; +#ifdef TC_WINDOWS + virtual void InitLibrary (const wstring &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) =0; +#else + virtual void InitLibrary (const string &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) =0; +#endif + virtual bool IsInitialized () =0; + virtual bool IsKeyfilePathValid (const wstring &securityTokenKeyfilePath) =0; + }; + class SecurityToken { public: - static void CloseAllSessions() throw (); - static void CloseLibrary(); - static void CreateKeyfile(CK_SLOT_ID slotId, vector & keyfileData, const string& name); - static void DeleteKeyfile(const SecurityTokenKeyfile& keyfile); - static vector GetAvailableKeyfiles(CK_SLOT_ID* slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); - static list GetAvailableTokens(); - static SecurityTokenInfo GetTokenInfo(CK_SLOT_ID slotId); + static void UseImpl(shared_ptr impl) { SecurityToken::impl = impl; }; + + static void CloseAllSessions () throw () { impl->CloseAllSessions(); }; + static void CloseLibrary () { impl-> CloseLibrary(); }; + static void CreateKeyfile (CK_SLOT_ID slotId, vector &keyfileData, const string &name) { impl->CreateKeyfile (slotId, keyfileData, name); }; + static void DeleteKeyfile (const SecurityTokenKeyfile &keyfile) { impl->DeleteKeyfile (keyfile); }; + static vector GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()) { return impl -> GetAvailableKeyfiles (slotIdFilter, keyfileIdFilter); }; + + static vector GetAvailablePrivateKeys (CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()) { return impl->GetAvailablePrivateKeys (slotIdFilterm, keyIdFilter); }; + static vector GetAvailablePublicKeys (CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()) { return impl->GetAvailablePublicKeys (slotIdFilterm, keyIdFilter); }; + static void GetSecurityTokenKey (wstring tokenKeyDescriptor, SecurityTokenKey &key, SecurityTokenKeyOperation mode) { impl->GetSecurityTokenKey (tokenKeyDescriptor, key, mode); }; + static void GetDecryptedData (SecurityTokenKey key, vector tokenDataToDecrypt, vector &decryptedData) { impl->GetDecryptedData (key, tokenDataToDecrypt, decryptedData); }; + static void GetEncryptedData (SecurityTokenKey key, vector plaintext, vector &ciphertext) { impl->GetEncryptedData (key, plaintext, ciphertext); }; + + + static void GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector &keyfileData) { impl->GetKeyfileData (keyfile, keyfileData); }; + static list GetAvailableTokens () { return impl->GetAvailableTokens (); }; + static SecurityTokenInfo GetTokenInfo (CK_SLOT_ID slotId) { return impl->GetTokenInfo (slotId); }; #ifdef TC_WINDOWS - static void InitLibrary(const wstring& pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback); + static void InitLibrary (const wstring &pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback) { impl->InitLibrary (pkcs11LibraryPath, pinCallback, warningCallback); }; #else - static void InitLibrary(const string& pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback); + static void InitLibrary (const string &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback) { impl->InitLibrary (pkcs11LibraryPath, pinCallback, warningCallback); }; #endif - static bool IsInitialized() { return Initialized; } - static bool IsKeyfilePathValid(const wstring& securityTokenKeyfilePath); + static bool IsInitialized () { return impl->IsInitialized (); }; + static bool IsKeyfilePathValid (const wstring &securityTokenKeyfilePath) { return impl->IsKeyfilePathValid (securityTokenKeyfilePath); }; static const size_t MaxPasswordLength = 128; protected: - static void CloseSession(CK_SLOT_ID slotId); - static vector GetObjects(CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass); - static void GetObjectAttribute(CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector & attributeValue); - static list GetTokenSlots(); - static void Login(CK_SLOT_ID slotId, const char* pin); - static void LoginUserIfRequired(CK_SLOT_ID slotId); - static void OpenSession(CK_SLOT_ID slotId); - static void CheckLibraryStatus(); - - static bool Initialized; - static unique_ptr PinCallback; - static CK_FUNCTION_LIST_PTR Pkcs11Functions; + static shared_ptr impl; + }; + + class SecurityTokenImpl : public SecurityTokenIface { + public: + SecurityTokenImpl() {} ; + virtual ~SecurityTokenImpl() {}; + void CloseAllSessions () throw (); + void CloseLibrary (); + void CreateKeyfile (CK_SLOT_ID slotId, vector &keyfileData, const string &name); + void DeleteKeyfile (const SecurityTokenKeyfile &keyfile); + vector GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); + + vector GetAvailablePrivateKeys(CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()); + vector GetAvailablePublicKeys(CK_SLOT_ID *slotIdFilterm = nullptr, const wstring keyIdFilter = wstring()); + void GetSecurityTokenKey(wstring tokenKeyDescriptor, SecurityTokenKey &key, SecurityTokenKeyOperation mode); + void GetDecryptedData(SecurityTokenKey key, vector tokenDataToDecrypt, vector &decryptedData); + void GetEncryptedData(SecurityTokenKey key, vector plaintext, vector &ciphertext); + + + void GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector &keyfileData); + list GetAvailableTokens (); + SecurityTokenInfo GetTokenInfo (CK_SLOT_ID slotId); #ifdef TC_WINDOWS - static HMODULE Pkcs11LibraryHandle; + void InitLibrary (const wstring &pkcs11LibraryPath, unique_ptr pinCallback, unique_ptr warningCallback); #else - static void* Pkcs11LibraryHandle; + virtual void InitLibrary (const string &pkcs11LibraryPath, shared_ptr pinCallback, shared_ptr warningCallback); #endif - static map Sessions; - static unique_ptr WarningCallback; + bool IsInitialized () { return Initialized; } + bool IsKeyfilePathValid (const wstring &securityTokenKeyfilePath); - friend void SecurityTokenKeyfile::GetKeyfileData(vector & keyfileData) const; + protected: + void CloseSession (CK_SLOT_ID slotId); + vector GetObjects (CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass); + void GetDecryptedData (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, vector edata, vector &keyfiledata); + void GetEncryptedData (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, vector plaintext, vector &ciphertext); + void GetObjectAttribute (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector &attributeValue); + list GetTokenSlots (); + void Login (CK_SLOT_ID slotId, const char* pin); + void LoginUserIfRequired (CK_SLOT_ID slotId); + void OpenSession (CK_SLOT_ID slotId); + void CheckLibraryStatus (); + + + bool Initialized; + shared_ptr PinCallback; + CK_FUNCTION_LIST_PTR Pkcs11Functions; +#ifdef TC_WINDOWS + HMODULE Pkcs11LibraryHandle; +#else + void *Pkcs11LibraryHandle; +#endif + map Sessions; + shared_ptr WarningCallback; + + + virtual CK_RV PKCS11Decrypt( + CK_SESSION_HANDLE hSession, + vector inEncryptedData, + vector &outData + ); + virtual CK_RV PKCS11Encrypt( + CK_SESSION_HANDLE hSession, + vector inEncryptedData, + vector &outData + ); }; } diff --git a/src/Core/Core.h b/src/Core/Core.h index b9e53021c3..85e69a6533 100644 --- a/src/Core/Core.h +++ b/src/Core/Core.h @@ -76,17 +76,20 @@ namespace VeraCrypt int m_pim; shared_ptr m_kdf; shared_ptr m_keyfiles; + wstring m_securityTokenKeySpec; shared_ptr m_newPassword; int m_newPim; shared_ptr m_newKeyfiles; + wstring m_newSecurityTokenSpec; shared_ptr m_newPkcs5Kdf; int m_wipeCount; bool m_emvSupportEnabled; bool m_masterKeyVulnerable; - ChangePasswordThreadRoutine(shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, shared_ptr newPkcs5Kdf, int wipeCount, bool emvSupportEnabled) : m_volumePath(volumePath), m_preserveTimestamps(preserveTimestamps), m_password(password), m_pim(pim), m_kdf(kdf), m_keyfiles(keyfiles), m_newPassword(newPassword), m_newPim(newPim), m_newKeyfiles(newKeyfiles), m_newPkcs5Kdf(newPkcs5Kdf), m_wipeCount(wipeCount), m_emvSupportEnabled(emvSupportEnabled), m_masterKeyVulnerable(false) {} + ChangePasswordThreadRoutine(shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, wstring newSecurityTokenKeySpec, shared_ptr newPkcs5Kdf, int wipeCount, bool emvSupportEnabled) : m_volumePath(volumePath), m_preserveTimestamps(preserveTimestamps), m_password(password), m_pim(pim), m_kdf(kdf), m_keyfiles(keyfiles), m_securityTokenKeySpec(securityTokenKeySpec), m_newPassword(newPassword), m_newPim(newPim), m_newKeyfiles(newKeyfiles), m_newSecurityTokenSpec(newSecurityTokenKeySpec), m_newPkcs5Kdf(newPkcs5Kdf), m_wipeCount(wipeCount), m_emvSupportEnabled(emvSupportEnabled), m_masterKeyVulnerable(false) {} virtual ~ChangePasswordThreadRoutine() { } virtual void ExecutionCode(void) { - shared_ptr openVolume = Core->ChangePassword(m_volumePath, m_preserveTimestamps, m_password, m_pim, m_kdf, m_keyfiles, m_newPassword, m_newPim, m_newKeyfiles, m_emvSupportEnabled, m_newPkcs5Kdf, m_wipeCount); + shared_ptr openVolume = Core->ChangePassword(m_volumePath, m_preserveTimestamps, m_password, m_pim, m_kdf, m_keyfiles, m_securityTokenKeySpec, m_newPassword, m_newPim, m_newKeyfiles, m_newSecurityTokenSpec, m_emvSupportEnabled, m_newPkcs5Kdf, + m_wipeCount); m_masterKeyVulnerable = openVolume->IsMasterKeyVulnerable(); } }; @@ -100,11 +103,13 @@ namespace VeraCrypt int m_pim; shared_ptr m_Kdf; shared_ptr m_keyfiles; + wstring m_securityTokenKeySpec; VolumeProtection::Enum m_protection; shared_ptr m_protectionPassword; int m_protectionPim; shared_ptr m_protectionKdf; shared_ptr m_protectionKeyfiles; + wstring m_protectionSecurityTokenKeySpec; bool m_sharedAccessAllowed; VolumeType::Enum m_volumeType; bool m_useBackupHeaders; @@ -112,14 +117,14 @@ namespace VeraCrypt shared_ptr m_pVolume; bool m_emvSupportEnabled; - OpenVolumeThreadRoutine(shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr Kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (), shared_ptr protectionKeyfiles = shared_ptr (), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false): - m_volumePath(volumePath), m_preserveTimestamps(preserveTimestamps), m_password(password), m_pim(pim), m_Kdf(Kdf), m_keyfiles(keyfiles), - m_protection(protection), m_protectionPassword(protectionPassword), m_protectionPim(protectionPim), m_protectionKdf(protectionKdf), m_protectionKeyfiles(protectionKeyfiles), m_sharedAccessAllowed(sharedAccessAllowed), m_volumeType(volumeType),m_useBackupHeaders(useBackupHeaders), + OpenVolumeThreadRoutine(shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr Kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (), shared_ptr protectionKeyfiles = shared_ptr (), wstring protectionSecurityTokenKeySpec = wstring(), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false): + m_volumePath(volumePath), m_preserveTimestamps(preserveTimestamps), m_password(password), m_pim(pim), m_Kdf(Kdf), m_keyfiles(keyfiles), m_securityTokenKeySpec(securityTokenKeySpec), + m_protection(protection), m_protectionPassword(protectionPassword), m_protectionPim(protectionPim), m_protectionKdf(protectionKdf), m_protectionKeyfiles(protectionKeyfiles), m_protectionSecurityTokenKeySpec(protectionSecurityTokenKeySpec), m_sharedAccessAllowed(sharedAccessAllowed), m_volumeType(volumeType),m_useBackupHeaders(useBackupHeaders), m_partitionInSystemEncryptionScope(partitionInSystemEncryptionScope), m_emvSupportEnabled(emvSupportEnabled) {} ~OpenVolumeThreadRoutine() {} - virtual void ExecutionCode(void) { m_pVolume = Core->OpenVolume(m_volumePath,m_preserveTimestamps,m_password,m_pim,m_Kdf,m_keyfiles, m_emvSupportEnabled, m_protection,m_protectionPassword,m_protectionPim,m_protectionKdf, m_protectionKeyfiles,m_sharedAccessAllowed,m_volumeType,m_useBackupHeaders, m_partitionInSystemEncryptionScope); } + virtual void ExecutionCode(void) { m_pVolume = Core->OpenVolume(m_volumePath,m_preserveTimestamps,m_password,m_pim,m_Kdf,m_keyfiles, m_securityTokenKeySpec, m_emvSupportEnabled, m_protection,m_protectionPassword,m_protectionPim,m_protectionKdf, m_protectionKeyfiles, m_protectionSecurityTokenKeySpec, m_sharedAccessAllowed, m_volumeType,m_useBackupHeaders, m_partitionInSystemEncryptionScope); } }; @@ -131,11 +136,12 @@ namespace VeraCrypt shared_ptr m_password; int m_pim; shared_ptr m_keyfiles; + wstring m_securityTokenKeySpec; bool m_emvSupportEnabled; - ReEncryptHeaderThreadRoutine(const BufferPtr &newHeaderBuffer, shared_ptr header, shared_ptr password, int pim, shared_ptr keyfiles, bool emvSupportEnabled) - : m_newHeaderBuffer(newHeaderBuffer), m_header(header), m_password(password), m_pim(pim), m_keyfiles(keyfiles), m_emvSupportEnabled(emvSupportEnabled) {} + ReEncryptHeaderThreadRoutine(const BufferPtr &newHeaderBuffer, shared_ptr header, shared_ptr password, int pim, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled) + : m_newHeaderBuffer(newHeaderBuffer), m_header(header), m_password(password), m_pim(pim), m_keyfiles(keyfiles), m_securityTokenKeySpec(securityTokenKeySpec), m_emvSupportEnabled(emvSupportEnabled) {} virtual ~ReEncryptHeaderThreadRoutine() { } - virtual void ExecutionCode(void) { Core->ReEncryptVolumeHeaderWithNewSalt (m_newHeaderBuffer, m_header, m_password, m_pim, m_keyfiles, m_emvSupportEnabled); } + virtual void ExecutionCode(void) { Core->ReEncryptVolumeHeaderWithNewSalt (m_newHeaderBuffer, m_header, m_password, m_pim, m_keyfiles, m_securityTokenKeySpec, m_emvSupportEnabled); } }; class DecryptThreadRoutine : public WaitThreadRoutine diff --git a/src/Core/Core.make b/src/Core/Core.make index 66aba90057..f43427612c 100644 --- a/src/Core/Core.make +++ b/src/Core/Core.make @@ -1,4 +1,3 @@ -# # Derived from source code of TrueCrypt 7.1a, which is # Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed # by the TrueCrypt License 3.0. @@ -23,9 +22,18 @@ OBJS += Unix/CoreServiceRequest.o OBJS += Unix/CoreServiceResponse.o OBJS += Unix/CoreUnix.o OBJS += Unix/$(PLATFORM)/Core$(PLATFORM).o -OBJS += Unix/$(PLATFORM)/Core$(PLATFORM).o + ifeq "$(PLATFORM)" "MacOSX" OBJS += Unix/FreeBSD/CoreFreeBSD.o endif +TEST_EXECS := CoreTest.o + +TEST_EXT_LIBS += $(shell pkg-config fuse --libs) +TEST_LFLAGS += -ldl + include $(BUILD_INC)/Makefile.inc + + + + diff --git a/src/Core/CoreBase.cpp b/src/Core/CoreBase.cpp index 0c6d5c9eea..5a04429590 100644 --- a/src/Core/CoreBase.cpp +++ b/src/Core/CoreBase.cpp @@ -30,7 +30,7 @@ namespace VeraCrypt { } - void CoreBase::ChangePassword (shared_ptr openVolume, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, bool emvSupportEnabled, shared_ptr newPkcs5Kdf, int wipeCount) const + void CoreBase::ChangePassword (shared_ptr openVolume, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, wstring newSecurityTokenKeySpec, bool emvSupportEnabled, shared_ptr newPkcs5Kdf, int wipeCount) const { if ((!newPassword || newPassword->Size() < 1) && (!newKeyfiles || newKeyfiles->empty())) throw PasswordEmpty (SRC_POS); @@ -52,7 +52,7 @@ namespace VeraCrypt SecureBuffer newSalt (openVolume->GetSaltSize()); SecureBuffer newHeaderKey (VolumeHeader::GetLargestSerializedKeySize()); - shared_ptr password (Keyfile::ApplyListToPassword (newKeyfiles, newPassword, emvSupportEnabled)); + shared_ptr password (Keyfile::ApplyListToPassword (newKeyfiles, newPassword, newSecurityTokenKeySpec, emvSupportEnabled)); bool backupHeader = false; while (true) @@ -77,10 +77,10 @@ namespace VeraCrypt } } - shared_ptr CoreBase::ChangePassword (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, bool emvSupportEnabled, shared_ptr newPkcs5Kdf, int wipeCount) const + shared_ptr CoreBase::ChangePassword (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, wstring newSecurityTokenKeySpec, bool emvSupportEnabled, shared_ptr newPkcs5Kdf, int wipeCount) const { - shared_ptr volume = OpenVolume (volumePath, preserveTimestamps, password, pim, kdf, keyfiles, emvSupportEnabled); - ChangePassword (volume, newPassword, newPim, newKeyfiles, emvSupportEnabled, newPkcs5Kdf, wipeCount); + shared_ptr volume = OpenVolume (volumePath, preserveTimestamps, password, pim, kdf, keyfiles, securityTokenKeySpec, emvSupportEnabled); + ChangePassword (volume, newPassword, newPim, newKeyfiles, newSecurityTokenKeySpec, emvSupportEnabled, newPkcs5Kdf, wipeCount); return volume; } @@ -256,10 +256,10 @@ namespace VeraCrypt return false; } - shared_ptr CoreBase::OpenVolume (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection, shared_ptr protectionPassword, int protectionPim, shared_ptr protectionKdf, shared_ptr protectionKeyfiles, bool sharedAccessAllowed, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) const + shared_ptr CoreBase::OpenVolume (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection, shared_ptr protectionPassword, int protectionPim, shared_ptr protectionKdf, shared_ptr protectionKeyfiles, wstring protectionSecurityTokenKeySpec, bool sharedAccessAllowed, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) const { make_shared_auto (Volume, volume); - volume->Open (*volumePath, preserveTimestamps, password, pim, kdf, keyfiles, emvSupportEnabled, protection, protectionPassword, protectionPim, protectionKdf, protectionKeyfiles, sharedAccessAllowed, volumeType, useBackupHeaders, partitionInSystemEncryptionScope); + volume->Open (*volumePath, preserveTimestamps, password, pim, kdf, keyfiles, securityTokenKeySpec, emvSupportEnabled, protection, protectionPassword, protectionPim, protectionKdf, protectionKeyfiles, protectionSecurityTokenKeySpec, sharedAccessAllowed, volumeType, useBackupHeaders, partitionInSystemEncryptionScope); return volume; } @@ -274,7 +274,7 @@ namespace VeraCrypt encryptionAlgorithm->GetMode()->SetKey (modeKey); } - void CoreBase::ReEncryptVolumeHeaderWithNewSalt (const BufferPtr &newHeaderBuffer, shared_ptr header, shared_ptr password, int pim, shared_ptr keyfiles, bool emvSupportEnabled) const + void CoreBase::ReEncryptVolumeHeaderWithNewSalt (const BufferPtr &newHeaderBuffer, shared_ptr header, shared_ptr password, int pim, shared_ptr keyfiles, wstring tokenDescriptor, bool emvSupportEnabled) const { shared_ptr pkcs5Kdf = header->GetPkcs5Kdf(); @@ -283,7 +283,7 @@ namespace VeraCrypt SecureBuffer newSalt (header->GetSaltSize()); SecureBuffer newHeaderKey (VolumeHeader::GetLargestSerializedKeySize()); - shared_ptr passwordKey (Keyfile::ApplyListToPassword (keyfiles, password, emvSupportEnabled)); + shared_ptr passwordKey (Keyfile::ApplyListToPassword (keyfiles, password, tokenDescriptor, emvSupportEnabled)); RandomNumberGenerator::GetData (newSalt); pkcs5Kdf->DeriveKey (newHeaderKey, *passwordKey, pim, newSalt); diff --git a/src/Core/CoreBase.h b/src/Core/CoreBase.h index e646fce3d3..8a4834c551 100644 --- a/src/Core/CoreBase.h +++ b/src/Core/CoreBase.h @@ -33,8 +33,8 @@ namespace VeraCrypt public: virtual ~CoreBase (); - virtual void ChangePassword (shared_ptr openVolume, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, bool emvSupportEnabled, shared_ptr newPkcs5Kdf = shared_ptr (), int wipeCount = PRAND_HEADER_WIPE_PASSES) const; - virtual shared_ptr ChangePassword (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, bool emvSupportEnabled, shared_ptr newPkcs5Kdf = shared_ptr (), int wipeCount = PRAND_HEADER_WIPE_PASSES) const; + virtual void ChangePassword (shared_ptr openVolume, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, wstring newSecurityTokenKeySpec, bool emvSupportEnabled, shared_ptr newPkcs5Kdf = shared_ptr (), int wipeCount = PRAND_HEADER_WIPE_PASSES) const; + virtual shared_ptr ChangePassword (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, wstring newSecurityTokenKeySpec, bool emvSupportEnabled, shared_ptr newPkcs5Kdf = shared_ptr (), int wipeCount = PRAND_HEADER_WIPE_PASSES) const; virtual void CheckFilesystem (shared_ptr mountedVolume, bool repair = false) const = 0; virtual void CoalesceSlotNumberAndMountPoint (MountOptions &options) const; virtual void CreateKeyfile (const FilePath &keyfilePath) const; @@ -69,9 +69,9 @@ namespace VeraCrypt virtual bool IsVolumeMounted (const VolumePath &volumePath) const; virtual VolumeSlotNumber MountPointToSlotNumber (const DirectoryPath &mountPoint) const = 0; virtual shared_ptr MountVolume (MountOptions &options) = 0; - virtual shared_ptr OpenVolume (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr Kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (), shared_ptr protectionKeyfiles = shared_ptr (), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false) const; + virtual shared_ptr OpenVolume (shared_ptr volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr Kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (), shared_ptr protectionKeyfiles = shared_ptr (), wstring protectionKeyFileSpec = wstring(), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false) const; virtual void RandomizeEncryptionAlgorithmKey (shared_ptr encryptionAlgorithm) const; - virtual void ReEncryptVolumeHeaderWithNewSalt (const BufferPtr &newHeaderBuffer, shared_ptr header, shared_ptr password, int pim, shared_ptr keyfiles, bool emvSupportEnabled) const; + virtual void ReEncryptVolumeHeaderWithNewSalt (const BufferPtr &newHeaderBuffer, shared_ptr header, shared_ptr password, int pim, shared_ptr keyfiles, wstring tokenDescriptor, bool emvSupportEnabled) const; virtual void SetAdminPasswordCallback (shared_ptr functor) { } virtual void SetApplicationExecutablePath (const FilePath &path) { ApplicationExecutablePath = path; } virtual void SetFileOwner (const FilesystemPath &path, const UserId &owner) const = 0; diff --git a/src/Core/CoreTest.cpp b/src/Core/CoreTest.cpp new file mode 100644 index 0000000000..7ed9c036e3 --- /dev/null +++ b/src/Core/CoreTest.cpp @@ -0,0 +1,955 @@ +#include + +#include "VolumeCreator.h" +#include "Unix/CoreService.h" +#include "RandomNumberGenerator.h" +#include "CoreException.h" + +#include "Volume/EncryptionThreadPool.h" +#include "Platform/SerializerFactory.h" +#include "Platform/Functor.h" +#include "Platform/FileStream.h" +#include "Common/SecurityToken.h" +#include "Common/MockSecurityToken.h" + +#include +#include +#include + +#include + +using namespace VeraCrypt; +using namespace std; + +#define DEFAULT_PASSWORD "12345" +#define PASSWORD_TO_CHANGE_TO "54321" +#define DEFAULT_REDKEY_DATA_SIZE (128 + 128/2) +#define TOKEN_KEY L"test token key" + + +#define KB(k) (k*1024) +#define MB(m) (KB(m)*1024) + + +static Buffer *redkeyBuffer; + + +struct VolumeTestParams { + string caseName; + shared_ptr opts; + shared_ptr createOpts; + bool useBluekey; +}; + +template ParameterizedFunctionalTest::ParameterizedFunctionalTest(string name, paramTestFunc func, VolumeTestParams *param); + +class AdminPasswordRequestHandler : public GetStringFunctor +{ + public: + virtual void operator() (string &str) + { + throw ElevationFailed (SRC_POS, "sudo", 1, ""); + } +}; + +FilesystemPath TestFile(string name) { + struct stat fstat; + + auto found = false; + while (!found) { + if (stat ("Tests", &fstat) == 0) { + auto *wd = getcwd(NULL, 0); + return FilesystemPath(string(wd)).Append(L"Tests").Append(StringConverter::ToWide(name)); + } + chdir(".."); + } +} + +void SetUp() { + SerializerFactory::Initialize(); + + SecurityToken::UseImpl(shared_ptr(new MockSecurityTokenImpl())); + + VeraCrypt::CoreService::Start(); + + RandomNumberGenerator::Start(); + + // this is from UserInterface.cpp + // LangString.Init(); + VeraCrypt::Core->Init(); + VeraCrypt::Core->SetAdminPasswordCallback (shared_ptr (new AdminPasswordRequestHandler)); +} + +void TearDown() { + RandomNumberGenerator::Stop(); + CoreService::Stop(); + SerializerFactory::Deinitialize(); +} + + +shared_ptr GetPassword(string passwordString) { + size_t ulen = passwordString.length(); + return shared_ptr(new VolumePassword ((uint8*)passwordString.c_str(), ulen)); +} + + +shared_ptr GetOptions(string name) { + shared_ptr volumePath(new VolumePath(TestFile(name + ".vol"))); + shared_ptr password = GetPassword(DEFAULT_PASSWORD); + + + Sha512 *SelectedHash = new Sha512(); + shared_ptr kdf = Pkcs5Kdf::GetAlgorithm (*SelectedHash); + shared_ptr keyfiles(new KeyfileList()); + VolumeProtection::Enum protection = VolumeProtection::None; + shared_ptr protectionPassword; + shared_ptr protectionKdf; + shared_ptr protectionKeyfileList(new KeyfileList()); + VolumeType::Enum volumeType = VolumeType::Unknown; + wstring securityTokenKeySpec; + + + MountOptions opts; + opts.Path = volumePath; + opts.FilesystemOptions = wstring(); + opts.FilesystemType = wstring(); + opts.NoFilesystem = false; + opts.Password = password; + opts.Kdf = kdf; + opts.Keyfiles = keyfiles; + opts.Protection = protection; + opts.ProtectionPassword = protectionPassword; + opts.ProtectionKdf = protectionKdf; + opts.ProtectionKeyfiles = protectionKeyfileList; + opts.SecurityTokenKeySpec = securityTokenKeySpec; + + opts.SlotNumber = 0; + + shared_ptr result = shared_ptr(new MountOptions()); + *result = opts; + return result; +} + + +shared_ptr GetCreateOpts(string name) { + MountOptions mopts = *GetOptions(name); + + VolumeCreationOptions opts; + + opts.FilesystemClusterSize = 0; // default + opts.SectorSize = 512; + // XXX: other filesystems doesn't work, because we can only format fat fs within Core + opts.Filesystem = VolumeCreationOptions::FilesystemType::Enum::FAT; + opts.EA = shared_ptr (new AESTwofishSerpent ()); + opts.Quick = false; + opts.Size = 10*1024*1024; + opts.Type = VolumeType::Normal; + + opts.Password = make_shared(*(mopts.Password)); + opts.Pim = mopts.Pim; + opts.Keyfiles = mopts.Keyfiles; + opts.SecurityTokenKeySpec = mopts.SecurityTokenKeySpec; + opts.Path = *mopts.Path; + + opts.VolumeHeaderKdf = mopts.Kdf; + + shared_ptr result = shared_ptr(new VolumeCreationOptions()); + *result = opts; + return result; + +} + + +Test* WithParams(string name, paramTestFunc f, shared_ptr createOpts, shared_ptr mountOpts) { + VolumeTestParams *params = new VolumeTestParams{name, mountOpts, createOpts, false}; + return Testing::param(name, f, params); +} + +Test* WithDefaultParams(string name, paramTestFunc f) { + auto createOpts = GetCreateOpts(name); + auto mountOpts = GetOptions(name); + return WithParams(name, f, createOpts, mountOpts); +} + + + +void WithBluekey(const VolumeTestParams *params, shared_ptr kf) { + // setting this signals to use security token key + params->opts->SecurityTokenKeySpec = params->createOpts->SecurityTokenKeySpec = TOKEN_KEY; + params->createOpts->Keyfiles->push_back(kf); + params->opts->Keyfiles->push_back(kf); +} + + + + +shared_ptr CreateKeyfile(string name) { + SecureBuffer data(100); + RandomNumberGenerator::GetData(data); + + FilePath kfp(TestFile(name)); + File f; + f.Open(kfp, File::FileOpenMode::CreateWrite); + f.Write(data); + f.Close(); + + auto keyfile = shared_ptr(new Keyfile(kfp)); + return keyfile; +} + + + +shared_ptr CreateBluekey(size_t size) { + SecureBuffer buffer(size); + RandomNumberGenerator::GetData(buffer, true); + + redkeyBuffer = new Buffer(ConstBufferPtr(buffer)); + + File redkeyOriginal; + redkeyOriginal.Open(TestFile("redkey_origin.key"), File::FileOpenMode::CreateWrite); + redkeyOriginal.Write(*redkeyBuffer); + redkeyOriginal.Close(); + + FilePath bluekeyPath(TestFile("bluekey.key")); + Keyfile::CreateBluekey(bluekeyPath, TOKEN_KEY, buffer); + return shared_ptr(new Keyfile(bluekeyPath)); +} + +shared_ptr CreateBluekey() { + return CreateBluekey(DEFAULT_REDKEY_DATA_SIZE); +} + + + +VolumeTestParams *GetTestParams(void *arg) { + VolumeTestParams *params = (VolumeTestParams*) arg; + return params; +} + + + + +void EnsureBluekey(const VolumeTestParams *params, size_t keyfileSize) { + shared_ptr kf = CreateBluekey(keyfileSize); + WithBluekey(params, kf); +} + +void EnsureBluekey(const VolumeTestParams *params) { + EnsureBluekey(params, DEFAULT_REDKEY_DATA_SIZE); +} + +void CreateVolume(shared_ptr r, VolumeTestParams *params) { + VolumeCreator creator; + shared_ptr opts = params->createOpts; + + if (!opts->EA) { + r->Failed("encryption algorithm is null for creation"); + return; + } + creator.CreateVolume(opts); + + while (creator.GetProgressInfo().CreationInProgress) { + Thread::Sleep(1000); + } + creator.CheckResult(); + r->Phase("volume created successfully"); +} + +void Read(char *buf, shared_ptr v, size_t offset, size_t size); + +void DumpVolume() { + MountOptions opts = *GetOptions(TestFile("dump.vol")); + + try { + shared_ptr vol = VeraCrypt::Core->OpenVolume(opts.Path, + true, opts.Password, 0, opts.Kdf, + opts.Keyfiles, opts.SecurityTokenKeySpec, false, + opts.Protection, opts.ProtectionPassword, 0, opts.ProtectionKdf, opts.ProtectionKeyfiles, + opts.ProtectionSecurityTokenKeySpec, + false, VolumeType::Unknown, false, false); + + if (vol) { + trace_msg(vol->GetSize()); + trace_msg(vol->GetVolumeCreationTime()); + trace_msg(vol->GetFile()->IsOpen()); + trace_msg(string(vol->GetFile()->GetPath())); + + size_t rs = 256; + char *buffer = new char[rs]; + Read(buffer, vol, 0, rs); + + string s((char*)buffer, rs); + trace_msg("DATA" << s); + } else { + trace_msg("Volume is null"); + } + } catch (exception &ex) { + trace_msg("EX" << ex.what()); + } +} + +void EnsureVolumeMounts(shared_ptr r, VolumeTestParams params) { + try { + shared_ptr vi = VeraCrypt::Core->MountVolume(*params.opts); + if (vi) { + VeraCrypt::Core->DismountVolume(vi); + } else { + r->Failed("no volume information available after mounting"); + } + } catch (exception &e) { + r->Failed(string("ex caught") + e.what()); + } + +} + + +shared_ptr RevealRedkey(VolumeTestParams *params) { + shared_ptr kf = params->opts->Keyfiles->front(); + + + FilePath redkeyPath(TestFile("redkey.key")); + kf->RevealRedkey(redkeyPath, params->opts->SecurityTokenKeySpec); + return shared_ptr(new Keyfile(redkeyPath)); +} + + +void Read(char *buf, shared_ptr v, size_t offset, size_t size) { + if ((uint64) offset + size > v->GetSize()) + size = v->GetSize() - offset; + + size_t sectorSize = v->GetSectorSize(); + if (size % sectorSize != 0 || offset % sectorSize != 0) + { + // Support for non-sector-aligned read operations is required by some loop device tools + // which may analyze the volume image before attaching it as a device + + uint64 alignedOffset = offset - (offset % sectorSize); + uint64 alignedSize = size + (offset % sectorSize); + + if (alignedSize % sectorSize != 0) + alignedSize += sectorSize - (alignedSize % sectorSize); + + SecureBuffer alignedBuffer (alignedSize); + + // FuseService::ReadVolumeSectors (alignedBuffer, alignedOffset); + v->ReadSectors(alignedBuffer, alignedOffset); + BufferPtr ((uint8 *) buf, size).CopyFrom (alignedBuffer.GetRange (offset % sectorSize, size)); + } + else + { + v->ReadSectors(BufferPtr ((uint8 *) buf, size), offset); + // FuseService::ReadVolumeSectors (, offset); + } +} + + +#define PHASE(msg) trace_msg(">>>>>> " << msg << "<<<<<<<<") + + +void ChangeSecurityParametersTest(shared_ptr r, VolumeTestParams *params, + shared_ptr newPassword, + int newPim, + shared_ptr newKeyfiles, + shared_ptr newSecurityTokenKeySpec, + shared_ptr newPkcs5Kdf + ) { + + auto opts = params->opts; + + auto volumePath = opts->Path; + bool preserveTimestamps = params->opts->PreserveTimestamps; + bool truecryptMode = false; + + + auto password = opts->Password; + auto pim = opts->Pim; + auto kdf = opts->Kdf; + shared_ptr keyfiles = opts->Keyfiles; + wstring securityTokenKeySpec = opts->SecurityTokenKeySpec; + + + if (!newPkcs5Kdf) { + newPkcs5Kdf = kdf; + } + + // null value => same + // empty list => drop kf + // KEYFILES_TO_CHANGE_TO => replace kefiles + shared_ptr greenKeyfiles = newKeyfiles; + if (!greenKeyfiles) { + r->Phase("keeping the same keyfiles"); + greenKeyfiles = keyfiles; + } + + + // null => same + // empty => drop key + // non-empty => use specified + wstring greenSecurityTokenKeySpec; + if (!newSecurityTokenKeySpec) { + r->Phase("keeping the same tokenspec"); + greenSecurityTokenKeySpec = securityTokenKeySpec; + } else { + greenSecurityTokenKeySpec = *newSecurityTokenKeySpec; + } + + auto greenPim = newPim; + if (greenPim < 0) { + r->Phase("keeping the same pim"); + greenPim = pim; + } + + auto greenPassword = newPassword; + if (!greenPassword) { + r->Phase("keeping the same password"); + greenPassword = password; + } + + int wipeCount = 3; + + + r->Phase("applying security parameters changes"); + try { + VeraCrypt::Core->ChangePassword(volumePath, preserveTimestamps, + password, pim, kdf, keyfiles, securityTokenKeySpec, + greenPassword, greenPim, greenKeyfiles, greenSecurityTokenKeySpec, false, + newPkcs5Kdf, wipeCount); + } catch (exception &e) { + r->Failed("unable to change security parameters"); + return; + } + + + params->opts->Password = greenPassword; + params->opts->Pim = greenPim; + params->opts->Keyfiles = greenKeyfiles; + params->opts->SecurityTokenKeySpec = greenSecurityTokenKeySpec; + params->opts->Kdf = newPkcs5Kdf; + + r->Phase("mounting updated volume"); + EnsureVolumeMounts(r, *params); +} + +void ChangePasswordTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("changings password"); + + auto newPassword = GetPassword(PASSWORD_TO_CHANGE_TO); + + ChangeSecurityParametersTest(r, params, newPassword, -1, + shared_ptr(nullptr), + shared_ptr(nullptr), shared_ptr(nullptr)); + +} + +void AddKeyfileToVolumeTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + + r->Phase("creating keyfile"); + shared_ptr kf = CreateKeyfile("added_keyfile.key"); + + r->Phase("creating kfl"); + shared_ptr kfl = shared_ptr(new KeyfileList()); + kfl->push_back(kf); + + r->Phase("adding keyfile to the volume"); + ChangeSecurityParametersTest(r, params, shared_ptr(nullptr), + -1, shared_ptr(kfl), + shared_ptr(nullptr), shared_ptr(nullptr)); +} + +void AddBluekeyToVolumeTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("creating bluekey"); + shared_ptr kfl = shared_ptr(new KeyfileList()); + kfl->push_back(CreateBluekey()); + + r->Phase("adding bluekey to the volume"); + ChangeSecurityParametersTest(r, params, shared_ptr(nullptr), + -1, shared_ptr(kfl), + shared_ptr(new wstring(TOKEN_KEY)), shared_ptr(nullptr)); +} + +void RemoveBluekeyFromVolumeTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + EnsureBluekey(params); + CreateVolume(r, params); + + shared_ptr kfl = shared_ptr(new KeyfileList()); + + r->Phase("removing bluekey from the volume"); + ChangeSecurityParametersTest(r, params, shared_ptr(nullptr), + -1, shared_ptr(kfl), + shared_ptr(new wstring(L"")), shared_ptr(nullptr)); +} + + +void UseBluekeyAsRedkeyTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + EnsureBluekey(params); + CreateVolume(r, params); + + + r->Phase("removing bluekey from the volume"); + ChangeSecurityParametersTest(r, params, + shared_ptr(nullptr), + -1, + shared_ptr(nullptr), + shared_ptr(new wstring(L"")), + shared_ptr(nullptr)); +} + + +void UseTokenKeyWithoutKeyfilesTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + EnsureBluekey(params); + CreateVolume(r, params); + + + shared_ptr kfl = shared_ptr(new KeyfileList()); + + r->Phase("removing bluekey from the volume"); + ChangeSecurityParametersTest(r, params, shared_ptr(nullptr), + -1, shared_ptr(nullptr), + shared_ptr(nullptr), shared_ptr(nullptr)); +} + +void AssertEquals(shared_ptr r, size_t expected, size_t actual) { + if (expected != actual) { + r->Failed(string("Size differ. Expected") + std::to_string(expected) + ", actual " + std::to_string(actual)); + return; + } +} + +void AssertEquals(shared_ptr r, BufferPtr actual, BufferPtr expected) { + if (actual.Size() != expected.Size()) { + r->Failed("Size differ"); + return; + } + + if (!std::equal(actual.Get(), actual.Get()+actual.Size(), expected.Get())) { + r->Failed("Data differ"); + return; + } +} + +void RevealRedkeyTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating bluekey"); + shared_ptr kf = CreateBluekey(); + WithBluekey(params, kf); + + r->Phase("revealing redkey"); + shared_ptr redkeyKf = RevealRedkey(params); + + r->Phase("Reading revealed redkey"); + FilePath redkeyPath = *redkeyKf; + auto redkey = shared_ptr(new File()); + redkey->Open(redkeyPath, File::FileOpenMode::OpenRead); + FileStream rkFs(redkey); + string redkeyData = rkFs.ReadToEnd(); + redkey->Close(); + + r->Phase("comparing the data bluekey is based on with revealed keyfile"); + AssertEquals(r, BufferPtr((uint8*)redkeyData.c_str(), redkeyData.size()), *redkeyBuffer); +} + +void CreateBluekeyTest(shared_ptr r) { + // just checks if blue key gets created + // doesn't check if volume can be mounted, redkey revealed, etc. + // compares the sized + shared_ptr kf = CreateBluekey(); + FilePath bluekeyPath = *kf; + File bluekey; + bluekey.Open(bluekeyPath, File::FileOpenMode::OpenRead); + AssertEquals(r, DEFAULT_REDKEY_DATA_SIZE, bluekey.Length()); +} + + + +void CreateVolumeTest(shared_ptr r, VolumeTestParams *params) { + CreateVolume(r, params); +} + +void MountVolumeTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("volume created, mounting"); + EnsureVolumeMounts(r, *params); +} + +void DumpVolumeTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("volume created, dumping"); + DumpVolume(); +} + +void MountWithBlueKeyTest(shared_ptr r, VolumeTestParams *params, size_t keyfileSize) { + r->Phase("creating bluekey"); + EnsureBluekey(params, keyfileSize); + + r->Phase("creating volume"); + CreateVolume(r, params); + + // mounting with the same set of parameters + r->Phase("mounting with the same set of parameters"); + EnsureVolumeMounts(r, *params); + + + r->Phase("mounting with redkey"); + shared_ptr redkey = RevealRedkey(params); + + params->opts->Keyfiles->clear(); + params->opts->Keyfiles->push_back(redkey); + params->opts->SecurityTokenKeySpec = L""; // do not use security key + + EnsureVolumeMounts(r, *params); +} + +void MountWithBlueKeyTest(shared_ptr r, VolumeTestParams *params) { + MountWithBlueKeyTest(r, params, DEFAULT_REDKEY_DATA_SIZE); +} + +void CreateVolumeWithBluekeySizeGreaterThanEncryptionKeySizeTest(shared_ptr r, VolumeTestParams *params) { + MountWithBlueKeyTest(r, params, DEFAULT_REDKEY_DATA_SIZE + 200); +} + + +void CreateVolumeWithBluekeySizeLessThanEncryptionKeySizeTest(shared_ptr r, VolumeTestParams *params) { + try { + MountWithBlueKeyTest(r, params, DEFAULT_REDKEY_DATA_SIZE - 92); + r->Failed("shouldn't use keyfiles less than encryption key size"); + } catch (InsufficientData &e) { + r->Success(); + } +} + +void CreateHiddenVolumeTest(shared_ptr r, VolumeTestParams *params) { + // create outer volume + r->Phase("creating outer volume"); + auto outerParams = unique_ptr(new VolumeTestParams()); + *outerParams = *params; + + auto outerCreateOpts = make_shared(); + *outerCreateOpts = *params->createOpts; + outerParams->createOpts = outerCreateOpts; + + outerCreateOpts->Size = MB(20); + outerCreateOpts->Type = VolumeType::Enum::Normal; + outerCreateOpts->Password = GetPassword("outervolumepassword"); + outerParams->opts->Password = outerCreateOpts->Password; + + + CreateVolume(r, outerParams.get()); + + // shared_ptr vi = VeraCrypt::Core->MountVolume(*outerParams->opts); + // if (!vi) { + // r->Failed("couldn't mount created mounted volume to get hidden volume max size"); + // } + + // r->Phase("getting outer volume available space"); + // const DirectoryPath &outerVolumeMountPoint = vi->MountPoint; + // struct statvfs stat; + // uint64 outerVolumeAvailableSpace = 0; + uint64 maxHiddenVolumeSize = outerCreateOpts->Size / 2; + // if (statvfs(((string)outerVolumeMountPoint).c_str(), &stat) == 0) + // { + // outerVolumeAvailableSpace = (uint64) stat.f_bsize * (uint64) stat.f_bavail; + + // maxHiddenVolumeSize = (4ULL * outerVolumeAvailableSpace) / 5ULL; + // uint64 reservedSize = outerCreateOpts->Size / 200; + // if (reservedSize > MB(10)) + // reservedSize = MB(10); + // if (maxHiddenVolumeSize < reservedSize) + // maxHiddenVolumeSize = 0; + // else + // maxHiddenVolumeSize -= reservedSize; + + // maxHiddenVolumeSize -= maxHiddenVolumeSize % outerCreateOpts->SectorSize; + + // stringstream desc; + // desc << "outer volume available space: " << outerVolumeAvailableSpace << ", hidden volume size: " << maxHiddenVolumeSize; + // r->Phase(desc.str()); + // } + // Core->DismountVolume(vi); + + r->Phase("creating hidden volume"); + auto hiddenParams = unique_ptr(new VolumeTestParams()); + *hiddenParams = *params; + + auto hiddenCreateOpts = make_shared(); + *hiddenCreateOpts = *params->createOpts; + hiddenParams->createOpts = hiddenCreateOpts; + + hiddenCreateOpts->Size = maxHiddenVolumeSize; + hiddenCreateOpts->Type = VolumeType::Enum::Hidden; + hiddenCreateOpts->Password = GetPassword("hiddenvolumepassword"); + hiddenParams->opts->Password = hiddenCreateOpts->Password; + CreateVolume(r, hiddenParams.get()); + + r->Phase("mounting outer volume"); + EnsureVolumeMounts(r, *outerParams); + + r->Phase("mounting hidden volume"); + EnsureVolumeMounts(r, *hiddenParams); + + outerParams->opts->Protection = VolumeProtection::HiddenVolumeReadOnly; + outerParams->opts->ProtectionPassword = hiddenCreateOpts->Password; +} + + +void FilesTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("mounting volume"); + auto vi = VeraCrypt::Core->MountVolume(*params->opts); + auto mp = vi->MountPoint; + auto volumeSize = vi->Size; + + r->Phase("creating files"); + size_t size = 50; + size_t step = 50; + size_t total = 0; + while (total + size < volumeSize) { + File f; + auto filePath = mp.Append(L"test" + std::to_wstring(size) + L".txt"); + f.Open(filePath, File::CreateWrite); + Buffer buffer(size); + buffer.Zero(); + f.Write(buffer); + f.Close(); + + total += size; + step = 2*step; + size += step; + } + + r->Phase("dismounting"); + VeraCrypt::Core->DismountVolume(vi); + + r->Phase("mounting back"); + vi = VeraCrypt::Core->MountVolume(*params->opts); + mp = vi->MountPoint; + volumeSize = vi->Size; + + r->Phase("checking files"); + size = 50; + step = 50; + total = 0; + while (total + size < volumeSize) { + File f; + auto filePath = mp.Append(L"test" + std::to_wstring(size) + L".txt"); + f.Open(filePath, File::OpenRead); + Buffer buffer(size); + f.ReadCompleteBuffer(buffer); + // for (auto i = buffer.Ptr(); i < buffer.Ptr() + buffer.Size(); i++) { + // *i = (i - buffer.Ptr()) % 0x100; + // } + // f.SeekAt(0); + // f.Write(buffer); + f.Close(); + + total += size; + step = 2*step; + size += step; + } + + r->Phase("re-creating files"); + size = 50; + step = 50; + total = 0; + while (total + size < volumeSize) { + File f; + auto filePath = mp.Append(L"test" + std::to_wstring(size) + L".txt"); + f.Open(filePath, File::CreateReadWrite); + Buffer buffer(size); + size_t read = f.Read(buffer); + for (auto i = buffer.Ptr(); i < buffer.Ptr() + buffer.Size(); i++) { + *i = (i - buffer.Ptr()) % 0x100; + } + f.SeekAt(0); + f.Write(buffer); + f.Close(); + + total += size; + step = 2*step; + size += step; + } + + VeraCrypt::Core->DismountVolume(vi); +} + +void OutOfSpaceTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("mounting volume"); + // EnsureVolumeMounts(r, *params); + + VolumeTestParams p = *params; + MountOptions opt = *p.opts; + auto vi = VeraCrypt::Core->MountVolume(opt); + auto mp = vi->MountPoint; + auto volumeSize = vi->Size; + + r->Phase("writing oversized file"); + File f; + auto filePath = mp.Append(L"test.txt"); + f.Open(filePath, File::CreateWrite); + Buffer buffer(volumeSize); + try { + f.Write(buffer); + f.Close(); + r->Failed("write was successful"); + } catch (...) { + f.Close(); + VeraCrypt::Core->DismountVolume(vi); + } + +} + +void WriteBeyondSpaceTest(shared_ptr r, VolumeTestParams *params) { + r->Phase("creating volume"); + CreateVolume(r, params); + + r->Phase("mounting volume"); + VolumeTestParams p = *params; + MountOptions opt = *p.opts; + auto vi = VeraCrypt::Core->MountVolume(opt); + auto mp = vi->MountPoint; + auto volumeSize = vi->Size; + + + auto smallFileSize = KB(100); + auto largeFileSize = volumeSize - smallFileSize; + + r->Phase("writing large file"); + File f; + auto filePath = mp.Append(L"test-large.txt"); + f.Open(filePath, File::CreateWrite); + Buffer buffer(largeFileSize); + buffer.Zero(); + f.Write(buffer); + f.Close(); + + + r->Phase("writing small file by byte"); + filePath = mp.Append(L"test-small.txt"); + f.Open(filePath, File::CreateWrite); + Buffer smallBuff(1); + + for (size_t i = 0; i < smallFileSize; i++) { + *smallBuff.Ptr() = (i % 0x100); + try { + f.Write(smallBuff); + } catch (...) { + f.Close(); + VeraCrypt::Core->DismountVolume(vi); + return; + } + } + f.Close(); + r->Failed("write was successful"); +} + + +vector GenerateCombinations() { + auto EAs = VeraCrypt::EncryptionAlgorithm::GetAvailableAlgorithms(); + auto hashAlgos = VeraCrypt::Hash::GetAvailableAlgorithms(); + + + vector res; + + for (auto ea : EAs) { + for (auto ha : hashAlgos) { + ea->GetName(); + ha->GetName(); + shared_ptr kdf = Pkcs5Kdf::GetAlgorithm (*ha); + + wstringstream wname; + wname << ea->GetName() << "_" << ha->GetName() << "_" << kdf->GetName(); + + string name = StringConverter::ToSingle(wname.str()); + auto createOpts = GetCreateOpts(name); + auto mountOpts = GetOptions(name); + createOpts->EA = ea; + createOpts->VolumeHeaderKdf = kdf; + + mountOpts->Kdf = kdf; + + res.push_back(VolumeTestParams{name, mountOpts, createOpts}); + } + } + return res; +} + + +int main() { + SetUp(); + VeraCrypt::Testing t; + + + + // t.AddTest(WithDefaultParams("create volume with bluekey, size > encryption size", &CreateVolumeWithBluekeySizeGreaterThanEncryptionKeySizeTest)); + // t.AddTest(WithDefaultParams("create volume with bluekey, size < encryption size", &CreateVolumeWithBluekeySizeLessThanEncryptionKeySizeTest)); + // t.AddTest(WithDefaultParams("files test", &FilesTest)); + // t.AddTest(WithDefaultParams("create hidden volume", &CreateHiddenVolumeTest)); + // for (auto p : GenerateCombinations()) { + // t.AddTest(WithParams(p.caseName, MountVolumeTest, p.createOpts, p.opts)); + // } + // t.Main(); + // TearDown(); + // return 0; + + /* + * Test not related to the volume + */ + t.AddTest("create blue key", &CreateBluekeyTest); + t.AddTest(WithDefaultParams("reveal redkey", &RevealRedkeyTest)); + + /* + * Test related to volume creation/mounting/changing + */ + t.AddTest(WithDefaultParams("create volume", &CreateVolumeTest)); + t.AddTest(WithDefaultParams("create hidden volume", &CreateHiddenVolumeTest)); + t.AddTest(WithDefaultParams("create volume with bluekey", &MountWithBlueKeyTest)); + t.AddTest(WithDefaultParams("create volume with bluekey, size > encryption size", &CreateVolumeWithBluekeySizeGreaterThanEncryptionKeySizeTest)); + t.AddTest(WithDefaultParams("create volume with bluekey, size < encryption size", &CreateVolumeWithBluekeySizeLessThanEncryptionKeySizeTest)); + t.AddTest(WithDefaultParams("change password", &ChangePasswordTest)); + t.AddTest(WithDefaultParams("add keyfile to the volume", &AddKeyfileToVolumeTest)); + t.AddTest(WithDefaultParams("add bluekey to existing volume", &AddBluekeyToVolumeTest)); + t.AddTest(WithDefaultParams("remove blue key from existing volume", &RemoveBluekeyFromVolumeTest)); + t.AddTest(WithDefaultParams("use bluekey as redkey", &UseBluekeyAsRedkeyTest)); + t.AddTest(WithDefaultParams("use token key without keyfiles", &UseTokenKeyWithoutKeyfilesTest)); + + t.AddTest(WithDefaultParams("test creating files of differing sizes", &FilesTest)); + t.AddTest(WithDefaultParams("out of space test", &OutOfSpaceTest)); + t.AddTest(WithDefaultParams("test writing beyond available space", &WriteBeyondSpaceTest)); + + + /* + * Parameterized tests + * The combination of parameters covers all possible security options (keyfiles, passwords, pim, truecrypt, algos) + * and filesystems + */ + + TestSuite *algosSuite = new TestSuite(); + algosSuite->StopOnFirstFailure(); + for (auto p : GenerateCombinations()) { + algosSuite->AddTest(WithParams(p.caseName, MountVolumeTest, p.createOpts, p.opts)); + } + + t.AddTest(algosSuite); + + t.Main(); + TearDown(); +} diff --git a/src/Core/MountOptions.cpp b/src/Core/MountOptions.cpp index 2f28c089ff..06dc48caef 100644 --- a/src/Core/MountOptions.cpp +++ b/src/Core/MountOptions.cpp @@ -48,10 +48,12 @@ namespace VeraCrypt else ProtectionKdf.reset(); TC_CLONE_SHARED (KeyfileList, ProtectionKeyfiles); + TC_CLONE (ProtectionSecurityTokenKeySpec); TC_CLONE (Removable); TC_CLONE (SharedAccessAllowed); TC_CLONE (SlotNumber); TC_CLONE (UseBackupHeaders); + TC_CLONE (SecurityTokenKeySpec); } void MountOptions::Deserialize (shared_ptr stream) @@ -95,11 +97,14 @@ namespace VeraCrypt ProtectionPassword.reset(); ProtectionKeyfiles = Keyfile::DeserializeList (stream, "ProtectionKeyfiles"); + sr.Deserialize ("ProtectionSecurityTokenKeySpec", ProtectionSecurityTokenKeySpec); sr.Deserialize ("Removable", Removable); sr.Deserialize ("SharedAccessAllowed", SharedAccessAllowed); sr.Deserialize ("SlotNumber", SlotNumber); sr.Deserialize ("UseBackupHeaders", UseBackupHeaders); + sr.Deserialize("SecurityTokenKeySpec", SecurityTokenKeySpec); + try { if (!sr.DeserializeBool ("KdfNull")) @@ -159,11 +164,13 @@ namespace VeraCrypt ProtectionPassword->Serialize (stream); Keyfile::SerializeList (stream, "ProtectionKeyfiles", ProtectionKeyfiles); + sr.Serialize ("ProtectionSecurityTokenKeySpec", ProtectionSecurityTokenKeySpec); sr.Serialize ("Removable", Removable); sr.Serialize ("SharedAccessAllowed", SharedAccessAllowed); sr.Serialize ("SlotNumber", SlotNumber); sr.Serialize ("UseBackupHeaders", UseBackupHeaders); + sr.Serialize("SecurityTokenKeySpec", SecurityTokenKeySpec); sr.Serialize ("KdfNull", Kdf == nullptr); if (Kdf) sr.Serialize ("Kdf", Kdf->GetName()); diff --git a/src/Core/MountOptions.h b/src/Core/MountOptions.h index 3dcfa599d1..bc8a0c8e4e 100644 --- a/src/Core/MountOptions.h +++ b/src/Core/MountOptions.h @@ -34,10 +34,12 @@ namespace VeraCrypt PreserveTimestamps (true), Protection (VolumeProtection::None), ProtectionPim (-1), + ProtectionSecurityTokenKeySpec(wstring()), Removable (false), SharedAccessAllowed (false), SlotNumber (0), - UseBackupHeaders (false) + UseBackupHeaders (false), + SecurityTokenKeySpec(wstring()) { } @@ -67,10 +69,12 @@ namespace VeraCrypt int ProtectionPim; shared_ptr ProtectionKdf; shared_ptr ProtectionKeyfiles; + wstring ProtectionSecurityTokenKeySpec; bool Removable; bool SharedAccessAllowed; VolumeSlotNumber SlotNumber; bool UseBackupHeaders; + wstring SecurityTokenKeySpec; bool EMVSupportEnabled; protected: diff --git a/src/Core/Unix/CoreServiceProxy.h b/src/Core/Unix/CoreServiceProxy.h index d57d8163bd..ab687a390e 100644 --- a/src/Core/Unix/CoreServiceProxy.h +++ b/src/Core/Unix/CoreServiceProxy.h @@ -97,12 +97,11 @@ namespace VeraCrypt else { MountOptions newOptions = options; - - newOptions.Password = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled); + newOptions.Password = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.SecurityTokenKeySpec, options.EMVSupportEnabled); if (newOptions.Keyfiles) newOptions.Keyfiles->clear(); - newOptions.ProtectionPassword = Keyfile::ApplyListToPassword (options.ProtectionKeyfiles, options.ProtectionPassword, options.EMVSupportEnabled); + newOptions.ProtectionPassword = Keyfile::ApplyListToPassword (options.ProtectionKeyfiles, options.ProtectionPassword, options.ProtectionSecurityTokenKeySpec, options.EMVSupportEnabled); if (newOptions.ProtectionKeyfiles) newOptions.ProtectionKeyfiles->clear(); @@ -126,7 +125,7 @@ namespace VeraCrypt if (options.CachePassword && ((options.Password && !options.Password->IsEmpty()) || (options.Keyfiles && !options.Keyfiles->empty()))) { - VolumePasswordCache::Store (*Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled)); + VolumePasswordCache::Store (*Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.SecurityTokenKeySpec, options.EMVSupportEnabled)); } } diff --git a/src/Core/Unix/CoreUnix.cpp b/src/Core/Unix/CoreUnix.cpp index 1868eb6dcd..71f0897bac 100644 --- a/src/Core/Unix/CoreUnix.cpp +++ b/src/Core/Unix/CoreUnix.cpp @@ -575,12 +575,14 @@ namespace VeraCrypt options.Pim, options.Kdf, options.Keyfiles, + options.SecurityTokenKeySpec, options.EMVSupportEnabled, options.Protection, options.ProtectionPassword, options.ProtectionPim, options.ProtectionKdf, options.ProtectionKeyfiles, + options.ProtectionSecurityTokenKeySpec, options.SharedAccessAllowed, VolumeType::Unknown, options.UseBackupHeaders, diff --git a/src/Core/VolumeCreator.cpp b/src/Core/VolumeCreator.cpp index fefbddde82..22d646faea 100644 --- a/src/Core/VolumeCreator.cpp +++ b/src/Core/VolumeCreator.cpp @@ -315,7 +315,7 @@ namespace VeraCrypt // Header key HeaderKey.Allocate (VolumeHeader::GetLargestSerializedKeySize()); - PasswordKey = Keyfile::ApplyListToPassword (options->Keyfiles, options->Password, options->EMVSupportEnabled); + PasswordKey = Keyfile::ApplyListToPassword (options->Keyfiles, options->Password, options->SecurityTokenKeySpec, options->EMVSupportEnabled); options->VolumeHeaderKdf->DeriveKey (HeaderKey, *PasswordKey, options->Pim, salt); headerOptions.HeaderKey = HeaderKey; diff --git a/src/Core/VolumeCreator.h b/src/Core/VolumeCreator.h index 781354b9eb..405c63e2da 100644 --- a/src/Core/VolumeCreator.h +++ b/src/Core/VolumeCreator.h @@ -37,6 +37,7 @@ namespace VeraCrypt shared_ptr Keyfiles; shared_ptr VolumeHeaderKdf; shared_ptr EA; + wstring SecurityTokenKeySpec; bool Quick; bool EMVSupportEnabled; diff --git a/src/Driver/Fuse/FuseService.h b/src/Driver/Fuse/FuseService.h index d09a40dbea..7998fae5e3 100644 --- a/src/Driver/Fuse/FuseService.h +++ b/src/Driver/Fuse/FuseService.h @@ -25,8 +25,9 @@ namespace VeraCrypt class FuseService { protected: - struct ExecFunctor : public ProcessExecFunctor + class ExecFunctor : public ProcessExecFunctor { + public: ExecFunctor (shared_ptr openVolume, VolumeSlotNumber slotNumber) : MountedVolume (openVolume), SlotNumber (slotNumber) { @@ -38,7 +39,7 @@ namespace VeraCrypt VolumeSlotNumber SlotNumber; }; - friend struct ExecFunctor; + friend class ExecFunctor; public: static bool AuxDeviceInfoReceived () { return !OpenVolumeInfo.VirtualDevice.IsEmpty(); } diff --git a/src/Main/CommandLineInterface.cpp b/src/Main/CommandLineInterface.cpp index 735cbeef50..2d0e1e53b1 100644 --- a/src/Main/CommandLineInterface.cpp +++ b/src/Main/CommandLineInterface.cpp @@ -95,6 +95,7 @@ namespace VeraCrypt parser.AddSwitch (L"", L"quick", _("Enable quick format")); parser.AddOption (L"", L"size", _("Size in bytes")); parser.AddOption (L"", L"slot", _("Volume slot number")); + parser.AddOption (L"", L"security-token-key", _("Security token key to use in (:)")); parser.AddSwitch (L"", L"test", _("Test internal algorithms")); parser.AddSwitch (L"t", L"text", _("Use text user interface")); parser.AddOption (L"", L"token-lib", _("Security token library")); @@ -565,6 +566,16 @@ namespace VeraCrypt throw_err (LangString["UNKNOWN_OPTION"] + L": " + str); } + if (parser.Found (L"security-token-key", &str)) + { + ArgMountOptions.SecurityTokenKeySpec = wstring (str); + } + + if (parser.Found(L"protection-security-token-key", &str)) + { + ArgMountOptions.ProtectionSecurityTokenKeySpec = wstring (str); + } + ArgQuick = parser.Found (L"quick"); if (parser.Found (L"random-source", &str)) diff --git a/src/Main/CommandLineInterface.h b/src/Main/CommandLineInterface.h index f773ca6f81..dd973505f5 100644 --- a/src/Main/CommandLineInterface.h +++ b/src/Main/CommandLineInterface.h @@ -72,6 +72,7 @@ namespace VeraCrypt shared_ptr ArgMountPoint; shared_ptr ArgNewHash; shared_ptr ArgNewKeyfiles; + wstring ArgSecurityTokenKeySpec; shared_ptr ArgNewPassword; int ArgNewPim; bool ArgNoHiddenVolumeProtection; diff --git a/src/Main/Forms/ChangePasswordDialog.cpp b/src/Main/Forms/ChangePasswordDialog.cpp index 39da8e6046..e1052a3ac9 100644 --- a/src/Main/Forms/ChangePasswordDialog.cpp +++ b/src/Main/Forms/ChangePasswordDialog.cpp @@ -29,7 +29,7 @@ namespace VeraCrypt } #endif - ChangePasswordDialog::ChangePasswordDialog (wxWindow* parent, shared_ptr volumePath, Mode::Enum mode, shared_ptr password, shared_ptr keyfiles, shared_ptr newPassword, shared_ptr newKeyfiles) + ChangePasswordDialog::ChangePasswordDialog (wxWindow* parent, shared_ptr volumePath, Mode::Enum mode, shared_ptr password, shared_ptr keyfiles, wstring securityTokenKeySpec, shared_ptr newPassword, shared_ptr newKeyfiles, wstring newSecurityTokenKeySpec) : ChangePasswordDialogBase (parent), DialogMode (mode), Path (volumePath) { bool enableNewPassword = false; @@ -67,11 +67,11 @@ namespace VeraCrypt GraphicUserInterface::InstallPasswordEntryCustomKeyboardShortcuts (this); #endif - CurrentPasswordPanel = new VolumePasswordPanel (this, NULL, password, keyfiles, false, true, true, false, true, true); + CurrentPasswordPanel = new VolumePasswordPanel (this, NULL, password, keyfiles, securityTokenKeySpec, SecurityTokenKeyOperation::DECRYPT, false, true, true, false, true, true); CurrentPasswordPanel->UpdateEvent.Connect (EventConnector (this, &ChangePasswordDialog::OnPasswordPanelUpdate)); CurrentPasswordPanelSizer->Add (CurrentPasswordPanel, 1, wxALL | wxEXPAND); - NewPasswordPanel = new VolumePasswordPanel (this, NULL, newPassword, newKeyfiles, false, enableNewPassword, enableNewKeyfiles, enableNewPassword, enablePkcs5Prf); + NewPasswordPanel = new VolumePasswordPanel (this, NULL, newPassword, newKeyfiles, newSecurityTokenKeySpec, SecurityTokenKeyOperation::DECRYPT, false, enableNewPassword, enableNewKeyfiles, enableNewPassword, enablePkcs5Prf); NewPasswordPanel->UpdateEvent.Connect (EventConnector (this, &ChangePasswordDialog::OnPasswordPanelUpdate)); NewPasswordPanelSizer->Add (NewPasswordPanel, 1, wxALL | wxEXPAND); @@ -110,6 +110,7 @@ namespace VeraCrypt shared_ptr newPassword; int newPim = 0; + wstring newSecurityTokenSpec = wstring(); if (DialogMode == Mode::ChangePasswordAndKeyfiles) { try @@ -128,6 +129,7 @@ namespace VeraCrypt NewPasswordPanel->SetFocusToPimTextCtrl(); return; } + newSecurityTokenSpec = NewPasswordPanel->GetSecurityTokenKeySpec(); if (newPassword->Size() > 0) { @@ -159,13 +161,18 @@ namespace VeraCrypt { newPassword = CurrentPasswordPanel->GetPassword(); newPim = CurrentPasswordPanel->GetVolumePim(); + newSecurityTokenSpec = CurrentPasswordPanel->GetSecurityTokenKeySpec(); } shared_ptr newKeyfiles; - if (DialogMode == Mode::ChangePasswordAndKeyfiles || DialogMode == Mode::ChangeKeyfiles) + if (DialogMode == Mode::ChangePasswordAndKeyfiles || DialogMode == Mode::ChangeKeyfiles) { newKeyfiles = NewPasswordPanel->GetKeyfiles(); - else if (DialogMode != Mode::RemoveAllKeyfiles) + newSecurityTokenSpec = NewPasswordPanel->GetSecurityTokenKeySpec(); + } + else if (DialogMode != Mode::RemoveAllKeyfiles) { newKeyfiles = CurrentPasswordPanel->GetKeyfiles(); + newSecurityTokenSpec = CurrentPasswordPanel->GetSecurityTokenKeySpec(); + } /* force the display of the random enriching interface */ RandomNumberGenerator::SetEnrichedByUserStatus (false); @@ -192,7 +199,12 @@ namespace VeraCrypt wxBusyCursor busy; ChangePasswordThreadRoutine routine(Path, Gui->GetPreferences().DefaultMountOptions.PreserveTimestamps, CurrentPasswordPanel->GetPassword(), CurrentPasswordPanel->GetVolumePim(), CurrentPasswordPanel->GetPkcs5Kdf(), CurrentPasswordPanel->GetKeyfiles(), - newPassword, newPim, newKeyfiles, NewPasswordPanel->GetPkcs5Kdf(), NewPasswordPanel->GetHeaderWipeCount(), Gui->GetPreferences().EMVSupportEnabled); + CurrentPasswordPanel->GetSecurityTokenKeySpec(), + newPassword, newPim, newKeyfiles, newSecurityTokenSpec, + NewPasswordPanel->GetPkcs5Kdf(), + NewPasswordPanel->GetHeaderWipeCount(), + Gui->GetPreferences().EMVSupportEnabled + ); Gui->ExecuteWaitThreadRoutine (this, &routine); masterKeyVulnerable = routine.m_masterKeyVulnerable; } diff --git a/src/Main/Forms/ChangePasswordDialog.h b/src/Main/Forms/ChangePasswordDialog.h index 66fbfecf37..3f2c594edb 100644 --- a/src/Main/Forms/ChangePasswordDialog.h +++ b/src/Main/Forms/ChangePasswordDialog.h @@ -33,7 +33,7 @@ namespace VeraCrypt }; }; - ChangePasswordDialog (wxWindow* parent, shared_ptr volumePath, Mode::Enum mode = Mode::ChangePasswordAndKeyfiles, shared_ptr password = shared_ptr (), shared_ptr keyfiles = shared_ptr (), shared_ptr newPassword = shared_ptr (), shared_ptr newKeyfiles = shared_ptr ()); + ChangePasswordDialog (wxWindow* parent, shared_ptr volumePath, Mode::Enum mode = Mode::ChangePasswordAndKeyfiles, shared_ptr password = shared_ptr (), shared_ptr keyfiles = shared_ptr (), wstring securityTokenKeySpec = wstring(), shared_ptr newPassword = shared_ptr (), shared_ptr newKeyfiles = shared_ptr (), wstring newSecurityTokenKeySpec = wstring()); virtual ~ChangePasswordDialog (); #ifdef TC_MACOSX diff --git a/src/Main/Forms/Forms.cpp b/src/Main/Forms/Forms.cpp index 9ffad55583..0f4a75c92f 100644 --- a/src/Main/Forms/Forms.cpp +++ b/src/Main/Forms/Forms.cpp @@ -118,6 +118,10 @@ MainFrameBase::MainFrameBase( wxWindow* parent, wxWindowID id, const wxString& t ManageSecurityTokenKeyfilesMenuItem = new wxMenuItem( ToolsMenu, wxID_ANY, wxString( _("IDM_MANAGE_TOKEN_KEYFILES") ) , wxEmptyString, wxITEM_NORMAL ); ToolsMenu->Append( ManageSecurityTokenKeyfilesMenuItem ); + wxMenuItem* RevealRedkeyMenuItem; + RevealRedkeyMenuItem = new wxMenuItem( ToolsMenu, wxID_ANY, wxString( _("IDM_REVEAL_REDKEY") ), wxEmptyString, wxITEM_NORMAL ); + ToolsMenu->Append( RevealRedkeyMenuItem ); + wxMenuItem* CloseAllSecurityTokenSessionsMenuItem; CloseAllSecurityTokenSessionsMenuItem = new wxMenuItem( ToolsMenu, wxID_ANY, wxString( _("IDM_CLOSE_ALL_TOKEN_SESSIONS") ) , wxEmptyString, wxITEM_NORMAL ); ToolsMenu->Append( CloseAllSecurityTokenSessionsMenuItem ); @@ -435,6 +439,7 @@ MainFrameBase::MainFrameBase( wxWindow* parent, wxWindowID id, const wxString& t ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnBackupVolumeHeadersMenuItemSelected ), this, BackupVolumeHeadersMenuItem->GetId()); ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnRestoreVolumeHeaderMenuItemSelected ), this, RestoreVolumeHeaderMenuItem->GetId()); ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnCreateKeyfileMenuItemSelected ), this, CreateKeyfileMenuItem->GetId()); + ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnRevealRedkeyMenuItemSelected ), this, RevealRedkeyMenuItem->GetId()); ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnManageSecurityTokenKeyfilesMenuItemSelected ), this, ManageSecurityTokenKeyfilesMenuItem->GetId()); ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnCloseAllSecurityTokenSessionsMenuItemSelected ), this, CloseAllSecurityTokenSessionsMenuItem->GetId()); ToolsMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrameBase::OnWipeCacheButtonClick ), this, WipeCachedPasswordsMenuItem->GetId()); @@ -1419,7 +1424,7 @@ KeyfileGeneratorDialogBase::KeyfileGeneratorDialogBase( wxWindow* parent, wxWind bSizer162 = new wxBoxSizer( wxVERTICAL ); wxFlexGridSizer* fgSizer8; - fgSizer8 = new wxFlexGridSizer( 3, 3, 0, 0 ); + fgSizer8 = new wxFlexGridSizer( 4, 3, 0, 0 ); fgSizer8->AddGrowableCol( 2 ); fgSizer8->SetFlexibleDirection( wxBOTH ); fgSizer8->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); @@ -1451,6 +1456,21 @@ KeyfileGeneratorDialogBase::KeyfileGeneratorDialogBase( wxWindow* parent, wxWind KeyfilesBaseName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); fgSizer8->Add( KeyfilesBaseName, 0, wxALL, 5 ); + m_panel20 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + fgSizer8->Add( m_panel20, 1, wxEXPAND | wxALL, 5 ); + + m_staticText66 = new wxStaticText( this, wxID_ANY, _("IDC_SECURITY_TOKEN_KEY"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText66->Wrap( -1 ); + + fgSizer8->Add( m_staticText66, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + SecurityTokenKeyDesc = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + ChooseSecurityTokenButton = new wxButton( this, wxID_ANY, _("IDC_SECURITY_TOKEN_KEY"), wxDefaultPosition, wxDefaultSize, 0 ); + fgSizer8->Add(SecurityTokenKeyDesc, 0, wxALL, 5 ); + fgSizer8->Add(ChooseSecurityTokenButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + + m_panel19 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); fgSizer8->Add( m_panel19, 1, wxEXPAND | wxALL, 5 ); @@ -1490,6 +1510,7 @@ KeyfileGeneratorDialogBase::KeyfileGeneratorDialogBase( wxWindow* parent, wxWind ShowRandomPoolCheckBox->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnShowRandomPoolCheckBoxClicked ), NULL, this ); RandomSizeCheckBox->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnRandomSizeCheckBoxClicked ), NULL, this ); GenerateButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnGenerateButtonClick ), NULL, this ); + ChooseSecurityTokenButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnSelectSecurityTokenKeyClick ), NULL, this); } KeyfileGeneratorDialogBase::~KeyfileGeneratorDialogBase() @@ -1500,7 +1521,7 @@ KeyfileGeneratorDialogBase::~KeyfileGeneratorDialogBase() ShowRandomPoolCheckBox->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnShowRandomPoolCheckBoxClicked ), NULL, this ); RandomSizeCheckBox->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnRandomSizeCheckBoxClicked ), NULL, this ); GenerateButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnGenerateButtonClick ), NULL, this ); - + ChooseSecurityTokenButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( KeyfileGeneratorDialogBase::OnSelectSecurityTokenKeyClick ), NULL, this); } LegalNoticesDialogBase::LegalNoticesDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2590,6 +2611,65 @@ SecurityTokenKeyfilesDialogBase::~SecurityTokenKeyfilesDialogBase() } +SecurityTokenKeysDialogBase::SecurityTokenKeysDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize ); + this->SetExtraStyle( GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY ); + + // whole dialog sizer + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer( wxVERTICAL ); + + // list control sizer for list control and buttons sizer (remove) + wxBoxSizer* bSizer138; + bSizer138 = new wxBoxSizer( wxHORIZONTAL ); + + // sizer for list control only + wxBoxSizer* bSizer142; + bSizer142 = new wxBoxSizer( wxVERTICAL ); + + SecurityTokenKeyListCtrl = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_VRULES|wxSUNKEN_BORDER ); + bSizer142->Add( SecurityTokenKeyListCtrl, 1, wxALL|wxEXPAND, 5 ); + + + bSizer138->Add( bSizer142, 1, wxEXPAND, 5 ); + + // ok cancel buttons + wxBoxSizer* bSizer139; + bSizer139 = new wxBoxSizer( wxVERTICAL ); + + OKButton = new wxButton( this, wxID_OK, _("IDOK"), wxDefaultPosition, wxDefaultSize, 0 ); + OKButton->SetDefault(); + bSizer139->Add( OKButton, 0, wxALL, 5 ); + + CancelButton = new wxButton( this, wxID_CANCEL, _("IDCANCEL"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer139->Add( CancelButton, 0, wxALL, 5 ); + + + bSizer138->Add( bSizer139, 0, wxEXPAND, 5 ); + + + bSizer3->Add( bSizer138, 1, wxEXPAND|wxALL, 5 ); + + this->SetSizer( bSizer3 ); + this->Layout(); + bSizer3->Fit( this ); + + // Connect Events + SecurityTokenKeyListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( SecurityTokenKeysDialogBase::OnListItemActivated ), NULL, this ); + SecurityTokenKeyListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( SecurityTokenKeysDialogBase::OnListItemDeselected ), NULL, this ); + SecurityTokenKeyListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( SecurityTokenKeysDialogBase::OnListItemSelected ), NULL, this ); + OKButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SecurityTokenKeysDialogBase::OnOKButtonClick ), NULL, this ); +} + +SecurityTokenKeysDialogBase::~SecurityTokenKeysDialogBase() +{ + SecurityTokenKeyListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( SecurityTokenKeysDialogBase::OnListItemActivated ), NULL, this ); + SecurityTokenKeyListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler( SecurityTokenKeysDialogBase::OnListItemDeselected ), NULL, this ); + SecurityTokenKeyListCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( SecurityTokenKeysDialogBase::OnListItemSelected ), NULL, this ); + OKButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SecurityTokenKeysDialogBase::OnOKButtonClick ), NULL, this ); +} + VolumePropertiesDialogBase::VolumePropertiesDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); @@ -3407,6 +3487,11 @@ VolumePasswordPanelBase::VolumePasswordPanelBase( wxWindow* parent, wxWindowID i KeyfilesButton = new wxButton( this, wxID_ANY, _("IDC_KEYFILES_HIDVOL_PROT"), wxDefaultPosition, wxDefaultSize, 0 ); GridBagSizer->Add( KeyfilesButton, wxGBPosition( 7, 2 ), wxGBSpan( 1, 1 ), wxALIGN_RIGHT|wxALIGN_BOTTOM|wxLEFT, 5 ); + SecurityTokenKeySpecText = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + SecurityTokenKeySpecButton = new wxButton(this, wxID_ANY, _("IDC_SECURITY_TOKEN_KEY"), wxDefaultPosition, wxDefaultSize, 0); + GridBagSizer->Add (SecurityTokenKeySpecText, wxGBPosition(8, 1), wxGBSpan( 1, 1), wxTOP | wxRIGHT | wxLEFT, 5); + GridBagSizer->Add (SecurityTokenKeySpecButton, wxGBPosition (8, 2), wxGBSpan( 1, 1), wxALIGN_RIGHT|wxALIGN_BOTTOM|wxLEFT, 5); + Pkcs5PrfSizer = new wxBoxSizer( wxVERTICAL ); @@ -3457,6 +3542,7 @@ VolumePasswordPanelBase::VolumePasswordPanelBase( wxWindow* parent, wxWindowID i KeyfilesButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( VolumePasswordPanelBase::OnKeyfilesButtonClick ), NULL, this ); KeyfilesButton->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( VolumePasswordPanelBase::OnKeyfilesButtonRightDown ), NULL, this ); KeyfilesButton->Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( VolumePasswordPanelBase::OnKeyfilesButtonRightClick ), NULL, this ); + SecurityTokenKeySpecButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxMouseEventHandler( VolumePasswordPanelBase::OnSecurityTokenKeySpecButtonClick ), NULL, this ); } VolumePasswordPanelBase::~VolumePasswordPanelBase() @@ -3471,7 +3557,7 @@ VolumePasswordPanelBase::~VolumePasswordPanelBase() KeyfilesButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( VolumePasswordPanelBase::OnKeyfilesButtonClick ), NULL, this ); KeyfilesButton->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( VolumePasswordPanelBase::OnKeyfilesButtonRightDown ), NULL, this ); KeyfilesButton->Disconnect( wxEVT_RIGHT_UP, wxMouseEventHandler( VolumePasswordPanelBase::OnKeyfilesButtonRightClick ), NULL, this ); - + SecurityTokenKeySpecButton->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxMouseEventHandler( VolumePasswordPanelBase::OnSecurityTokenKeySpecButtonClick ), NULL, this ); } VolumePasswordWizardPageBase::VolumePasswordWizardPageBase( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : WizardPage( parent, id, pos, size, style, name ) diff --git a/src/Main/Forms/Forms.h b/src/Main/Forms/Forms.h index 70a8c230b6..6ec3df3caf 100644 --- a/src/Main/Forms/Forms.h +++ b/src/Main/Forms/Forms.h @@ -116,6 +116,7 @@ namespace VeraCrypt virtual void OnRestoreVolumeHeaderMenuItemSelected( wxCommandEvent& event ) { event.Skip(); } virtual void OnCreateKeyfileMenuItemSelected( wxCommandEvent& event ) { event.Skip(); } virtual void OnManageSecurityTokenKeyfilesMenuItemSelected( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRevealRedkeyMenuItemSelected( wxCommandEvent& event ) { event.Skip(); } virtual void OnCloseAllSecurityTokenSessionsMenuItemSelected( wxCommandEvent& event ) { event.Skip(); } virtual void OnWipeCacheButtonClick( wxCommandEvent& event ) { event.Skip(); } virtual void OnLanguageMenuItemSelected( wxCommandEvent& event ) { event.Skip(); } @@ -436,6 +437,10 @@ namespace VeraCrypt wxCheckBox* RandomSizeCheckBox; wxStaticText* m_staticText65; wxTextCtrl* KeyfilesBaseName; + wxTextCtrl* SecurityTokenKeyDesc; + wxStaticText* m_staticText66; + wxPanel* m_panel20; + wxButton *ChooseSecurityTokenButton; wxPanel* m_panel19; wxButton* GenerateButton; @@ -445,8 +450,9 @@ namespace VeraCrypt virtual void OnShowRandomPoolCheckBoxClicked( wxCommandEvent& event ) { event.Skip(); } virtual void OnRandomSizeCheckBoxClicked( wxCommandEvent& event ) { event.Skip(); } virtual void OnGenerateButtonClick( wxCommandEvent& event ) { event.Skip(); } - - + virtual void OnSelectSecurityTokenKeyClick( wxCommandEvent& event) { event.Skip(); } + + public: KeyfileGeneratorDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); @@ -720,6 +726,25 @@ namespace VeraCrypt }; + class SecurityTokenKeysDialogBase : public wxDialog + { + private: + + protected: + wxListCtrl* SecurityTokenKeyListCtrl; + wxButton* OKButton; + wxButton* CancelButton; + + virtual void OnListItemActivated( wxListEvent& event ) { event.Skip(); } + virtual void OnListItemDeselected( wxListEvent& event ) { event.Skip(); } + virtual void OnListItemSelected( wxListEvent& event ) { event.Skip(); } + virtual void OnOKButtonClick( wxCommandEvent& event ) { event.Skip(); } + + public: + SecurityTokenKeysDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Security Token Keys"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~SecurityTokenKeysDialogBase(); + }; + /////////////////////////////////////////////////////////////////////////////// /// Class VolumePropertiesDialogBase /////////////////////////////////////////////////////////////////////////////// @@ -1015,6 +1040,8 @@ namespace VeraCrypt wxCheckBox* DisplayPasswordCheckBox; wxCheckBox* UseKeyfilesCheckBox; wxButton* KeyfilesButton; + wxTextCtrl* SecurityTokenKeySpecText; + wxButton* SecurityTokenKeySpecButton; wxBoxSizer* Pkcs5PrfSizer; wxStaticText* Pkcs5PrfStaticText; wxChoice* Pkcs5PrfChoice; @@ -1031,6 +1058,7 @@ namespace VeraCrypt virtual void OnKeyfilesButtonClick( wxCommandEvent& event ) { event.Skip(); } virtual void OnKeyfilesButtonRightDown( wxMouseEvent& event ) { event.Skip(); } virtual void OnKeyfilesButtonRightClick( wxMouseEvent& event ) { event.Skip(); } + virtual void OnSecurityTokenKeySpecButtonClick( wxMouseEvent& event ) { event.Skip(); } public: diff --git a/src/Main/Forms/KeyfileGeneratorDialog.cpp b/src/Main/Forms/KeyfileGeneratorDialog.cpp index 85443f4501..a62fbd9f80 100644 --- a/src/Main/Forms/KeyfileGeneratorDialog.cpp +++ b/src/Main/Forms/KeyfileGeneratorDialog.cpp @@ -14,6 +14,7 @@ #include "Main/GraphicUserInterface.h" #include "Volume/Hash.h" #include "KeyfileGeneratorDialog.h" +#include "SecurityTokenKeysDialog.h" namespace VeraCrypt { @@ -60,6 +61,7 @@ namespace VeraCrypt int keyfilesSize = KeyfilesSize->GetValue(); bool useRandomSize = RandomSizeCheckBox->IsChecked(); wxString keyfileBaseName = KeyfilesBaseName->GetValue(); + wxString securityTokenKeySpec = SecurityTokenKeyDesc->GetValue(); keyfileBaseName.Trim(true); keyfileBaseName.Trim(false); @@ -139,13 +141,16 @@ namespace VeraCrypt return; } - { - FilePath keyfilePath((const wchar_t*) keyfileName.GetFullPath().c_str()); + FilePath keyfilePath((const wchar_t*) keyfileName.GetFullPath().c_str()); + + if (!securityTokenKeySpec.IsEmpty()) { + Keyfile::CreateBluekey(keyfilePath, securityTokenKeySpec.wc_str(), keyfileBuffer); + } else { File keyfile; keyfile.Open (keyfilePath, File::CreateWrite); keyfile.Write (keyfileBuffer); + keyfile.Close(); } - } Gui->ShowInfo ("KEYFILE_CREATED"); } @@ -229,4 +234,28 @@ namespace VeraCrypt textCtrl->SetLabel (str.c_str()); } + + void KeyfileGeneratorDialog::OnSelectSecurityTokenKeyClick( wxCommandEvent& event) { + try + { + SecurityTokenKeysDialog dialog (this, SecurityTokenKeyOperation::ENCRYPT); + if (dialog.ShowModal() == wxID_OK) + { + auto keySpec = dialog.GetSelectedSecurityTokenKeySpec(); + SecurityTokenKeyDesc->SetValue(wxString(keySpec)); + if (!keySpec.empty()) { + SecurityTokenKey key; + SecurityToken::GetSecurityTokenKey(keySpec, key, SecurityTokenKeyOperation::ENCRYPT); + KeyfilesSize->SetRange(key.maxEncryptBufferSize, 1048576); + if (KeyfilesSize->GetValue() < key.maxEncryptBufferSize) { + KeyfilesSize->SetValue(key.maxEncryptBufferSize); + } + } + } + } + catch (exception &e) + { + Gui->ShowError (e); + } + } } diff --git a/src/Main/Forms/KeyfileGeneratorDialog.h b/src/Main/Forms/KeyfileGeneratorDialog.h index 7b8b2b297a..c0f58abf27 100644 --- a/src/Main/Forms/KeyfileGeneratorDialog.h +++ b/src/Main/Forms/KeyfileGeneratorDialog.h @@ -32,6 +32,7 @@ namespace VeraCrypt void OnRandomSizeCheckBoxClicked( wxCommandEvent& event ); void ShowBytes (wxStaticText *textCtrl, const ConstBufferPtr &buffer, bool appendDots = true); void HideBytes (wxStaticText *textCtrl, size_t len); + void OnSelectSecurityTokenKeyClick( wxCommandEvent& event); HashList Hashes; int MouseEventsCounter; diff --git a/src/Main/Forms/MainFrame.cpp b/src/Main/Forms/MainFrame.cpp index 77f371d837..26ab4e6a27 100644 --- a/src/Main/Forms/MainFrame.cpp +++ b/src/Main/Forms/MainFrame.cpp @@ -1218,6 +1218,18 @@ namespace VeraCrypt } } + void MainFrame::OnRevealRedkeyMenuItemSelected (wxCommandEvent& event) + { + try + { + Gui->RevealRedkey (GetSelectedVolumePath()); + } + catch (exception &e) + { + Gui->ShowError (e); + } + } + void MainFrame::OnMountAllDevicesButtonClick (wxCommandEvent& event) { MountAllDevices(); diff --git a/src/Main/Forms/MainFrame.h b/src/Main/Forms/MainFrame.h index ed1c44f706..0ac906b98b 100644 --- a/src/Main/Forms/MainFrame.h +++ b/src/Main/Forms/MainFrame.h @@ -97,6 +97,7 @@ namespace VeraCrypt void OnAddAllMountedToFavoritesMenuItemSelected (wxCommandEvent& event); void OnAddToFavoritesMenuItemSelected (wxCommandEvent& event); void OnBackupVolumeHeadersMenuItemSelected (wxCommandEvent& event); + void OnRevealRedkeyMenuItemSelected (wxCommandEvent& event); void OnBeginnersTutorialMenuItemSelected (wxCommandEvent& event) { Gui->OpenHomepageLink (this, L"tutorial"); } void OnBenchmarkMenuItemSelected (wxCommandEvent& event); void OnChangeKeyfilesMenuItemSelected (wxCommandEvent& event) { ChangePassword (ChangePasswordDialog::Mode::ChangeKeyfiles); } diff --git a/src/Main/Forms/MountOptionsDialog.cpp b/src/Main/Forms/MountOptionsDialog.cpp index 85a06d1ed7..7a8f9ab1bc 100644 --- a/src/Main/Forms/MountOptionsDialog.cpp +++ b/src/Main/Forms/MountOptionsDialog.cpp @@ -50,7 +50,7 @@ namespace VeraCrypt GraphicUserInterface::InstallPasswordEntryCustomKeyboardShortcuts (this); #endif - PasswordPanel = new VolumePasswordPanel (this, &options, options.Password, options.Keyfiles, !disableMountOptions, true, true, false, true, true); + PasswordPanel = new VolumePasswordPanel (this, &options, options.Password, options.Keyfiles, options.SecurityTokenKeySpec, SecurityTokenKeyOperation::DECRYPT, !disableMountOptions, true, true, false, true, true); PasswordPanel->SetCacheCheckBoxValidator (wxGenericValidator (&Options.CachePassword)); PasswordSizer->Add (PasswordPanel, 1, wxALL | wxEXPAND); @@ -82,7 +82,7 @@ namespace VeraCrypt OptionsButton->SetLabel (OptionsButtonLabel + L" >"); OptionsPanel->Show (false); - ProtectionPasswordPanel = new VolumePasswordPanel (ProtectionSizer->GetStaticBox(), &options, options.ProtectionPassword, options.ProtectionKeyfiles, false, true, true, false, true, true, LangString["IDT_HIDDEN_PROT_PASSWD"]); + ProtectionPasswordPanel = new VolumePasswordPanel (ProtectionSizer->GetStaticBox(), &options, options.ProtectionPassword, options.ProtectionKeyfiles, options.ProtectionSecurityTokenKeySpec, SecurityTokenKeyOperation::DECRYPT, false, true, true, false, true, true, LangString["IDT_HIDDEN_PROT_PASSWD"]); ProtectionPasswordPanel->TopOwnerParent = this; ProtectionPasswordSizer->Add (ProtectionPasswordPanel, 1, wxALL | wxEXPAND); @@ -143,6 +143,7 @@ namespace VeraCrypt Options.Pim = Pim; Options.Kdf = PasswordPanel->GetPkcs5Kdf(); Options.Keyfiles = PasswordPanel->GetKeyfiles(); + Options.SecurityTokenKeySpec = PasswordPanel->GetSecurityTokenKeySpec(); if (ReadOnlyCheckBox->IsChecked()) { @@ -163,6 +164,7 @@ namespace VeraCrypt Options.ProtectionPim = ProtectionPim; Options.ProtectionKdf = ProtectionPasswordPanel->GetPkcs5Kdf(); Options.ProtectionKeyfiles = ProtectionPasswordPanel->GetKeyfiles(); + Options.ProtectionSecurityTokenKeySpec = ProtectionPasswordPanel->GetSecurityTokenKeySpec(); } else { diff --git a/src/Main/Forms/SecurityTokenKeysDialog.cpp b/src/Main/Forms/SecurityTokenKeysDialog.cpp new file mode 100644 index 0000000000..36fe66442c --- /dev/null +++ b/src/Main/Forms/SecurityTokenKeysDialog.cpp @@ -0,0 +1,105 @@ +/* + Derived from source code of TrueCrypt 7.1a, which is + Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed + by the TrueCrypt License 3.0. + + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2015 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. +*/ + +#include "System.h" +#include "Main/GraphicUserInterface.h" +#include "Common/SecurityToken.h" +#include "NewSecurityTokenKeyfileDialog.h" +#include "SecurityTokenKeysDialog.h" +#include + +namespace VeraCrypt +{ + SecurityTokenKeysDialog::SecurityTokenKeysDialog (wxWindow* parent, SecurityTokenKeyOperation mode, bool selectionMode) + : SecurityTokenKeysDialogBase (parent) + { + if (selectionMode) + SetTitle (_("SELECT_TOKEN_KEYS")); + + list colPermilles; + + SecurityTokenKeyListCtrl->InsertColumn (ColumnSecurityTokenSlotId, _("TOKEN_SLOT_ID"), wxLIST_FORMAT_CENTER, 1); + colPermilles.push_back (102); + SecurityTokenKeyListCtrl->InsertColumn (ColumnSecurityTokenLabel, _("TOKEN_NAME"), wxLIST_FORMAT_LEFT, 1); + colPermilles.push_back (368); + SecurityTokenKeyListCtrl->InsertColumn (ColumnSecurityTokenKeyLabel, _("TOKEN_KEY_LABEL"), wxLIST_FORMAT_LEFT, 1); + colPermilles.push_back (529); + + KeyType keyType = KeyType::PUBLIC; + if (mode == SecurityTokenKeyOperation::DECRYPT) { + keyType = KeyType::PRIVATE; + } + FillSecurityTokenKeyListCtrl(keyType); + + Gui->SetListCtrlWidth (SecurityTokenKeyListCtrl, 65); + Gui->SetListCtrlHeight (SecurityTokenKeyListCtrl, 16); + Gui->SetListCtrlColumnWidths (SecurityTokenKeyListCtrl, colPermilles); + + Fit(); + Layout(); + Center(); + + OKButton->SetDefault(); + } + + void SecurityTokenKeysDialog::FillSecurityTokenKeyListCtrl (KeyType keyType) + { + wxBusyCursor busy; + + SecurityTokenKeyListCtrl->DeleteAllItems(); + switch (keyType) { + case KeyType::PRIVATE: + SecurityTokenKeyList = SecurityToken::GetAvailablePrivateKeys(); + break; + case KeyType::PUBLIC: + SecurityTokenKeyList = SecurityToken::GetAvailablePublicKeys(); + break; + default: + throw_err("Unknown key type"); + } + + size_t i = 0; + foreach (const SecurityTokenKey &key, SecurityTokenKeyList) + { + vector fields (SecurityTokenKeyListCtrl->GetColumnCount()); + + fields[ColumnSecurityTokenSlotId] = StringConverter::ToWide ((uint64) key.SlotId); + fields[ColumnSecurityTokenLabel] = key.Token.Label; + fields[ColumnSecurityTokenKeyLabel] = key.Id; + + Gui->AppendToListCtrl (SecurityTokenKeyListCtrl, fields, 0, &SecurityTokenKeyList[i++]); + } + + } + + + void SecurityTokenKeysDialog::OnListItemDeselected (wxListEvent& event) + { + } + + void SecurityTokenKeysDialog::OnListItemSelected (wxListEvent& event) + { + } + + void SecurityTokenKeysDialog::OnOKButtonClick () + { + foreach (long item, Gui->GetListCtrlSelectedItems (SecurityTokenKeyListCtrl)) + { + SecurityTokenKey *key = reinterpret_cast (SecurityTokenKeyListCtrl->GetItemData (item)); + wstringstream ss; + ss << key->SlotId << ":" << key->Id; + SelectedSecurityTokenKeySpec = ss.str(); + } + + EndModal (wxID_OK); + } +} diff --git a/src/Main/Forms/SecurityTokenKeysDialog.h b/src/Main/Forms/SecurityTokenKeysDialog.h new file mode 100644 index 0000000000..90f4191d4b --- /dev/null +++ b/src/Main/Forms/SecurityTokenKeysDialog.h @@ -0,0 +1,54 @@ +/* + Derived from source code of TrueCrypt 7.1a, which is + Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed + by the TrueCrypt License 3.0. + + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2015 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. +*/ + +#ifndef TC_HEADER_Main_Forms_SecurityTokenKeysDialog +#define TC_HEADER_Main_Forms_SecurityTokenKeysDialog + +#include "Forms.h" +#include "Common/SecurityToken.h" +#include "Main/Main.h" + +namespace VeraCrypt +{ + + enum KeyType { + PRIVATE, + PUBLIC + }; + + class SecurityTokenKeysDialog : public SecurityTokenKeysDialogBase + { + public: + SecurityTokenKeysDialog (wxWindow* parent, SecurityTokenKeyOperation mode, bool selectionMode = true); + wstring GetSelectedSecurityTokenKeySpec() const { return SelectedSecurityTokenKeySpec; } + + protected: + enum + { + ColumnSecurityTokenSlotId = 0, + ColumnSecurityTokenLabel, + ColumnSecurityTokenKeyLabel, + }; + + void FillSecurityTokenKeyListCtrl (KeyType keyType); + void OnListItemActivated (wxListEvent& event) { OnOKButtonClick(); } + void OnListItemDeselected (wxListEvent& event); + void OnListItemSelected (wxListEvent& event); + void OnOKButtonClick (); + void OnOKButtonClick (wxCommandEvent& event) { OnOKButtonClick(); } + + vector SecurityTokenKeyList; + wstring SelectedSecurityTokenKeySpec; + }; +} + +#endif // TC_HEADER_Main_Forms_SecurityTokenKeysDialog diff --git a/src/Main/Forms/VolumeCreationWizard.cpp b/src/Main/Forms/VolumeCreationWizard.cpp index 311738ca67..b27015df4e 100644 --- a/src/Main/Forms/VolumeCreationWizard.cpp +++ b/src/Main/Forms/VolumeCreationWizard.cpp @@ -223,7 +223,7 @@ namespace VeraCrypt case Step::VolumePassword: { - VolumePasswordWizardPage *page = new VolumePasswordWizardPage (GetPageParent(), Password, Keyfiles); + VolumePasswordWizardPage *page = new VolumePasswordWizardPage (GetPageParent(), Password, Keyfiles, SecurityTokenKeySpec); page->EnableUsePim (); // force displaying "Use PIM" page->SetPimSelected (Pim > 0); @@ -771,6 +771,7 @@ namespace VeraCrypt Kdf = page->GetPkcs5Kdf(); Keyfiles = page->GetKeyfiles(); + SecurityTokenKeySpec = page->GetSecurityTokenKeySpec(); if (forward && Password && !Password->IsEmpty()) { @@ -795,7 +796,7 @@ namespace VeraCrypt shared_ptr hiddenPassword; try { - hiddenPassword = Keyfile::ApplyListToPassword (Keyfiles, Password, Gui->GetPreferences().EMVSupportEnabled); + hiddenPassword = Keyfile::ApplyListToPassword (Keyfiles, Password, SecurityTokenKeySpec, Gui->GetPreferences().EMVSupportEnabled); } catch (...) { @@ -846,7 +847,7 @@ namespace VeraCrypt shared_ptr hiddenPassword; try { - hiddenPassword = Keyfile::ApplyListToPassword (Keyfiles, Password, Gui->GetPreferences().EMVSupportEnabled); + hiddenPassword = Keyfile::ApplyListToPassword (Keyfiles, Password, SecurityTokenKeySpec, Gui->GetPreferences().EMVSupportEnabled); } catch (...) { @@ -1027,6 +1028,7 @@ namespace VeraCrypt options->Password = Password; options->Pim = Pim; options->Keyfiles = Keyfiles; + options->SecurityTokenKeySpec = SecurityTokenKeySpec; options->Path = SelectedVolumePath; options->Quick = QuickFormatEnabled; options->Size = VolumeSize; @@ -1127,7 +1129,7 @@ namespace VeraCrypt }); #endif - shared_ptr outerVolume = Core->OpenVolume (make_shared (SelectedVolumePath), true, Password, Pim, Kdf, Keyfiles, VolumeProtection::ReadOnly); + shared_ptr outerVolume = Core->OpenVolume (make_shared (SelectedVolumePath), true, Password, Pim, Kdf, Keyfiles, SecurityTokenKeySpec, VolumeProtection::ReadOnly); try { MaxHiddenVolumeSize = Core->GetMaxHiddenVolumeSize (outerVolume); @@ -1162,7 +1164,7 @@ namespace VeraCrypt // remember Outer password and keyfiles in order to be able to compare it with those of Hidden volume try { - OuterPassword = Keyfile::ApplyListToPassword (Keyfiles, Password, Gui->GetPreferences().EMVSupportEnabled); + OuterPassword = Keyfile::ApplyListToPassword (Keyfiles, Password, SecurityTokenKeySpec, Gui->GetPreferences().EMVSupportEnabled); } catch (...) { diff --git a/src/Main/Forms/VolumeCreationWizard.h b/src/Main/Forms/VolumeCreationWizard.h index fd4b3e06b3..ac5fd8cca9 100644 --- a/src/Main/Forms/VolumeCreationWizard.h +++ b/src/Main/Forms/VolumeCreationWizard.h @@ -70,6 +70,7 @@ namespace VeraCrypt unique_ptr ProgressTimer; unique_ptr RandomPoolUpdateTimer; shared_ptr Keyfiles; + wstring SecurityTokenKeySpec; bool LargeFilesSupport; uint64 MaxHiddenVolumeSize; shared_ptr MountedOuterVolume; diff --git a/src/Main/Forms/VolumePasswordPanel.cpp b/src/Main/Forms/VolumePasswordPanel.cpp index 0555f33908..a376bcd456 100644 --- a/src/Main/Forms/VolumePasswordPanel.cpp +++ b/src/Main/Forms/VolumePasswordPanel.cpp @@ -15,22 +15,28 @@ #include "KeyfilesDialog.h" #include "VolumePasswordPanel.h" #include "SecurityTokenKeyfilesDialog.h" +#include "SecurityTokenKeysDialog.h" namespace VeraCrypt { - VolumePasswordPanel::VolumePasswordPanel (wxWindow* parent, MountOptions* options, shared_ptr password, shared_ptr keyfiles, bool enableCache, bool enablePassword, bool enableKeyfiles, bool enableConfirmation, bool enablePkcs5Prf, bool isMountPassword, const wxString &passwordLabel) - : VolumePasswordPanelBase (parent), TopOwnerParent(NULL), Keyfiles (new KeyfileList), EnablePimEntry (true) + VolumePasswordPanel::VolumePasswordPanel (wxWindow* parent, MountOptions* options, shared_ptr password, shared_ptr keyfiles, wstring securityTokenKeySpec, SecurityTokenKeyOperation mode, bool enableCache, bool enablePassword, bool enableKeyfiles, bool enableConfirmation, bool enablePkcs5Prf, bool isMountPassword, const wxString &passwordLabel) + : VolumePasswordPanelBase (parent), TopOwnerParent(NULL), Keyfiles (new KeyfileList), EnablePimEntry (true), Mode(mode) { size_t maxPasswordLength = CmdLine->ArgUseLegacyPassword? VolumePassword::MaxLegacySize : VolumePassword::MaxSize; if (keyfiles) { *Keyfiles = *keyfiles; UseKeyfilesCheckBox->SetValue (!Keyfiles->empty()); + SecurityTokenKeySpecButton->Enable(!keyfiles->empty()); + SecurityTokenKeySpecText->Enable(!keyfiles->empty()); } else { *Keyfiles = Gui->GetPreferences().DefaultKeyfiles; - UseKeyfilesCheckBox->SetValue (Gui->GetPreferences().UseKeyfiles && !Keyfiles->empty()); + auto show = Gui->GetPreferences().UseKeyfiles && !Keyfiles->empty(); + UseKeyfilesCheckBox->SetValue (show); + SecurityTokenKeySpecButton->Enable(show); + SecurityTokenKeySpecText->Enable(show); } PasswordTextCtrl->SetMaxLength (maxPasswordLength); @@ -75,6 +81,10 @@ namespace VeraCrypt UseKeyfilesCheckBox->Show (enableKeyfiles); KeyfilesButton->Show (enableKeyfiles); + SecurityTokenKeySpecText->Show (enableKeyfiles); + SecurityTokenKeySpecButton->Show (enableKeyfiles); + SecurityTokenKeySpecText->SetValue(securityTokenKeySpec); + Pkcs5PrfStaticText->Show (enablePkcs5Prf); Pkcs5PrfChoice->Show (enablePkcs5Prf); @@ -250,6 +260,12 @@ namespace VeraCrypt } } + wstring VolumePasswordPanel::GetSecurityTokenKeySpec () const + { + wxString spec = SecurityTokenKeySpecText->GetValue(); + return spec.ToStdWstring(); + } + int VolumePasswordPanel::GetVolumePim () const { if (VolumePimTextCtrl->IsEnabled () && VolumePimTextCtrl->IsShown ()) @@ -330,6 +346,26 @@ namespace VeraCrypt Keyfiles->push_back (make_shared (f)); UseKeyfilesCheckBox->SetValue (!Keyfiles->empty()); + SecurityTokenKeySpecText->Enable(!Keyfiles->empty()); + SecurityTokenKeySpecButton->Enable(!Keyfiles->empty()); + OnUpdate(); + } + } + catch (exception &e) + { + Gui->ShowError (e); + } + } + + void VolumePasswordPanel::OnSecurityTokenKeySpecButtonClick( wxMouseEvent& event ) + { + try + { + SecurityTokenKeysDialog dialog (this, Mode); + if (dialog.ShowModal() == wxID_OK) + { + wxString keySpec( dialog.GetSelectedSecurityTokenKeySpec() ); + SecurityTokenKeySpecText->SetValue(keySpec); OnUpdate(); } } @@ -386,6 +422,8 @@ namespace VeraCrypt Keyfiles = dialog.GetKeyfiles(); UseKeyfilesCheckBox->SetValue (!Keyfiles->empty()); + SecurityTokenKeySpecText->Enable(!Keyfiles->empty()); + SecurityTokenKeySpecButton->Enable(!Keyfiles->empty()); OnUpdate(); } } diff --git a/src/Main/Forms/VolumePasswordPanel.h b/src/Main/Forms/VolumePasswordPanel.h index 7019e8fdbf..4325722dc8 100644 --- a/src/Main/Forms/VolumePasswordPanel.h +++ b/src/Main/Forms/VolumePasswordPanel.h @@ -16,18 +16,20 @@ #include "Forms.h" #include "Platform/Functor.h" #include "Main/Main.h" +#include "Common/SecurityToken.h" namespace VeraCrypt { class VolumePasswordPanel : public VolumePasswordPanelBase { public: - VolumePasswordPanel (wxWindow* parent, MountOptions* options, shared_ptr password, shared_ptr keyfiles, bool enableCache = false, bool enablePassword = true, bool enableKeyfiles = true, bool enableConfirmation = false, bool enablePkcs5Prf = false, bool isMountPassword = false, const wxString &passwordLabel = wxString()); + VolumePasswordPanel (wxWindow* parent, MountOptions* options, shared_ptr password, shared_ptr keyfiles, wstring securityTokenKeySpec, SecurityTokenKeyOperation mode, bool enableCache = false, bool enablePassword = true, bool enableKeyfiles = true, bool enableConfirmation = false, bool enablePkcs5Prf = false, bool isMountPassword = false, const wxString &passwordLabel = wxString()); virtual ~VolumePasswordPanel (); void AddKeyfile (shared_ptr keyfile); shared_ptr GetKeyfiles () const { return UseKeyfilesCheckBox->IsChecked() ? Keyfiles : shared_ptr (); } shared_ptr GetPassword (bool bForceLegacyPassword = false) const; + wstring GetSecurityTokenKeySpec () const; shared_ptr GetPkcs5Kdf () const; int GetVolumePim () const; int GetHeaderWipeCount () const; @@ -61,10 +63,12 @@ namespace VeraCrypt void OnUpdate () { UpdateEvent.Raise(); } void OnUseKeyfilesCheckBoxClick (wxCommandEvent& event) { OnUpdate(); } void WipeTextCtrl (wxTextCtrl *textCtrl); + void OnSecurityTokenKeySpecButtonClick( wxMouseEvent& event ); shared_ptr Keyfiles; shared_ptr UpdateCallback; bool EnablePimEntry; + SecurityTokenKeyOperation Mode; }; } diff --git a/src/Main/Forms/VolumePasswordWizardPage.cpp b/src/Main/Forms/VolumePasswordWizardPage.cpp index 859a613af8..663e2a4424 100644 --- a/src/Main/Forms/VolumePasswordWizardPage.cpp +++ b/src/Main/Forms/VolumePasswordWizardPage.cpp @@ -16,10 +16,10 @@ namespace VeraCrypt { - VolumePasswordWizardPage::VolumePasswordWizardPage (wxPanel* parent, shared_ptr password, shared_ptr keyfiles, bool enableConfirmation) + VolumePasswordWizardPage::VolumePasswordWizardPage (wxPanel* parent, shared_ptr password, shared_ptr keyfiles, wstring securityTokenKeySpec, bool enableConfirmation) : VolumePasswordWizardPageBase (parent), ConfirmationMode (enableConfirmation) { - PasswordPanel = new VolumePasswordPanel (this, NULL, password, keyfiles, false, true, true, enableConfirmation, !enableConfirmation, !enableConfirmation); + PasswordPanel = new VolumePasswordPanel (this, NULL, password, keyfiles, securityTokenKeySpec, SecurityTokenKeyOperation::DECRYPT, false, true, true, enableConfirmation, !enableConfirmation, !enableConfirmation); PasswordPanel->UpdateEvent.Connect (EventConnector (this, &VolumePasswordWizardPage::OnPasswordPanelUpdate)); PasswordPanelSizer->Add (PasswordPanel, 1, wxALL | wxEXPAND); diff --git a/src/Main/Forms/VolumePasswordWizardPage.h b/src/Main/Forms/VolumePasswordWizardPage.h index 525db216de..96d9314b99 100644 --- a/src/Main/Forms/VolumePasswordWizardPage.h +++ b/src/Main/Forms/VolumePasswordWizardPage.h @@ -21,9 +21,11 @@ namespace VeraCrypt class VolumePasswordWizardPage : public VolumePasswordWizardPageBase { public: - VolumePasswordWizardPage (wxPanel* parent, shared_ptr password, shared_ptr keyfiles, bool enableConfirmation = true); + VolumePasswordWizardPage (wxPanel* parent, shared_ptr password, shared_ptr keyfiles, wstring securityTokenKeySpec, bool enableConfirmation = true); ~VolumePasswordWizardPage (); + wstring GetSecurityTokenKeySpec () const { return + PasswordPanel->GetSecurityTokenKeySpec(); } shared_ptr GetKeyfiles () const { return PasswordPanel->GetKeyfiles(); } shared_ptr GetPassword () const { return PasswordPanel->GetPassword(); } void EnableUsePim () { PasswordPanel->EnableUsePim (); } diff --git a/src/Main/GraphicUserInterface.cpp b/src/Main/GraphicUserInterface.cpp index 1cb62671c8..a86b1ff67a 100644 --- a/src/Main/GraphicUserInterface.cpp +++ b/src/Main/GraphicUserInterface.cpp @@ -25,6 +25,7 @@ #endif #include "Common/SecurityToken.h" +#include "Volume/Keyfile.h" #include "Application.h" #include "GraphicUserInterface.h" #include "FatalErrorHandler.h" @@ -34,6 +35,7 @@ #include "Forms/MountOptionsDialog.h" #include "Forms/RandomPoolEnrichmentDialog.h" #include "Forms/SecurityTokenKeyfilesDialog.h" +#include "Forms/SecurityTokenKeysDialog.h" namespace VeraCrypt { @@ -144,6 +146,45 @@ namespace VeraCrypt OnVolumesAutoDismounted(); } + void GraphicUserInterface::RevealRedkey (shared_ptr volumePath) const + { + wxWindow *parent = GetActiveWindow(); + + ShowInfo ("REVEAL_REDKEY_INFO"); + + // choose blue key file + FilePathList files = SelectFiles (parent, wxEmptyString, false, false); + if (files.empty()) + return; + + DirectoryPath blueKey = *files.front(); + + // choose security key + SecurityTokenKeysDialog dialog (parent, SecurityTokenKeyOperation::DECRYPT); + if (dialog.ShowModal() != wxID_OK) { + return; + } + + + wxString keySpec( dialog.GetSelectedSecurityTokenKeySpec() ); + + + // choose red key filepath + files = SelectFiles (parent, wxString(LangString["REVEAL_REDKEY_PATH"]), true, false); + if (files.empty()) + return; + + DirectoryPath redKeyPath = *files.front(); + + // apply security key to blue key file in decryption mode + Keyfile kf(blueKey); + + // save result to red key file + kf.RevealRedkey(redKeyPath, keySpec.ToStdWstring()); + + ShowWarning ("REVEAL_REDKEY_DONE"); + } + void GraphicUserInterface::BackupVolumeHeaders (shared_ptr volumePath) const { wxWindow *parent = GetActiveWindow(); @@ -219,12 +260,14 @@ namespace VeraCrypt options->Pim, options->Kdf, options->Keyfiles, + options->SecurityTokenKeySpec, options->EMVSupportEnabled, options->Protection, options->ProtectionPassword, options->ProtectionPim, options->ProtectionKdf, options->ProtectionKeyfiles, + options->ProtectionSecurityTokenKeySpec, true, volumeType, options->UseBackupHeaders @@ -247,12 +290,14 @@ namespace VeraCrypt options->Pim, options->Kdf, options->Keyfiles, + options->SecurityTokenKeySpec, options->EMVSupportEnabled, options->Protection, options->ProtectionPassword, options->ProtectionPim, options->ProtectionKdf, options->ProtectionKeyfiles, + options->ProtectionSecurityTokenKeySpec, true, volumeType, true @@ -349,7 +394,7 @@ namespace VeraCrypt // Re-encrypt volume header SecureBuffer newHeaderBuffer (normalVolume->GetLayout()->GetHeaderSize()); - ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, normalVolume->GetHeader(), normalVolumeMountOptions.Password, normalVolumeMountOptions.Pim, normalVolumeMountOptions.Keyfiles, normalVolumeMountOptions.EMVSupportEnabled); + ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, normalVolume->GetHeader(), normalVolumeMountOptions.Password, normalVolumeMountOptions.Pim, normalVolumeMountOptions.Keyfiles, normalVolumeMountOptions.SecurityTokenKeySpec, normalVolumeMountOptions.EMVSupportEnabled); ExecuteWaitThreadRoutine (parent, &routine); @@ -358,7 +403,7 @@ namespace VeraCrypt if (hiddenVolume) { // Re-encrypt hidden volume header - ReEncryptHeaderThreadRoutine hiddenRoutine(newHeaderBuffer, hiddenVolume->GetHeader(), hiddenVolumeMountOptions.Password, hiddenVolumeMountOptions.Pim, hiddenVolumeMountOptions.Keyfiles, hiddenVolumeMountOptions.EMVSupportEnabled); + ReEncryptHeaderThreadRoutine hiddenRoutine(newHeaderBuffer, hiddenVolume->GetHeader(), hiddenVolumeMountOptions.Password, hiddenVolumeMountOptions.Pim, hiddenVolumeMountOptions.Keyfiles, hiddenVolumeMountOptions.SecurityTokenKeySpec, hiddenVolumeMountOptions.EMVSupportEnabled); ExecuteWaitThreadRoutine (parent, &hiddenRoutine); } @@ -1478,12 +1523,14 @@ namespace VeraCrypt options.Pim, options.Kdf, options.Keyfiles, + options.SecurityTokenKeySpec, options.EMVSupportEnabled, options.Protection, options.ProtectionPassword, options.ProtectionPim, options.ProtectionKdf, options.ProtectionKeyfiles, + options.ProtectionSecurityTokenKeySpec, options.SharedAccessAllowed, VolumeType::Unknown, true @@ -1513,7 +1560,7 @@ namespace VeraCrypt // Re-encrypt volume header wxBusyCursor busy; SecureBuffer newHeaderBuffer (volume->GetLayout()->GetHeaderSize()); - ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, volume->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.EMVSupportEnabled); + ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, volume->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.SecurityTokenKeySpec, options.EMVSupportEnabled); ExecuteWaitThreadRoutine (parent, &routine); @@ -1594,7 +1641,7 @@ namespace VeraCrypt backupFile.ReadAt (headerBuffer, layout->GetType() == VolumeType::Hidden ? layout->GetHeaderSize() : 0); // Decrypt header - shared_ptr passwordKey = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled); + shared_ptr passwordKey = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.SecurityTokenKeySpec, options.EMVSupportEnabled); Pkcs5KdfList keyDerivationFunctions = layout->GetSupportedKeyDerivationFunctions(); EncryptionAlgorithmList encryptionAlgorithms = layout->GetSupportedEncryptionAlgorithms(); EncryptionModeList encryptionModes = layout->GetSupportedEncryptionModes(); @@ -1629,7 +1676,7 @@ namespace VeraCrypt // Re-encrypt volume header wxBusyCursor busy; SecureBuffer newHeaderBuffer (decryptedLayout->GetHeaderSize()); - ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.EMVSupportEnabled); + ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.SecurityTokenKeySpec, options.EMVSupportEnabled); ExecuteWaitThreadRoutine (parent, &routine); @@ -1645,7 +1692,7 @@ namespace VeraCrypt if (decryptedLayout->HasBackupHeader()) { // Re-encrypt backup volume header - ReEncryptHeaderThreadRoutine backupRoutine(newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.EMVSupportEnabled); + ReEncryptHeaderThreadRoutine backupRoutine(newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.SecurityTokenKeySpec, options.EMVSupportEnabled); ExecuteWaitThreadRoutine (parent, &backupRoutine); diff --git a/src/Main/GraphicUserInterface.h b/src/Main/GraphicUserInterface.h index d333551c58..4c6ae78eaa 100644 --- a/src/Main/GraphicUserInterface.h +++ b/src/Main/GraphicUserInterface.h @@ -32,9 +32,10 @@ namespace VeraCrypt virtual bool AskYesNo (const wxString &message, bool defaultYes = false, bool warning = false) const; virtual void AutoDismountVolumes (VolumeInfoList mountedVolumes, bool alwaysForce = true); virtual void BackupVolumeHeaders (shared_ptr volumePath) const; + virtual void RevealRedkey (shared_ptr volumePath) const; virtual void BeginBusyState () const { wxBeginBusyCursor(); } virtual void BeginInteractiveBusyState (wxWindow *window); - virtual void ChangePassword (shared_ptr volumePath = shared_ptr (), shared_ptr password = shared_ptr (), int pim = 0, shared_ptr currentHash = shared_ptr (), shared_ptr keyfiles = shared_ptr (), shared_ptr newPassword = shared_ptr (), int newPim = 0, shared_ptr newKeyfiles = shared_ptr (), shared_ptr newHash = shared_ptr ()) const { ThrowTextModeRequired(); } + virtual void ChangePassword (shared_ptr volumePath = shared_ptr (), shared_ptr password = shared_ptr (), int pim = 0, shared_ptr currentHash = shared_ptr (), shared_ptr keyfiles = shared_ptr (), wstring securityTokenKeySpec = wstring(), shared_ptr newPassword = shared_ptr (), int newPim = 0, shared_ptr newKeyfiles = shared_ptr (), shared_ptr newHash = shared_ptr ()) const { ThrowTextModeRequired(); } wxHyperlinkCtrl *CreateHyperlink (wxWindow *parent, const wxString &linkUrl, const wxString &linkText) const; virtual void CreateKeyfile (shared_ptr keyfilePath = shared_ptr ()) const; virtual void CreateVolume (shared_ptr options) const { ThrowTextModeRequired(); } diff --git a/src/Main/Main.make b/src/Main/Main.make index 178c466960..897490a7b0 100755 --- a/src/Main/Main.make +++ b/src/Main/Main.make @@ -47,6 +47,7 @@ OBJS += Forms/PreferencesDialog.o OBJS += Forms/ProgressWizardPage.o OBJS += Forms/RandomPoolEnrichmentDialog.o OBJS += Forms/SecurityTokenKeyfilesDialog.o +OBJS += Forms/SecurityTokenKeysDialog.o OBJS += Forms/SelectDirectoryWizardPage.o OBJS += Forms/VolumePasswordPanel.o OBJS += Forms/VolumePropertiesDialog.o @@ -257,7 +258,11 @@ install: prepare package: prepare ifdef VC_LEGACY_BUILD /usr/local/bin/packagesbuild $(BASE_DIR)/Setup/MacOSX/veracrypt_Legacy.pkgproj - productsign --sign "Developer ID Installer: IDRIX (Z933746L2S)" --timestamp "$(BASE_DIR)/Setup/MacOSX/VeraCrypt Legacy $(TC_VERSION).pkg" $(BASE_DIR)/Setup/MacOSX/VeraCrypt_$(TC_VERSION).pkg +ifdef $(VC_OSX_DEVELOPER_ID) + productsign --sign "Developer ID Installer: $(VC_OSX_DEVELOPER_ID)" --timestamp "$(BASE_DIR)/Setup/MacOSX/VeraCrypt Legacy $(TC_VERSION).pkg" $(BASE_DIR)/Setup/MacOSX/VeraCrypt_$(TC_VERSION).pkg +else + cp "$(BASE_DIR)/Setup/MacOSX/VeraCrypt Legacy $(TC_VERSION).pkg" $(BASE_DIR)/Setup/MacOSX/VeraCrypt_$(TC_VERSION).pkg +endif rm -f $(APPNAME)_Legacy_$(TC_VERSION).dmg else ifeq "$(VC_OSX_FUSET)" "1" diff --git a/src/Main/TextUserInterface.cpp b/src/Main/TextUserInterface.cpp index bc3f6f5ad8..0a783b3071 100644 --- a/src/Main/TextUserInterface.cpp +++ b/src/Main/TextUserInterface.cpp @@ -92,6 +92,11 @@ namespace VeraCrypt return AskString (!message.empty() ? message : wxString (_("Enter filename: "))); } + wstring TextUserInterface::AskSecurityTokenKeySpec(const wxString &message) const + { + return AskString (!message.empty() ? message : wxString (_("Enter security token key spec: "))); + } + shared_ptr TextUserInterface::AskKeyfiles (const wxString &message) const { wxString msg = _("Enter keyfile"); @@ -328,6 +333,7 @@ namespace VeraCrypt options->Password = AskPassword (LangString[volumeType == VolumeType::Hidden ? "ENTER_HIDDEN_VOL_PASSWORD" : "ENTER_NORMAL_VOL_PASSWORD"]); options->Pim = AskPim (volumeType == VolumeType::Hidden ?_("Enter PIM for the hidden volume") : _("Enter PIM for the normal/outer volume")); options->Keyfiles = AskKeyfiles(); + options->SecurityTokenKeySpec = AskSecurityTokenKeySpec(); try { @@ -338,12 +344,14 @@ namespace VeraCrypt options->Pim, kdf, options->Keyfiles, + options->SecurityTokenKeySpec, options->EMVSupportEnabled, options->Protection, options->ProtectionPassword, options->ProtectionPim, options->ProtectionKdf, options->ProtectionKeyfiles, + options->ProtectionSecurityTokenKeySpec, true, volumeType, options->UseBackupHeaders @@ -363,12 +371,14 @@ namespace VeraCrypt options->Pim, kdf, options->Keyfiles, + options->SecurityTokenKeySpec, options->EMVSupportEnabled, options->Protection, options->ProtectionPassword, options->ProtectionPim, options->ProtectionKdf, options->ProtectionKeyfiles, + options->ProtectionSecurityTokenKeySpec, true, volumeType, true @@ -441,14 +451,15 @@ namespace VeraCrypt // Re-encrypt volume header SecureBuffer newHeaderBuffer (normalVolume->GetLayout()->GetHeaderSize()); - Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, normalVolume->GetHeader(), normalVolumeMountOptions.Password, normalVolumeMountOptions.Pim, normalVolumeMountOptions.Keyfiles, normalVolumeMountOptions.EMVSupportEnabled); + Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, normalVolume->GetHeader(), normalVolumeMountOptions.Password, normalVolumeMountOptions.Pim, normalVolumeMountOptions.Keyfiles, normalVolumeMountOptions.SecurityTokenKeySpec, normalVolumeMountOptions.EMVSupportEnabled); backupFile.Write (newHeaderBuffer); if (hiddenVolume) { // Re-encrypt hidden volume header - Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, hiddenVolume->GetHeader(), hiddenVolumeMountOptions.Password, hiddenVolumeMountOptions.Pim, hiddenVolumeMountOptions.Keyfiles, hiddenVolumeMountOptions.EMVSupportEnabled); + Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, hiddenVolume->GetHeader(), hiddenVolumeMountOptions.Password, hiddenVolumeMountOptions.Pim, hiddenVolumeMountOptions.Keyfiles, + hiddenVolumeMountOptions.SecurityTokenKeySpec, hiddenVolumeMountOptions.EMVSupportEnabled); } else { @@ -468,10 +479,12 @@ namespace VeraCrypt ShowWarning ("ERR_XTS_MASTERKEY_VULNERABLE"); } - void TextUserInterface::ChangePassword (shared_ptr volumePath, shared_ptr password, int pim, shared_ptr currentHash, shared_ptr keyfiles, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, shared_ptr newHash) const + void TextUserInterface::ChangePassword (shared_ptr volumePath, shared_ptr password, int pim, shared_ptr currentHash, shared_ptr keyfiles, wstring securityTokenKeySpec, shared_ptr newPassword, int newPim, shared_ptr newKeyfiles, shared_ptr newHash) const { shared_ptr volume; + wstring newSecurityTokenKeySpec = wstring(); + // Volume path if (!volumePath.get()) { @@ -486,6 +499,7 @@ namespace VeraCrypt bool passwordInteractive = !password.get(); bool keyfilesInteractive = !keyfiles.get(); + bool securityTokenKeySpecInteractive = securityTokenKeySpec.empty(); shared_ptr kdf; if (currentHash) @@ -511,6 +525,14 @@ namespace VeraCrypt pim = AskPim (_("Enter current PIM")); } + if (!securityTokenKeySpecInteractive) { + + } + else if (!Preferences.NonInteractive) + { + securityTokenKeySpec = AskSecurityTokenKeySpec(); + } + // Current keyfiles try { @@ -520,7 +542,7 @@ namespace VeraCrypt try { keyfiles.reset (new KeyfileList); - volume = Core->OpenVolume (volumePath, Preferences.DefaultMountOptions.PreserveTimestamps, password, pim, kdf, keyfiles, true); + volume = Core->OpenVolume (volumePath, Preferences.DefaultMountOptions.PreserveTimestamps, password, pim, kdf, keyfiles, securityTokenKeySpec, true); } catch (PasswordException&) { @@ -530,7 +552,7 @@ namespace VeraCrypt } if (!volume.get()) - volume = Core->OpenVolume (volumePath, Preferences.DefaultMountOptions.PreserveTimestamps, password, pim, kdf, keyfiles, true); + volume = Core->OpenVolume (volumePath, Preferences.DefaultMountOptions.PreserveTimestamps, password, pim, kdf, keyfiles, securityTokenKeySpec, true); } catch (PasswordException &e) { @@ -571,7 +593,7 @@ namespace VeraCrypt RandomNumberGenerator::SetEnrichedByUserStatus (false); UserEnrichRandomPool(); - Core->ChangePassword (volume, newPassword, newPim, newKeyfiles, true, + Core->ChangePassword (volume, newPassword, newPim, newKeyfiles, newSecurityTokenKeySpec, true, newHash ? Pkcs5Kdf::GetAlgorithm (*newHash) : shared_ptr ()); ShowInfo ("PASSWORD_CHANGED"); @@ -1389,6 +1411,8 @@ namespace VeraCrypt options.ProtectionPim = AskPim (_("Enter PIM for hidden volume")); if (!options.ProtectionKeyfiles) options.ProtectionKeyfiles = AskKeyfiles (_("Enter keyfile for hidden volume")); + if (!options.ProtectionSecurityTokenKeySpec.empty()) + options.ProtectionSecurityTokenKeySpec = AskSecurityTokenKeySpec(_("Enter security token key spec")); } try @@ -1582,12 +1606,14 @@ namespace VeraCrypt options.Pim, kdf, options.Keyfiles, + options.SecurityTokenKeySpec, options.EMVSupportEnabled, options.Protection, options.ProtectionPassword, options.ProtectionPim, options.ProtectionKdf, options.ProtectionKeyfiles, + options.ProtectionSecurityTokenKeySpec, options.SharedAccessAllowed, VolumeType::Unknown, true @@ -1612,7 +1638,7 @@ namespace VeraCrypt // Re-encrypt volume header SecureBuffer newHeaderBuffer (volume->GetLayout()->GetHeaderSize()); - Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, volume->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.EMVSupportEnabled); + Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, volume->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.SecurityTokenKeySpec, options.EMVSupportEnabled); // Write volume header int headerOffset = volume->GetLayout()->GetHeaderOffset(); @@ -1690,7 +1716,7 @@ namespace VeraCrypt backupFile.ReadAt (headerBuffer, layout->GetType() == VolumeType::Hidden ? layout->GetHeaderSize() : 0); // Decrypt header - shared_ptr passwordKey = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.EMVSupportEnabled); + shared_ptr passwordKey = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password, options.SecurityTokenKeySpec, options.EMVSupportEnabled); if (layout->GetHeader()->Decrypt (headerBuffer, *passwordKey, options.Pim, kdf, layout->GetSupportedKeyDerivationFunctions(), layout->GetSupportedEncryptionAlgorithms(), layout->GetSupportedEncryptionModes())) { decryptedLayout = layout; @@ -1716,7 +1742,7 @@ namespace VeraCrypt // Re-encrypt volume header SecureBuffer newHeaderBuffer (decryptedLayout->GetHeaderSize()); - Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.EMVSupportEnabled); + Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.SecurityTokenKeySpec, options.EMVSupportEnabled); // Write volume header int headerOffset = decryptedLayout->GetHeaderOffset(); @@ -1730,7 +1756,7 @@ namespace VeraCrypt if (decryptedLayout->HasBackupHeader()) { // Re-encrypt backup volume header - Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.EMVSupportEnabled); + Core->ReEncryptVolumeHeaderWithNewSalt (newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles, options.SecurityTokenKeySpec, options.EMVSupportEnabled); // Write backup volume header headerOffset = decryptedLayout->GetBackupHeaderOffset(); diff --git a/src/Main/TextUserInterface.h b/src/Main/TextUserInterface.h index 34a7cb40fa..722a3f7a0e 100644 --- a/src/Main/TextUserInterface.h +++ b/src/Main/TextUserInterface.h @@ -29,6 +29,7 @@ namespace VeraCrypt virtual FilePath AskFilePath (const wxString &message = wxEmptyString) const; virtual shared_ptr AskKeyfiles (const wxString &message = L"") const; + virtual wstring AskSecurityTokenKeySpec(const wxString &message = L"") const; virtual shared_ptr AskPassword (const wxString &message = L"", bool verify = false) const; virtual int AskPim (const wxString &message = L"") const; virtual ssize_t AskSelection (ssize_t optionCount, ssize_t defaultOption = -1) const; @@ -37,7 +38,7 @@ namespace VeraCrypt virtual bool AskYesNo (const wxString &message, bool defaultYes = false, bool warning = false) const; virtual void BackupVolumeHeaders (shared_ptr volumePath) const; virtual void BeginBusyState () const { } - virtual void ChangePassword (shared_ptr volumePath = shared_ptr (), shared_ptr password = shared_ptr (), int pim = 0, shared_ptr currentHash = shared_ptr (), shared_ptr keyfiles = shared_ptr (), shared_ptr newPassword = shared_ptr (), int newPim = 0, shared_ptr newKeyfiles = shared_ptr (), shared_ptr newHash = shared_ptr ()) const; + virtual void ChangePassword (shared_ptr volumePath = shared_ptr (), shared_ptr password = shared_ptr (), int pim = 0, shared_ptr currentHash = shared_ptr (), shared_ptr keyfiles = shared_ptr (), wstring securityTokenKeySpec = wstring(), shared_ptr newPassword = shared_ptr (), int newPim = 0, shared_ptr newKeyfiles = shared_ptr (), shared_ptr newHash = shared_ptr ()) const; virtual void CreateKeyfile (shared_ptr keyfilePath = shared_ptr ()) const; virtual void CreateVolume (shared_ptr options) const; virtual void DeleteSecurityTokenKeyfiles () const; diff --git a/src/Main/Unix/Main.cpp b/src/Main/Unix/Main.cpp index ffc71a8d7e..184ac3cb8b 100644 --- a/src/Main/Unix/Main.cpp +++ b/src/Main/Unix/Main.cpp @@ -43,6 +43,8 @@ int main (int argc, char **argv) setenv ("PATH", sysPathStr.c_str(), 1); + SecurityToken::UseImpl(make_shared()); + if (argc > 1 && strcmp (argv[1], TC_CORE_SERVICE_CMDLINE_OPTION) == 0) { // Process elevated requests diff --git a/src/Main/UserInterface.cpp b/src/Main/UserInterface.cpp index b216101ac1..b7eac61803 100644 --- a/src/Main/UserInterface.cpp +++ b/src/Main/UserInterface.cpp @@ -1036,8 +1036,9 @@ static bool IsExecutable(const string& exe) { if (Preferences.NonInteractive) { // Volume path - if (!cmdLine.ArgMountOptions.Path) + if (!cmdLine.ArgMountOptions.Path) { throw MissingArgument (SRC_POS); + } mountedVolumes.push_back (Core->MountVolume (cmdLine.ArgMountOptions)); } @@ -1076,7 +1077,7 @@ static bool IsExecutable(const string& exe) { return true; case CommandId::ChangePassword: - ChangePassword (cmdLine.ArgVolumePath, cmdLine.ArgPassword, cmdLine.ArgPim, cmdLine.ArgHash, cmdLine.ArgKeyfiles, cmdLine.ArgNewPassword, cmdLine.ArgNewPim, cmdLine.ArgNewKeyfiles, cmdLine.ArgNewHash); + ChangePassword (cmdLine.ArgVolumePath, cmdLine.ArgPassword, cmdLine.ArgPim, cmdLine.ArgHash, cmdLine.ArgKeyfiles, cmdLine.ArgSecurityTokenKeySpec, cmdLine.ArgNewPassword, cmdLine.ArgNewPim, cmdLine.ArgNewKeyfiles, cmdLine.ArgNewHash); return true; case CommandId::CreateKeyfile: diff --git a/src/Main/UserInterface.h b/src/Main/UserInterface.h index 41415e9d59..b0c35302fa 100644 --- a/src/Main/UserInterface.h +++ b/src/Main/UserInterface.h @@ -33,7 +33,7 @@ namespace VeraCrypt virtual bool AskYesNo (const wxString &message, bool defaultYes = false, bool warning = false) const = 0; virtual void BackupVolumeHeaders (shared_ptr volumePath) const = 0; virtual void BeginBusyState () const = 0; - virtual void ChangePassword (shared_ptr volumePath = shared_ptr (), shared_ptr password = shared_ptr (), int pim = 0, shared_ptr currentHash = shared_ptr (), shared_ptr keyfiles = shared_ptr (), shared_ptr newPassword = shared_ptr (), int newPim = 0, shared_ptr newKeyfiles = shared_ptr (), shared_ptr newHash = shared_ptr ()) const = 0; + virtual void ChangePassword (shared_ptr volumePath = shared_ptr (), shared_ptr password = shared_ptr (), int pim = 0, shared_ptr currentHash = shared_ptr (), shared_ptr keyfiles = shared_ptr (), wstring securityTokenKeySpec = wstring(), shared_ptr newPassword = shared_ptr (), int newPim = 0, shared_ptr newKeyfiles = shared_ptr (), shared_ptr newHash = shared_ptr ()) const = 0; virtual void CheckRequirementsForMountingVolume () const; virtual void CloseExplorerWindows (shared_ptr mountedVolume) const; virtual void CreateKeyfile (shared_ptr keyfilePath = shared_ptr ()) const = 0; diff --git a/src/Makefile b/src/Makefile index b176975e3b..9716d040c5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,7 +19,7 @@ # NOTEST: Do not test release binary # RESOURCEDIR: Run-time resource directory # VERBOSE: Enable verbose messages -# WXSTATIC: Use static wxWidgets library +# WXSTATIC: Use static wxWidgets library. If FULL, builds everything. If other value, builds only bare essentials. # SSSE3: Enable SSSE3 support in compiler # SSE41: Enable SSE4.1 support in compiler # NOSSE2: Disable SEE2 support in compiler @@ -118,7 +118,12 @@ else #------ Debug configuration ------ C_CXX_FLAGS += -DDEBUG - CXXFLAGS += -fno-default-inline -Wno-unused-function -Wno-unused-variable + ifeq '' '$(findstring clang++,$(CXX))' + C_CXX_FLAGS += + else + C_CXX_FLAGS += -fno-default-inline + endif + CXXFLAGS += -Wno-unused-function -Wno-unused-variable export WX_BUILD_DIR ?= $(BASE_DIR)/wxdebug WX_CONFIGURE_FLAGS += --enable-debug_flag --disable-debug_gdb --disable-debug_info @@ -547,17 +552,19 @@ WX_CONFIGURE_FLAGS += --disable-protocol --disable-protocols --disable-url --dis --disable-xrc --disable-aui --disable-postscript --disable-printarch \ --disable-arcstream --disable-fs_archive --disable-fs_zip --disable-tarstream --disable-zipstream \ --disable-animatectrl --disable-bmpcombobox --disable-calendar --disable-caret --disable-checklst --disable-collpane --disable-colourpicker --disable-comboctrl \ - --disable-datepick --disable-display --disable-dirpicker --disable-filepicker --disable-fontpicker --disable-grid --disable-dataviewctrl \ + --disable-datepick --disable-timepick --disable-display --disable-fontpicker --disable-grid --disable-dataviewctrl \ --disable-listbook --disable-odcombobox --disable-sash --disable-searchctrl --disable-slider --disable-splitter --disable-togglebtn \ --disable-toolbar --disable-tbarnative --disable-treebook --disable-toolbook --disable-tipwindow --disable-popupwin \ --disable-commondlg --disable-aboutdlg --disable-coldlg --disable-finddlg --disable-fontdlg --disable-numberdlg --disable-splash \ --disable-tipdlg --disable-progressdlg --disable-wizarddlg --disable-miniframe --disable-splines --disable-palette \ --disable-richtext --disable-dialupman --disable-debugreport --disable-filesystem --disable-rearrangectrl --disable-treelist --disable-richmsgdlg \ --disable-richtooltip --disable-propgrid --disable-stc --without-libnotify \ - --without-gtkprint --without-gnomevfs --disable-fsvolume --disable-fswatcher \ + --without-gtkprint --without-gnomevfs --disable-fswatcher \ --disable-sound --disable-mediactrl --disable-joystick --disable-apple_ieee \ --disable-gif --disable-pcx --disable-tga --disable-iff --disable-gif --disable-pnm --disable-svg \ - --without-expat --without-libtiff --without-libjpeg --without-libpng -without-regex --without-zlib + --without-expat --without-libtiff --without-libjpeg --without-libpng -without-regex --without-zlib \ + --disable-webrequest --without-liblzma + ifneq (,$(filter Linux FreeBSD,$(PLATFORM))) WX_CONFIGURE_FLAGS += --disable-tooltips @@ -577,7 +584,7 @@ endif #------ Project build ------ -PROJ_DIRS := Platform Volume Driver/Fuse Core Main +PROJ_DIRS := Testing Platform Volume Driver/Fuse Core Main .PHONY: all clean wxbuild @@ -586,8 +593,14 @@ all clean: @for DIR in $(PROJ_DIRS); do \ PROJ=$$(echo $$DIR | cut -d/ -f1); \ + echo "Building $$PROJ"; \ $(MAKE) -C $$DIR -f $$PROJ.make NAME=$$PROJ $(MAKECMDGOALS) || exit $?; \ - export LIBS="$(BASE_DIR)/$$DIR/$$PROJ.a $$LIBS"; \ + if [ -e $(BASE_DIR)/$$DIR/$$PROJ.a ]; then \ + export LIBS="$(BASE_DIR)/$$DIR/$$PROJ.a $$LIBS"; \ + fi; \ + if [ -e $(BASE_DIR)/$$DIR/$${PROJ}Test.a ]; then \ + export TEST_LIBS="$(BASE_DIR)/$$DIR/$${PROJ}Test.a $$TEST_LIBS"; \ + fi; \ done install: diff --git a/src/Platform/Buffer.cpp b/src/Platform/Buffer.cpp index 5829b1d9fe..9e7821a7cc 100644 --- a/src/Platform/Buffer.cpp +++ b/src/Platform/Buffer.cpp @@ -24,6 +24,10 @@ namespace VeraCrypt Allocate (size, alignment); } + Buffer::Buffer (const ConstBufferPtr &bufferPtr, size_t alignment) : DataPtr(nullptr), DataSize(0), DataAlignment(0) { + CopyFrom (bufferPtr, alignment); + } + Buffer::~Buffer () { if (DataPtr != nullptr) diff --git a/src/Platform/Buffer.h b/src/Platform/Buffer.h index a1eb0918bc..7d78576237 100644 --- a/src/Platform/Buffer.h +++ b/src/Platform/Buffer.h @@ -72,7 +72,7 @@ namespace VeraCrypt public: Buffer (); Buffer (size_t size, size_t alignment = 0); - Buffer (const ConstBufferPtr &bufferPtr, size_t alignment = 0) { CopyFrom (bufferPtr, alignment); } + Buffer (const ConstBufferPtr &bufferPtr, size_t alignment = 0); virtual ~Buffer (); virtual void Allocate (size_t size, size_t alignment = 0); diff --git a/src/Platform/FilesystemPath.h b/src/Platform/FilesystemPath.h index c92f684eb5..b279a6f189 100644 --- a/src/Platform/FilesystemPath.h +++ b/src/Platform/FilesystemPath.h @@ -58,6 +58,7 @@ namespace VeraCrypt bool IsEmpty () const throw () { try { return Path.empty(); } catch (...) { return false; } } bool IsFile () const throw () { try { return GetType() == FilesystemPathType::File; } catch (...) { return false; } } FilesystemPath ToBaseName () const; + FilesystemPath Append(wstring name) const; FilesystemPath ToHostDriveOfPartition () const; static const int MaxSize = 260; diff --git a/src/Platform/Finally.h b/src/Platform/Finally.h index 63f0710917..c114352f58 100644 --- a/src/Platform/Finally.h +++ b/src/Platform/Finally.h @@ -35,6 +35,17 @@ struct TC_JOIN(Finally,__LINE__) \ TC_UNUSED_VAR \ TC_JOIN(finally,__LINE__) (arg) +#define finally_do_member(clazz, argType, arg, code) \ +struct TC_JOIN(Finally,__LINE__) \ +{ \ + TC_JOIN(Finally,__LINE__) (clazz *obj, argType a) : finally_arg (a), finally_obj(obj) { } \ + TC_JOIN(~Finally,__LINE__) () { try { code } catch (...) { } } \ + argType finally_arg; \ + clazz *finally_obj; \ +}\ +TC_UNUSED_VAR \ +TC_JOIN(finally,__LINE__) (this, arg) + #define finally_do_arg2(argType, arg, argType2, arg2, code) \ struct TC_JOIN(Finally,__LINE__) \ { \ diff --git a/src/Platform/PipelineStream.cpp b/src/Platform/PipelineStream.cpp new file mode 100644 index 0000000000..2ddfe0d0fd --- /dev/null +++ b/src/Platform/PipelineStream.cpp @@ -0,0 +1,62 @@ +/* + Derived from source code of TrueCrypt 7.1a, which is + Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed + by the TrueCrypt License 3.0. + + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2017 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. +*/ + +#include "Exception.h" +#include "PipelineStream.h" + +using namespace std; + +namespace VeraCrypt +{ + + uint64 PipelineStream::Read (const BufferPtr &buffer) + { + if (streams.size() < 1 || CurrentStreamIdx >= streams.size()) { + return 0; + } + + auto s = streams.at(CurrentStreamIdx); + + size_t read = s->Read(buffer); + if (read != 0) { + return read; + } + + bool hasMoreStreams = CurrentStreamIdx + 1 < streams.size(); + while (hasMoreStreams) { + CurrentStreamIdx++; + s = streams.at(CurrentStreamIdx); + read = s->Read(buffer); + if (read != 0) { + return read; + } + hasMoreStreams = CurrentStreamIdx + 1 < streams.size(); + } + + return read; + } + + void PipelineStream::ReadCompleteBuffer (const BufferPtr &buffer) + { + if (Read (buffer) != buffer.Size()) + throw InsufficientData (SRC_POS); + } + + void PipelineStream::AddStream(shared_ptr stream) { + streams.push_back(stream); + } + + void PipelineStream::Write (const ConstBufferPtr &data) + { + throw std::domain_error("write is not supported for pipeline stream"); + } +} diff --git a/src/Platform/PipelineStream.h b/src/Platform/PipelineStream.h new file mode 100644 index 0000000000..545f78d90b --- /dev/null +++ b/src/Platform/PipelineStream.h @@ -0,0 +1,40 @@ +/* + Derived from source code of TrueCrypt 7.1a, which is + Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed + by the TrueCrypt License 3.0. + + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2017 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. +*/ + +#ifndef TC_HEADER_Platform_PipelineStream +#define TC_HEADER_Platform_PipelineStream + +#include "PlatformBase.h" +#include "Stream.h" + +namespace VeraCrypt +{ + class PipelineStream : public Stream + { + public: + PipelineStream () : streams(), ReadPosition (0), CurrentStreamIdx(0) { } + ~PipelineStream () { } + + void AddStream(shared_ptr stream); + + uint64 Read (const BufferPtr &buffer); + void ReadCompleteBuffer (const BufferPtr &buffer); + void Write (const ConstBufferPtr &data); + + protected: + vector > streams; + size_t ReadPosition; + size_t CurrentStreamIdx; + }; +} + +#endif // TC_HEADER_Platform_PipelineStream diff --git a/src/Platform/PipelineStreamTest.cpp b/src/Platform/PipelineStreamTest.cpp new file mode 100644 index 0000000000..f769240dce --- /dev/null +++ b/src/Platform/PipelineStreamTest.cpp @@ -0,0 +1,173 @@ +#include + +#include "Testing.h" +#include "PipelineStream.h" +#include "MemoryStream.h" +#include "Stream.h" + + +using namespace VeraCrypt; + +#define MK(type, name) shared_ptr name = shared_ptr(new type()); + +size_t ReadFully(shared_ptr s, Buffer *rb, int chunkSize = 10) { + vector buffers; + vector lengths; + size_t n = 0; + size_t tot = 0; + Buffer *buff = new Buffer(chunkSize); + while ((n = s->Read(*buff)) > 0) { + buffers.push_back(buff); + lengths.push_back(n); + buff = new Buffer(chunkSize); + tot += n; + } + + Buffer *buffer = new Buffer(tot); + size_t offset = 0; + for (size_t i = 0; i < buffers.size(); i++) { + memcpy(buffer->Ptr()+offset, buffers[i]->GetRange(0, lengths[i]), lengths[i]); + offset += lengths[i]; + } + rb = buffer; + return tot; +} + + +void FillBuffer(Buffer &buff) { + uint8 *b = buff.Ptr(); + for (auto i = 0; i < buff.Size(); ++i) { + b[i] = i+1; + } +} + +void EmptyTest(shared_ptr r) { + PipelineStream s; + + Buffer buff(1); + size_t n = s.Read(buff); + + r->Info("N" + to_string(n)); + if (n != 0) { + r->Failed("read some data, expected none"); + } +} + +void SingleByteSingleStreamTest(shared_ptr r) { + Buffer buff(1); + FillBuffer(buff); + + auto m = make_shared(buff); + + MK(PipelineStream, s); + s->AddStream(m); + + Buffer *rb = nullptr; + size_t n = ReadFully(s, rb); + r->Info("N" + to_string(n)); + if (n != 1) { + r->Failed("Expected 1 byte"); + } + +} + +void SingleByteTwoStreamsTest(shared_ptr r) { + Buffer buf1(1); + Buffer buf2(1); + + FillBuffer(buf1); + FillBuffer(buf2); + + auto m1 = make_shared(buf1); + auto m2 = make_shared(buf2); + + MK(PipelineStream, s); + s->AddStream(m1); + s->AddStream(m2); + + + Buffer *rb = nullptr; + size_t n = ReadFully(s, rb); + r->Info("N" + to_string(n)); + if (n != 2) { + r->Failed("Expected 2 bytes"); + } + +} + + + +void LongStreamAndSingleByteStreamTest(shared_ptr r) { + Buffer buf1(10); + Buffer buf2(1); + FillBuffer(buf1); + FillBuffer(buf2); + + auto m1 = make_shared(buf1); + auto m2 = make_shared(buf2); + + MK(PipelineStream,s); + s->AddStream(m1); + s->AddStream(m2); + + Buffer *rb = nullptr; + size_t n = ReadFully(s, rb); + r->Info("N" + to_string(n)); + if (n != 11) { + r->Failed("Expected 11 bytes"); + } +} + +void ReadWholeStreamAtOnceTest(shared_ptr r) { + Buffer buf1(10); + Buffer buf2(5); + FillBuffer(buf1); + FillBuffer(buf2); + + auto m1 = make_shared(buf1); + auto m2 = make_shared(buf2); + + MK(PipelineStream, s); + s->AddStream(m1); + s->AddStream(m2); + + Buffer *rb = nullptr; + size_t n = ReadFully(s, rb, 20); + r->Info("N" + to_string(n)); + if (n != 15) { + r->Failed("Expected 15 bytes"); + } +} + +void ReadStreamByteByByteTest(shared_ptr r) { + Buffer buf1(10); + Buffer buf2(1); + FillBuffer(buf1); + FillBuffer(buf2); + + auto m1 = make_shared(buf1); + auto m2 = make_shared(buf2); + + MK(PipelineStream, s); + s->AddStream(m1); + s->AddStream(m2); + + Buffer *rb = nullptr; + size_t n = ReadFully(s, rb, 1); + r->Info("N" + to_string(n)); + if (n != 11) { + r->Failed("Expected 11 bytes"); + } +} + +int main() { + VeraCrypt::Testing t; + t.AddTest("empty", &EmptyTest); + t.AddTest("single byte single stream", &SingleByteSingleStreamTest); + t.AddTest("two single byte streams", &SingleByteTwoStreamsTest); + t.AddTest("long stream and single byte stream", &LongStreamAndSingleByteStreamTest); + t.AddTest("read full stream at once", &ReadWholeStreamAtOnceTest); + t.AddTest("read byte by byte", &ReadStreamByteByByteTest); + t.Main(); +}; + diff --git a/src/Platform/Platform.make b/src/Platform/Platform.make index 0a3c1435f6..a6585521e0 100644 --- a/src/Platform/Platform.make +++ b/src/Platform/Platform.make @@ -15,6 +15,7 @@ OBJS += Exception.o OBJS += Event.o OBJS += FileCommon.o OBJS += MemoryStream.o +OBJS += PipelineStream.o OBJS += Memory.o OBJS += PlatformTest.o OBJS += Serializable.o @@ -36,4 +37,7 @@ OBJS += Unix/SystemLog.o OBJS += Unix/Thread.o OBJS += Unix/Time.o +TEST_OBJS := PipelineStreamTest.o +TEST_LFLAGS := -lpthread + include $(BUILD_INC)/Makefile.inc diff --git a/src/Platform/Unix/FilesystemPath.cpp b/src/Platform/Unix/FilesystemPath.cpp index 1230c2aa20..4092266365 100644 --- a/src/Platform/Unix/FilesystemPath.cpp +++ b/src/Platform/Unix/FilesystemPath.cpp @@ -67,6 +67,15 @@ namespace VeraCrypt return Path.substr (pos + 1); } + FilesystemPath FilesystemPath::Append(wstring name) const { + wstring newPath = Path; + if (newPath.at(newPath.length()-1) == L'/') { + return FilesystemPath(newPath + name); + } else { + return FilesystemPath(newPath + L'/' + name); + } + } + FilesystemPath FilesystemPath::ToHostDriveOfPartition () const { DevicePath path; diff --git a/src/Testing/SampleTest.cpp b/src/Testing/SampleTest.cpp new file mode 100644 index 0000000000..529dbd7bc8 --- /dev/null +++ b/src/Testing/SampleTest.cpp @@ -0,0 +1,46 @@ + +#include "Testing.h" +#include "SampleTest.h" + +using namespace VeraCrypt; + +static bool functionDidRaise = true; +static bool functionWasRun = true; + +void exceptionalTest(shared_ptr r) { + r->Phase("throwing exception"); + functionWasRun = true; + throw std::invalid_argument("intentionally raised exception within test"); + functionDidRaise = false; +} + +void failedAssertionTest(shared_ptr r) { + r->Failed("intentionally failed without exception"); +} + +int main() { + VeraCrypt::Testing t; + + auto classTest = new SampleTest("sample"); + t.AddTest(classTest); + t.AddTest("failing test", failedAssertionTest); + t.AddTest("functional sample test", &exceptionalTest); + + t.Main(); + + + if (!classTest->WasRun) { + cerr << "Test was not run" << endl; + std::exit(1); + } + + if (!functionWasRun) { + cerr << "Test was not run" << endl; + std::exit(1); + } + if (!functionDidRaise) { + cerr << "Test did not raise as expected"; + std::exit(1); + } + +} \ No newline at end of file diff --git a/src/Testing/SampleTest.h b/src/Testing/SampleTest.h new file mode 100644 index 0000000000..e10f962d6d --- /dev/null +++ b/src/Testing/SampleTest.h @@ -0,0 +1,15 @@ +#include + +#include "Testing.h" + +namespace VeraCrypt { + + + class SampleTest : public Test { + public: + SampleTest(string name) : Test(name), WasRun(false) {}; + void Run(shared_ptr r) { WasRun = true; }; + bool WasRun; + }; + +}; \ No newline at end of file diff --git a/src/Testing/Testing.cpp b/src/Testing/Testing.cpp new file mode 100644 index 0000000000..3091fec483 --- /dev/null +++ b/src/Testing/Testing.cpp @@ -0,0 +1,94 @@ +#include "Testing.h" +#include + +using namespace std; + +namespace VeraCrypt { + + void Testing::Main() { + auto r = make_shared(this->GetName()); + Run(r); + Report(); + }; + + void Testing::Report() { + size_t passed = 0; + size_t failed = 0; + auto results = GetResults(); + cout << endl; + cout << DECORATE("TESTS SUMMARY") << endl; + for (auto t = results.begin(); t != results.end(); ++t) { + if (t->IsSuccess()) { + cout << "."; + passed ++; + } else { + cout << "E"; + failed ++; + } + } + cout << endl; + cout << passed << " passed, " << failed << " failed" << endl; + + if (failed > 0) { + cout << DECORATE("Failed test details:") << endl; + } + for (auto t = results.begin(); t != results.end(); ++t) { + if (t->IsFailed()) { + cout << "* " << t->GetName() << endl; + cout << " " << t->GetFailureReason() << endl; + auto phases = t->GetPhases(); + if (phases.size() > 0) { + cout << " Phases:" << endl; + for (auto phaseName = phases.begin(); phaseName != phases.end(); ++phaseName) { + cout << " - " << *phaseName << endl; + } + } + } + } + cout << endl; + } + + shared_ptr TestSuite::RunSingle(Test *t) { + shared_ptr result = shared_ptr(new TestResult(t->GetName())); + try { + t->Run(result); + } catch (TestFailedException& e) { + } catch (const exception& e) { + result->MarkFailed("Test case threw exception: " + string(e.what())); + } + return result; + }; + + void TestSuite::Run(shared_ptr res) { + try { + for (auto t = tests.begin(); t != tests.end(); ++t) { + auto r = RunSingle(*t); + results.push_back(*r); + if (r->IsFailed()) { + res->MarkFailed(r->GetFailureReason()); + } + if (stopOnFirstFailure && r->IsFailed()) { + return; + } + } + } catch (const exception &e) { + cerr << "Testing system failure: " << e.what() << endl; + } catch (...) { + cerr << "Testing system failure" << endl; + } + } + + void TestSuite::AddTest(Test *test) { + tests.push_back(test); + }; + + void TestSuite::AddTest(string name, testFunc func) { + AddTest(new FunctionalTest(name, func)); + }; + + void TestSuite::AddTest(TestSuite *suite, bool rollUp) { + suite->MarkRollUp(); + tests.push_back(suite); + } + +}; \ No newline at end of file diff --git a/src/Testing/Testing.h b/src/Testing/Testing.h new file mode 100644 index 0000000000..0f94918254 --- /dev/null +++ b/src/Testing/Testing.h @@ -0,0 +1,130 @@ +#ifndef TC_HEADER_Testing +#define TC_HEADER_Testing + +#include +#include +#include +#include + +#define DECORATE(msg) ">>>>> " << msg << " <<<<<" + +using namespace std; + +namespace VeraCrypt +{ + class TestFailedException : public std::exception { + public: + virtual const char * what () const noexcept { + return "test failed"; + } + + }; + + class TestResult { + public: + TestResult(string testName) : failed(false), ex(), testName(testName) { }; + void Phase(string msg) { phaseMsgs.push_back(msg); }; + + void Success() { }; + void Failed(string reason, const exception &e) { ex = &e; Failed(reason); }; + void Failed(string reason) { failReason = reason; failed = true; throw TestFailedException(); } + void MarkFailed(string reason) { failReason = reason; failed = true; } + + void Info(string s) { cout << "[" << testName << "] " << s << endl; }; + + + bool IsSuccess() { return !failed; }; + bool IsFailed() { return failed; }; + const exception* Ex() { return ex; }; + string GetName() { return testName; }; + string GetFailureReason() { return failReason; } + vector GetPhases() { return phaseMsgs; }; + private: + string failReason; + bool failed; + const exception *ex; + string testName; + vector phaseMsgs; + }; + + using testFunc = void (*)(shared_ptr); + + template + using paramTestFunc = void (*)(shared_ptr, T *); + + class Test { + public: + Test(string name) : name(name) {}; + + virtual void Run(shared_ptr r) = 0; + + string GetName() { return name; }; + protected: + string name; + + }; + + class FunctionalTest : public Test { + public: + FunctionalTest(string name, testFunc func) : Test(name), func(func){}; + void Run(shared_ptr r) { func(r); } + + private: + testFunc func; + + }; + + template + class ParameterizedFunctionalTest : public Test { + public: + ParameterizedFunctionalTest(string name, paramTestFunc

    func, P *param); + void Run(shared_ptr r) { func(r, param); } + private: + paramTestFunc

    func; + P *param; + }; + + + template + inline ParameterizedFunctionalTest

    ::ParameterizedFunctionalTest(string name, paramTestFunc

    func, P *param) + : Test(name), func(func), param(param) { + + }; + + class TestSuite : public Test { + public: + TestSuite() : Test("") { }; + void AddTest(Test* test); + void AddTest(string name, testFunc func); + void AddTest(TestSuite* suite, bool rollUp); + + + template + static ParameterizedFunctionalTest

    *param(string name, paramTestFunc

    func, P *arg) { return new ParameterizedFunctionalTest

    (name, func, arg); } + + void Run(shared_ptr r); + + vector GetResults() { return results; } + void StopOnFirstFailure() { stopOnFirstFailure = true; } + void MarkRollUp() { rollUp = true; } + + protected: + shared_ptr RunSingle(Test *t); + + private: + bool stopOnFirstFailure = false; + bool rollUp = false; + vector tests; + vector results; + }; + + class Testing : public TestSuite { + public: + Testing() : TestSuite() {}; + void Main(); + void Report(); + }; + +}; + +#endif \ No newline at end of file diff --git a/src/Testing/Testing.make b/src/Testing/Testing.make new file mode 100644 index 0000000000..8b6ac461a0 --- /dev/null +++ b/src/Testing/Testing.make @@ -0,0 +1,6 @@ +OBJS := + +TEST_OBJS := Testing.o +TEST_EXECS := SampleTest.o + +include $(BUILD_INC)/Makefile.inc diff --git a/src/Volume/Keyfile.cpp b/src/Volume/Keyfile.cpp index e756cdf1fc..cc151a76ce 100644 --- a/src/Volume/Keyfile.cpp +++ b/src/Volume/Keyfile.cpp @@ -12,38 +12,34 @@ #include "Platform/Serializer.h" #include "Common/SecurityToken.h" +#include "Platform/MemoryStream.h" +#include "Platform/PipelineStream.h" +#include "Platform/FileStream.h" #include "Common/EMVToken.h" #include "Crc32.h" #include "Keyfile.h" #include "VolumeException.h" namespace VeraCrypt { - void Keyfile::Apply (const BufferPtr &pool, bool emvSupportEnabled) const - { + void Keyfile::Apply (const BufferPtr &pool, wstring tokenKeyDescriptor, bool emvSupportEnabled) const { if (Path.IsDirectory()) throw ParameterIncorrect (SRC_POS); - File file; - Crc32 crc32; size_t poolPos = 0; uint64 totalLength = 0; uint64 readLength; + shared_ptr s = PrepareStream(tokenKeyDescriptor, emvSupportEnabled); + SecureBuffer keyfileBuf (File::GetOptimalReadSize()); + File encryptedKeyfile; - if (Token::IsKeyfilePathValid (Path, emvSupportEnabled)) + + while ((readLength = s->Read (keyfileBuf)) > 0) { - // Apply keyfile generated by a security token - vector keyfileData; - Token::getTokenKeyfile(wstring(Path))->GetKeyfileData(keyfileData); - - if (keyfileData.size() < MinProcessedLength) - throw InsufficientData(SRC_POS, Path); - - for (size_t i = 0; i < keyfileData.size(); i++) - { - uint32 crc = crc32.Process(keyfileData[i]); + for (uint64 i = 0; i < readLength; i++) { + uint32 crc = crc32.Process (keyfileBuf[i]); pool[poolPos++] += (uint8)(crc >> 24); pool[poolPos++] += (uint8)(crc >> 16); @@ -56,36 +52,12 @@ namespace VeraCrypt if (++totalLength >= MaxProcessedLength) break; } - - - burn(&keyfileData.front(), keyfileData.size()); - goto done; } - - file.Open (Path, File::OpenRead, File::ShareRead); - - while ((readLength = file.Read (keyfileBuf)) > 0) - { - for (size_t i = 0; i < readLength; i++) - { - uint32 crc = crc32.Process(keyfileBuf[i]); - pool[poolPos++] += (uint8)(crc >> 24); - pool[poolPos++] += (uint8)(crc >> 16); - pool[poolPos++] += (uint8)(crc >> 8); - pool[poolPos++] += (uint8) crc; - if (poolPos >= pool.Size()) - poolPos = 0; - if (++totalLength >= MaxProcessedLength) - goto done; - } - } - done: - - if (totalLength < MinProcessedLength) - throw InsufficientData (SRC_POS, Path); } - shared_ptr Keyfile::ApplyListToPassword (shared_ptr keyfiles, shared_ptr password, bool emvSupportEnabled) + + shared_ptr Keyfile::ApplyListToPassword (shared_ptr keyfiles, shared_ptr password, + wstring tokenDescriptor, bool emvSupportEnabled) { if (!password) password.reset (new VolumePassword); @@ -116,8 +88,9 @@ namespace VeraCrypt ++keyfileCount; } - if (keyfileCount == 0) + if (keyfileCount == 0) { throw KeyfilePathEmpty (SRC_POS, FilesystemPath (*keyfile)); + } } else { @@ -142,7 +115,7 @@ namespace VeraCrypt // Apply all keyfiles foreach_ref (const Keyfile &k, keyfilesExp) { - k.Apply (keyfilePool, emvSupportEnabled); + k.Apply (keyfilePool, tokenDescriptor, emvSupportEnabled); } newPassword->Set (keyfilePool); @@ -180,5 +153,149 @@ namespace VeraCrypt } } + void Keyfile::CreateBluekey(FilePath bluekeyFile, wstring tokenKeyDescriptor, SecureBuffer &buffer) { + SecurityTokenKey key; + SecurityToken::GetSecurityTokenKey(tokenKeyDescriptor, key, SecurityTokenKeyOperation::ENCRYPT); + + size_t inputBufferSize = key.maxDecryptBufferSize; + size_t outputBufferSize = key.maxEncryptBufferSize; + + vector tokenDataToProcess; + vector processedData(outputBufferSize); + + tokenDataToProcess.reserve(inputBufferSize); + + BufferPtr remainder; + if (buffer.Size() >= inputBufferSize) { + std::copy(buffer.Ptr(), buffer.Ptr() + inputBufferSize, back_inserter(tokenDataToProcess)); + remainder = buffer.GetRange(inputBufferSize, buffer.Size() - inputBufferSize); + } else { + // buffer size less than encryption buffer size + // in order to provide the best security, we shouldn't work with such keyfiles + throw InsufficientData(); + } + + SecurityToken::GetEncryptedData(key, tokenDataToProcess, processedData); + SecureBuffer result(ConstBufferPtr(processedData.data(), processedData.size())); + + PipelineStream bkfs; + auto m = make_shared(result); + + bkfs.AddStream(m); + + if (remainder.Size() > 0) { + auto r = make_shared(remainder); + bkfs.AddStream(r); + } + + File keyfile; + keyfile.Open (bluekeyFile, File::CreateWrite); + + size_t n; + SecureBuffer writeBuffer(File::GetOptimalWriteSize()); + while ((n = bkfs.Read(writeBuffer)) > 0) { + keyfile.Write (writeBuffer, n); + } + } + + void Keyfile::RevealRedkey(FilePath redkey, wstring tokenKeyDescriptor) { + shared_ptr kfs = PrepareStream(tokenKeyDescriptor, false); + + File redKey; + redKey.Open (redkey, File::CreateWrite, File::ShareReadWriteIgnoreLock); + size_t read; + SecureBuffer buffer (File::GetOptimalReadSize()); + while ((read = kfs->Read(buffer)) > 0) { + redKey.Write(buffer, read); + } + redKey.Close(); + } + + shared_ptr Keyfile::PrepareStream(wstring tokenKeyDescriptor, bool emvSupportEnabled) const { + if (Token::IsKeyfilePathValid (Path, emvSupportEnabled)) + { + // Apply keyfile generated by a security token + vector keyfileData; + Token::getTokenKeyfile(wstring(Path))->GetKeyfileData(keyfileData); + + if (keyfileData.size() < MinProcessedLength) + throw InsufficientData (SRC_POS, Path); + + MemoryStream *ms = new MemoryStream(ConstBufferPtr(keyfileData.data(), keyfileData.size())); + return shared_ptr(ms); + } + + shared_ptr ps = shared_ptr(new PipelineStream()); + + shared_ptr file = shared_ptr (new File()); + SecureBuffer keyfileBuf (File::GetOptimalReadSize()); + uint64 readLength; + + File encryptedKeyfile; + + + file->Open (Path, File::OpenRead, File::ShareRead); + + if (!tokenKeyDescriptor.empty()) { + // if token is specified, first part of the file is/should be encrypted + + + // get token slot and key from descriptor + SecurityTokenKey key; + SecurityToken::GetSecurityTokenKey(tokenKeyDescriptor, key, SecurityTokenKeyOperation::DECRYPT); + + // set proper vector size based on key length + // and mode (encryption/decryption) + size_t inputBufferSize = key.maxEncryptBufferSize; + size_t outputBufferSize = key.maxDecryptBufferSize; + uint64 appendBytesCount = 0; + + vector tokenDataToProcess; + vector processedData(outputBufferSize); + + + while ((readLength = file->Read (keyfileBuf)) > 0) + { + if (tokenDataToProcess.size() < inputBufferSize) { + appendBytesCount = readLength; + if (tokenDataToProcess.size() + appendBytesCount > inputBufferSize) { + appendBytesCount = inputBufferSize - tokenDataToProcess.size(); + tokenDataToProcess.insert(tokenDataToProcess.end(), keyfileBuf.Ptr(), keyfileBuf.Ptr() + appendBytesCount); + break; + } + tokenDataToProcess.insert(tokenDataToProcess.end(), keyfileBuf.Ptr(), keyfileBuf.Ptr() + appendBytesCount); + } + } + + string s(tokenDataToProcess.begin(), tokenDataToProcess.end()); + + + SecurityToken::GetDecryptedData(key, tokenDataToProcess, processedData); + + auto tokenStream = make_shared(ConstBufferPtr(processedData.data(), processedData.size())); + ps->AddStream(tokenStream); + + // process the rest of the buffer as an ordinary (non-encrypted) data + // otherwise we'd get non-deterministic behavior, because Read() could produce buffers of different sizes + BufferPtr remainderBuffer = keyfileBuf.GetRange(appendBytesCount, readLength-appendBytesCount); + if (encryptedKeyfile.IsOpen()) { + // dump read but unused chunk first + if (appendBytesCount < readLength) { + string ss(keyfileBuf.Ptr() + appendBytesCount, keyfileBuf.Ptr() + readLength); + encryptedKeyfile.Write(ConstBufferPtr(&keyfileBuf[appendBytesCount], readLength-appendBytesCount)); + } + } + + auto remainderStream = make_shared(remainderBuffer); + ps->AddStream(remainderStream); + } + + auto fs = make_shared(file); + ps->AddStream(fs); + + return ps; + + } + bool Keyfile::HiddenFileWasPresentInKeyfilePath = false; } diff --git a/src/Volume/Keyfile.h b/src/Volume/Keyfile.h index 1d87a98384..b282719935 100644 --- a/src/Volume/Keyfile.h +++ b/src/Volume/Keyfile.h @@ -16,6 +16,7 @@ #include "Platform/Platform.h" #include "Platform/Stream.h" #include "VolumePassword.h" +#include "Common/SecurityToken.h" namespace VeraCrypt { @@ -26,20 +27,23 @@ namespace VeraCrypt { public: Keyfile (const FilesystemPath &path) : Path (path) { } - virtual ~Keyfile () { }; operator FilesystemPath () const { return Path; } - static shared_ptr ApplyListToPassword (shared_ptr keyfiles, shared_ptr password, bool emvSupportEnabled = false); + static shared_ptr ApplyListToPassword (shared_ptr keyfiles, shared_ptr password, + wstring tokenDescriptor, bool emvSupportEnabled = false); static shared_ptr DeserializeList (shared_ptr stream, const string &name); static void SerializeList (shared_ptr stream, const string &name, shared_ptr keyfiles); static bool WasHiddenFilePresentInKeyfilePath() { bool r = HiddenFileWasPresentInKeyfilePath; HiddenFileWasPresentInKeyfilePath = false; return r; } static const size_t MinProcessedLength = 1; static const size_t MaxProcessedLength = 1024 * 1024; - + + void RevealRedkey(FilePath redkey, wstring tokenKeyDescriptor); + static void CreateBluekey(FilePath bluekeyFile, wstring tokenKeyDescriptor, SecureBuffer &buffer); protected: - void Apply (const BufferPtr &pool, bool emvSupportEnabled) const; - + void Apply (const BufferPtr &pool, wstring tokenKeyDescriptor, bool emvSupportEnabled) const; + shared_ptr PrepareStream(wstring tokenKeyDescriptor, bool emvSupportEnabled) const; + static bool HiddenFileWasPresentInKeyfilePath; FilesystemPath Path; diff --git a/src/Volume/Volume.cpp b/src/Volume/Volume.cpp index 524f23957c..4af23b66b0 100644 --- a/src/Volume/Volume.cpp +++ b/src/Volume/Volume.cpp @@ -70,7 +70,7 @@ namespace VeraCrypt return EA->GetMode(); } - void Volume::Open (const VolumePath &volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection, shared_ptr protectionPassword, int protectionPim, shared_ptr protectionKdf, shared_ptr protectionKeyfiles, bool sharedAccessAllowed, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) + void Volume::Open (const VolumePath &volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection, shared_ptr protectionPassword, int protectionPim, shared_ptr protectionKdf, shared_ptr protectionKeyfiles, wstring protectionSecurityTokenKeySpec, bool sharedAccessAllowed, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) { make_shared_auto (File, file); @@ -101,10 +101,10 @@ namespace VeraCrypt throw; } - return Open (file, password, pim, kdf, keyfiles, emvSupportEnabled, protection, protectionPassword, protectionPim, protectionKdf,protectionKeyfiles, volumeType, useBackupHeaders, partitionInSystemEncryptionScope); + return Open (file, password, pim, kdf, keyfiles, securityTokenKeySpec, emvSupportEnabled, protection, protectionPassword, protectionPim, protectionKdf,protectionKeyfiles, protectionSecurityTokenKeySpec, volumeType, useBackupHeaders, partitionInSystemEncryptionScope); } - void Volume::Open (shared_ptr volumeFile, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection, shared_ptr protectionPassword, int protectionPim, shared_ptr protectionKdf,shared_ptr protectionKeyfiles, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) + void Volume::Open (shared_ptr volumeFile, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection, shared_ptr protectionPassword, int protectionPim, shared_ptr protectionKdf,shared_ptr protectionKeyfiles, wstring protectionSecurityTokenKeySpec, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) { if (!volumeFile) throw ParameterIncorrect (SRC_POS); @@ -116,7 +116,7 @@ namespace VeraCrypt try { VolumeHostSize = VolumeFile->Length(); - shared_ptr passwordKey = Keyfile::ApplyListToPassword (keyfiles, password, emvSupportEnabled); + shared_ptr passwordKey = Keyfile::ApplyListToPassword (keyfiles, password, securityTokenKeySpec, emvSupportEnabled); bool skipLayoutV1Normal = false; @@ -242,12 +242,12 @@ namespace VeraCrypt Volume protectedVolume; protectedVolume.Open (VolumeFile, - protectionPassword, protectionPim, protectionKdf, protectionKeyfiles, + protectionPassword, protectionPim, protectionKdf, protectionKeyfiles, protectionSecurityTokenKeySpec, emvSupportEnabled, VolumeProtection::ReadOnly, - shared_ptr (), 0, shared_ptr (),shared_ptr (), + shared_ptr (), 0, shared_ptr (),shared_ptr (), wstring(), VolumeType::Hidden, - useBackupHeaders); + useBackupHeaders, false); if (protectedVolume.GetType() != VolumeType::Hidden) ParameterIncorrect (SRC_POS); diff --git a/src/Volume/Volume.h b/src/Volume/Volume.h index 4b91e4359e..8905a01748 100644 --- a/src/Volume/Volume.h +++ b/src/Volume/Volume.h @@ -108,8 +108,8 @@ namespace VeraCrypt uint64 GetVolumeCreationTime () const { return Header->GetVolumeCreationTime(); } bool IsHiddenVolumeProtectionTriggered () const { return HiddenVolumeProtectionTriggered; } bool IsInSystemEncryptionScope () const { return SystemEncryption; } - void Open (const VolumePath &volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (),shared_ptr protectionKeyfiles = shared_ptr (), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false); - void Open (shared_ptr volumeFile, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (), shared_ptr protectionKeyfiles = shared_ptr (), VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false); + void Open (const VolumePath &volumePath, bool preserveTimestamps, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (),shared_ptr protectionKeyfiles = shared_ptr (), wstring protectionSecurityTokenKeySpec = wstring(), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false); + void Open (shared_ptr volumeFile, shared_ptr password, int pim, shared_ptr kdf, shared_ptr keyfiles, wstring securityTokenKeySpec, bool emvSupportEnabled, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr protectionPassword = shared_ptr (), int protectionPim = 0, shared_ptr protectionKdf = shared_ptr (), shared_ptr protectionKeyfiles = shared_ptr (), wstring protectionSecurityTokenKeySpec = wstring(), VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false); void ReadSectors (const BufferPtr &buffer, uint64 byteOffset); void ReEncryptHeader (bool backupHeader, const ConstBufferPtr &newSalt, const ConstBufferPtr &newHeaderKey, shared_ptr newPkcs5Kdf); void WriteSectors (const ConstBufferPtr &buffer, uint64 byteOffset); diff --git a/src/Volume/Volume.make b/src/Volume/Volume.make index 52d212ebc0..c49997615f 100644 --- a/src/Volume/Volume.make +++ b/src/Volume/Volume.make @@ -135,7 +135,10 @@ OBJS += ../Common/Endian.o OBJS += ../Common/GfMul.o OBJS += ../Common/SecurityToken.o -VolumeLibrary: Volume.a +TEST_OBJS := +TEST_OBJS += ../Common/MockSecurityToken.o + +VolumeLibrary: Volume.a VolumeTest.a ifeq "$(ENABLE_WOLFCRYPT)" "0" ifeq "$(PLATFORM)" "MacOSX"