From c5be03ad3abea3aef5b0fcc5aa3af8cba2befdd1 Mon Sep 17 00:00:00 2001 From: Hardcore Sushi Date: Wed, 29 Jun 2022 19:16:45 +0200 Subject: [PATCH] libcryfs: Allow changing volume password --- src/cryfs/impl/config/CryConfigLoader.cpp | 11 ++- src/cryfs/impl/config/CryConfigLoader.h | 1 + .../CryPresetPasswordBasedKeyProvider.cpp | 18 ++--- .../CryPresetPasswordBasedKeyProvider.h | 2 + src/jni/include/libcryfs-jni.h | 4 ++ src/jni/libcryfs-jni.cpp | 69 +++++++++++++++++-- 6 files changed, 89 insertions(+), 16 deletions(-) diff --git a/src/cryfs/impl/config/CryConfigLoader.cpp b/src/cryfs/impl/config/CryConfigLoader.cpp index 0d335a7f..b600f6df 100644 --- a/src/cryfs/impl/config/CryConfigLoader.cpp +++ b/src/cryfs/impl/config/CryConfigLoader.cpp @@ -93,8 +93,6 @@ void CryConfigLoader::_checkMissingBlocksAreIntegrityViolations(CryConfigFile *c auto exclusiveClientId = configFile->config()->ExclusiveClientId(); if (exclusiveClientId != none && *exclusiveClientId != myClientId) { throw CryfsException("File system is in single-client mode and can only be used from the client that created it.", ErrorCode::SingleClientFileSystem); - configFile->config()->SetExclusiveClientId(none); - configFile->save(); } } @@ -110,6 +108,15 @@ either CryConfigLoa } } +boost::optional CryConfigLoader::changeEncryptionKey(bf::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, unique_ref newKeyProvider) { + auto config = _loadConfig(filename, allowFilesystemUpgrade, allowReplacedFilesystem, CryConfigFile::Access::ReadWrite); + if (config.is_left()) { + return config.left(); + } + CryConfigFile(filename, *config.right().configFile->config(), CryConfigEncryptorFactory::deriveNewKey(newKeyProvider.get()), CryConfigFile::Access::ReadWrite).save(); + return none; +} + CryConfigLoader::ConfigLoadResult CryConfigLoader::_createConfig(bf::path filename, bool allowReplacedFilesystem) { auto config = _creator.create(_cipherFromCommandLine, _blocksizeBytesFromCommandLine, _missingBlockIsIntegrityViolationFromCommandLine, allowReplacedFilesystem); auto result = CryConfigFile::create(std::move(filename), config.config, _keyProvider.get()); diff --git a/src/cryfs/impl/config/CryConfigLoader.h b/src/cryfs/impl/config/CryConfigLoader.h index f07e54b1..c209f9a4 100644 --- a/src/cryfs/impl/config/CryConfigLoader.h +++ b/src/cryfs/impl/config/CryConfigLoader.h @@ -26,6 +26,7 @@ public: cpputils::either loadOrCreate(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem); cpputils::either load(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, CryConfigFile::Access access); + boost::optional changeEncryptionKey(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, cpputils::unique_ref newKeyProvider); private: cpputils::either _loadConfig(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, CryConfigFile::Access access); diff --git a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp index d8d460be..2e90afd2 100644 --- a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp +++ b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.cpp @@ -11,21 +11,23 @@ namespace cryfs { CryPresetPasswordBasedKeyProvider::CryPresetPasswordBasedKeyProvider(std::string password, unique_ref kdf, SizedData* returnedHash) : _password(std::move(password)), _kdf(std::move(kdf)), _returnedHash(returnedHash) {} +void CryPresetPasswordBasedKeyProvider::saveEncryptionKey(EncryptionKey encryptionKey) { + if (_returnedHash != nullptr) { + _returnedHash->size = encryptionKey.binaryLength(); + _returnedHash->data = new unsigned char[_returnedHash->size]; + memcpy(_returnedHash->data, encryptionKey.data(), _returnedHash->size); + } +} + EncryptionKey CryPresetPasswordBasedKeyProvider::requestKeyForExistingFilesystem(size_t keySize, const Data& kdfParameters) { EncryptionKey encryptionKey = _kdf->deriveExistingKey(keySize, _password, kdfParameters); - if (_returnedHash != nullptr) { - _returnedHash->data = static_cast(encryptionKey.data()); - _returnedHash->size = encryptionKey.binaryLength(); - } + saveEncryptionKey(encryptionKey); 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(); - } + saveEncryptionKey(keyResult.key); 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 373b1ed9..389b864d 100644 --- a/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h +++ b/src/cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h @@ -21,6 +21,8 @@ namespace cryfs { KeyResult requestKeyForNewFilesystem(size_t keySize) override; private: + void saveEncryptionKey(cpputils::EncryptionKey encryptionKey); + std::string _password; cpputils::unique_ref _kdf; SizedData* _returnedHash; diff --git a/src/jni/include/libcryfs-jni.h b/src/jni/include/libcryfs-jni.h index 3b7b1bb4..3673f429 100644 --- a/src/jni/include/libcryfs-jni.h +++ b/src/jni/include/libcryfs-jni.h @@ -3,6 +3,10 @@ jlong cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword, jbyteArray jgivenHash, jobject returnedHash, jboolean createBaseDir, jstring jcipher); +jboolean cryfs_change_encryption_key(JNIEnv *env, + jstring jbaseDir, jstring jlocalStateDir, + jbyteArray jcurrentPassword, jbyteArray jgivenHash, + jbyteArray jnewPassword, jobject jreturnedHash); 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 d1aeaa42..d678943e 100644 --- a/src/jni/libcryfs-jni.cpp +++ b/src/jni/libcryfs-jni.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include using boost::none; using cpputils::Random; @@ -11,6 +14,14 @@ using fspp::fuse::Fuse; std::set validFusePtrs; +void setReturnedPasswordHash(JNIEnv* env, jobject jreturnedHash, const SizedData& returnedHash) { + 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)); + delete[] returnedHash.data; + env->SetObjectField(jreturnedHash, value, jpasswordHash); +} + extern "C" jlong cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpassword, jbyteArray jgivenHash, jobject jreturnedHash, jboolean createBaseDir, @@ -48,19 +59,65 @@ cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpa if (jpassword == NULL) { env->ReleaseByteArrayElements(jgivenHash, reinterpret_cast(credentials.givenHash.data), 0); } + if (credentials.returnedHash != nullptr) { + setReturnedPasswordHash(env, jreturnedHash, returnedHash); + } 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; } +extern "C" jboolean cryfs_change_encryption_key(JNIEnv* env, jstring jbaseDir, jstring jlocalStateDir, + jbyteArray jcurrentPassword, jbyteArray jgivenHash, + jbyteArray jnewPassword, jobject jreturnedHash) { + using namespace cryfs; + + const char* baseDir = env->GetStringUTFChars(jbaseDir, NULL); + const char* localStateDir = env->GetStringUTFChars(jlocalStateDir, NULL); + + struct SizedData givenHash; + std::unique_ptr currentKeyProvider; + if (jcurrentPassword == NULL) { + givenHash.data = reinterpret_cast(env->GetByteArrayElements(jgivenHash, NULL)); + givenHash.size = env->GetArrayLength(jgivenHash); + currentKeyProvider = std::make_unique(givenHash); + } else { + jbyte* currentPassword = env->GetByteArrayElements(jcurrentPassword, NULL); + currentKeyProvider = std::make_unique( + reinterpret_cast(currentPassword), + cpputils::make_unique_ref(SCrypt::DefaultSettings), + nullptr + ); + env->ReleaseByteArrayElements(jcurrentPassword, currentPassword, 0); + } + struct SizedData returnedHash = {nullptr, 0}; + jbyte* newPassword = env->GetByteArrayElements(jnewPassword, NULL); + cpputils::unique_ref newKeyProvider = cpputils::make_unique_ref( + reinterpret_cast(newPassword), + cpputils::make_unique_ref(SCrypt::DefaultSettings), + jreturnedHash == NULL ? nullptr : &returnedHash + ); + env->ReleaseByteArrayElements(jnewPassword, newPassword, 0); + CryConfigLoader configLoader = CryConfigLoader( + Random::OSRandom(), std::move(*cpputils::nullcheck(std::move(currentKeyProvider))), + LocalStateDir(localStateDir), none, none, none + ); + env->ReleaseStringUTFChars(jlocalStateDir, localStateDir); + + auto result = configLoader.changeEncryptionKey(boost::filesystem::path(baseDir) / "cryfs.config", false, false, std::move(newKeyProvider)); + + if (jcurrentPassword == NULL) { + env->ReleaseByteArrayElements(jgivenHash, reinterpret_cast(givenHash.data), 0); + } + env->ReleaseStringUTFChars(jbaseDir, baseDir); + if (returnedHash.data != nullptr) { + setReturnedPasswordHash(env, jreturnedHash, returnedHash); + } + return result == none; +} + extern "C" jlong cryfs_create(JNIEnv* env, jlong fusePtr, jstring jpath, mode_t mode) { Fuse* fuse = reinterpret_cast(fusePtr); const char* path = env->GetStringUTFChars(jpath, NULL);