Added a crypto library with scrypt key derivation function and random padding

This commit is contained in:
Sebastian Messmer 2015-10-27 22:19:06 +01:00
parent 64397978e0
commit 7b269a1184
14 changed files with 415 additions and 0 deletions

View File

@ -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
View 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
View 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

View File

@ -0,0 +1 @@
#include "DerivedKey.h"

39
crypto/kdf/DerivedKey.h Normal file
View 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

View 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);
}
}

View 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
View 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
View 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

View 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());
}

View 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());
}

View 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());
}

View 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;

View 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