Merge from develop

This commit is contained in:
Sebastian Messmer 2016-09-24 20:43:54 +02:00
commit b027f8c007
40 changed files with 336 additions and 189 deletions

View File

@ -31,7 +31,7 @@ install:
- echo Using $NUMCORES cores
# Install dependencies
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then ./travis.install_boost.sh; fi
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then brew upgrade boost && brew install cryptopp osxfuse; fi
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then brew upgrade boost && brew cask install osxfuse && brew install cryptopp; fi
# By default, travis only fetches the newest 50 commits. We need more in case we're further from the last version tag, so the build doesn't fail because it can't generate the version number.
- git fetch --unshallow
# Setup target directory

View File

@ -9,7 +9,7 @@ require_clang_version(3.7)
# Default value is not to build test cases
if(NOT BUILD_TESTING)
set(BUILD_TESTING OFF CACHE INTERNAL "BUILD_TESTING")
set(BUILD_TESTING OFF CACHE BOOL "BUILD_TESTING")
endif(NOT BUILD_TESTING)
# Default vaule is to build in release mode
@ -17,6 +17,11 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE INTERNAL "CMAKE_BUILD_TYPE")
endif(NOT CMAKE_BUILD_TYPE)
# Default value is to do update checks
if(NOT CRYFS_UPDATE_CHECKS)
set(CRYFS_UPDATE_CHECKS ON CACHE BOOL "CRYFS_UPDATE_CHECKS")
endif(NOT CRYFS_UPDATE_CHECKS)
add_subdirectory(vendor)
add_subdirectory(src)
add_subdirectory(test)

View File

@ -9,8 +9,16 @@ Improvements:
Version 0.9.6 (unreleased)
---------------
Fixed bugs:
* Fix potential deadlock
* Fix potential crash
Improvements:
* Allow building with -DCRYFS_UPDATE_CHECKS=off, which will create an executable with disabled update checks (the alternative to disable them in the environment also still works).
Compatibility:
* Compatible with libcurl >= 7.50.0
* Compatible with libcurl version >= 7.50.0, and <= 7.21.6 (tested down to 7.19.0)
* Compatible with Crypto++ 5.6.4
Version 0.9.5
---------------

View File

