Implement new sbox, reduction, and expansion function

This commit is contained in:
Leonetienne 2022-05-26 02:30:16 +02:00
parent 8ddd9d6bfb
commit bc3dae96a3
No known key found for this signature in database
GPG Key ID: C33879CD92E9708C
5 changed files with 132 additions and 63 deletions

View File

@ -163,8 +163,15 @@ namespace Leonetienne::GCrypt {
//! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16)
[[nodiscard]] const T& operator[](const std::uint8_t index) const; [[nodiscard]] const T& operator[](const std::uint8_t index) const;
//! Will return a reference to the data array
T* Data() noexcept;
//! Will return a reference to the data array
const T* Data() const noexcept;
static constexpr std::size_t CHUNK_SIZE = sizeof(T); static constexpr std::size_t CHUNK_SIZE = sizeof(T);
static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8;
static constexpr std::size_t BLOCK_SIZE = CHUNK_SIZE * 16;
static constexpr std::size_t BLOCK_SIZE_BITS = CHUNK_SIZE_BITS * 16; static constexpr std::size_t BLOCK_SIZE_BITS = CHUNK_SIZE_BITS * 16;
friend std::ostream& operator<<(std::ostream& os, const Basic_Block<T>& b) { friend std::ostream& operator<<(std::ostream& os, const Basic_Block<T>& b) {

View File

@ -46,11 +46,11 @@ namespace Leonetienne::GCrypt {
//! Will expand a halfblock to a fullblock //! Will expand a halfblock to a fullblock
static Block ExpansionFunction(const Halfblock& block); static Block ExpansionFunction(const Halfblock& block);
//! Will compress a fullblock to a halfblock //! Will reduce a fullblock to a halfblock
static Halfblock CompressionFunction(const Block& block); static Halfblock ReductionFunction(const Block& block);
//! Substitutes four bits by static random others //! Substitutes eight bits by static random others, inplace
static std::string SBox(const std::string& in); static void SBox(Block& block);
//! Will generate a the round keys //! Will generate a the round keys
void GenerateRoundKeys(const Key& seedKey); void GenerateRoundKeys(const Key& seedKey);

View File

@ -0,0 +1,46 @@
#ifndef GCRYPT_SBOX_LOOKUP
#define GCRYPT_SBOX_LOOKUP
#include <array>
namespace Leonetienne::GCrypt {
static const std::array<std::uint8_t, 256> sboxLookup {
0x23,0xF7,0xA2,0x31,0x5B,0x0C,0x13,0xEE,
0xF8,0x1B,0x0B,0xA9,0x37,0x9F,0x55,0xF3,
0x7D,0x71,0x9E,0x89,0x38,0x53,0x3D,0xE9,
0x47,0xA4,0x30,0xBF,0x82,0xE3,0x69,0x5C,
0x3C,0x88,0xDE,0x7F,0x29,0xEB,0x5F,0x02,
0x63,0x42,0xDC,0x36,0x20,0x6B,0x9C,0x4A,
0xA8,0x11,0x6D,0x67,0x3A,0xF4,0x33,0x61,
0x1C,0x4C,0x22,0x07,0x6F,0x80,0xA5,0x96,
0x77,0x62,0xDD,0x6A,0x60,0x05,0x08,0x72,
0xE5,0x1D,0x39,0xA7,0x58,0x3F,0x57,0xAD,
0xFF,0x09,0xC5,0xB2,0xE7,0x94,0xEA,0x34,
0x9A,0x5D,0x52,0xE2,0xAE,0x99,0xBB,0x44,
0xFD,0x73,0xEC,0x87,0xED,0xBA,0x7C,0xF5,
0xDA,0x01,0xC7,0xC1,0xB6,0x81,0x12,0xD5,
0x7A,0x16,0x18,0x97,0x74,0x32,0xBD,0x56,
0xFE,0x79,0x3E,0x95,0x93,0xAB,0x6C,0xC6,
0x2A,0x27,0x19,0x26,0x2E,0x41,0x0F,0x85,
0x66,0x59,0xEF,0x98,0x10,0xE8,0xE6,0x49,
0xAC,0x0D,0x2D,0xD3,0xF0,0x92,0x8F,0xD9,
0xAF,0xC8,0xB5,0xBC,0x6E,0xD6,0x78,0x8E,
0x17,0xCB,0x75,0x50,0x51,0x84,0xB7,0x4D,
0x70,0x9D,0x8A,0x2B,0x0E,0x35,0xB9,0x40,
0x00,0x21,0xC3,0xB3,0x43,0xCD,0x65,0xC0,
0x4E,0xCF,0xCA,0x28,0x45,0x46,0x54,0x8B,
0x0A,0x5A,0x1F,0x24,0xFA,0xA6,0xB4,0xD7,
0x3B,0xFC,0x5E,0xA3,0xB8,0x04,0xCE,0xF2,
0xFB,0xD4,0x8C,0xE4,0x90,0xB1,0x06,0x8D,
0x86,0xA1,0xE0,0x68,0xD1,0x2C,0x03,0x64,
0x9B,0x4F,0x14,0x1E,0x7B,0x76,0x48,0xCC,
0xC4,0x15,0xAA,0xC9,0xE1,0x91,0xF6,0xD0,
0x25,0xA0,0x7E,0xB0,0x1A,0xBE,0xC2,0x4B,
0xF1,0xD2,0xDF,0x2F,0xF9,0xDB,0xD8,0x83
};
}
#endif

View File

@ -694,6 +694,16 @@ namespace Leonetienne::GCrypt {
return data[index]; return data[index];
} }
template <typename T>
T* Basic_Block<T>::Data() noexcept {
return data.data();
}
template <typename T>
const T* Basic_Block<T>::Data() const noexcept {
return data.data();
}
template <typename T> template <typename T>
bool Basic_Block<T>::operator==(const Basic_Block<T>& other) const { bool Basic_Block<T>::operator==(const Basic_Block<T>& other) const {
return data == other.data; return data == other.data;

View File

@ -2,6 +2,7 @@
#include "GCrypt/Feistel.h" #include "GCrypt/Feistel.h"
#include "GCrypt/Util.h" #include "GCrypt/Util.h"
#include "GCrypt/Config.h" #include "GCrypt/Config.h"
#include "GCrypt/SBoxLookup.h"
namespace Leonetienne::GCrypt { namespace Leonetienne::GCrypt {
@ -54,14 +55,14 @@ namespace Leonetienne::GCrypt {
// Block has finished de*ciphering. // Block has finished de*ciphering.
// Let's generate a new set of round keys. // Let's generate a new set of round keys.
GenerateRoundKeys((Key)roundKeys.back()); GenerateRoundKeys(roundKeys.back());
return FeistelCombine(r, l); return FeistelCombine(r, l);
} }
Halfblock Feistel::F(Halfblock m, const Key& 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
Block m_expanded = ExpansionFunction(m); Block m_expanded = ExpansionFunction(m);
@ -75,82 +76,86 @@ namespace Leonetienne::GCrypt {
// Now do a bitshift // Now do a bitshift
m_expanded.ShiftBitsLeftInplace(); m_expanded.ShiftBitsLeftInplace();
// Non-linearly apply subsitution boxes // Apply the sbox
std::stringstream ss; SBox(m_expanded);
const std::string m_str = m_expanded.ToString();
for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 4) {
ss << SBox(m_str.substr(i, 4));
}
m_expanded = Block(ss.str());
// Return the compressed version, shifted by 3 // Reduce back to a halfblock
//return Shiftl(CompressionFunction(m_expanded), 3); Halfblock hb = ReductionFunction(m_expanded);
return (CompressionFunction(m_expanded));
// To jumble it up a last time,
// matrix-multiply it with the input halfblock
hb *= m;
return hb;
} }
std::pair<Halfblock, Halfblock> Feistel::FeistelSplit(const Block& block) { std::pair<Halfblock, Halfblock> Feistel::FeistelSplit(const Block& block) {
const std::string bits = block.ToString(); Halfblock l;
Halfblock r;
Halfblock l(bits.substr(0, bits.size() / 2)); memcpy(l.Data(), block.Data(), Halfblock::BLOCK_SIZE);
Halfblock r(bits.substr(bits.size() / 2)); memcpy(r.Data(), block.Data() + 8, Halfblock::BLOCK_SIZE);
// +8, because 8 is HALF the number of elements in the array. We only want to copy HALF a full-sized block.
return std::make_pair(l, r); return std::make_pair(l, r);
} }
Block Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) { Block Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) {
return Block(l.ToString() + r.ToString()); Block b;
memcpy(b.Data(), l.Data(), Halfblock::BLOCK_SIZE);
memcpy(b.Data() + 8, r.Data(), Halfblock::BLOCK_SIZE);
// +8, because 8 is HALF the number of elements in the array. We only want to copy HALF a full-sized block.
return b;
} }
Block Feistel::ExpansionFunction(const Halfblock& block) { Block Feistel::ExpansionFunction(const Halfblock& hb) {
std::stringstream ss; Block b;
const std::string bits = block.ToString();
std::unordered_map<std::string, std::string> expansionMap; // Copy the bits over
expansionMap["00"] = "1101"; for (std::size_t i = 0; i < 16; i++) {
expansionMap["01"] = "1000"; b[i] = hb[i];
expansionMap["10"] = "0010";
expansionMap["11"] = "0111";
// We have to double the bits!
for (std::size_t i = 0; i < Halfblock::BLOCK_SIZE_BITS; i += 2) {
const std::string sub = bits.substr(i, 2);
ss << expansionMap[sub];
} }
return Block(ss.str()); // Multiply the block a few tims with a bitshifted version
// This is irriversible, too
for (std::size_t i = 0; i < 3; i++) {
b *= b.ShiftBitsRight();
} }
Halfblock Feistel::CompressionFunction(const Block& block) { return b;
std::stringstream ss;
const std::string bits = block.ToString();
std::unordered_map<std::string, std::string> compressionMap;
compressionMap["0000"] = "10";
compressionMap["0001"] = "01";
compressionMap["0010"] = "11";
compressionMap["0011"] = "10";
compressionMap["0100"] = "11";
compressionMap["0101"] = "01";
compressionMap["0110"] = "00";
compressionMap["0111"] = "01";
compressionMap["1000"] = "11";
compressionMap["1001"] = "00";
compressionMap["1010"] = "11";
compressionMap["1011"] = "00";
compressionMap["1100"] = "11";
compressionMap["1101"] = "10";
compressionMap["1110"] = "00";
compressionMap["1111"] = "01";
// We have to half the bits!
for (std::size_t i = 0; i < Block::BLOCK_SIZE_BITS; i += 4) {
const std::string sub = bits.substr(i, 4);
ss << compressionMap[sub];
} }
return Halfblock(ss.str()); Halfblock Feistel::ReductionFunction(const Block& block) {
// Just apply a modulo operation, remapping a 32bit integer
// onto 16bit space (default configuration).
// Without saying, modulo is irreversible.
Halfblock hb;
for (std::size_t i = 0; i < 16; i++) {
hb[i] = block[i] % (1 << (Halfblock::CHUNK_SIZE_BITS - 1));
} }
return hb;
}
void Feistel::SBox(Block& block) {
std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data();
// Iterate over all bytes in the block
for (std::size_t i = 0; i < Block::BLOCK_SIZE; i++) {
curByte++;
// Subsitute byte
*curByte = sboxLookup[*curByte];
}
return;
}
/*
std::string Feistel::SBox(const std::string& in) { std::string Feistel::SBox(const std::string& in) {
static std::unordered_map<std::string, std::string> subMap; static std::unordered_map<std::string, std::string> subMap;
static bool mapInitialized = false; static bool mapInitialized = false;
@ -176,6 +181,7 @@ namespace Leonetienne::GCrypt {
return subMap[in]; return subMap[in];
} }
*/
void Feistel::GenerateRoundKeys(const Key& seedKey) { void Feistel::GenerateRoundKeys(const Key& seedKey) {
// Clear initial key memory // Clear initial key memory