libcryfs: Allow changing volume password

This commit is contained in:
Matéo Duparc 2022-06-29 19:16:45 +02:00
parent cf822d6a5b
commit c5be03ad3a
Signed by: hardcoresushi
GPG Key ID: AFE384344A45E13A
6 changed files with 89 additions and 16 deletions

View File

@ -93,8 +93,6 @@ void CryConfigLoader::_checkMissingBlocksAreIntegrityViolations(CryConfigFile *c
auto exclusiveClientId = configFile->config()->ExclusiveClientId(); auto exclusiveClientId = configFile->config()->ExclusiveClientId();
if (exclusiveClientId != none && *exclusiveClientId != myClientId) { 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); 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<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> CryConfigLoa
} }
} }
boost::optional<CryConfigFile::LoadError> CryConfigLoader::changeEncryptionKey(bf::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, unique_ref<CryKeyProvider> 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) { CryConfigLoader::ConfigLoadResult CryConfigLoader::_createConfig(bf::path filename, bool allowReplacedFilesystem) {
auto config = _creator.create(_cipherFromCommandLine, _blocksizeBytesFromCommandLine, _missingBlockIsIntegrityViolationFromCommandLine, allowReplacedFilesystem); auto config = _creator.create(_cipherFromCommandLine, _blocksizeBytesFromCommandLine, _missingBlockIsIntegrityViolationFromCommandLine, allowReplacedFilesystem);
auto result = CryConfigFile::create(std::move(filename), config.config, _keyProvider.get()); auto result = CryConfigFile::create(std::move(filename), config.config, _keyProvider.get());

View File

@ -26,6 +26,7 @@ public:
cpputils::either<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> loadOrCreate(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem); cpputils::either<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> loadOrCreate(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem);
cpputils::either<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> load(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, CryConfigFile::Access access); cpputils::either<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> load(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, CryConfigFile::Access access);
boost::optional<CryConfigFile::LoadError> changeEncryptionKey(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, cpputils::unique_ref<CryKeyProvider> newKeyProvider);
private: private:
cpputils::either<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> _loadConfig(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, CryConfigFile::Access access); cpputils::either<CryConfigFile::LoadError, CryConfigLoader::ConfigLoadResult> _loadConfig(boost::filesystem::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem, CryConfigFile::Access access);

View File

@ -11,21 +11,23 @@ namespace cryfs {
CryPresetPasswordBasedKeyProvider::CryPresetPasswordBasedKeyProvider(std::string password, unique_ref<PasswordBasedKDF> kdf, SizedData* returnedHash) CryPresetPasswordBasedKeyProvider::CryPresetPasswordBasedKeyProvider(std::string password, unique_ref<PasswordBasedKDF> kdf, SizedData* returnedHash)
: _password(std::move(password)), _kdf(std::move(kdf)), _returnedHash(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 CryPresetPasswordBasedKeyProvider::requestKeyForExistingFilesystem(size_t keySize, const Data& kdfParameters) {
EncryptionKey encryptionKey = _kdf->deriveExistingKey(keySize, _password, kdfParameters); EncryptionKey encryptionKey = _kdf->deriveExistingKey(keySize, _password, kdfParameters);
if (_returnedHash != nullptr) { saveEncryptionKey(encryptionKey);
_returnedHash->data = static_cast<unsigned char*>(encryptionKey.data());
_returnedHash->size = encryptionKey.binaryLength();
}
return encryptionKey; return encryptionKey;
} }
CryPresetPasswordBasedKeyProvider::KeyResult CryPresetPasswordBasedKeyProvider::requestKeyForNewFilesystem(size_t keySize) { CryPresetPasswordBasedKeyProvider::KeyResult CryPresetPasswordBasedKeyProvider::requestKeyForNewFilesystem(size_t keySize) {
auto keyResult = _kdf->deriveNewKey(keySize, _password); auto keyResult = _kdf->deriveNewKey(keySize, _password);
if (_returnedHash != nullptr) { saveEncryptionKey(keyResult.key);
_returnedHash->data = static_cast<unsigned char*>(keyResult.key.data());
_returnedHash->size = keyResult.key.binaryLength();
}
return {std::move(keyResult.key), std::move(keyResult.kdfParameters)}; return {std::move(keyResult.key), std::move(keyResult.kdfParameters)};
} }

View File

@ -21,6 +21,8 @@ namespace cryfs {
KeyResult requestKeyForNewFilesystem(size_t keySize) override; KeyResult requestKeyForNewFilesystem(size_t keySize) override;
private: private:
void saveEncryptionKey(cpputils::EncryptionKey encryptionKey);
std::string _password; std::string _password;
cpputils::unique_ref<cpputils::PasswordBasedKDF> _kdf; cpputils::unique_ref<cpputils::PasswordBasedKDF> _kdf;
SizedData* _returnedHash; SizedData* _returnedHash;

View File

@ -3,6 +3,10 @@
jlong cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword, jlong cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword,
jbyteArray jgivenHash, jobject returnedHash, jboolean createBaseDir, jbyteArray jgivenHash, jobject returnedHash, jboolean createBaseDir,
jstring jcipher); 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_create(JNIEnv* env, jlong fusePtr, jstring jpath, mode_t mode);
jlong cryfs_open(JNIEnv* env, jlong fusePtr, jstring jpath, jint flags); jlong cryfs_open(JNIEnv* env, jlong fusePtr, jstring jpath, jint flags);
jint cryfs_read(JNIEnv* env, jlong fusePtr, jlong fileHandle, jbyteArray jbuffer, jlong offset); jint cryfs_read(JNIEnv* env, jlong fusePtr, jlong fileHandle, jbyteArray jbuffer, jlong offset);

View File

@ -1,6 +1,9 @@
#include <jni.h> #include <jni.h>
#include <cryfs-cli/Cli.h> #include <cryfs-cli/Cli.h>
#include <fspp/fuse/Fuse.h> #include <fspp/fuse/Fuse.h>
#include <cryfs/impl/config/CryKeyProvider.h>
#include <cryfs/impl/config/CryDirectKeyProvider.h>
#include <cryfs/impl/config/CryPresetPasswordBasedKeyProvider.h>
using boost::none; using boost::none;
using cpputils::Random; using cpputils::Random;
@ -11,6 +14,14 @@ using fspp::fuse::Fuse;
std::set<jlong> validFusePtrs; std::set<jlong> 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<const jbyte*>(returnedHash.data));
delete[] returnedHash.data;
env->SetObjectField(jreturnedHash, value, jpasswordHash);
}
extern "C" jlong extern "C" jlong
cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpassword, cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpassword,
jbyteArray jgivenHash, jobject jreturnedHash, jboolean createBaseDir, jbyteArray jgivenHash, jobject jreturnedHash, jboolean createBaseDir,
@ -48,19 +59,65 @@ cryfs_init(JNIEnv *env, jstring jbaseDir, jstring jlocalStateDir, jbyteArray jpa
if (jpassword == NULL) { if (jpassword == NULL) {
env->ReleaseByteArrayElements(jgivenHash, reinterpret_cast<jbyte*>(credentials.givenHash.data), 0); env->ReleaseByteArrayElements(jgivenHash, reinterpret_cast<jbyte*>(credentials.givenHash.data), 0);
} }
if (credentials.returnedHash != nullptr) {
setReturnedPasswordHash(env, jreturnedHash, returnedHash);
}
jlong fusePtr = reinterpret_cast<jlong>(fuse); jlong fusePtr = reinterpret_cast<jlong>(fuse);
if (fusePtr != 0) { if (fusePtr != 0) {
validFusePtrs.insert(fusePtr); 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<const jbyte*>(returnedHash.data));
env->SetObjectField(jreturnedHash, value, jpasswordHash);
}
} }
return fusePtr; 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<CryKeyProvider> currentKeyProvider;
if (jcurrentPassword == NULL) {
givenHash.data = reinterpret_cast<unsigned char*>(env->GetByteArrayElements(jgivenHash, NULL));
givenHash.size = env->GetArrayLength(jgivenHash);
currentKeyProvider = std::make_unique<CryDirectKeyProvider>(givenHash);
} else {
jbyte* currentPassword = env->GetByteArrayElements(jcurrentPassword, NULL);
currentKeyProvider = std::make_unique<CryPresetPasswordBasedKeyProvider>(
reinterpret_cast<const char*>(currentPassword),
cpputils::make_unique_ref<SCrypt>(SCrypt::DefaultSettings),
nullptr
);
env->ReleaseByteArrayElements(jcurrentPassword, currentPassword, 0);
}
struct SizedData returnedHash = {nullptr, 0};
jbyte* newPassword = env->GetByteArrayElements(jnewPassword, NULL);
cpputils::unique_ref<CryKeyProvider> newKeyProvider = cpputils::make_unique_ref<CryPresetPasswordBasedKeyProvider>(
reinterpret_cast<const char*>(newPassword),
cpputils::make_unique_ref<SCrypt>(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<jbyte*>(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) { extern "C" jlong cryfs_create(JNIEnv* env, jlong fusePtr, jstring jpath, mode_t mode) {
Fuse* fuse = reinterpret_cast<Fuse*>(fusePtr); Fuse* fuse = reinterpret_cast<Fuse*>(fusePtr);
const char* path = env->GetStringUTFChars(jpath, NULL); const char* path = env->GetStringUTFChars(jpath, NULL);