diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index 64038a7..032ebfc 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -163,8 +163,15 @@ namespace Leonetienne::GCrypt { //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) [[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_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; friend std::ostream& operator<<(std::ostream& os, const Basic_Block& b) { diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index cb7d35f..60f3d10 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -46,11 +46,11 @@ namespace Leonetienne::GCrypt { //! Will expand a halfblock to a fullblock static Block ExpansionFunction(const Halfblock& block); - //! Will compress a fullblock to a halfblock - static Halfblock CompressionFunction(const Block& block); + //! Will reduce a fullblock to a halfblock + static Halfblock ReductionFunction(const Block& block); - //! Substitutes four bits by static random others - static std::string SBox(const std::string& in); + //! Substitutes eight bits by static random others, inplace + static void SBox(Block& block); //! Will generate a the round keys void GenerateRoundKeys(const Key& seedKey); diff --git a/GCryptLib/include/GCrypt/SBoxLookup.h b/GCryptLib/include/GCrypt/SBoxLookup.h new file mode 100644 index 0000000..ded1088 --- /dev/null +++ b/GCryptLib/include/GCrypt/SBoxLookup.h @@ -0,0 +1,46 @@ +#ifndef GCRYPT_SBOX_LOOKUP +#define GCRYPT_SBOX_LOOKUP + +#include + +namespace Leonetienne::GCrypt { + + static const std::array 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 + diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index 809d6bf..3a83d2c 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -694,6 +694,16 @@ namespace Leonetienne::GCrypt { return data[index]; } + template + T* Basic_Block::Data() noexcept { + return data.data(); + } + + template + const T* Basic_Block::Data() const noexcept { + return data.data(); + } + template bool Basic_Block::operator==(const Basic_Block& other) const { return data == other.data; diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 57a5844..7fb731e 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -2,6 +2,7 @@ #include "GCrypt/Feistel.h" #include "GCrypt/Util.h" #include "GCrypt/Config.h" +#include "GCrypt/SBoxLookup.h" namespace Leonetienne::GCrypt { @@ -54,14 +55,14 @@ namespace Leonetienne::GCrypt { // Block has finished de*ciphering. // Let's generate a new set of round keys. - GenerateRoundKeys((Key)roundKeys.back()); + GenerateRoundKeys(roundKeys.back()); return FeistelCombine(r, l); } Halfblock Feistel::F(Halfblock m, const Key& key) { - // Made-up F function + // Made-up F function: // Expand to full bitwidth Block m_expanded = ExpansionFunction(m); @@ -75,82 +76,86 @@ namespace Leonetienne::GCrypt { // Now do a bitshift m_expanded.ShiftBitsLeftInplace(); - // Non-linearly apply subsitution boxes - std::stringstream ss; - 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()); + // Apply the sbox + SBox(m_expanded); - // Return the compressed version, shifted by 3 - //return Shiftl(CompressionFunction(m_expanded), 3); - return (CompressionFunction(m_expanded)); + // Reduce back to a halfblock + Halfblock hb = ReductionFunction(m_expanded); + + // To jumble it up a last time, + // matrix-multiply it with the input halfblock + hb *= m; + + return hb; } std::pair Feistel::FeistelSplit(const Block& block) { - const std::string bits = block.ToString(); + Halfblock l; + Halfblock r; - Halfblock l(bits.substr(0, bits.size() / 2)); - Halfblock r(bits.substr(bits.size() / 2)); + memcpy(l.Data(), block.Data(), Halfblock::BLOCK_SIZE); + 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); } 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) { - std::stringstream ss; - const std::string bits = block.ToString(); + Block Feistel::ExpansionFunction(const Halfblock& hb) { + Block b; - std::unordered_map expansionMap; - expansionMap["00"] = "1101"; - expansionMap["01"] = "1000"; - 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]; + // Copy the bits over + for (std::size_t i = 0; i < 16; i++) { + b[i] = hb[i]; } - return Block(ss.str()); - } - - Halfblock Feistel::CompressionFunction(const Block& block) { - std::stringstream ss; - const std::string bits = block.ToString(); - - std::unordered_map 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]; + // 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(); } - return Halfblock(ss.str()); + return b; } + 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) { static std::unordered_map subMap; static bool mapInitialized = false; @@ -176,6 +181,7 @@ namespace Leonetienne::GCrypt { return subMap[in]; } + */ void Feistel::GenerateRoundKeys(const Key& seedKey) { // Clear initial key memory