Added a FeistelManager to en/decipher arbitrarily long messages using cipher block chaining

This commit is contained in:
Leonetienne 2021-12-06 00:39:58 +01:00
parent 61a74f89a5
commit 4855869e54
8 changed files with 202 additions and 10 deletions

View File

@ -21,17 +21,17 @@ void Feistel::SetKey(const Block& key)
return;
}
Block Feistel::Encipher(const Block& data)
Block Feistel::Encipher(const Block& data) const
{
return Run(data, false);
}
Block Feistel::Decipher(const Block& data)
Block Feistel::Decipher(const Block& data) const
{
return Run(data, true);
}
Block Feistel::Run(const Block& data, bool reverseKeys)
Block Feistel::Run(const Block& data, bool reverseKeys) const
{
const auto splitData = FeistelSplit(data);
Halfblock l = splitData.first;
@ -173,6 +173,8 @@ std::string Feistel::SBox(const std::string& in)
void Feistel::GenerateRoundKeys(const Block& seedKey)
{
// Generate round keys via output feedback modus (OFM) method
// Clear initial key memory
ZeroKeyMemory();
roundKeys = Keyset();
@ -190,7 +192,7 @@ void Feistel::GenerateRoundKeys(const Block& seedKey)
}
// These pragmas only work for MSVC, as far as i know. Beware!!!
#pragma optimize( "", off )
#pragma optimize("", off )
void Feistel::ZeroKeyMemory()
{
for (Block& key : roundKeys)
@ -198,4 +200,4 @@ void Feistel::ZeroKeyMemory()
return;
}
#pragma optimize( "", on )
#pragma optimize("", on )

View File

@ -8,7 +8,11 @@
class Feistel
{
public:
Feistel(const Block& key);
explicit Feistel(const Block& key);
Feistel(const Feistel& other) = delete;
Feistel(Feistel&& other) noexcept = delete;
~Feistel();
//! Will set the seed-key for this feistel network.
@ -16,14 +20,14 @@ public:
void SetKey(const Block& key);
//! Will encipher a data block via the set seed-key
Block Encipher(const Block& data);
Block Encipher(const Block& data) const;
//! Will decipher a data block via the set seed-key
Block Decipher(const Block& data);
Block Decipher(const Block& data) const;
private:
//! Will run the feistel rounds, with either regular key order or reversed key order
Block Run(const Block& data, bool reverseKeys);
Block Run(const Block& data, bool reverseKeys) const;
//! Arbitrary cipher function
static Halfblock F(Halfblock m, const Block& key);

View File

@ -146,12 +146,15 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Feistel.cpp" />
<ClCompile Include="FeistelMan.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Block.h" />
<ClInclude Include="Config.h" />
<ClInclude Include="Feistel.h" />
<ClInclude Include="FeistelMan.h" />
<ClInclude Include="Flexblock.h" />
<ClInclude Include="Halfblock.h" />
<ClInclude Include="Keyset.h" />
<ClInclude Include="Util.h" />

View File

@ -24,6 +24,9 @@
<ClCompile Include="main.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="FeistelMan.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Feistel.h">
@ -44,5 +47,11 @@
<ClInclude Include="Util.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="FeistelMan.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="Flexblock.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
</Project>

114
FeistelMan.cpp Normal file
View File

@ -0,0 +1,114 @@
#include "FeistelMan.h"
#include "Util.h"
#include <iostream>
FeistelMan::FeistelMan(const Block& key)
:
key { key }
{
return;
}
FeistelMan::FeistelMan(const std::string& password)
{
key = PasswordToKey(password);
return;
}
FeistelMan::~FeistelMan()
{
// Clear key memory
ZeroKeyMemory();
return;
}
void FeistelMan::SetKey(const Block& key)
{
ZeroKeyMemory();
this->key = key;
return;
}
void FeistelMan::SetPassword(const std::string& password)
{
ZeroKeyMemory();
key = PasswordToKey(password);
return;
}
Flexblock FeistelMan::Encipher(const Flexblock& data) const
{
// Split cleartext into blocks
std::vector<Block> blocks;
for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE)
blocks.push_back(Block(
PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false))
);
// Encrypt individual blocks using cipher block chaining
Feistel feistel(key);
for (std::size_t i = 0; i < blocks.size(); i++)
{
const Block& lastBlock = (i>0) ? blocks[i-1] : emptyBlock;
blocks[i] = feistel.Encipher(blocks[i] ^ lastBlock);
}
// Concatenate ciphertext blocks back into a flexblock
std::stringstream ss;
for (Block& b : blocks)
ss << b;
// Return it
return ss.str();
}
Flexblock FeistelMan::Decipher(const Flexblock& data) const
{
// Split ciphertext into blocks
std::vector<Block> blocks;
for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE)
blocks.push_back(Block(
PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false))
);
// Decrypt individual blocks
Feistel feistel(key);
// We can't do this in-loop for decryption, because we are decrypting the blocks in-place.
Block lastBlock = emptyBlock;
for (std::size_t i = 0; i < blocks.size(); i++)
{
Block tmpCopy = blocks[i];
blocks[i] = feistel.Decipher(blocks[i]) ^ lastBlock;
lastBlock = std::move(tmpCopy);
}
// Concatenate ciphertext blocks back into a flexblock
std::stringstream ss;
for (Block& b : blocks)
ss << b;
// Return it
return ss.str();
}
#pragma optimize("", off )
void FeistelMan::ZeroKeyMemory()
{
key.reset();
return;
}
#pragma optimize("", on )
const Block FeistelMan::emptyBlock;

38
FeistelMan.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include "Feistel.h"
#include "Flexblock.h"
/** Class to apply a block cipher to messages of arbitrary length in a distributed manner
*/
class FeistelMan
{
public:
explicit FeistelMan(const Block& key);
explicit FeistelMan(const std::string& password);
FeistelMan(const FeistelMan& other) = delete;
FeistelMan(FeistelMan&& other) noexcept = delete;
~FeistelMan();
//! Will set the key
void SetKey(const Block& key);
//! Will set the key from a password
void SetPassword(const std::string& password);
//! Will encipher a flexblock of data
Flexblock Encipher(const Flexblock& data) const;
//! Will decipher a flexblock of data
Flexblock Decipher(const Flexblock& data) const;
private:
Block key;
//! Will zero the memory used by the key
void ZeroKeyMemory();
// Initial value for cipher block chaining
static const Block emptyBlock;
};

5
Flexblock.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <vector>
//! A "bitset" of variable length
typedef std::string Flexblock;

View File

@ -1,10 +1,27 @@
#pragma once
#include <iostream>
#include "Util.h"
#include "Feistel.h"
#include "FeistelMan.h"
int main()
{
FeistelMan feistel("Password yo");
const std::string message = "I am a veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery long message!";
std::cout << "Cleartext: " << message << std::endl;
// Encrypt
const Flexblock ciphertext = feistel.Encipher(StringToBits(message));
const std::string cipherHex = BitsToHexstring(ciphertext);
std::cout << "Ciphertext: " << cipherHex << std::endl;
// Decrypt
const Flexblock cleartextBits = feistel.Decipher(HexstringToBits(cipherHex));
std::cout << "Decrypted: " << BitsToString(cleartextBits) << std::endl;
return 0;
}