@ -37,7 +37,7 @@ Manual install (Debian)
GUI
===
If you want to use a GUI to mount your CryFS volumes, take a look at the [cryfs-gui project](https://mhogomchungu.github.io/cryfs-gui/). You have to install the GUI **and** also CryFS itself for it to work.
If you want to use a GUI to mount your CryFS volumes, take a look at the [SiriKali project](https://mhogomchungu.github.io/sirikali/). You have to install the GUI **and** also CryFS itself for it to work.
Building from source
====================
@ -54,7 +54,8 @@ Requirements
- chrono
- program_options
- thread
- Crypto++ version >= 5.6.3 (including development headers)
- Crypto++ version == 5.6.3 (including development headers)
(not compatible to Crypto++ 5.6.4, but will be compatible with Crypto++ 5.6.5+)
- SSL development libraries (including development headers, e.g. libssl-dev)
- libFUSE version >= 2.8.6 (including development headers), on Mac OS X instead install osxfuse from https://osxfuse.github.io/
- Python >= 2.7
@ -62,10 +63,10 @@ Requirements
You can use the following commands to install these requirements
# Ubuntu
$ sudo apt-get install git g++ cmake libcurl4-openssl-dev libboost-filesystem-dev libboost-system-dev libboost-chrono-dev libboost-program-options-dev libboost-thread-dev libcrypto++-dev libssl-dev libfuse-dev python
$ sudo apt-get install git g++ cmake make libcurl4-openssl-dev libboost-filesystem-dev libboost-system-dev libboost-chrono-dev libboost-program-options-dev libboost-thread-dev libcrypto++-dev libssl-dev libfuse-dev python
# Fedora
sudo dnf install git gcc-c++ cmake libcurl-devel boost-devel boost-static cryptopp-devel openssl-devel fuse-devel python
sudo dnf install git gcc-c++ cmake make libcurl-devel boost-devel boost-static cryptopp-devel openssl-devel fuse-devel python
# Macintosh
brew install cmake boost cryptopp openssl
@ -91,6 +92,7 @@ Build & Install
You can pass the following variables to the *cmake* command (using *-Dvariablename=value*):
- -D**CMAKE_BUILD_TYPE**=[Release|Debug]: Whether to run code optimization or add debug symbols. Default: Release
- -D**BUILD_TESTING**=[on|off]: Whether to build the test cases (can take a long time). Default: off
- -D**CRYFS_UPDATE_CHECKS**=off: Build a CryFS that doesn't check online for updates and security vulnerabilities.
Troubleshooting
---------------
@ -149,3 +151,9 @@ There are additional requirements if you want to create .deb packages. They are:
$ mkdir cmake && cd cmake
$ cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=off
$ make package
Disclaimer
----------------------
On the event of a password leak, you are strongly advised to create a new filesystem and copy all the data over from the previous one. Done this, all copies of the compromised filesystem and config file must be removed (e.g, from the "previous versions" feature of your cloud system) to prevent access to the key (and, as a result, your data) using the leaked password.

View File

@ -88,7 +88,7 @@ uint32_t DataTree::_computeNumLeaves(const DataNode &node) const {
}
const DataInnerNode &inner = dynamic_cast<const DataInnerNode&>(node);
uint64_t numLeavesInLeftChildren = (inner.numChildren()-1) * leavesPerFullChild(inner);
uint64_t numLeavesInLeftChildren = (uint64_t)(inner.numChildren()-1) * leavesPerFullChild(inner);
auto lastChild = _nodeStore->load(inner.LastChild()->key());
ASSERT(lastChild != none, "Couldn't load last child");
uint64_t numLeavesInRightChild = _computeNumLeaves(**lastChild);

View File

@ -111,6 +111,7 @@ void Cache<Key, Value, MAX_ENTRIES>::_deleteEntry(std::unique_lock<std::mutex> *
// i.e. pop() and push() can be called here, except for pop() on the element in _currentlyFlushingEntries
lock->unlock();
value = boost::none; // Call destructor
lockEntryFromBeingPopped.unlock(); // unlock this one first to keep same locking oder (preventing potential deadlock)
lock->lock();
};

View File

@ -14,6 +14,9 @@ set(SOURCES
network/CurlHttpClient.cpp
network/FakeHttpClient.cpp
io/Console.cpp
io/DontEchoStdinToStdoutRAII.cpp
io/IOStreamConsole.cpp
io/NoninteractiveConsole.cpp
io/pipestream.cpp
thread/LoopThread.cpp
thread/ThreadSystem.cpp

View File

@ -23,8 +23,12 @@ namespace cpputils {
DEFINE_CIPHER(Cast256_GCM);
DEFINE_CIPHER(Cast256_CFB);
#if CRYPTOPP_VERSION != 564
DEFINE_CIPHER(Mars448_GCM);
DEFINE_CIPHER(Mars448_CFB);
#else
# warning "You're using Crypto++ 5.6.4. In this version, the MARS-448 cipher is not available. Your CryFS executable will not be able to load file systems using this cipher. Please use Crypto++ 5.6.3 or 5.6.5+ instead."
#endif
DEFINE_CIPHER(Mars256_GCM);
DEFINE_CIPHER(Mars256_CFB);
DEFINE_CIPHER(Mars128_GCM);

View File

@ -41,9 +41,11 @@ static_assert(32 == CryptoPP::CAST256::MAX_KEYLENGTH, "If Cast offered larger ke
DECLARE_CIPHER(Cast256_GCM, "cast-256-gcm", GCM_Cipher, CryptoPP::CAST256, 32);
DECLARE_CIPHER(Cast256_CFB, "cast-256-cfb", CFB_Cipher, CryptoPP::CAST256, 32);
#if CRYPTOPP_VERSION != 564
static_assert(56 == CryptoPP::MARS::MAX_KEYLENGTH, "If Mars offered larger keys, we should offer a variant with it");
DECLARE_CIPHER(Mars448_GCM, "mars-448-gcm", GCM_Cipher, CryptoPP::MARS, 56);
DECLARE_CIPHER(Mars448_CFB, "mars-448-cfb", CFB_Cipher, CryptoPP::MARS, 56);
#endif
DECLARE_CIPHER(Mars256_GCM, "mars-256-gcm", GCM_Cipher, CryptoPP::MARS, 32);
DECLARE_CIPHER(Mars256_CFB, "mars-256-cfb", CFB_Cipher, CryptoPP::MARS, 32);
DECLARE_CIPHER(Mars128_GCM, "mars-128-gcm", GCM_Cipher, CryptoPP::MARS, 16);

View File

@ -1,99 +1,2 @@
#include "Console.h"
#include <boost/optional.hpp>
#include <boost/algorithm/string/trim.hpp>
using std::string;
using std::vector;
using std::ostream;
using std::istream;
using std::flush;
using std::getline;
using boost::optional;
using boost::none;
using std::function;
using namespace cpputils;
IOStreamConsole::IOStreamConsole(): IOStreamConsole(std::cout, std::cin) {
}
IOStreamConsole::IOStreamConsole(ostream &output, istream &input): _output(output), _input(input) {
}
optional<int> parseInt(const string &str) {
try {
string trimmed = str;
boost::algorithm::trim(trimmed);
int parsed = std::stoi(str);
if (std::to_string(parsed) != trimmed) {
return none;
}
return parsed;
} catch (const std::invalid_argument &e) {
return none;
} catch (const std::out_of_range &e) {
return none;
}
}
function<optional<unsigned int>(const std::string &input)> parseUIntWithMinMax(unsigned int min, unsigned int max) {
return [min, max] (const string &input) {
optional<int> parsed = parseInt(input);
if (parsed == none) {
return optional<unsigned int>(none);
}
unsigned int value = static_cast<unsigned int>(*parsed);
if (value < min || value > max) {
return optional<unsigned int>(none);
}
return optional<unsigned int>(value);
};
}
template<typename Return>
Return IOStreamConsole::_askForChoice(const string &question, function<optional<Return> (const string&)> parse) {
optional<Return> choice = none;
do {
_output << question << flush;
string choiceStr;
getline(_input, choiceStr);
choice = parse(choiceStr);
} while(choice == none);
return *choice;
}
unsigned int IOStreamConsole::ask(const string &question, const vector<string> &options) {
if(options.size() == 0) {
throw std::invalid_argument("options should have at least one entry");
}
_output << question << "\n";
for (unsigned int i = 0; i < options.size(); ++i) {
_output << " [" << (i+1) << "] " << options[i] << "\n";
}
int choice = _askForChoice("Your choice [1-" + std::to_string(options.size()) + "]: ", parseUIntWithMinMax(1, options.size()));
return choice-1;
}
function<optional<bool>(const string &input)> parseYesNo() {
return [] (const string &input) {
string trimmed = input;
boost::algorithm::trim(trimmed);
if(trimmed == "Y" || trimmed == "y" || trimmed == "Yes" || trimmed == "yes") {
return optional<bool>(true);
} else if (trimmed == "N" || trimmed == "n" || trimmed == "No" || trimmed == "no") {
return optional<bool>(false);
} else {
return optional<bool>(none);
}
};
}
bool IOStreamConsole::askYesNo(const string &question) {
_output << question << "\n";
return _askForChoice("Your choice [y/n]: ", parseYesNo());
}
void IOStreamConsole::print(const std::string &output) {
_output << output << std::flush;
}

View File

@ -7,6 +7,7 @@
#include <iostream>
#include <boost/optional.hpp>
#include "../macros.h"
#include "../pointer/unique_ref.h"
namespace cpputils {
@ -14,27 +15,10 @@ class Console {
public:
virtual ~Console() {}
virtual unsigned int ask(const std::string &question, const std::vector<std::string> &options) = 0;
virtual bool askYesNo(const std::string &question) = 0;
virtual bool askYesNo(const std::string &question, bool defaultValue) = 0; // NoninteractiveConsole will just return the default value without asking the user.
virtual void print(const std::string &output) = 0;
};
class IOStreamConsole final: public Console {
public:
IOStreamConsole();
IOStreamConsole(std::ostream &output, std::istream &input);
unsigned int ask(const std::string &question, const std::vector<std::string> &options) override;
bool askYesNo(const std::string &question) override;
void print(const std::string &output) override;
private:
template<typename Return>
Return _askForChoice(const std::string &question, std::function<boost::optional<Return> (const std::string&)> parse);
std::ostream &_output;
std::istream &_input;
DISALLOW_COPY_AND_ASSIGN(IOStreamConsole);
};
}

View File

@ -0,0 +1,98 @@
#include "IOStreamConsole.h"
#include <boost/algorithm/string/trim.hpp>
using std::ostream;
using std::istream;
using std::string;
using std::vector;
using std::flush;
using std::function;
using boost::optional;
using boost::none;
namespace cpputils {
IOStreamConsole::IOStreamConsole(): IOStreamConsole(std::cout, std::cin) {
}
IOStreamConsole::IOStreamConsole(ostream &output, istream &input): _output(output), _input(input) {
}
optional<int> IOStreamConsole::_parseInt(const string &str) {
try {
string trimmed = str;
boost::algorithm::trim(trimmed);
int parsed = std::stoi(str);
if (std::to_string(parsed) != trimmed) {
return none;
}
return parsed;
} catch (const std::invalid_argument &e) {
return none;
} catch (const std::out_of_range &e) {
return none;
}
}
function<optional<unsigned int>(const string &input)> IOStreamConsole::_parseUIntWithMinMax(unsigned int min, unsigned int max) {
return [min, max] (const string &input) {
optional<int> parsed = _parseInt(input);
if (parsed == none) {
return optional<unsigned int>(none);
}
unsigned int value = static_cast<unsigned int>(*parsed);
if (value < min || value > max) {
return optional<unsigned int>(none);
}
return optional<unsigned int>(value);
};
}
template<typename Return>
Return IOStreamConsole::_askForChoice(const string &question, function<optional<Return> (const string&)> parse) {
optional<Return> choice = none;
do {
_output << question << flush;
string choiceStr;
getline(_input, choiceStr);
choice = parse(choiceStr);
} while(choice == none);
return *choice;
}
unsigned int IOStreamConsole::ask(const string &question, const vector<string> &options) {
if(options.size() == 0) {
throw std::invalid_argument("options should have at least one entry");
}
_output << question << "\n";
for (unsigned int i = 0; i < options.size(); ++i) {
_output << " [" << (i+1) << "] " << options[i] << "\n";
}
int choice = _askForChoice("Your choice [1-" + std::to_string(options.size()) + "]: ", _parseUIntWithMinMax(1, options.size()));
return choice-1;
}
function<optional<bool>(const string &input)> IOStreamConsole::_parseYesNo() {
return [] (const string &input) {
string trimmed = input;
boost::algorithm::trim(trimmed);
if(trimmed == "Y" || trimmed == "y" || trimmed == "Yes" || trimmed == "yes") {
return optional<bool>(true);
} else if (trimmed == "N" || trimmed == "n" || trimmed == "No" || trimmed == "no") {
return optional<bool>(false);
} else {
return optional<bool>(none);
}
};
}
bool IOStreamConsole::askYesNo(const string &question, bool /*defaultValue*/) {
_output << question << "\n";
return _askForChoice("Your choice [y/n]: ", _parseYesNo());
}
void IOStreamConsole::print(const std::string &output) {
_output << output << std::flush;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#ifndef MESSMER_CPPUTILS_IO_IOSTREAMCONSOLE_H
#define MESSMER_CPPUTILS_IO_IOSTREAMCONSOLE_H
#include "Console.h"
namespace cpputils {
class IOStreamConsole final: public Console {
public:
IOStreamConsole();
IOStreamConsole(std::ostream &output, std::istream &input);
unsigned int ask(const std::string &question, const std::vector<std::string> &options) override;
bool askYesNo(const std::string &question, bool defaultValue) override;
void print(const std::string &output) override;
private:
template<typename Return>
Return _askForChoice(const std::string &question, std::function<boost::optional<Return> (const std::string&)> parse);
static std::function<boost::optional<bool>(const std::string &input)> _parseYesNo();
static std::function<boost::optional<unsigned int>(const std::string &input)> _parseUIntWithMinMax(unsigned int min, unsigned int max);
static boost::optional<int> _parseInt(const std::string &str);
std::ostream &_output;
std::istream &_input;
DISALLOW_COPY_AND_ASSIGN(IOStreamConsole);
};
}
#endif

View File

@ -0,0 +1,23 @@
#include "NoninteractiveConsole.h"
using std::string;
using std::vector;
namespace cpputils {
NoninteractiveConsole::NoninteractiveConsole(unique_ref<Console> baseConsole): _baseConsole(std::move(baseConsole)) {
}
bool NoninteractiveConsole::askYesNo(const string &/*question*/, bool defaultValue) {
return defaultValue;
}
void NoninteractiveConsole::print(const std::string &output) {
_baseConsole->print(output);
}
unsigned int NoninteractiveConsole::ask(const string &/*question*/, const vector<string> &/*options*/) {
throw std::logic_error("Tried to ask a multiple choice question in noninteractive mode");
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#ifndef MESSMER_CPPUTILS_IO_NONINTERACTIVECONSOLE_H
#define MESSMER_CPPUTILS_IO_NONINTERACTIVECONSOLE_H
#include "Console.h"
namespace cpputils {
//TODO Add test cases for NoninteractiveConsole
class NoninteractiveConsole final: public Console {
public:
NoninteractiveConsole(unique_ref<Console> baseConsole);
unsigned int ask(const std::string &question, const std::vector<std::string> &options) override;
bool askYesNo(const std::string &question, bool defaultValue) override;
void print(const std::string &output) override;
private:
unique_ref<Console> _baseConsole;
DISALLOW_COPY_AND_ASSIGN(NoninteractiveConsole);
};
}
#endif

View File

@ -20,11 +20,13 @@ namespace cpputils {
public:
LockPool();
~LockPool();
void lock(const LockName &lock, std::unique_lock<std::mutex> *lockToFreeWhileWaiting = nullptr);
void release(const LockName &lock);
void lock(const LockName &lockName);
void lock(const LockName &lockName, std::unique_lock<std::mutex> *lockToFreeWhileWaiting);
void release(const LockName &lockName);
private:
bool _isLocked(const LockName &lock) const;
bool _isLocked(const LockName &lockName) const;
template<class OuterLock> void _lock(const LockName &lockName, OuterLock *lockToFreeWhileWaiting);
std::vector<LockName> _lockedLocks;
std::mutex _mutex;
@ -41,30 +43,44 @@ namespace cpputils {
}
template<class LockName>
inline void LockPool<LockName>::lock(const LockName &lock, std::unique_lock<std::mutex> *lockToFreeWhileWaiting) {
inline void LockPool<LockName>::lock(const LockName &lockName, std::unique_lock<std::mutex> *lockToFreeWhileWaiting) {
ASSERT(lockToFreeWhileWaiting->owns_lock(), "Given lock must be locked");
std::unique_lock<std::mutex> mutexLock(_mutex); // TODO Is shared_lock enough here?
if (_isLocked(lock)) {
// Order of locking/unlocking is important and should be the same order as everywhere else to prevent deadlocks.
// Since when entering the function, lockToFreeWhileWaiting is already locked and mutexLock is locked afterwards,
// the condition variable should do it in the same order. We use combinedLock for this.
CombinedLock combinedLock(lockToFreeWhileWaiting, &mutexLock);
_cv.wait(combinedLock, [this, &lock]{
return !_isLocked(lock);
// Order of locking/unlocking is important and should be the same order as everywhere else to prevent deadlocks.
// Since when entering the function, lockToFreeWhileWaiting is already locked and mutexLock is locked afterwards,
// the condition variable should do it in the same order. We use combinedLock for this.
CombinedLock combinedLock(lockToFreeWhileWaiting, &mutexLock);
_lock(lockName, &combinedLock);
ASSERT(mutexLock.owns_lock() && lockToFreeWhileWaiting->owns_lock(), "Locks haven't been correctly relocked");
}
template<class LockName>
inline void LockPool<LockName>::lock(const LockName &lockName) {
std::unique_lock<std::mutex> mutexLock(_mutex); // TODO Is shared_lock enough here?
_lock(lockName, &mutexLock);
ASSERT(mutexLock.owns_lock(), "Lock hasn't been correctly relocked");
}
template<class LockName>
template<class OuterLock>
inline void LockPool<LockName>::_lock(const LockName &lockName, OuterLock *mutexLock) {
if (_isLocked(lockName)) {
_cv.wait(*mutexLock, [this, &lockName]{
return !_isLocked(lockName);
});
ASSERT(mutexLock.owns_lock() && lockToFreeWhileWaiting->owns_lock(), "Locks haven't been correctly relocked");
}
_lockedLocks.push_back(lock);
_lockedLocks.push_back(lockName);
}
template<class LockName>
inline bool LockPool<LockName>::_isLocked(const LockName &lock) const {
return std::find(_lockedLocks.begin(), _lockedLocks.end(), lock) != _lockedLocks.end();
inline bool LockPool<LockName>::_isLocked(const LockName &lockName) const {
return std::find(_lockedLocks.begin(), _lockedLocks.end(), lockName) != _lockedLocks.end();
}
template<class LockName>
inline void LockPool<LockName>::release(const LockName &lock) {
inline void LockPool<LockName>::release(const LockName &lockName) {
std::unique_lock<std::mutex> mutexLock(_mutex);
auto found = std::find(_lockedLocks.begin(), _lockedLocks.end(), lock);
auto found = std::find(_lockedLocks.begin(), _lockedLocks.end(), lockName);
ASSERT(found != _lockedLocks.end(), "Lock given to release() was not locked");
_lockedLocks.erase(found);
_cv.notify_all();

View File

@ -23,11 +23,16 @@ namespace cpputils {
~MutexPoolLock() {
if (_pool != nullptr) {
_pool->release(_lockName);
_pool = nullptr;
unlock();
}
}
void unlock() {
ASSERT(_pool != nullptr, "MutexPoolLock is not locked");
_pool->release(_lockName);
_pool = nullptr;
}
private:
LockPool<LockName> *_pool;
LockName _lockName;

View File

@ -30,7 +30,7 @@ namespace cpputils {
// example.com is redirected, so we tell libcurl to follow redirection
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
curl_easy_setopt(curl, CURLOPT_ENCODING, "deflate");
ostringstream out;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlHttpClient::write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);

View File

@ -15,6 +15,10 @@ target_link_libraries(${PROJECT_NAME} PUBLIC cryfs cpp-utils gitversion)
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})
if(NOT CRYFS_UPDATE_CHECKS)
target_compile_definitions(${PROJECT_NAME} PRIVATE -DCRYFS_NO_UPDATE_CHECKS)
endif(NOT CRYFS_UPDATE_CHECKS)
add_executable(${PROJECT_NAME}_bin main.cpp)
set_target_properties(${PROJECT_NAME}_bin PROPERTIES OUTPUT_NAME cryfs)
target_link_libraries(${PROJECT_NAME}_bin PUBLIC ${PROJECT_NAME})

View File

@ -22,6 +22,7 @@
#include "VersionChecker.h"
#include <gitversion/VersionCompare.h>
#include <cpp-utils/io/NoninteractiveConsole.h>
#include "Environment.h"
//TODO Fails with gpg-homedir in filesystem: gpg --homedir gpg-homedir --gen-key
@ -38,7 +39,7 @@ using program_options::ProgramOptions;
using cpputils::make_unique_ref;
using cpputils::Random;
using cpputils::IOStreamConsole;
using cpputils::NoninteractiveConsole;
using cpputils::TempFile;
using cpputils::RandomGenerator;
using cpputils::unique_ref;
@ -74,9 +75,14 @@ using gitversion::VersionCompare;
namespace cryfs {
Cli::Cli(RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, shared_ptr<Console> console, shared_ptr<HttpClient> httpClient):
_keyGenerator(keyGenerator), _scryptSettings(scryptSettings), _console(console), _httpClient(httpClient), _noninteractive(false) {
Cli::Cli(RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, unique_ref<Console> console, shared_ptr<HttpClient> httpClient):
_keyGenerator(keyGenerator), _scryptSettings(scryptSettings), _console(), _httpClient(httpClient), _noninteractive(false) {
_noninteractive = Environment::isNoninteractive();
if (_noninteractive) {
_console = make_shared<NoninteractiveConsole>(std::move(console));
} else {
_console = cpputils::to_unique_ptr(std::move(console));
}
}
void Cli::_showVersion() {
@ -86,18 +92,19 @@ namespace cryfs {
". Please do not use in production!" << endl;
} else if (!gitversion::IsStableVersion()) {
cout << "WARNING! This is an experimental version. Please backup your data frequently!" << endl;
} else {
//TODO This is even shown for stable version numbers like 0.8 - remove once we reach 1.0
cout << "WARNING! This version is not considered stable. Please backup your data frequently!" << endl;
}
#ifndef NDEBUG
cout << "WARNING! This is a debug build. Performance might be slow." << endl;
#endif
#ifndef CRYFS_NO_UPDATE_CHECKS
if (!Environment::noUpdateCheck()) {
_checkForUpdates();
} else {
cout << "Automatic checking for security vulnerabilities and updates is disabled." << endl;
}
#else
# warning Update checks are disabled. The resulting executable will not go online to check for newer versions or known security vulnerabilities.
#endif
cout << endl;
}
@ -211,14 +218,12 @@ namespace cryfs {
return CryConfigLoader(_console, _keyGenerator, _scryptSettings,
&Cli::_askPasswordNoninteractive,
&Cli::_askPasswordNoninteractive,
cipher, blocksizeBytes, missingBlockIsIntegrityViolation,
_noninteractive).loadOrCreate(configFilePath);
cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(configFilePath);
} else {
return CryConfigLoader(_console, _keyGenerator, _scryptSettings,
&Cli::_askPasswordForExistingFilesystem,
&Cli::_askPasswordForNewFilesystem,
cipher, blocksizeBytes, missingBlockIsIntegrityViolation,
_noninteractive).loadOrCreate(configFilePath);
cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(configFilePath);
}
}
@ -295,11 +300,7 @@ namespace cryfs {
void Cli::_checkDirAccessible(const bf::path &dir, const std::string &name) {
if (!bf::exists(dir)) {
if (_noninteractive) {
//If we use the noninteractive frontend, don't ask whether to create the directory, but just fail.
throw std::runtime_error(name + " not found");
}
bool create = _console->askYesNo("Could not find " + name + ". Do you want to create it?");
bool create = _console->askYesNo("Could not find " + name + ". Do you want to create it?", false);
if (create) {
if (!bf::create_directory(dir)) {
throw std::runtime_error("Error creating "+name);

View File

@ -16,7 +16,7 @@
namespace cryfs {
class Cli final {
public:
Cli(cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, std::shared_ptr<cpputils::Console> console, std::shared_ptr<cpputils::HttpClient> httpClient);
Cli(cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, cpputils::unique_ref<cpputils::Console> console, std::shared_ptr<cpputils::HttpClient> httpClient);
int main(int argc, const char *argv[]);
private:

View File

@ -2,15 +2,24 @@
#include <cpp-utils/random/Random.h>
#include <cpp-utils/crypto/kdf/Scrypt.h>
#include <cpp-utils/network/CurlHttpClient.h>
#include <cpp-utils/io/IOStreamConsole.h>
using namespace cryfs;
using cpputils::Random;
using cpputils::SCrypt;
using cpputils::CurlHttpClient;
using std::make_shared;
using cpputils::make_unique_ref;
using cpputils::IOStreamConsole;
using std::make_shared;
using std::cerr;
int main(int argc, const char *argv[]) {
auto &keyGenerator = Random::OSRandom();
return Cli(keyGenerator, SCrypt::DefaultSettings, make_shared<IOStreamConsole>(), make_shared<CurlHttpClient>()).main(argc, argv);
try {
auto &keyGenerator = Random::OSRandom();
return Cli(keyGenerator, SCrypt::DefaultSettings, make_unique_ref<IOStreamConsole>(),
make_shared<CurlHttpClient>()).main(argc, argv);
} catch (const std::exception &e) {
cerr << "Error: " << e.what();
return EXIT_FAILURE;
}
}

View File

@ -73,8 +73,10 @@ const vector<shared_ptr<CryCipher>> CryCiphers::SUPPORTED_CIPHERS = {
make_shared<CryCipherInstance<Serpent128_CFB>>(INTEGRITY_WARNING),
make_shared<CryCipherInstance<Cast256_GCM>>(),
make_shared<CryCipherInstance<Cast256_CFB>>(INTEGRITY_WARNING),
#if CRYPTOPP_VERSION != 564
make_shared<CryCipherInstance<Mars448_GCM>>(),
make_shared<CryCipherInstance<Mars448_CFB>>(INTEGRITY_WARNING),
#endif
make_shared<CryCipherInstance<Mars256_GCM>>(),
make_shared<CryCipherInstance<Mars256_CFB>>(INTEGRITY_WARNING),
make_shared<CryCipherInstance<Mars128_GCM>>(),

View File

@ -28,6 +28,10 @@ CryConfig::CryConfig(CryConfig &&rhs)
: _rootBlob(std::move(rhs._rootBlob)), _encKey(std::move(rhs._encKey)), _cipher(std::move(rhs._cipher)), _version(std::move(rhs._version)), _createdWithVersion(std::move(rhs._createdWithVersion)), _blocksizeBytes(rhs._blocksizeBytes), _filesystemId(std::move(rhs._filesystemId)), _exclusiveClientId(std::move(rhs._exclusiveClientId)), _hasVersionNumbers(rhs._hasVersionNumbers) {
}
CryConfig::CryConfig(const CryConfig &rhs)
: _rootBlob(rhs._rootBlob), _encKey(rhs._encKey), _cipher(rhs._cipher), _version(rhs._version), _createdWithVersion(rhs._createdWithVersion), _blocksizeBytes(rhs._blocksizeBytes), _filesystemId(rhs._filesystemId) {
}
CryConfig CryConfig::load(const Data &data) {
stringstream stream;
data.StoreToStream(stream);

View File

@ -15,6 +15,7 @@ public:
//TODO No default constructor, pass in config values instead!
CryConfig();
CryConfig(CryConfig &&rhs);
CryConfig(const CryConfig &rhs);
const std::string &RootBlob() const;
void SetRootBlob(const std::string &value);
@ -66,7 +67,7 @@ private:
bool _hasVersionNumbers;
#endif
DISALLOW_COPY_AND_ASSIGN(CryConfig);
CryConfig &operator=(const CryConfig &rhs) = delete;
};
}

View File

@ -13,8 +13,8 @@ namespace cryfs {
constexpr const char *CryConfigConsole::DEFAULT_CIPHER;
constexpr uint32_t CryConfigConsole::DEFAULT_BLOCKSIZE_BYTES;
CryConfigConsole::CryConfigConsole(shared_ptr<Console> console, bool noninteractive)
: _console(std::move(console)), _useDefaultSettings(noninteractive ? optional<bool>(true) : none) {
CryConfigConsole::CryConfigConsole(shared_ptr<Console> console)
: _console(std::move(console)), _useDefaultSettings(none) {
}
string CryConfigConsole::askCipher() {
@ -43,7 +43,7 @@ namespace cryfs {
if (warning == none) {
return true;
}
return _console->askYesNo(string() + (*warning) + " Do you want to take this cipher nevertheless?");
return _console->askYesNo(string() + (*warning) + " Do you want to take this cipher nevertheless?", true);
}
uint32_t CryConfigConsole::askBlocksizeBytes() {
@ -77,12 +77,12 @@ namespace cryfs {
}
bool CryConfigConsole::_askMissingBlockIsIntegrityViolation() const {
return _console->askYesNo("\nMost integrity checks are enabled by default. However, by default CryFS does not treat missing blocks as integrity violations.\nThat is, if CryFS finds a block missing, it will assume that this is due to a synchronization delay and not because an attacker deleted the block.\nIf you are in a single-client setting, you can let it treat missing blocks as integrity violations, which will ensure that you notice if an attacker deletes one of your files.\nHowever, in this case, you will not be able to use the file system with other devices anymore.\nDo you want to treat missing blocks as integrity violations?");
return _console->askYesNo("\nMost integrity checks are enabled by default. However, by default CryFS does not treat missing blocks as integrity violations.\nThat is, if CryFS finds a block missing, it will assume that this is due to a synchronization delay and not because an attacker deleted the block.\nIf you are in a single-client setting, you can let it treat missing blocks as integrity violations, which will ensure that you notice if an attacker deletes one of your files.\nHowever, in this case, you will not be able to use the file system with other devices anymore.\nDo you want to treat missing blocks as integrity violations?", false);
}
bool CryConfigConsole::_checkUseDefaultSettings() {
if (_useDefaultSettings == none) {
_useDefaultSettings = _console->askYesNo("Use default settings?");
_useDefaultSettings = _console->askYesNo("Use default settings?", true);
}
return *_useDefaultSettings;
}

View File

@ -9,7 +9,7 @@
namespace cryfs {
class CryConfigConsole final {
public:
CryConfigConsole(std::shared_ptr<cpputils::Console> console, bool noninteractive);
CryConfigConsole(std::shared_ptr<cpputils::Console> console);
CryConfigConsole(CryConfigConsole &&rhs) = default;
std::string askCipher();

View File

@ -17,8 +17,8 @@ using boost::none;
namespace cryfs {
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator, bool noninteractive)
:_console(console), _configConsole(console, noninteractive), _encryptionKeyGenerator(encryptionKeyGenerator) {
CryConfigCreator::CryConfigCreator(shared_ptr<Console> console, RandomGenerator &encryptionKeyGenerator)
:_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator) {
}
CryConfigCreator::ConfigCreateResult CryConfigCreator::create(const optional<string> &cipherFromCommandLine, const optional<uint32_t> &blocksizeBytesFromCommandLine, const optional<bool> &missingBlockIsIntegrityViolationFromCommandLine) {

View File

@ -11,7 +11,7 @@
namespace cryfs {
class CryConfigCreator final {
public:
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator, bool noninteractive);
CryConfigCreator(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator);
CryConfigCreator(CryConfigCreator &&rhs) = default;
struct ConfigCreateResult {

View File

@ -53,17 +53,17 @@ optional<CryConfigFile> CryConfigFile::load(const bf::path &path, const string &
return std::move(configFile);
}
CryConfigFile CryConfigFile::create(const bf::path &path, CryConfig config, const string &password, const SCryptSettings &scryptSettings) {
CryConfigFile CryConfigFile::create(const bf::path &path, const CryConfig &config, const string &password, const SCryptSettings &scryptSettings) {
if (bf::exists(path)) {
throw std::runtime_error("Config file exists already.");
}
auto result = CryConfigFile(path, std::move(config), CryConfigEncryptorFactory::deriveKey(password, scryptSettings));
auto result = CryConfigFile(path, config, CryConfigEncryptorFactory::deriveKey(password, scryptSettings));
result.save();
return result;
}
CryConfigFile::CryConfigFile(const bf::path &path, CryConfig config, unique_ref<CryConfigEncryptor> encryptor)
: _path (path), _config(std::move(config)), _encryptor(std::move(encryptor)) {
CryConfigFile::CryConfigFile(const bf::path &path, const CryConfig &config, unique_ref<CryConfigEncryptor> encryptor)
: _path (path), _config(config), _encryptor(std::move(encryptor)) {
}
void CryConfigFile::save() const {

View File

@ -14,7 +14,7 @@ namespace cryfs {
CryConfigFile(CryConfigFile &&rhs) = default;
~CryConfigFile();
static CryConfigFile create(const boost::filesystem::path &path, CryConfig config, const std::string &password, const cpputils::SCryptSettings &scryptSettings);
static CryConfigFile create(const boost::filesystem::path &path, const CryConfig &config, const std::string &password, const cpputils::SCryptSettings &scryptSettings);
static boost::optional<CryConfigFile> load(const boost::filesystem::path &path, const std::string &password);
void save() const;
@ -22,7 +22,7 @@ namespace cryfs {
const CryConfig *config() const;
private:
CryConfigFile(const boost::filesystem::path &path, CryConfig config, cpputils::unique_ref<CryConfigEncryptor> encryptor);
CryConfigFile(const boost::filesystem::path &path, const CryConfig &config, cpputils::unique_ref<CryConfigEncryptor> encryptor);
boost::filesystem::path _path;
CryConfig _config;

View File

@ -13,7 +13,6 @@ namespace bf = boost::filesystem;
using cpputils::unique_ref;
using cpputils::make_unique_ref;
using cpputils::Console;
using cpputils::IOStreamConsole;
using cpputils::Random;
using cpputils::RandomGenerator;
using cpputils::SCryptSettings;
@ -31,8 +30,8 @@ using namespace cpputils::logging;
namespace cryfs {
CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine, bool noninteractive)
: _console(console), _creator(console, keyGenerator, noninteractive), _scryptSettings(scryptSettings),
CryConfigLoader::CryConfigLoader(shared_ptr<Console> console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function<string()> askPasswordForExistingFilesystem, function<string()> askPasswordForNewFilesystem, const optional<string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine)
: _console(console), _creator(console, keyGenerator), _scryptSettings(scryptSettings),
_askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem),
_cipherFromCommandLine(cipherFromCommandLine), _blocksizeBytesFromCommandLine(blocksizeBytesFromCommandLine),
_missingBlockIsIntegrityViolationFromCommandLine(missingBlockIsIntegrityViolationFromCommandLine) {
@ -65,13 +64,13 @@ optional<CryConfigLoader::ConfigLoadResult> CryConfigLoader::_loadConfig(const b
void CryConfigLoader::_checkVersion(const CryConfig &config) {
if (gitversion::VersionCompare::isOlderThan(gitversion::VersionString(), config.Version())) {
if (!_console->askYesNo("This filesystem is for CryFS " + config.Version() + " and should not be opened with older versions. It is strongly recommended to update your CryFS version. However, if you have backed up your base directory and know what you're doing, you can continue trying to load it. Do you want to continue?")) {
throw std::runtime_error("Not trying to load file system.");
if (!_console->askYesNo("This filesystem is for CryFS " + config.Version() + " and should not be opened with older versions. It is strongly recommended to update your CryFS version. However, if you have backed up your base directory and know what you're doing, you can continue trying to load it. Do you want to continue?", false)) {
throw std::runtime_error("This filesystem is for CryFS " + config.Version() + ". Please update your CryFS version.");
}
}
if (gitversion::VersionCompare::isOlderThan(config.Version(), gitversion::VersionString())) {
if (!_console->askYesNo("This filesystem is for CryFS " + config.Version() + ". It can be migrated to CryFS " + gitversion::VersionString() + ", but afterwards couldn't be opened anymore with older versions. Do you want to migrate it?")) {
throw std::runtime_error(string() + "Not migrating file system.");
if (!_console->askYesNo("This filesystem is for CryFS " + config.Version() + ". It can be migrated to CryFS " + gitversion::VersionString() + ", but afterwards couldn't be opened anymore with older versions. Do you want to migrate it?", false)) {
throw std::runtime_error("This filesystem is for CryFS " + config.Version() + ". It has to be migrated.");
}
}
}
@ -93,7 +92,7 @@ void CryConfigLoader::_checkMissingBlocksAreIntegrityViolations(CryConfigFile *c
// If the file system is set up to treat missing blocks as integrity violations, but we're accessing from a different client, ask whether they want to disable the feature.
auto exclusiveClientId = configFile->config()->ExclusiveClientId();
if (exclusiveClientId != none && *exclusiveClientId != myClientId) {
if (!_console->askYesNo("\nThis filesystem is setup to treat missing blocks as integrity violations and therefore only works in single-client mode. You are trying to access it from a different client.\nDo you want to disable this integrity feature and stop treating missing blocks as integrity violations?\nChoosing yes will not affect the confidentiality of your data, but in future you might not notice if an attacker deletes one of your files.")) {
if (!_console->askYesNo("\nThis filesystem is setup to treat missing blocks as integrity violations and therefore only works in single-client mode. You are trying to access it from a different client.\nDo you want to disable this integrity feature and stop treating missing blocks as integrity violations?\nChoosing yes will not affect the confidentiality of your data, but in future you might not notice if an attacker deletes one of your files.", false)) {
throw std::runtime_error("File system is in single-client mode and can only be used from the client that created it.");
}
configFile->config()->SetExclusiveClientId(none);

View File

@ -13,7 +13,7 @@ namespace cryfs {
class CryConfigLoader final {
public:
CryConfigLoader(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, std::function<std::string()> askPasswordForExistingFilesystem, std::function<std::string()> askPasswordForNewFilesystem, const boost::optional<std::string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine, bool noninteractive);
CryConfigLoader(std::shared_ptr<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, std::function<std::string()> askPasswordForExistingFilesystem, std::function<std::string()> askPasswordForNewFilesystem, const boost::optional<std::string> &cipherFromCommandLine, const boost::optional<uint32_t> &blocksizeBytesFromCommandLine, const boost::optional<bool> &missingBlockIsIntegrityViolationFromCommandLine);
CryConfigLoader(CryConfigLoader &&rhs) = default;
struct ConfigLoadResult {

View File

@ -12,6 +12,7 @@
namespace cryfs {
class InnerEncryptor {
public:
virtual ~InnerEncryptor() {}
virtual InnerConfig encrypt(const cpputils::Data &plaintext) const = 0;
virtual boost::optional<cpputils::Data> decrypt(const InnerConfig &innerConfig) const = 0;
};

View File

@ -9,5 +9,5 @@ setup(name='git-version',
description='Make git version information (e.g. git tag name, git commit id, ...) available to C++ source files.',
author='Sebastian Messmer',
author_email='messmer@cryfs.org',
license='GPLv3'
license='LGPLv3'
)

View File

@ -244,9 +244,11 @@ INSTANTIATE_TYPED_TEST_CASE_P(Cast256_CFB, CipherTest, Cast256_CFB); //CFB mode
INSTANTIATE_TYPED_TEST_CASE_P(Cast256_GCM, CipherTest, Cast256_GCM);
INSTANTIATE_TYPED_TEST_CASE_P(Cast256_GCM, AuthenticatedCipherTest, Cast256_GCM);
#if CRYPTOPP_VERSION != 564
INSTANTIATE_TYPED_TEST_CASE_P(Mars448_CFB, CipherTest, Mars448_CFB); //CFB mode is not authenticated
INSTANTIATE_TYPED_TEST_CASE_P(Mars448_GCM, CipherTest, Mars448_GCM);
INSTANTIATE_TYPED_TEST_CASE_P(Mars448_GCM, AuthenticatedCipherTest, Mars448_GCM);
#endif
INSTANTIATE_TYPED_TEST_CASE_P(Mars256_CFB, CipherTest, Mars256_CFB); //CFB mode is not authenticated
INSTANTIATE_TYPED_TEST_CASE_P(Mars256_GCM, CipherTest, Mars256_GCM);
INSTANTIATE_TYPED_TEST_CASE_P(Mars256_GCM, AuthenticatedCipherTest, Mars256_GCM);
@ -275,8 +277,10 @@ TEST(CipherNameTest, TestCipherNames) {
EXPECT_EQ("cast-256-gcm", string(Cast256_GCM::NAME));
EXPECT_EQ("cast-256-cfb", string(Cast256_CFB::NAME));
#if CRYPTOPP_VERSION != 564
EXPECT_EQ("mars-448-gcm", string(Mars448_GCM::NAME));
EXPECT_EQ("mars-448-cfb", string(Mars448_CFB::NAME));
#endif
EXPECT_EQ("mars-256-gcm", string(Mars256_GCM::NAME));
EXPECT_EQ("mars-256-cfb", string(Mars256_CFB::NAME));
EXPECT_EQ("mars-128-gcm", string(Mars128_GCM::NAME));

View File

@ -19,3 +19,4 @@ add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})

View File

@ -100,8 +100,10 @@ TEST_F(CryCipherTest, CreatesCorrectEncryptedBlockStore) {
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Serpent128_CFB>("serpent-128-cfb");
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Cast256_GCM>("cast-256-gcm");
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Cast256_CFB>("cast-256-cfb");
#if CRYPTOPP_VERSION != 564
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Mars448_GCM>("mars-448-gcm");
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Mars448_CFB>("mars-448-cfb");
#endif
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Mars256_GCM>("mars-256-gcm");
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Mars256_CFB>("mars-256-cfb");
EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE<Mars128_GCM>("mars-128-gcm");
@ -121,9 +123,11 @@ TEST_F(CryCipherTest, ThereIsACipherWithIntegrityWarning) {
EXPECT_THAT(CryCiphers::find("aes-256-cfb").warning().get(), MatchesRegex(".*integrity.*"));
}
#if CRYPTOPP_VERSION != 564
TEST_F(CryCipherTest, EncryptionKeyHasCorrectSize_448) {
EXPECT_EQ(Mars448_GCM::EncryptionKey::STRING_LENGTH, CryCiphers::find("mars-448-gcm").createKey(Random::PseudoRandom()).size());
}
#endif
TEST_F(CryCipherTest, EncryptionKeyHasCorrectSize_256) {
EXPECT_EQ(AES256_GCM::EncryptionKey::STRING_LENGTH, CryCiphers::find("aes-256-gcm").createKey(Random::PseudoRandom()).size());

View File

@ -155,6 +155,7 @@ TEST_F(CryConfigCreatorTest, ChoosesEmptyRootBlobId) {
EXPECT_EQ("", config.RootBlob()); // This tells CryFS to create a new root blob
}
#if CRYPTOPP_VERSION != 564
TEST_F(CryConfigCreatorTest, ChoosesValidEncryptionKey_448) {
AnswerNoToDefaultSettings();
IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION();
@ -162,6 +163,7 @@ TEST_F(CryConfigCreatorTest, ChoosesValidEncryptionKey_448) {
CryConfig config = creator.create(none, none, none).config;
cpputils::Mars448_GCM::EncryptionKey::FromString(config.EncryptionKey()); // This crashes if invalid
}
#endif
TEST_F(CryConfigCreatorTest, ChoosesValidEncryptionKey_256) {
AnswerNoToDefaultSettings();

View File

@ -37,7 +37,7 @@ FuseTest::FuseTest(): fsimpl() {
ON_CALL(fsimpl, rename(_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, readDir(_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, utimens(_,_,_)).WillByDefault(defaultAction);
ON_CALL(fsimpl, statfs(_,_)).WillByDefault(Invoke([](const char *path, struct statvfs *result) {
ON_CALL(fsimpl, statfs(_,_)).WillByDefault(Invoke([](const char */*path*/, struct statvfs *result) {
::statvfs("/", result); // As dummy value take the values from the root filesystem
}));
ON_CALL(fsimpl, chmod(_,_)).WillByDefault(defaultAction);