Added a crypto library with scrypt key derivation function and random padding
This commit is contained in:
parent
64397978e0
commit
7b269a1184
@ -5,6 +5,7 @@
|
||||
google/gmock: 4
|
||||
google/gtest: 11
|
||||
messmer/cmake: 3
|
||||
messmer/scrypt: 0
|
||||
messmer/spdlog: 1
|
||||
|
||||
[parent]
|
||||
|
32
crypto/RandomPadding.cpp
Normal file
32
crypto/RandomPadding.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "RandomPadding.h"
|
||||
#include "../logging/logging.h"
|
||||
#include "../random/Random.h"
|
||||
|
||||
using boost::optional;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cpputils {
|
||||
Data RandomPadding::add(const Data &data, size_t targetSize) {
|
||||
uint32_t size = data.size();
|
||||
ASSERT(size < targetSize - sizeof(size), "Config data too large. We should increase padding target size.");
|
||||
Data randomData = Random::PseudoRandom().get(targetSize-sizeof(size)-size);
|
||||
ASSERT(sizeof(size) + size + randomData.size() == targetSize, "Calculated size of randomData incorrectly");
|
||||
Data result(targetSize);
|
||||
std::memcpy(reinterpret_cast<char*>(result.data()), &size, sizeof(size));
|
||||
std::memcpy(reinterpret_cast<char*>(result.dataOffset(sizeof(size))), reinterpret_cast<const char*>(data.data()), size);
|
||||
std::memcpy(reinterpret_cast<char*>(result.dataOffset(sizeof(size)+size)), reinterpret_cast<const char*>(randomData.data()), randomData.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<Data> RandomPadding::remove(const Data &data) {
|
||||
uint32_t size;
|
||||
std::memcpy(&size, reinterpret_cast<const char*>(data.data()), sizeof(size));
|
||||
if(sizeof(size) + size >= data.size()) {
|
||||
LOG(ERROR) << "Config file is invalid: Invalid padding.";
|
||||
return boost::none;
|
||||
};
|
||||
Data result(size);
|
||||
std::memcpy(reinterpret_cast<char*>(result.data()), reinterpret_cast<const char*>(data.dataOffset(sizeof(size))), size);
|
||||
return std::move(result);
|
||||
}
|
||||
}
|
17
crypto/RandomPadding.h
Normal file
17
crypto/RandomPadding.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_CRYPTO_RANDOMPADDING_H
|
||||
#define MESSMER_CPPUTILS_CRYPTO_RANDOMPADDING_H
|
||||
|
||||
#include "../data/Data.h"
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace cpputils {
|
||||
//TODO Test
|
||||
class RandomPadding {
|
||||
public:
|
||||
static Data add(const Data &data, size_t targetSize);
|
||||
static boost::optional<Data> remove(const Data &data);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
1
crypto/kdf/DerivedKey.cpp
Normal file
1
crypto/kdf/DerivedKey.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "DerivedKey.h"
|
39
crypto/kdf/DerivedKey.h
Normal file
39
crypto/kdf/DerivedKey.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_CRYPTO_KDF_DERIVEDKEY_H
|
||||
#define MESSMER_CPPUTILS_CRYPTO_KDF_DERIVEDKEY_H
|
||||
|
||||
#include "../../data/FixedSizeData.h"
|
||||
#include "DerivedKeyConfig.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
template<size_t KEY_LENGTH>
|
||||
class DerivedKey {
|
||||
public:
|
||||
DerivedKey(DerivedKeyConfig config, const FixedSizeData<KEY_LENGTH> &key): _config(std::move(config)), _key(key) {}
|
||||
DerivedKey(DerivedKey &&rhs) = default;
|
||||
|
||||
const DerivedKeyConfig &config() const {
|
||||
return _config;
|
||||
}
|
||||
|
||||
DerivedKeyConfig moveOutConfig() {
|
||||
return std::move(_config);
|
||||
}
|
||||
|
||||
const FixedSizeData<KEY_LENGTH> &key() const {
|
||||
return _key;
|
||||
}
|
||||
|
||||
FixedSizeData<KEY_LENGTH> moveOutKey() {
|
||||
return std::move(_key);
|
||||
}
|
||||
private:
|
||||
DerivedKeyConfig _config;
|
||||
FixedSizeData<KEY_LENGTH> _key;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DerivedKey);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
27
crypto/kdf/DerivedKeyConfig.cpp
Normal file
27
crypto/kdf/DerivedKeyConfig.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "DerivedKeyConfig.h"
|
||||
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
|
||||
namespace cpputils {
|
||||
void DerivedKeyConfig::serialize(Serializer *target) const {
|
||||
target->writeData(_salt);
|
||||
target->writeUint64(_N);
|
||||
target->writeUint32(_r);
|
||||
target->writeUint32(_p);
|
||||
}
|
||||
|
||||
size_t DerivedKeyConfig::serializedSize() const {
|
||||
return Serializer::DataSize(_salt) + sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t);
|
||||
}
|
||||
|
||||
DerivedKeyConfig DerivedKeyConfig::load(Deserializer *source) {
|
||||
Data salt = source->readData();
|
||||
uint64_t N = source->readUint64();
|
||||
uint32_t r = source->readUint32();
|
||||
uint32_t p = source->readUint32();
|
||||
return DerivedKeyConfig(std::move(salt), N, r, p);
|
||||
}
|
||||
}
|
51
crypto/kdf/DerivedKeyConfig.h
Normal file
51
crypto/kdf/DerivedKeyConfig.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_CRYPTO_KDF_KEYCONFIG_H
|
||||
#define MESSMER_CPPUTILS_CRYPTO_KDF_KEYCONFIG_H
|
||||
|
||||
#include "../../data/Data.h"
|
||||
#include "../../data/Serializer.h"
|
||||
#include "../../data/Deserializer.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
class DerivedKeyConfig {
|
||||
public:
|
||||
DerivedKeyConfig(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 Data &salt() const {
|
||||
return _salt;
|
||||
}
|
||||
|
||||
size_t N() const {
|
||||
return _N;
|
||||
}
|
||||
|
||||
size_t r() const {
|
||||
return _r;
|
||||
}
|
||||
|
||||
size_t p() const {
|
||||
return _p;
|
||||
}
|
||||
|
||||
void serialize(Serializer *destination) const;
|
||||
|
||||
size_t serializedSize() const;
|
||||
|
||||
static DerivedKeyConfig load(Deserializer *source);
|
||||
|
||||
private:
|
||||
Data _salt;
|
||||
uint64_t _N;
|
||||
uint32_t _r;
|
||||
uint32_t _p;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
13
crypto/kdf/Scrypt.cpp
Normal file
13
crypto/kdf/Scrypt.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "Scrypt.h"
|
||||
|
||||
namespace cpputils {
|
||||
constexpr size_t SCryptDefaultSettings::SALT_LEN;
|
||||
constexpr uint64_t SCryptDefaultSettings::N;
|
||||
constexpr uint32_t SCryptDefaultSettings::r;
|
||||
constexpr uint32_t SCryptDefaultSettings::p;
|
||||
|
||||
constexpr size_t SCryptParanoidSettings::SALT_LEN;
|
||||
constexpr uint64_t SCryptParanoidSettings::N;
|
||||
constexpr uint32_t SCryptParanoidSettings::r;
|
||||
constexpr uint32_t SCryptParanoidSettings::p;
|
||||
}
|
57
crypto/kdf/Scrypt.h
Normal file
57
crypto/kdf/Scrypt.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_CRYPTO_KDF_SCRYPT_H
|
||||
#define MESSMER_CPPUTILS_CRYPTO_KDF_SCRYPT_H
|
||||
|
||||
#include "../../macros.h"
|
||||
#include "../../random/Random.h"
|
||||
extern "C" {
|
||||
#include <messmer/scrypt/lib/crypto/crypto_scrypt.h>
|
||||
}
|
||||
#include <stdexcept>
|
||||
#include "DerivedKey.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
struct SCryptParanoidSettings {
|
||||
constexpr static size_t SALT_LEN = 32; // Size of the salt
|
||||
constexpr static uint64_t N = 1048576; // CPU/Memory cost
|
||||
constexpr static uint32_t r = 8; // Blocksize
|
||||
constexpr static uint32_t p = 16; // Parallelization
|
||||
};
|
||||
|
||||
struct SCryptDefaultSettings {
|
||||
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
|
||||
};
|
||||
|
||||
class SCrypt {
|
||||
public:
|
||||
SCrypt() {}
|
||||
|
||||
template<size_t KEYSIZE, class Settings = SCryptDefaultSettings> DerivedKey<KEYSIZE> generateKey(const std::string &password) {
|
||||
auto salt = Random::PseudoRandom().get(Settings::SALT_LEN);
|
||||
auto config = DerivedKeyConfig(std::move(salt), Settings::N, Settings::r, Settings::p);
|
||||
auto key = generateKeyFromConfig<KEYSIZE>(password, config);
|
||||
return DerivedKey<KEYSIZE>(std::move(config), key);
|
||||
}
|
||||
|
||||
template<size_t KEYSIZE> FixedSizeData<KEYSIZE> generateKeyFromConfig(const std::string &password, const DerivedKeyConfig &config) {
|
||||
auto key = FixedSizeData<KEYSIZE>::Null();
|
||||
int errorcode = crypto_scrypt(reinterpret_cast<const uint8_t*>(password.c_str()), password.size(),
|
||||
reinterpret_cast<const uint8_t*>(config.salt().data()), config.salt().size(),
|
||||
config.N(), config.r(), config.p(),
|
||||
static_cast<uint8_t*>(key.data()), KEYSIZE);
|
||||
if (errorcode != 0) {
|
||||
throw std::runtime_error("Error running scrypt key derivation.");
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(SCrypt);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
86
test/crypto/kdf/DerivedKeyConfigTest.cpp
Normal file
86
test/crypto/kdf/DerivedKeyConfigTest.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include "../../../crypto/kdf/DerivedKeyConfig.h"
|
||||
#include "../../../data/DataFixture.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace cpputils;
|
||||
|
||||
class DerivedKeyConfigTest : public ::testing::Test {
|
||||
public:
|
||||
DerivedKeyConfig SaveAndLoad(const DerivedKeyConfig &source) {
|
||||
Serializer serializer(source.serializedSize());
|
||||
source.serialize(&serializer);
|
||||
Data serialized = serializer.finished();
|
||||
Deserializer deserializer(&serialized);
|
||||
return DerivedKeyConfig::load(&deserializer);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, Salt) {
|
||||
DerivedKeyConfig cfg(DataFixture::generate(32), 0, 0, 0);
|
||||
EXPECT_EQ(DataFixture::generate(32), cfg.salt());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, Salt_Move) {
|
||||
DerivedKeyConfig cfg(DataFixture::generate(32), 0, 0, 0);
|
||||
DerivedKeyConfig moved = std::move(cfg);
|
||||
EXPECT_EQ(DataFixture::generate(32), moved.salt());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, Salt_SaveAndLoad) {
|
||||
DerivedKeyConfig cfg(DataFixture::generate(32), 0, 0, 0);
|
||||
DerivedKeyConfig loaded = SaveAndLoad(cfg);
|
||||
EXPECT_EQ(DataFixture::generate(32), loaded.salt());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, N) {
|
||||
DerivedKeyConfig cfg(Data(0), 1024, 0, 0);
|
||||
EXPECT_EQ(1024, cfg.N());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, N_Move) {
|
||||
DerivedKeyConfig cfg(Data(0), 1024, 0, 0);
|
||||
DerivedKeyConfig moved = std::move(cfg);
|
||||
EXPECT_EQ(1024, moved.N());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, N_SaveAndLoad) {
|
||||
DerivedKeyConfig cfg(Data(0), 1024, 0, 0);
|
||||
DerivedKeyConfig loaded = SaveAndLoad(cfg);
|
||||
EXPECT_EQ(1024, loaded.N());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, r) {
|
||||
DerivedKeyConfig cfg(Data(0), 0, 8, 0);
|
||||
EXPECT_EQ(8, cfg.r());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, r_Move) {
|
||||
DerivedKeyConfig cfg(Data(0), 0, 8, 0);
|
||||
DerivedKeyConfig moved = std::move(cfg);
|
||||
EXPECT_EQ(8, moved.r());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, r_SaveAndLoad) {
|
||||
DerivedKeyConfig cfg(Data(0), 0, 8, 0);
|
||||
DerivedKeyConfig loaded = SaveAndLoad(cfg);
|
||||
EXPECT_EQ(8, loaded.r());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, p) {
|
||||
DerivedKeyConfig cfg(Data(0), 0, 0, 16);
|
||||
EXPECT_EQ(16, cfg.p());
|
||||
}
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, p_Move) {
|
||||
DerivedKeyConfig cfg(Data(0), 0, 0, 16);
|
||||
DerivedKeyConfig moved = std::move(cfg);
|
||||
EXPECT_EQ(16, moved.p());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(DerivedKeyConfigTest, p_SaveAndLoad) {
|
||||
DerivedKeyConfig cfg(Data(0), 0, 0, 16);
|
||||
DerivedKeyConfig loaded = SaveAndLoad(cfg);
|
||||
EXPECT_EQ(16, loaded.p());
|
||||
}
|
20
test/crypto/kdf/DerivedKeyTest.cpp
Normal file
20
test/crypto/kdf/DerivedKeyTest.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include "../../../crypto/kdf/DerivedKey.h"
|
||||
#include "../../../data/DataFixture.h"
|
||||
|
||||
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());
|
||||
}
|
51
test/crypto/kdf/SCryptTest.cpp
Normal file
51
test/crypto/kdf/SCryptTest.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include "../../../crypto/kdf/Scrypt.h"
|
||||
#include "testutils/SCryptTestSettings.h"
|
||||
|
||||
using namespace cryfs;
|
||||
|
||||
TEST(SCryptTest, GeneratedKeyIsReproductible_448) {
|
||||
auto created = SCrypt().generateKey<56, SCryptTestSettings>("mypassword");
|
||||
auto recreated = SCrypt().generateKeyFromConfig<56>("mypassword", created.config());
|
||||
EXPECT_EQ(created.key(), recreated);
|
||||
}
|
||||
|
||||
TEST(SCryptTest, GeneratedKeyIsReproductible_256) {
|
||||
auto created = SCrypt().generateKey<32, SCryptTestSettings>("mypassword");
|
||||
auto recreated = SCrypt().generateKeyFromConfig<32>("mypassword", created.config());
|
||||
EXPECT_EQ(created.key(), recreated);
|
||||
}
|
||||
|
||||
TEST(SCryptTest, GeneratedKeyIsReproductible_128) {
|
||||
auto created = SCrypt().generateKey<16, SCryptTestSettings>("mypassword");
|
||||
auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword", created.config());
|
||||
EXPECT_EQ(created.key(), recreated);
|
||||
}
|
||||
|
||||
TEST(SCryptTest, GeneratedKeyIsReproductible_DefaultSettings) {
|
||||
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, SCryptTestSettings>("mypassword");
|
||||
auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword2", created.config());
|
||||
EXPECT_NE(created.key(), recreated);
|
||||
}
|
||||
|
||||
TEST(SCryptTest, UsesCorrectSettings) {
|
||||
auto created = SCrypt().generateKey<16, SCryptTestSettings>("mypassword");
|
||||
EXPECT_EQ(SCryptTestSettings::SALT_LEN, created.config().salt().size());
|
||||
EXPECT_EQ(SCryptTestSettings::N, created.config().N());
|
||||
EXPECT_EQ(SCryptTestSettings::r, created.config().r());
|
||||
EXPECT_EQ(SCryptTestSettings::p, created.config().p());
|
||||
}
|
||||
|
||||
TEST(SCryptTest, UsesCorrectDefaultSettings) {
|
||||
auto created = SCrypt().generateKey<16>("mypassword");
|
||||
EXPECT_EQ(SCryptDefaultSettings::SALT_LEN, created.config().salt().size());
|
||||
EXPECT_EQ(SCryptDefaultSettings::N, created.config().N());
|
||||
EXPECT_EQ(SCryptDefaultSettings::r, created.config().r());
|
||||
EXPECT_EQ(SCryptDefaultSettings::p, created.config().p());
|
||||
}
|
6
test/crypto/kdf/testutils/SCryptTestSettings.cpp
Normal file
6
test/crypto/kdf/testutils/SCryptTestSettings.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "SCryptTestSettings.h"
|
||||
|
||||
constexpr size_t SCryptTestSettings::SALT_LEN;
|
||||
constexpr uint64_t SCryptTestSettings::N;
|
||||
constexpr uint32_t SCryptTestSettings::r;
|
||||
constexpr uint32_t SCryptTestSettings::p;
|
14
test/crypto/kdf/testutils/SCryptTestSettings.h
Normal file
14
test/crypto/kdf/testutils/SCryptTestSettings.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef MESSMER_CPPUTILS_TEST_CRYPTO_KDF_TESTUTILS_SCRYPTTESTSETTINGS_H
|
||||
#define MESSMER_CPPUTILS_TEST_CRYPTO_KDF_TESTUTILS_SCRYPTTESTSETTINGS_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
struct SCryptTestSettings {
|
||||
constexpr static size_t SALT_LEN = 32; // Size of the salt
|
||||
constexpr static uint64_t N = 1024; // CPU/Memory cost
|
||||
constexpr static uint32_t r = 1; // Blocksize
|
||||
constexpr static uint32_t p = 1; // Parallelization
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user