Implemented a key class

This commit is contained in:
Leonetienne 2022-05-22 13:43:23 +02:00
parent bb76cbb2d7
commit 9fdc642bd6
No known key found for this signature in database
GPG Key ID: C33879CD92E9708C
13 changed files with 100 additions and 95 deletions

View File

@ -3,6 +3,7 @@
#include <GCrypt/SecureBitset.h> #include <GCrypt/SecureBitset.h>
#include <GCrypt/Util.h> #include <GCrypt/Util.h>
#include <GCrypt/InitializationVector.h> #include <GCrypt/InitializationVector.h>
#include <GCrypt/Key.h>
using namespace Leonetienne::GCrypt; using namespace Leonetienne::GCrypt;
@ -14,11 +15,11 @@ void ExampleString() {
std::cout << input << std::endl; std::cout << input << std::endl;
// Encrypt // Encrypt
const std::string encrypted = GWrapper::EncryptString(input, "password1"); const std::string encrypted = GWrapper::EncryptString(input, Key::FromPassword("password1"));
std::cout << encrypted << std::endl; std::cout << encrypted << std::endl;
// Decrypt // Decrypt
const std::string decrypted = GWrapper::DecryptString(encrypted, "password1"); const std::string decrypted = GWrapper::DecryptString(encrypted, Key::FromPassword("password1"));
std::cout << decrypted << std::endl; std::cout << decrypted << std::endl;
return; return;
@ -28,10 +29,10 @@ void ExampleFiles() {
std::cout << "Example on how to encrypt & decrypt any file:" << std::endl; std::cout << "Example on how to encrypt & decrypt any file:" << std::endl;
// Encrypt // Encrypt
GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1"); GWrapper::EncryptFile("main.cpp", "main.cpp.crypt", Key::FromPassword("password1"));
// Decrypt // Decrypt
GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1"); GWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", Key::FromPassword("password1"));
return; return;
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "GCrypt/Keyset.h" #include "GCrypt/Keyset.h"
#include "GCrypt/Block.h" #include "GCrypt/Block.h"
#include "GCrypt/Key.h"
#include "GCrypt/Halfblock.h" #include "GCrypt/Halfblock.h"
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
@ -8,7 +9,7 @@ namespace Leonetienne::GCrypt {
*/ */
class Feistel { class Feistel {
public: public:
explicit Feistel(const Block& key); explicit Feistel(const Key& key);
Feistel(const Feistel& other) = delete; Feistel(const Feistel& other) = delete;
Feistel(Feistel&& other) noexcept = delete; Feistel(Feistel&& other) noexcept = delete;
@ -17,7 +18,7 @@ namespace Leonetienne::GCrypt {
//! Will set the seed-key for this feistel network. //! Will set the seed-key for this feistel network.
//! Roundkeys will be derived from this. //! Roundkeys will be derived from this.
void SetKey(const Block& key); void SetKey(const Key& key);
//! Will encipher a data block via the set seed-key //! Will encipher a data block via the set seed-key
Block Encipher(const Block& data); Block Encipher(const Block& data);
@ -31,7 +32,7 @@ namespace Leonetienne::GCrypt {
Block Run(const Block& data, bool reverseKeys); Block Run(const Block& data, bool reverseKeys);
//! Arbitrary cipher function //! Arbitrary cipher function
static Halfblock F(Halfblock m, const Block& key); static Halfblock F(Halfblock m, const Key& key);
//! Split a data block into two half blocks (into L and R) //! Split a data block into two half blocks (into L and R)
static std::pair<Halfblock, Halfblock> FeistelSplit(const Block& block); static std::pair<Halfblock, Halfblock> FeistelSplit(const Block& block);
@ -49,7 +50,7 @@ namespace Leonetienne::GCrypt {
static std::string SBox(const std::string& in); static std::string SBox(const std::string& in);
//! Will generate a the round keys //! Will generate a the round keys
void GenerateRoundKeys(const Block& seedKey); void GenerateRoundKeys(const Key& seedKey);
//! Will zero the memory used by the keyset //! Will zero the memory used by the keyset
void ZeroKeyMemory(); void ZeroKeyMemory();

View File

@ -14,22 +14,16 @@ namespace Leonetienne::GCrypt {
}; };
//! Will initialize this cipher with a key //! Will initialize this cipher with a key
explicit GCipher(const Block& key, const DIRECTION direction); explicit GCipher(const Key& key, const DIRECTION direction);
//! Will initialize this cipher with a key
explicit GCipher(const std::string& password, const DIRECTION direction);
// Disable copying // Disable copying
GCipher(const GCipher& other) = delete; GCipher(const GCipher& other) = delete;
GCipher(GCipher&& other) noexcept = delete; GCipher(GCipher&& other) noexcept = delete;
~GCipher();
//! Will digest a data block, and return it //! Will digest a data block, and return it
Block Digest(const Block& input); Block Digest(const Block& input);
private: private:
Block key;
const DIRECTION direction; const DIRECTION direction;
//! The feistel instance to be used //! The feistel instance to be used
@ -37,8 +31,5 @@ namespace Leonetienne::GCrypt {
//! The last block, required for CBC. //! The last block, required for CBC.
Block lastBlock; Block lastBlock;
//! Will zero the memory used by the key
void ZeroKeyMemory();
}; };
} }

View File

@ -3,6 +3,8 @@
#include "GCrypt/Flexblock.h" #include "GCrypt/Flexblock.h"
#include "GCrypt/Block.h" #include "GCrypt/Block.h"
#include "GCrypt/GCipher.h" #include "GCrypt/GCipher.h"
#include "GCrypt/Key.h"
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
/** This class is a wrapper to make working with the GhettoCipher /** This class is a wrapper to make working with the GhettoCipher
@ -11,25 +13,25 @@ namespace Leonetienne::GCrypt {
class GWrapper { class GWrapper {
public: public:
//! Will encrypt a string and return it hexadecimally encoded. //! Will encrypt a string and return it hexadecimally encoded.
static std::string EncryptString(const std::string& cleartext, const std::string& password); static std::string EncryptString(const std::string& cleartext, const Key& key);
//! Will decrypt a hexadecimally encoded string. //! Will decrypt a hexadecimally encoded string.
static std::string DecryptString(const std::string& ciphertext, const std::string& password); static std::string DecryptString(const std::string& ciphertext, const Key& key);
//! Will encrypt a file. //! Will encrypt a file.
//! Returns false if anything goes wrong (like, file-access). //! Returns false if anything goes wrong (like, file-access).
//! @filename_in The file to be read. //! @filename_in The file to be read.
//! @filename_out The file the encrypted version should be saved in. //! @filename_out The file the encrypted version should be saved in.
static bool EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); static bool EncryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false);
//! Will decrypt a file. //! Will decrypt a file.
//! Returns false if anything goes wrong (like, file-access). //! Returns false if anything goes wrong (like, file-access).
//! @filename_in The file to be read. //! @filename_in The file to be read.
//! @filename_out The file the decrypted version should be saved in. //! @filename_out The file the decrypted version should be saved in.
static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false);
//! Will enncrypt or decrypt an entire flexblock of binary data, given a key. //! Will enncrypt or decrypt an entire flexblock of binary data, given a key.
static Flexblock CipherFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction); static Flexblock CipherFlexblock(const Flexblock& data, const Key& key, const GCipher::DIRECTION direction);
private: private:

View File

@ -0,0 +1,26 @@
#ifndef GCRYPT_KEY_H
#define GCRYPT_KEY_H
#include "GCrypt/Block.h"
#include <string>
namespace Leonetienne::GCrypt {
/* This class represents encryption keys.
You can copy them, create them from data blocks,
or even read from files (to be implemented).
*/
class Key : public Block {
public:
static Key FromPassword(const std::string& password);
Key();
Key(const Key& k);
Key(const Block& b);
private:
};
}
#endif

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include <array> #include <array>
#include "GCrypt/Block.h" #include "GCrypt/Key.h"
#include "GCrypt/Config.h" #include "GCrypt/Config.h"
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
typedef std::array<Block, N_ROUNDS> Keyset; typedef std::array<Key, N_ROUNDS> Keyset;
} }

