Added a FeistelManager to en/decipher arbitrarily long messages using cipher block chaining
This commit is contained in:
parent
61a74f89a5
commit
4855869e54
12
Feistel.cpp
12
Feistel.cpp
@ -21,17 +21,17 @@ void Feistel::SetKey(const Block& key)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block Feistel::Encipher(const Block& data)
|
Block Feistel::Encipher(const Block& data) const
|
||||||
{
|
{
|
||||||
return Run(data, false);
|
return Run(data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block Feistel::Decipher(const Block& data)
|
Block Feistel::Decipher(const Block& data) const
|
||||||
{
|
{
|
||||||
return Run(data, true);
|
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);
|
const auto splitData = FeistelSplit(data);
|
||||||
Halfblock l = splitData.first;
|
Halfblock l = splitData.first;
|
||||||
@ -173,6 +173,8 @@ std::string Feistel::SBox(const std::string& in)
|
|||||||
|
|
||||||
void Feistel::GenerateRoundKeys(const Block& seedKey)
|
void Feistel::GenerateRoundKeys(const Block& seedKey)
|
||||||
{
|
{
|
||||||
|
// Generate round keys via output feedback modus (OFM) method
|
||||||
|
|
||||||
// Clear initial key memory
|
// Clear initial key memory
|
||||||
ZeroKeyMemory();
|
ZeroKeyMemory();
|
||||||
roundKeys = Keyset();
|
roundKeys = Keyset();
|
||||||
@ -190,7 +192,7 @@ void Feistel::GenerateRoundKeys(const Block& seedKey)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// These pragmas only work for MSVC, as far as i know. Beware!!!
|
// These pragmas only work for MSVC, as far as i know. Beware!!!
|
||||||
#pragma optimize( "", off )
|
#pragma optimize("", off )
|
||||||
void Feistel::ZeroKeyMemory()
|
void Feistel::ZeroKeyMemory()
|
||||||
{
|
{
|
||||||
for (Block& key : roundKeys)
|
for (Block& key : roundKeys)
|
||||||
@ -198,4 +200,4 @@ void Feistel::ZeroKeyMemory()
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#pragma optimize( "", on )
|
#pragma optimize("", on )
|
||||||
|
12
Feistel.h
12
Feistel.h
@ -8,7 +8,11 @@
|
|||||||
class Feistel
|
class Feistel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Feistel(const Block& key);
|
explicit Feistel(const Block& key);
|
||||||
|
|
||||||
|
Feistel(const Feistel& other) = delete;
|
||||||
|
Feistel(Feistel&& other) noexcept = delete;
|
||||||
|
|
||||||
~Feistel();
|
~Feistel();
|
||||||
|
|
||||||
//! Will set the seed-key for this feistel network.
|
//! Will set the seed-key for this feistel network.
|
||||||
@ -16,14 +20,14 @@ public:
|
|||||||
void SetKey(const Block& key);
|
void SetKey(const Block& 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) const;
|
||||||
|
|
||||||
//! Will decipher a data block via the set seed-key
|
//! Will decipher a data block via the set seed-key
|
||||||
Block Decipher(const Block& data);
|
Block Decipher(const Block& data) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Will run the feistel rounds, with either regular key order or reversed key order
|
//! 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
|
//! Arbitrary cipher function
|
||||||
static Halfblock F(Halfblock m, const Block& key);
|
static Halfblock F(Halfblock m, const Block& key);
|
||||||
|
@ -146,12 +146,15 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Feistel.cpp" />
|
<ClCompile Include="Feistel.cpp" />
|
||||||
|
<ClCompile Include="FeistelMan.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Block.h" />
|
<ClInclude Include="Block.h" />
|
||||||
<ClInclude Include="Config.h" />
|
<ClInclude Include="Config.h" />
|
||||||
<ClInclude Include="Feistel.h" />
|
<ClInclude Include="Feistel.h" />
|
||||||
|
<ClInclude Include="FeistelMan.h" />
|
||||||
|
<ClInclude Include="Flexblock.h" />
|
||||||
<ClInclude Include="Halfblock.h" />
|
<ClInclude Include="Halfblock.h" />
|
||||||
<ClInclude Include="Keyset.h" />
|
<ClInclude Include="Keyset.h" />
|
||||||
<ClInclude Include="Util.h" />
|
<ClInclude Include="Util.h" />
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
<ClCompile Include="main.cpp">
|
<ClCompile Include="main.cpp">
|
||||||
<Filter>Quelldateien</Filter>
|
<Filter>Quelldateien</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="FeistelMan.cpp">
|
||||||
|
<Filter>Quelldateien</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Feistel.h">
|
<ClInclude Include="Feistel.h">
|
||||||
@ -44,5 +47,11 @@
|
|||||||
<ClInclude Include="Util.h">
|
<ClInclude Include="Util.h">
|
||||||
<Filter>Headerdateien</Filter>
|
<Filter>Headerdateien</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="FeistelMan.h">
|
||||||
|
<Filter>Headerdateien</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Flexblock.h">
|
||||||
|
<Filter>Headerdateien</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
114
FeistelMan.cpp
Normal file
114
FeistelMan.cpp
Normal 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
38
FeistelMan.h
Normal 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
5
Flexblock.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//! A "bitset" of variable length
|
||||||
|
typedef std::string Flexblock;
|
19
main.cpp
19
main.cpp
@ -1,10 +1,27 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "Feistel.h"
|
#include "FeistelMan.h"
|
||||||
|
|
||||||
int main()
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user