diff --git a/biicode.conf b/biicode.conf index 886c80b5..152e1e20 100644 --- a/biicode.conf +++ b/biicode.conf @@ -10,6 +10,7 @@ messmer/fspp: 1 messmer/gitversion: 5 messmer/parallelaccessstore: 1 + messmer/scrypt: 0 [parent] messmer/cryfs: 3 diff --git a/src/config/crypto/DerivedKey.cpp b/src/config/crypto/DerivedKey.cpp new file mode 100644 index 00000000..7968d456 --- /dev/null +++ b/src/config/crypto/DerivedKey.cpp @@ -0,0 +1 @@ +#include "DerivedKey.h" diff --git a/src/config/crypto/DerivedKey.h b/src/config/crypto/DerivedKey.h new file mode 100644 index 00000000..b6b77c0b --- /dev/null +++ b/src/config/crypto/DerivedKey.h @@ -0,0 +1,31 @@ +#pragma once +#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_DERIVEDKEY_H +#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_DERIVEDKEY_H + +#include +#include "DerivedKeyConfig.h" + +namespace cryfs { + + template + class DerivedKey { + public: + DerivedKey(DerivedKeyConfig config, const cpputils::FixedSizeData &key): _config(std::move(config)), _key(key) {} + DerivedKey(DerivedKey &&rhs) = default; + + const DerivedKeyConfig &config() const { + return _config; + } + + const cpputils::FixedSizeData &key() const { + return _key; + } + private: + DerivedKeyConfig _config; + cpputils::FixedSizeData _key; + + DISALLOW_COPY_AND_ASSIGN(DerivedKey); + }; +} + +#endif diff --git a/src/config/crypto/DerivedKeyConfig.cpp b/src/config/crypto/DerivedKeyConfig.cpp new file mode 100644 index 00000000..12fde801 --- /dev/null +++ b/src/config/crypto/DerivedKeyConfig.cpp @@ -0,0 +1 @@ +#include "DerivedKeyConfig.h" diff --git a/src/config/crypto/DerivedKeyConfig.h b/src/config/crypto/DerivedKeyConfig.h new file mode 100644 index 00000000..55f86dc1 --- /dev/null +++ b/src/config/crypto/DerivedKeyConfig.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KEYCONFIG_H +#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KEYCONFIG_H + +#include + +namespace cryfs { + + class DerivedKeyConfig { + public: + DerivedKeyConfig(cpputils::Data salt, uint64_t N, uint32_t r, uint32_t p) + : _salt(std::move(salt)), + _N(N), _r(r), _p(p) { } + + DerivedKeyConfig(DerivedKeyConfig &&rhs) = default; + + const cpputils::Data &salt() const { + return _salt; + } + + size_t N() const { + return _N; + } + + size_t r() const { + return _r; + } + + size_t p() const { + return _p; + } + + private: + cpputils::Data _salt; + uint64_t _N; + uint32_t _r; + uint32_t _p; + + DISALLOW_COPY_AND_ASSIGN(DerivedKeyConfig); + }; + +} + +#endif diff --git a/src/config/crypto/Scrypt.cpp b/src/config/crypto/Scrypt.cpp new file mode 100644 index 00000000..e37292cf --- /dev/null +++ b/src/config/crypto/Scrypt.cpp @@ -0,0 +1,8 @@ +#include "Scrypt.h" + +namespace cryfs { + constexpr size_t SCrypt::SALT_LEN; + constexpr uint64_t SCrypt::N; + constexpr uint32_t SCrypt::r; + constexpr uint32_t SCrypt::p; +} \ No newline at end of file diff --git a/src/config/crypto/Scrypt.h b/src/config/crypto/Scrypt.h new file mode 100644 index 00000000..dd110216 --- /dev/null +++ b/src/config/crypto/Scrypt.h @@ -0,0 +1,49 @@ +#pragma once +#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_SCRYPT_H +#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_SCRYPT_H + +#include +#include +extern "C" { + #include +} +#include +#include "DerivedKey.h" + +namespace cryfs { + + class SCrypt { + public: + //TODO Make user-configurable. For sensitive storage, N=1048576, r=8 is recommended. + constexpr static size_t SALT_LEN = 32; // Size of the salt + constexpr static uint64_t N = 524288; // CPU/Memory cost + constexpr static uint32_t r = 1; // Blocksize + constexpr static uint32_t p = 1; // Parallelization + + SCrypt() {} + + template DerivedKey generateKey(const std::string &password) { + auto salt = cpputils::Random::PseudoRandom().get(SALT_LEN); + auto config = DerivedKeyConfig(std::move(salt), N, r, p); + auto key = generateKeyFromConfig(password, config); + return DerivedKey(std::move(config), key); + } + + template cpputils::FixedSizeData generateKeyFromConfig(const std::string &password, const DerivedKeyConfig &config) { + auto key = cpputils::FixedSizeData::Null(); + int errorcode = crypto_scrypt(reinterpret_cast(password.c_str()), password.size(), + reinterpret_cast(config.salt().data()), config.salt().size(), + config.N(), config.r(), config.p(), + static_cast(key.data()), KEYSIZE); + if (errorcode != 0) { + throw std::runtime_error("Error running scrypt key derivation."); + } + return key; + } + + private: + DISALLOW_COPY_AND_ASSIGN(SCrypt); + }; +} + +#endif diff --git a/test/config/crypto/DerivedKeyConfigTest.cpp b/test/config/crypto/DerivedKeyConfigTest.cpp new file mode 100644 index 00000000..e4c92e4c --- /dev/null +++ b/test/config/crypto/DerivedKeyConfigTest.cpp @@ -0,0 +1,51 @@ +#include +#include "../../../src/config/crypto/DerivedKeyConfig.h" +#include + +using namespace cryfs; +using cpputils::DataFixture; +using cpputils::Data; + +TEST(DerivedKeyConfigTest, Salt) { + DerivedKeyConfig cfg(DataFixture::generate(32), 0, 0, 0); + EXPECT_EQ(DataFixture::generate(32), cfg.salt()); +} + +TEST(DerivedKeyConfigTest, Salt_Move) { + DerivedKeyConfig cfg(DataFixture::generate(32), 0, 0, 0); + DerivedKeyConfig moved = std::move(cfg); + EXPECT_EQ(DataFixture::generate(32), moved.salt()); +} + +TEST(DerivedKeyConfigTest, N) { + DerivedKeyConfig cfg(Data(0), 1024, 0, 0); + EXPECT_EQ(1024, cfg.N()); +} + +TEST(DerivedKeyConfigTest, N_Move) { + DerivedKeyConfig cfg(Data(0), 1024, 0, 0); + DerivedKeyConfig moved = std::move(cfg); + EXPECT_EQ(1024, moved.N()); +} + +TEST(DerivedKeyConfigTest, r) { + DerivedKeyConfig cfg(Data(0), 0, 8, 0); + EXPECT_EQ(8, cfg.r()); +} + +TEST(DerivedKeyConfigTest, r_Move) { + DerivedKeyConfig cfg(Data(0), 0, 8, 0); + DerivedKeyConfig moved = std::move(cfg); + EXPECT_EQ(8, moved.r()); +} + +TEST(DerivedKeyConfigTest, p) { + DerivedKeyConfig cfg(Data(0), 0, 0, 16); + EXPECT_EQ(16, cfg.p()); +} + +TEST(DerivedKeyConfigTest, p_Move) { + DerivedKeyConfig cfg(Data(0), 0, 0, 16); + DerivedKeyConfig moved = std::move(cfg); + EXPECT_EQ(16, moved.p()); +} diff --git a/test/config/crypto/DerivedKeyTest.cpp b/test/config/crypto/DerivedKeyTest.cpp new file mode 100644 index 00000000..8dcce5e1 --- /dev/null +++ b/test/config/crypto/DerivedKeyTest.cpp @@ -0,0 +1,20 @@ +#include +#include "../../../src/config/crypto/DerivedKey.h" +#include + +using namespace cryfs; +using cpputils::DataFixture; +using cpputils::Data; + +TEST(DerivedKeyTest, Config) { + DerivedKey<32> key(DerivedKeyConfig(DataFixture::generate(32, 1), 1024, 8, 16), DataFixture::generateFixedSize<32>(2)); + EXPECT_EQ(DataFixture::generate(32, 1), key.config().salt()); + EXPECT_EQ(1024, key.config().N()); + EXPECT_EQ(8, key.config().r()); + EXPECT_EQ(16, key.config().p()); +} + +TEST(DerivedKeyTest, Key) { + DerivedKey<32> key(DerivedKeyConfig(DataFixture::generate(32, 1), 1024, 8, 16), DataFixture::generateFixedSize<32>(2)); + EXPECT_EQ(DataFixture::generateFixedSize<32>(2), key.key()); +} diff --git a/test/config/crypto/SCryptTest.cpp b/test/config/crypto/SCryptTest.cpp new file mode 100644 index 00000000..49ede455 --- /dev/null +++ b/test/config/crypto/SCryptTest.cpp @@ -0,0 +1,36 @@ +#include +#include "../../../src/config/crypto/Scrypt.h" + +using namespace cryfs; + +TEST(SCryptTest, GeneratedKeyIsReproductible_448) { + auto created = SCrypt().generateKey<56>("mypassword"); + auto recreated = SCrypt().generateKeyFromConfig<56>("mypassword", created.config()); + EXPECT_EQ(created.key(), recreated); +} + +TEST(SCryptTest, GeneratedKeyIsReproductible_256) { + auto created = SCrypt().generateKey<32>("mypassword"); + auto recreated = SCrypt().generateKeyFromConfig<32>("mypassword", created.config()); + EXPECT_EQ(created.key(), recreated); +} + +TEST(SCryptTest, GeneratedKeyIsReproductible_128) { + auto created = SCrypt().generateKey<16>("mypassword"); + auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword", created.config()); + EXPECT_EQ(created.key(), recreated); +} + +TEST(SCryptTest, DifferentPasswordResultsInDifferentKey) { + auto created = SCrypt().generateKey<16>("mypassword"); + auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword2", created.config()); + EXPECT_NE(created.key(), recreated); +} + +TEST(SCryptTest, UsesCorrectDefaultParameters) { + auto created = SCrypt().generateKey<16>("mypassword"); + EXPECT_EQ(SCrypt::SALT_LEN, created.config().salt().size()); + EXPECT_EQ(SCrypt::N, created.config().N()); + EXPECT_EQ(SCrypt::r, created.config().r()); + EXPECT_EQ(SCrypt::p, created.config().p()); +}