View File

@ -227,9 +227,6 @@ namespace Leonetienne::GCrypt {
return ss.str(); return ss.str();
} }
//! Creates a key of size BLOCK_SIZE from a password of arbitrary length.
Block PasswordToKey(const std::string& in);
//! Will read a file into a flexblock //! Will read a file into a flexblock
inline Flexblock ReadFileToBits(const std::string& filepath) { inline Flexblock ReadFileToBits(const std::string& filepath) {
// Read file // Read file

View File

@ -5,7 +5,7 @@
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
Feistel::Feistel(const Block& key) { Feistel::Feistel(const Key& key) {
SetKey(key); SetKey(key);
return; return;
} }
@ -16,7 +16,7 @@ namespace Leonetienne::GCrypt {
return; return;
} }
void Feistel::SetKey(const Block& key) { void Feistel::SetKey(const Key& key) {
GenerateRoundKeys(key); GenerateRoundKeys(key);
return; return;
} }
@ -59,7 +59,7 @@ namespace Leonetienne::GCrypt {
return FeistelCombine(r, l); return FeistelCombine(r, l);
} }
Halfblock Feistel::F(Halfblock m, const Block& key) { Halfblock Feistel::F(Halfblock m, const Key& key) {
// Made-up F function // Made-up F function
// Expand to full bitwidth // Expand to full bitwidth
@ -174,7 +174,7 @@ namespace Leonetienne::GCrypt {
return subMap[in]; return subMap[in];
} }
void Feistel::GenerateRoundKeys(const Block& seedKey) { void Feistel::GenerateRoundKeys(const Key& seedKey) {
// Clear initial key memory // Clear initial key memory
ZeroKeyMemory(); ZeroKeyMemory();
roundKeys = Keyset(); roundKeys = Keyset();
@ -234,7 +234,7 @@ namespace Leonetienne::GCrypt {
Halfblock halfkey1 = F(halfkeys.first, roundKeys[i - 2]); Halfblock halfkey1 = F(halfkeys.first, roundKeys[i - 2]);
Halfblock halfkey2 = halfkeys.second ^ halfkey1; // I know this is reversible, but it helps to diffuse future round keys. Halfblock halfkey2 = halfkeys.second ^ halfkey1; // I know this is reversible, but it helps to diffuse future round keys.
roundKeys[i] = FeistelCombine(halfkey1, halfkey2); roundKeys[i] = Key(FeistelCombine(halfkey1, halfkey2));
} }
return; return;
@ -248,7 +248,7 @@ namespace Leonetienne::GCrypt {
#pragma GCC optimize ("O0") #pragma GCC optimize ("O0")
#endif #endif
void Feistel::ZeroKeyMemory() { void Feistel::ZeroKeyMemory() {
for (Block& key : roundKeys) { for (Key& key : roundKeys) {
key.reset(); key.reset();
} }

View File

@ -7,9 +7,8 @@
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
GCipher::GCipher(const Block& key, const DIRECTION direction) GCipher::GCipher(const Key& key, const DIRECTION direction)
: :
key { key },
direction { direction }, direction { direction },
lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key
feistel(key) { feistel(key) {
@ -17,22 +16,6 @@ namespace Leonetienne::GCrypt {
return; return;
} }
GCipher::GCipher(const std::string& password, const DIRECTION direction)
:
key { PasswordToKey(password) },
direction { direction },
lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) {
feistel(key) {
return;
}
GCipher::~GCipher() {
// Clear key memory
ZeroKeyMemory();
return;
}
Block GCipher::Digest(const Block& input) { Block GCipher::Digest(const Block& input) {
switch (direction) { switch (direction) {
@ -67,23 +50,5 @@ namespace Leonetienne::GCrypt {
throw std::runtime_error("Unreachable branch reached."); throw std::runtime_error("Unreachable branch reached.");
} }
// These pragmas only work for MSVC and g++, as far as i know. Beware!!!
#if defined _WIN32 || defined _WIN64
#pragma optimize("", off )
#elif defined __GNUG__
#pragma GCC push_options
#pragma GCC optimize ("O0")
#endif
void GCipher::ZeroKeyMemory() {
key.reset();
return;
}
#if defined _WIN32 || defined _WIN64
#pragma optimize("", on )
#elif defined __GNUG__
#pragma GCC pop_options
#endif
} }

View File

@ -7,7 +7,9 @@ namespace Leonetienne::GCrypt {
GHash::GHash() : GHash::GHash() :
// Initialize our cipher with a static, but randomly distributed key. // Initialize our cipher with a static, but randomly distributed key.
cipher( cipher(
StringToBitblock("CfRtNdMTP4Y5CWRd"), // Can't use Key::FromPassword here, because it depends on GHash.
// Instead use a hardcoded key.
Key(StringToBitblock("CfRtNdMTP4Y5CWRd")),
GCipher::DIRECTION::ENCIPHER GCipher::DIRECTION::ENCIPHER
) { ) {
block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN"));

View File

@ -4,10 +4,10 @@
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
std::string GWrapper::EncryptString(const std::string& cleartext, const std::string& password) { std::string GWrapper::EncryptString(
// Transform the password to a key const std::string& cleartext,
const Block key = PasswordToKey(password); const Key& key)
{
// Recode the ascii-string to bits // Recode the ascii-string to bits
const Flexblock cleartext_bits = StringToBits(cleartext); const Flexblock cleartext_bits = StringToBits(cleartext);
@ -21,10 +21,10 @@ namespace Leonetienne::GCrypt {
return ciphertext; return ciphertext;
} }
std::string GWrapper::DecryptString(const std::string& ciphertext, const std::string& password) { std::string GWrapper::DecryptString(
// Transform the password to a key const std::string& ciphertext,
const Block key = PasswordToKey(password); const Key& key)
{
// Recode the hex-string to bits // Recode the hex-string to bits
const Flexblock ciphertext_bits = HexstringToBits(ciphertext); const Flexblock ciphertext_bits = HexstringToBits(ciphertext);
@ -38,14 +38,16 @@ namespace Leonetienne::GCrypt {
return cleartext; return cleartext;
} }
bool GWrapper::EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { bool GWrapper::EncryptFile(
const std::string& filename_in,
const std::string& filename_out,
const Key& key,
bool printProgressReport)
{
try { try {
// Read the file to bits // Read the file to bits
const Flexblock cleartext_bits = ReadFileToBits(filename_in); const Flexblock cleartext_bits = ReadFileToBits(filename_in);
// Transform the password to a key
const Block key = PasswordToKey(password);
// Encrypt our cleartext bits // Encrypt our cleartext bits
const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); const Flexblock ciphertext_bits = CipherFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER);
@ -59,14 +61,16 @@ namespace Leonetienne::GCrypt {
} }
} }
bool GWrapper::DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport) { bool GWrapper::DecryptFile(
const std::string& filename_in,
const std::string& filename_out,
const Key& key,
bool printProgressReport)
{
try { try {
// Read the file to bits // Read the file to bits
const Flexblock ciphertext_bits = ReadFileToBits(filename_in); const Flexblock ciphertext_bits = ReadFileToBits(filename_in);
// Transform the password to a key
const Block key = PasswordToKey(password);
// Decrypt the ciphertext bits // Decrypt the ciphertext bits
const Flexblock cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); const Flexblock cleartext_bits = CipherFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER);
@ -82,7 +86,7 @@ namespace Leonetienne::GCrypt {
Flexblock GWrapper::CipherFlexblock( Flexblock GWrapper::CipherFlexblock(
const Flexblock& data, const Flexblock& data,
const Block& key, const Key& key,
const GCipher::DIRECTION direction) const GCipher::DIRECTION direction)
{ {
// Split input into blocks // Split input into blocks

22
GCryptLib/src/Key.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "GCrypt/Key.h"
#include "GCrypt/GHash.h"
#include "GCrypt/Util.h"
namespace Leonetienne::GCrypt {
Key Key::FromPassword(const std::string& password) {
return GHash::CalculateHashsum(
StringToBits(password)
);
}
Key::Key() : Block() {
}
Key::Key(const Block& b) : Block(b) {
}
Key::Key(const Key& k) : Block(k) {
}
}

View File

@ -2,12 +2,5 @@
#include "GCrypt/GHash.h" #include "GCrypt/GHash.h"
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
Block PasswordToKey(const std::string& in) {
// We already have a hashing algorithm, so why not use it
// Yeah, this won't work, because it would create an include loop. This method needs to be outsourced to a cpp file..
const Block hashedPassword = GHash::CalculateHashsum(StringToBits(in));
return hashedPassword;
}
} }