diff --git a/src/cpp-utils/SizedData.h b/src/cpp-utils/SizedData.h new file mode 100644 index 00000000..11ad5fae --- /dev/null +++ b/src/cpp-utils/SizedData.h @@ -0,0 +1,10 @@ +#pragma once +#ifndef CPPUTILS_SIZEDDATA_H +#define CPPUTILS_SIZEDDATA_H + +struct SizedData { + unsigned char* data; + size_t size; +}; + +#endif diff --git a/src/cryfs-cli/Cli.cpp b/src/cryfs-cli/Cli.cpp index 62c8a117..ad7b4107 100644 --- a/src/cryfs-cli/Cli.cpp +++ b/src/cryfs-cli/Cli.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -89,9 +90,9 @@ namespace cryfs_cli { basedirMetadata.save(); } - CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options, const LocalStateDir& localStateDir, unique_ptr password) { + CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options, const LocalStateDir& localStateDir, Credentials credentials) { auto configFile = _determineConfigFile(options); - auto config = _loadOrCreateConfigFile(std::move(configFile), localStateDir, std::move(password), options.cipher(), options.blocksizeBytes(), options.allowFilesystemUpgrade(), options.missingBlockIsIntegrityViolation(), options.allowReplacedFilesystem()); + auto config = _loadOrCreateConfigFile(std::move(configFile), localStateDir, credentials, options.cipher(), options.blocksizeBytes(), options.allowFilesystemUpgrade(), options.missingBlockIsIntegrityViolation(), options.allowReplacedFilesystem()); if (config.is_left()) { switch(config.left()) { case CryConfigFile::LoadError::DecryptionFailed: @@ -104,24 +105,30 @@ namespace cryfs_cli { return std::move(config.right()); } - either Cli::_loadOrCreateConfigFile(bf::path configFilePath, LocalStateDir localStateDir, unique_ptr password, const optional &cipher, const optional &blocksizeBytes, bool allowFilesystemUpgrade, const optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem) { - // TODO Instead of passing in _askPasswordXXX functions to KeyProvider, only pass in console and move logic to the key provider, - // for example by having a separate CryPasswordBasedKeyProvider / CryNoninteractivePasswordBasedKeyProvider. - auto keyProvider = make_unique_ref( - *password.get(), - make_unique_ref(_scryptSettings) - ); - return CryConfigLoader(_keyGenerator, std::move(keyProvider), std::move(localStateDir), cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(std::move(configFilePath), allowFilesystemUpgrade, allowReplacedFilesystem); + unique_ref Cli::_createKeyProvider(Credentials credentials) { + if (credentials.password == none) { + return make_unique_ref(credentials.givenHash); + } else { + return make_unique_ref( + *credentials.password, + make_unique_ref(_scryptSettings), + credentials.returnedHash + ); + } } - fspp::fuse::Fuse* Cli::initFilesystem(const ProgramOptions &options, unique_ptr password) { + either Cli::_loadOrCreateConfigFile(bf::path configFilePath, LocalStateDir localStateDir, Credentials credentials, const optional &cipher, const optional &blocksizeBytes, bool allowFilesystemUpgrade, const optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem) { + return CryConfigLoader(_keyGenerator, _createKeyProvider(credentials), std::move(localStateDir), cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(std::move(configFilePath), allowFilesystemUpgrade, allowReplacedFilesystem); + } + + fspp::fuse::Fuse* Cli::initFilesystem(const ProgramOptions &options, Credentials credentials) { cpputils::showBacktraceOnCrash(); cpputils::set_thread_name("cryfs"); try { _sanityChecks(options); LocalStateDir localStateDir(options.localStateDir()); auto blockStore = make_unique_ref(options.baseDir()); - auto config = _loadOrCreateConfig(options, localStateDir, std::move(password)); + auto config = _loadOrCreateConfig(options, localStateDir, credentials); fspp::fuse::Fuse* fuse = nullptr; auto onIntegrityViolation = [&fuse] () { diff --git a/src/cryfs-cli/Cli.h b/src/cryfs-cli/Cli.h index 40236eff..0a991ec1 100644 --- a/src/cryfs-cli/Cli.h +++ b/src/cryfs-cli/Cli.h @@ -5,11 +5,13 @@ #include #include "program_options/ProgramOptions.h" #include +#include #include #include #include #include #include +#include #include #include "CallAfterTimeout.h" #include @@ -18,16 +20,20 @@ namespace cryfs_cli { class Cli final { public: + struct Credentials { + boost::optional password; + SizedData givenHash; + SizedData* returnedHash; + }; Cli(cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings& scryptSettings); - fspp::fuse::Fuse* initFilesystem(const program_options::ProgramOptions &options, std::unique_ptr password); + fspp::fuse::Fuse* initFilesystem(const program_options::ProgramOptions &options, Credentials credentials); private: - void _checkForUpdates(cpputils::unique_ref httpClient); - cryfs::CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options, const cryfs::LocalStateDir& localStateDir, std::unique_ptr password); + cryfs::CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options, const cryfs::LocalStateDir& localStateDir, Credentials credentials); void _checkConfigIntegrity(const boost::filesystem::path& basedir, const cryfs::LocalStateDir& localStateDir, const cryfs::CryConfigFile& config, bool allowReplacedFilesystem); - cpputils::either _loadOrCreateConfigFile(boost::filesystem::path configFilePath, cryfs::LocalStateDir localStateDir, std::unique_ptr password, const boost::optional &cipher, const boost::optional &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem); + cpputils::unique_ref _createKeyProvider(Credentials credentials); + cpputils::either _loadOrCreateConfigFile(boost::filesystem::path configFilePath, cryfs::LocalStateDir localStateDir, Credentials credentials, const boost::optional &cipher, const boost::optional &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem); boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options); - void _initLogfile(); void _sanityChecks(const program_options::ProgramOptions &options); void _checkDirAccessible(const boost::filesystem::path &dir, const std::string &name, bool createMissingDir, cryfs::ErrorCode errorCode); void _sanityCheckFilesystem(cryfs::CryDevice *device); diff --git a/src/cryfs/CMakeLists.txt b/src/cryfs/CMakeLists.txt index 10b56865..c2c0c837 100644 --- a/src/cryfs/CMakeLists.txt +++ b/src/cryfs/CMakeLists.txt @@ -19,6 +19,7 @@ set(LIB_SOURCES impl/config/CryKeyProvider.cpp impl/config/CryPasswordBasedKeyProvider.cpp impl/config/CryPresetPasswordBasedKeyProvider.cpp + impl/config/CryDirectKeyProvider.cpp impl/filesystem/CryOpenFile.cpp impl/filesystem/fsblobstore/utils/DirEntry.cpp impl/filesystem/fsblobstore/utils/DirEntryList.cpp diff --git a/src/cryfs/impl/config/CryDirectKeyProvider.cpp b/src/cryfs/impl/config/CryDirectKeyProvider.cpp new file mode 100644 index 00000000..72d62c47 --- /dev/null +++ b/src/cryfs/impl/config/CryDirectKeyProvider.cpp @@ -0,0 +1,18 @@ +#include "CryDirectKeyProvider.h" + +namespace cryfs { + + CryDirectKeyProvider::CryDirectKeyProvider(SizedData encryptionKey) : _encryptionKey(encryptionKey) {} + + cpputils::EncryptionKey CryDirectKeyProvider::requestKeyForExistingFilesystem(size_t keySize, const cpputils::Data& kdfParameters) { + ASSERT(_encryptionKey.size == keySize, "CryDirectKeyProvider: Invalid key size requested"); + cpputils::EncryptionKey encryptionKey = cpputils::EncryptionKey::Null(_encryptionKey.size); + memcpy(encryptionKey.data(), _encryptionKey.data, _encryptionKey.size); + return encryptionKey; + } + + CryKeyProvider::KeyResult CryDirectKeyProvider::requestKeyForNewFilesystem(size_t keySize) { + throw std::logic_error("CryDirectKeyProvider can't be used for new filesystems"); + } + +} diff --git a/src/cryfs/impl/config/CryDirectKeyProvider.h b/src/cryfs/impl/config/CryDirectKeyProvider.h new file mode 100644 index 00000000..bcc172c8 --- /dev/null +++ b/src/cryfs/impl/config/CryDirectKeyProvider.h @@ -0,0 +1,25 @@ +#pragma once +#ifndef CRYFS_CRYDIRECTKEYPROVIDER_H +#define CRYFS_CRYDIRECTKEYPROVIDER_H + +#include "CryKeyProvider.h" +#include + +namespace cryfs { + + class CryDirectKeyProvider final : public CryKeyProvider { + public: + explicit CryDirectKeyProvider(SizedData encryptionKey); + + cpputils::EncryptionKey requestKeyForExistingFilesystem(size_t keySize, const cpputils::Data& kdfParameters) override; + KeyResult requestKeyForNewFilesystem(size_t keySize) override; + + private: + SizedData _encryptionKey; + + DISALLOW_COPY_AND_ASSIGN(CryDirectKeyProvider); + }; + +} + +#endif \ No newline at end of file diff --git a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp index 9eddf4aa..d8d460be 100644 --- a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp +++ b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp @@ -8,15 +8,24 @@ using cpputils::Data; namespace cryfs { -CryPresetPasswordBasedKeyProvider::CryPresetPasswordBasedKeyProvider(std::string password, unique_ref kdf) -: _password(std::move(password)), _kdf(std::move(kdf)) {} +CryPresetPasswordBasedKeyProvider::CryPresetPasswordBasedKeyProvider(std::string password, unique_ref kdf, SizedData* returnedHash) +: _password(std::move(password)), _kdf(std::move(kdf)), _returnedHash(returnedHash) {} EncryptionKey CryPresetPasswordBasedKeyProvider::requestKeyForExistingFilesystem(size_t keySize, const Data& kdfParameters) { - return _kdf->deriveExistingKey(keySize, _password, kdfParameters); + EncryptionKey encryptionKey = _kdf->deriveExistingKey(keySize, _password, kdfParameters); + if (_returnedHash != nullptr) { + _returnedHash->data = static_cast(encryptionKey.data()); + _returnedHash->size = encryptionKey.binaryLength(); + } + return encryptionKey; } CryPresetPasswordBasedKeyProvider::KeyResult CryPresetPasswordBasedKeyProvider::requestKeyForNewFilesystem(size_t keySize) { auto keyResult = _kdf->deriveNewKey(keySize, _password); + if (_returnedHash != nullptr) { + _returnedHash->data = static_cast(keyResult.key.data()); + _returnedHash->size = keyResult.key.binaryLength(); + } return {std::move(keyResult.key), std::move(keyResult.kdfParameters)}; } diff --git a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h index d41b8720..373b1ed9 100644 --- a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h +++ b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h @@ -5,12 +5,17 @@ #include "CryKeyProvider.h" #include #include +#include namespace cryfs { class CryPresetPasswordBasedKeyProvider final : public CryKeyProvider { public: - explicit CryPresetPasswordBasedKeyProvider(std::string password, cpputils::unique_ref kdf); + explicit CryPresetPasswordBasedKeyProvider( + std::string password, + cpputils::unique_ref kdf, + SizedData* returnedHash + ); cpputils::EncryptionKey requestKeyForExistingFilesystem(size_t keySize, const cpputils::Data& kdfParameters) override; KeyResult requestKeyForNewFilesystem(size_t keySize) override; @@ -18,6 +23,7 @@ namespace cryfs { private: std::string _password; cpputils::unique_ref _kdf; + SizedData* _returnedHash; DISALLOW_COPY_AND_ASSIGN(CryPresetPasswordBasedKeyProvider); }; diff --git a/src/jni/include/libcryfs-jni.h b/src/jni/include/libcryfs-jni.h index c1acdad4..3b7b1bb4 100644 --- a/src/jni/include/libcryfs-jni.h +++ b/src/jni/include/libcryfs-jni.h @@ -1,6 +1,8 @@ #include -jlong cryfs_init(JNIEnv* env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword, jboolean createBaseDir, jstring jcipher); +jlong cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword, + jbyteArray jgivenHash, jobject returnedHash, jboolean createBaseDir, + jstring jcipher); jlong cryfs_create(JNIEnv* env, jlong fusePtr, jstring jpath, mode_t mode); jlong cryfs_open(JNIEnv* env, jlong fusePtr, jstring jpath, jint flags); jint cryfs_read(JNIEnv* env, jlong fusePtr, jlong fileHandle, jbyteArray jbuffer, jlong offset); diff --git a/src/jni/libcryfs-jni.cpp b/src/jni/libcryfs-jni.cpp index c8264600..d1aeaa42 100644 --- a/src/jni/libcryfs-jni.cpp +++ b/src/jni/libcryfs-jni.cpp @@ -2,8 +2,6 @@ #include #include -using std::unique_ptr; -using std::make_unique; using boost::none; using cpputils::Random; using cpputils::SCrypt; @@ -13,7 +11,10 @@ using fspp::fuse::Fuse; std::set validFusePtrs; -extern "C" jlong cryfs_init(JNIEnv* env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpassword, jboolean createBaseDir, jstring jcipher) { +extern "C" jlong +cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpassword, + jbyteArray jgivenHash, jobject jreturnedHash, jboolean createBaseDir, + jstring jcipher) { const char* baseDir = env->GetStringUTFChars(jbaseDir, NULL); const char* localStateDir = env->GetStringUTFChars(jlocalStateDir, NULL); boost::optional cipher = none; @@ -22,19 +23,40 @@ extern "C" jlong cryfs_init(JNIEnv* env, jstring jbaseDir, jstring jlocalStateDi cipher = boost::optional(cipherName); env->ReleaseStringUTFChars(jcipher, cipherName); } - auto &keyGenerator = Random::OSRandom(); + auto &keyGenerator = Random::OSRandom(); ProgramOptions options = ProgramOptions(baseDir, none, localStateDir, false, false, createBaseDir, cipher, none, false, none); - char* password = reinterpret_cast(env->GetByteArrayElements(jpassword, NULL)); - - Fuse* fuse = Cli(keyGenerator, SCrypt::DefaultSettings).initFilesystem(options, make_unique(password)); - - env->ReleaseByteArrayElements(jpassword, reinterpret_cast(password), 0); env->ReleaseStringUTFChars(jbaseDir, baseDir); env->ReleaseStringUTFChars(jlocalStateDir, localStateDir); + struct SizedData returnedHash; + struct Cli::Credentials credentials; + credentials.returnedHash = nullptr; + if (jpassword == NULL) { + credentials.password = none; + credentials.givenHash.data = reinterpret_cast(env->GetByteArrayElements(jgivenHash, NULL)); + credentials.givenHash.size = env->GetArrayLength(jgivenHash); + } else { + jbyte* password = env->GetByteArrayElements(jpassword, NULL); + credentials.password = string(reinterpret_cast(password)); + env->ReleaseByteArrayElements(jpassword, password, 0); + if (jreturnedHash != NULL) { + credentials.returnedHash = &returnedHash; + } + } + Fuse* fuse = Cli(keyGenerator, SCrypt::DefaultSettings).initFilesystem(options, credentials); + + if (jpassword == NULL) { + env->ReleaseByteArrayElements(jgivenHash, reinterpret_cast(credentials.givenHash.data), 0); + } jlong fusePtr = reinterpret_cast(fuse); if (fusePtr != 0) { validFusePtrs.insert(fusePtr); + if (credentials.returnedHash != nullptr) { + jfieldID value = env->GetFieldID(env->GetObjectClass(jreturnedHash), "value", "Ljava/lang/Object;"); + jbyteArray jpasswordHash = env->NewByteArray(returnedHash.size); + env->SetByteArrayRegion(jpasswordHash, 0, returnedHash.size, reinterpret_cast(returnedHash.data)); + env->SetObjectField(jreturnedHash, value, jpasswordHash); + } } return fusePtr; }