diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index db9552f..2184e75 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -1,12 +1,126 @@ #ifndef GCRYPT_BLOCK_H #define GCRYPT_BLOCK_H -#include "GCrypt/SecureBitset.h" -#include "GCrypt/Config.h" +#include +#include +#include +#include namespace Leonetienne::GCrypt { - typedef SecureBitset Block; + + /* This class represents a block of data, + * and provides functions to manipulate it + */ + class Block { + public: + //! Will constuct an uninitialized data block + Block(); + + //! Will construct this block from a string like "101010".. Length MUST be 512. + Block(const std::string& other); + + //! Copy-ctor + Block(const Block& other); + + ~Block(); + + //! Will construct this block from a string like "011101..". Length MUST be 512. + void FromString(const std::string& str); + + //! Will create a bitset-compatible string ("0101110..") representation + //! of this block. Length will always be 512. + std::string ToString() const; + + //! Will matrix-multiply two blocks together. + //! Since the matrices values are pretty much sudo-random, + //! they will most likely integer-overflow. + //! So see this as a one-way function. + Block MMul(const Block& other) const; + Block operator*(const Block& other) const; + + //! Will matrix-multiply two blocks together, + //! and directly write into this same block. + //! Since the matrices values are pretty much sudo-random, + //! they will most likely integer-overflow. + //! So see this as a one-way function. + void MMulInplace(const Block& other); + Block& operator*=(const Block& other); + + //! Will xor two blocks together + Block Xor(const Block& other) const; + //! Will xor two blocks together + Block operator^(const Block& other) const; + + //! Will xor two blocks together, inplace + void XorInplace(const Block& other); + //! Will xor two blocks together, inplace + Block& operator^=(const Block& other); + + // # TO BE IMPLEMENTED + //! Will shift rows upwards by n + void ShiftRowsUp(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift matrix rows downwards by n + void ShiftRowsDown(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift matrix columns to the left by n + void ShiftColumnsLeft(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift matrix columns to the right by n + void ShiftColumnsRight(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift array cells to the left by n + void ShiftCellsLeft(const std::size_t n); + + // # TO BE IMPLEMENTED + //! Will shift array cells to the right by n + void ShiftCellsRight(const std::size_t n); + + //! Will copy a block + Block& operator=(const Block& other); + + //! Will compare whether or not two blocks are equal + bool operator==(const Block& other) const; + //! Will compare whether or not two blocks are unequal + bool operator!=(const Block& other) const; + + //! Will zero all data + void Reset(); + + + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) + std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) + const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + std::uint32_t& Get(const std::uint8_t index); + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + const std::uint32_t& Get(const std::uint8_t index) const; + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + std::uint32_t& operator[](const std::uint8_t index); + + //! Returns 32-bit chunks of data, indexed by a 1d-index (0-16) + const std::uint32_t& operator[](const std::uint8_t index) const; + + static constexpr std::size_t CHUNK_SIZE = sizeof(std::uint32_t); + static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8; + + friend std::ostream& operator<<(std::ostream& os, const Block& b); + + private: + + std::array data; + }; + } + #endif diff --git a/GCryptLib/include/GCrypt/BlockMatrix.h b/GCryptLib/include/GCrypt/BlockMatrix.h deleted file mode 100644 index 6f28a84..0000000 --- a/GCryptLib/include/GCrypt/BlockMatrix.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef GCRYPT_BLOCKMATRIX_H -#define GCRYPT_BLOCKMATRIX_H - -#include "GCrypt/Block.h" -#include -#include - -namespace Leonetienne::GCrypt { - - /* This class represents a block as a matrix, - * providing typical matrix operations - */ - class BlockMatrix { - public: - BlockMatrix(); - BlockMatrix(const Block& block); - BlockMatrix(const BlockMatrix& other); - - //! Will calculate the product of two matrices. - //! Since the matrices values are pretty much sudo-random, - //! they will most likely integer-overflow. - //! So see this as a one-way function. - BlockMatrix MMult(const BlockMatrix& other) const; - BlockMatrix operator*(const BlockMatrix& other) const; - - //! Will do a regular matrix-mult, but instead of - //! adding, and multiplying, all ints get xored. - BlockMatrix MXor(const BlockMatrix& other) const; - - bool operator==(const BlockMatrix& other) const; - bool operator!=(const BlockMatrix& other) const; - - void FromBlock(const Block& block); - Block ToBlock() const; - - private: - //! Returns items of data, indexed by 4x4 coordinates - std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); - //! Returns items of data, indexed by 4x4 coordinates - const std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column) const; - - std::array data; - }; - -} - - -#endif - diff --git a/GCryptLib/include/GCrypt/Version.h b/GCryptLib/include/GCrypt/Version.h index 256c32b..e6e5330 100644 --- a/GCryptLib/include/GCrypt/Version.h +++ b/GCryptLib/include/GCrypt/Version.h @@ -1,7 +1,7 @@ #ifndef GCRYPT_VERSION_H #define GCRYPT_VERSION_H -#define GCRYPT_VERSION 0.231 +#define GCRYPT_VERSION 0.232 #endif diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp new file mode 100644 index 0000000..e30d738 --- /dev/null +++ b/GCryptLib/src/Block.cpp @@ -0,0 +1,220 @@ +#include "GCrypt/Block.h" +#include "GCrypt/Config.h" +#include +#include +#include +#include + +namespace Leonetienne::GCrypt { + + Block::Block() { + } + + Block::Block(const std::string& str) { + FromString(str); + } + + Block::Block(const Block& other) { + data = other.data; + } + + void Block::FromString(const std::string& str) { + + assert(str.length() == BLOCK_SIZE); + + for (std::size_t i = 0; i < data.size(); i++) { + data[i] = std::bitset( + str.substr(i*CHUNK_SIZE_BITS, CHUNK_SIZE_BITS) + ).to_ulong(); + } + + return; + } + + std::string Block::ToString() const { + + std::stringstream ss; + for (std::size_t i = 0; i < data.size(); i++) { + ss << std::bitset(data[i]).to_string(); + } + return ss.str(); + } + + Block Block::MMul(const Block& o) const { + + Block m; + + m.Get(0, 0) = (this->Get(0, 0) * o.Get(0, 0)) + (this->Get(0, 1) * o.Get(1, 0)) + (this->Get(0, 2) * o.Get(2, 0)) + (this->Get(0, 3) * o.Get(3, 0)); + m.Get(0, 1) = (this->Get(0, 0) * o.Get(0, 1)) + (this->Get(0, 1) * o.Get(1, 1)) + (this->Get(0, 2) * o.Get(2, 1)) + (this->Get(0, 3) * o.Get(3, 1)); + m.Get(0, 2) = (this->Get(0, 0) * o.Get(0, 2)) + (this->Get(0, 1) * o.Get(1, 2)) + (this->Get(0, 2) * o.Get(2, 2)) + (this->Get(0, 3) * o.Get(3, 2)); + m.Get(0, 3) = (this->Get(0, 0) * o.Get(0, 3)) + (this->Get(0, 1) * o.Get(1, 3)) + (this->Get(0, 2) * o.Get(2, 3)) + (this->Get(0, 3) * o.Get(3, 3)); + + m.Get(1, 0) = (this->Get(1, 0) * o.Get(0, 0)) + (this->Get(1, 1) * o.Get(1, 0)) + (this->Get(1, 2) * o.Get(2, 0)) + (this->Get(1, 3) * o.Get(3, 0)); + m.Get(1, 1) = (this->Get(1, 0) * o.Get(0, 1)) + (this->Get(1, 1) * o.Get(1, 1)) + (this->Get(1, 2) * o.Get(2, 1)) + (this->Get(1, 3) * o.Get(3, 1)); + m.Get(1, 2) = (this->Get(1, 0) * o.Get(0, 2)) + (this->Get(1, 1) * o.Get(1, 2)) + (this->Get(1, 2) * o.Get(2, 2)) + (this->Get(1, 3) * o.Get(3, 2)); + m.Get(1, 3) = (this->Get(1, 0) * o.Get(0, 3)) + (this->Get(1, 1) * o.Get(1, 3)) + (this->Get(1, 2) * o.Get(2, 3)) + (this->Get(1, 3) * o.Get(3, 3)); + + m.Get(2, 0) = (this->Get(2, 0) * o.Get(0, 0)) + (this->Get(2, 1) * o.Get(1, 0)) + (this->Get(2, 2) * o.Get(2, 0)) + (this->Get(2, 3) * o.Get(3, 0)); + m.Get(2, 1) = (this->Get(2, 0) * o.Get(0, 1)) + (this->Get(2, 1) * o.Get(1, 1)) + (this->Get(2, 2) * o.Get(2, 1)) + (this->Get(2, 3) * o.Get(3, 1)); + m.Get(2, 2) = (this->Get(2, 0) * o.Get(0, 2)) + (this->Get(2, 1) * o.Get(1, 2)) + (this->Get(2, 2) * o.Get(2, 2)) + (this->Get(2, 3) * o.Get(3, 2)); + m.Get(2, 3) = (this->Get(2, 0) * o.Get(0, 3)) + (this->Get(2, 1) * o.Get(1, 3)) + (this->Get(2, 2) * o.Get(2, 3)) + (this->Get(2, 3) * o.Get(3, 3)); + + m.Get(3, 0) = (this->Get(3, 0) * o.Get(0, 0)) + (this->Get(3, 1) * o.Get(1, 0)) + (this->Get(3, 2) * o.Get(2, 0)) + (this->Get(3, 3) * o.Get(3, 0)); + m.Get(3, 1) = (this->Get(3, 0) * o.Get(0, 1)) + (this->Get(3, 1) * o.Get(1, 1)) + (this->Get(3, 2) * o.Get(2, 1)) + (this->Get(3, 3) * o.Get(3, 1)); + m.Get(3, 2) = (this->Get(3, 0) * o.Get(0, 2)) + (this->Get(3, 1) * o.Get(1, 2)) + (this->Get(3, 2) * o.Get(2, 2)) + (this->Get(3, 3) * o.Get(3, 2)); + m.Get(3, 3) = (this->Get(3, 0) * o.Get(0, 3)) + (this->Get(3, 1) * o.Get(1, 3)) + (this->Get(3, 2) * o.Get(2, 3)) + (this->Get(3, 3) * o.Get(3, 3)); + + return m; + } + + Block Block::operator*(const Block& other) const { + return this->MMul(other); + } + + void Block::MMulInplace(const Block& o) { + + Block m = *this; + + this->Get(0, 0) = (m.Get(0, 0) * o.Get(0, 0)) + (m.Get(0, 1) * o.Get(1, 0)) + (m.Get(0, 2) * o.Get(2, 0)) + (m.Get(0, 3) * o.Get(3, 0)); + this->Get(0, 1) = (m.Get(0, 0) * o.Get(0, 1)) + (m.Get(0, 1) * o.Get(1, 1)) + (m.Get(0, 2) * o.Get(2, 1)) + (m.Get(0, 3) * o.Get(3, 1)); + this->Get(0, 2) = (m.Get(0, 0) * o.Get(0, 2)) + (m.Get(0, 1) * o.Get(1, 2)) + (m.Get(0, 2) * o.Get(2, 2)) + (m.Get(0, 3) * o.Get(3, 2)); + this->Get(0, 3) = (m.Get(0, 0) * o.Get(0, 3)) + (m.Get(0, 1) * o.Get(1, 3)) + (m.Get(0, 2) * o.Get(2, 3)) + (m.Get(0, 3) * o.Get(3, 3)); + + this->Get(1, 0) = (m.Get(1, 0) * o.Get(0, 0)) + (m.Get(1, 1) * o.Get(1, 0)) + (m.Get(1, 2) * o.Get(2, 0)) + (m.Get(1, 3) * o.Get(3, 0)); + this->Get(1, 1) = (m.Get(1, 0) * o.Get(0, 1)) + (m.Get(1, 1) * o.Get(1, 1)) + (m.Get(1, 2) * o.Get(2, 1)) + (m.Get(1, 3) * o.Get(3, 1)); + this->Get(1, 2) = (m.Get(1, 0) * o.Get(0, 2)) + (m.Get(1, 1) * o.Get(1, 2)) + (m.Get(1, 2) * o.Get(2, 2)) + (m.Get(1, 3) * o.Get(3, 2)); + this->Get(1, 3) = (m.Get(1, 0) * o.Get(0, 3)) + (m.Get(1, 1) * o.Get(1, 3)) + (m.Get(1, 2) * o.Get(2, 3)) + (m.Get(1, 3) * o.Get(3, 3)); + + this->Get(2, 0) = (m.Get(2, 0) * o.Get(0, 0)) + (m.Get(2, 1) * o.Get(1, 0)) + (m.Get(2, 2) * o.Get(2, 0)) + (m.Get(2, 3) * o.Get(3, 0)); + this->Get(2, 1) = (m.Get(2, 0) * o.Get(0, 1)) + (m.Get(2, 1) * o.Get(1, 1)) + (m.Get(2, 2) * o.Get(2, 1)) + (m.Get(2, 3) * o.Get(3, 1)); + this->Get(2, 2) = (m.Get(2, 0) * o.Get(0, 2)) + (m.Get(2, 1) * o.Get(1, 2)) + (m.Get(2, 2) * o.Get(2, 2)) + (m.Get(2, 3) * o.Get(3, 2)); + this->Get(2, 3) = (m.Get(2, 0) * o.Get(0, 3)) + (m.Get(2, 1) * o.Get(1, 3)) + (m.Get(2, 2) * o.Get(2, 3)) + (m.Get(2, 3) * o.Get(3, 3)); + + this->Get(3, 0) = (m.Get(3, 0) * o.Get(0, 0)) + (m.Get(3, 1) * o.Get(1, 0)) + (m.Get(3, 2) * o.Get(2, 0)) + (m.Get(3, 3) * o.Get(3, 0)); + this->Get(3, 1) = (m.Get(3, 0) * o.Get(0, 1)) + (m.Get(3, 1) * o.Get(1, 1)) + (m.Get(3, 2) * o.Get(2, 1)) + (m.Get(3, 3) * o.Get(3, 1)); + this->Get(3, 2) = (m.Get(3, 0) * o.Get(0, 2)) + (m.Get(3, 1) * o.Get(1, 2)) + (m.Get(3, 2) * o.Get(2, 2)) + (m.Get(3, 3) * o.Get(3, 2)); + this->Get(3, 3) = (m.Get(3, 0) * o.Get(0, 3)) + (m.Get(3, 1) * o.Get(1, 3)) + (m.Get(3, 2) * o.Get(2, 3)) + (m.Get(3, 3) * o.Get(3, 3)); + + return; + } + + Block& Block::operator*=(const Block& other) { + MMulInplace(other); + return *this; + } + + Block Block::Xor(const Block& other) const { + + Block m; + for (std::size_t i = 0; i < data.size(); i++) { + m.Get(i) = this->Get(i) ^ other.Get(i); + } + return m; + } + + Block Block::operator^(const Block& other) const { + return Xor(other); + } + + void Block::XorInplace(const Block& other) { + for (std::size_t i = 0; i < data.size(); i++) { + this->Get(i) ^= other.Get(i); + } + return; + } + + Block& Block::operator^=(const Block& other) { + XorInplace(other); + return *this; + } + + void ShiftRowsUp(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftRowsDown(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftColumnsLeft(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftColumnsRight(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftCellsLeft(const std::size_t n) { + // TO BE IMPLEMENTED + } + + void ShiftCellsRight(const std::size_t n) { + // TO BE IMPLEMENTED + } + + Block& Block::operator=(const Block& other) { + data = other.data; + return *this; + } + + std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ + return data[column*4 + row]; + } + + const std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column) const { + return data[column*4 + row]; + } + + std::uint32_t& Block::Get(const std::uint8_t index) { + return data[index]; + } + + const std::uint32_t& Block::Get(const std::uint8_t index) const { + return data[index]; + } + + std::uint32_t& Block::operator[](const std::uint8_t index) { + return data[index]; + } + + const std::uint32_t& Block::operator[](const std::uint8_t index) const { + return data[index]; + } + + bool Block::operator==(const Block& other) const { + return data == other.data; + } + + bool Block::operator!=(const Block& other) const { + return data != other.data; + } + + std::ostream& operator<<(std::ostream& os, const Block& b) { + for (std::size_t i = 0; i < b.data.size(); i++) { + os << std::bitset(b.data[i]).to_string(); + } + return os; + } + +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", off ) +#elif defined __GNUG__ +#pragma GCC push_options +#pragma GCC optimize ("O0") +#endif + Block::~Block() { + Reset(); + } + + void Block::Reset() { + memset(data.data(), 0, CHUNK_SIZE*data.size()); + return; + } + +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", on ) +#elif defined __GNUG__ +#pragma GCC pop_options +#endif +} + diff --git a/GCryptLib/src/BlockMatrix.cpp b/GCryptLib/src/BlockMatrix.cpp deleted file mode 100644 index e1915c9..0000000 --- a/GCryptLib/src/BlockMatrix.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "GCrypt/BlockMatrix.h" -#include - -namespace Leonetienne::GCrypt { - - BlockMatrix::BlockMatrix() { - } - - BlockMatrix::BlockMatrix(const Block& block) { - FromBlock(block); - } - - BlockMatrix::BlockMatrix(const BlockMatrix& other) { - data = other.data; - } - - void BlockMatrix::FromBlock(const Block& block) { - - const std::string blockstr = block.to_string(); - constexpr std::size_t cellSize = sizeof(std::uint32_t)*8; - - for (std::size_t i = 0; i < 16; i++) { - data[i] = std::bitset(blockstr.substr(i*cellSize, cellSize)).to_ulong(); - } - - return; - } - - Block BlockMatrix::ToBlock() const { - - std::stringstream ss; - constexpr std::size_t cellSize = sizeof(std::uint32_t)*8; - - for (std::size_t i = 0; i < 16; i++) { - ss << std::bitset(data[i]).to_string(); - } - return Block(ss.str()); - } - - BlockMatrix BlockMatrix::MMult(const BlockMatrix& o) const { - - BlockMatrix m; - - m.Get(0, 0) = (this->Get(0, 0) * o.Get(0, 0)) + (this->Get(0, 1) * o.Get(1, 0)) + (this->Get(0, 2) * o.Get(2, 0)) + (this->Get(0, 3) * o.Get(3, 0)); - m.Get(0, 1) = (this->Get(0, 0) * o.Get(0, 1)) + (this->Get(0, 1) * o.Get(1, 1)) + (this->Get(0, 2) * o.Get(2, 1)) + (this->Get(0, 3) * o.Get(3, 1)); - m.Get(0, 2) = (this->Get(0, 0) * o.Get(0, 2)) + (this->Get(0, 1) * o.Get(1, 2)) + (this->Get(0, 2) * o.Get(2, 2)) + (this->Get(0, 3) * o.Get(3, 2)); - m.Get(0, 3) = (this->Get(0, 0) * o.Get(0, 3)) + (this->Get(0, 1) * o.Get(1, 3)) + (this->Get(0, 2) * o.Get(2, 3)) + (this->Get(0, 3) * o.Get(3, 3)); - - m.Get(1, 0) = (this->Get(1, 0) * o.Get(0, 0)) + (this->Get(1, 1) * o.Get(1, 0)) + (this->Get(1, 2) * o.Get(2, 0)) + (this->Get(1, 3) * o.Get(3, 0)); - m.Get(1, 1) = (this->Get(1, 0) * o.Get(0, 1)) + (this->Get(1, 1) * o.Get(1, 1)) + (this->Get(1, 2) * o.Get(2, 1)) + (this->Get(1, 3) * o.Get(3, 1)); - m.Get(1, 2) = (this->Get(1, 0) * o.Get(0, 2)) + (this->Get(1, 1) * o.Get(1, 2)) + (this->Get(1, 2) * o.Get(2, 2)) + (this->Get(1, 3) * o.Get(3, 2)); - m.Get(1, 3) = (this->Get(1, 0) * o.Get(0, 3)) + (this->Get(1, 1) * o.Get(1, 3)) + (this->Get(1, 2) * o.Get(2, 3)) + (this->Get(1, 3) * o.Get(3, 3)); - - m.Get(2, 0) = (this->Get(2, 0) * o.Get(0, 0)) + (this->Get(2, 1) * o.Get(1, 0)) + (this->Get(2, 2) * o.Get(2, 0)) + (this->Get(2, 3) * o.Get(3, 0)); - m.Get(2, 1) = (this->Get(2, 0) * o.Get(0, 1)) + (this->Get(2, 1) * o.Get(1, 1)) + (this->Get(2, 2) * o.Get(2, 1)) + (this->Get(2, 3) * o.Get(3, 1)); - m.Get(2, 2) = (this->Get(2, 0) * o.Get(0, 2)) + (this->Get(2, 1) * o.Get(1, 2)) + (this->Get(2, 2) * o.Get(2, 2)) + (this->Get(2, 3) * o.Get(3, 2)); - m.Get(2, 3) = (this->Get(2, 0) * o.Get(0, 3)) + (this->Get(2, 1) * o.Get(1, 3)) + (this->Get(2, 2) * o.Get(2, 3)) + (this->Get(2, 3) * o.Get(3, 3)); - - m.Get(3, 0) = (this->Get(3, 0) * o.Get(0, 0)) + (this->Get(3, 1) * o.Get(1, 0)) + (this->Get(3, 2) * o.Get(2, 0)) + (this->Get(3, 3) * o.Get(3, 0)); - m.Get(3, 1) = (this->Get(3, 0) * o.Get(0, 1)) + (this->Get(3, 1) * o.Get(1, 1)) + (this->Get(3, 2) * o.Get(2, 1)) + (this->Get(3, 3) * o.Get(3, 1)); - m.Get(3, 2) = (this->Get(3, 0) * o.Get(0, 2)) + (this->Get(3, 1) * o.Get(1, 2)) + (this->Get(3, 2) * o.Get(2, 2)) + (this->Get(3, 3) * o.Get(3, 2)); - m.Get(3, 3) = (this->Get(3, 0) * o.Get(0, 3)) + (this->Get(3, 1) * o.Get(1, 3)) + (this->Get(3, 2) * o.Get(2, 3)) + (this->Get(3, 3) * o.Get(3, 3)); - - return m; - } - - BlockMatrix BlockMatrix::operator*(const BlockMatrix& other) const { - return this->MMult(other); - } - - BlockMatrix BlockMatrix::MXor(const BlockMatrix& o) const { - - BlockMatrix m; - - m.Get(0, 0) = this->Get(0, 0) ^ o.Get(0, 0) ^ this->Get(0, 1) ^ o.Get(1, 0) ^ this->Get(0, 2) ^ o.Get(2, 0) ^ this->Get(0, 3) ^ o.Get(3, 0); - m.Get(0, 1) = this->Get(0, 0) ^ o.Get(0, 1) ^ this->Get(0, 1) ^ o.Get(1, 1) ^ this->Get(0, 2) ^ o.Get(2, 1) ^ this->Get(0, 3) ^ o.Get(3, 1); - m.Get(0, 2) = this->Get(0, 0) ^ o.Get(0, 2) ^ this->Get(0, 1) ^ o.Get(1, 2) ^ this->Get(0, 2) ^ o.Get(2, 2) ^ this->Get(0, 3) ^ o.Get(3, 2); - m.Get(0, 3) = this->Get(0, 0) ^ o.Get(0, 3) ^ this->Get(0, 1) ^ o.Get(1, 3) ^ this->Get(0, 2) ^ o.Get(2, 3) ^ this->Get(0, 3) ^ o.Get(3, 3); - - m.Get(1, 0) = this->Get(1, 0) ^ o.Get(0, 0) ^ this->Get(1, 1) ^ o.Get(1, 0) ^ this->Get(1, 2) ^ o.Get(2, 0) ^ this->Get(1, 3) ^ o.Get(3, 0); - m.Get(1, 1) = this->Get(1, 0) ^ o.Get(0, 1) ^ this->Get(1, 1) ^ o.Get(1, 1) ^ this->Get(1, 2) ^ o.Get(2, 1) ^ this->Get(1, 3) ^ o.Get(3, 1); - m.Get(1, 2) = this->Get(1, 0) ^ o.Get(0, 2) ^ this->Get(1, 1) ^ o.Get(1, 2) ^ this->Get(1, 2) ^ o.Get(2, 2) ^ this->Get(1, 3) ^ o.Get(3, 2); - m.Get(1, 3) = this->Get(1, 0) ^ o.Get(0, 3) ^ this->Get(1, 1) ^ o.Get(1, 3) ^ this->Get(1, 2) ^ o.Get(2, 3) ^ this->Get(1, 3) ^ o.Get(3, 3); - - m.Get(2, 0) = this->Get(2, 0) ^ o.Get(0, 0) ^ this->Get(2, 1) ^ o.Get(1, 0) ^ this->Get(2, 2) ^ o.Get(2, 0) ^ this->Get(2, 3) ^ o.Get(3, 0); - m.Get(2, 1) = this->Get(2, 0) ^ o.Get(0, 1) ^ this->Get(2, 1) ^ o.Get(1, 1) ^ this->Get(2, 2) ^ o.Get(2, 1) ^ this->Get(2, 3) ^ o.Get(3, 1); - m.Get(2, 2) = this->Get(2, 0) ^ o.Get(0, 2) ^ this->Get(2, 1) ^ o.Get(1, 2) ^ this->Get(2, 2) ^ o.Get(2, 2) ^ this->Get(2, 3) ^ o.Get(3, 2); - m.Get(2, 3) = this->Get(2, 0) ^ o.Get(0, 3) ^ this->Get(2, 1) ^ o.Get(1, 3) ^ this->Get(2, 2) ^ o.Get(2, 3) ^ this->Get(2, 3) ^ o.Get(3, 3); - - m.Get(3, 0) = this->Get(3, 0) ^ o.Get(0, 0) ^ this->Get(3, 1) ^ o.Get(1, 0) ^ this->Get(3, 2) ^ o.Get(2, 0) ^ this->Get(3, 3) ^ o.Get(3, 0); - m.Get(3, 1) = this->Get(3, 0) ^ o.Get(0, 1) ^ this->Get(3, 1) ^ o.Get(1, 1) ^ this->Get(3, 2) ^ o.Get(2, 1) ^ this->Get(3, 3) ^ o.Get(3, 1); - m.Get(3, 2) = this->Get(3, 0) ^ o.Get(0, 2) ^ this->Get(3, 1) ^ o.Get(1, 2) ^ this->Get(3, 2) ^ o.Get(2, 2) ^ this->Get(3, 3) ^ o.Get(3, 2); - m.Get(3, 3) = this->Get(3, 0) ^ o.Get(0, 3) ^ this->Get(3, 1) ^ o.Get(1, 3) ^ this->Get(3, 2) ^ o.Get(2, 3) ^ this->Get(3, 3) ^ o.Get(3, 3); - - return m; - } - - const std::uint32_t& BlockMatrix::Get(const std::uint8_t row, const std::uint8_t column) const { - return data[column*4 + row]; - } - - std::uint32_t& BlockMatrix::Get(const std::uint8_t row, const std::uint8_t column){ - return data[column*4 + row]; - } - - bool BlockMatrix::operator==(const BlockMatrix& other) const { - return data == other.data; - } - - bool BlockMatrix::operator!=(const BlockMatrix& other) const { - return data != other.data; - } -} - diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index 31d916d..565d54a 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -68,25 +68,27 @@ namespace Leonetienne::GCrypt { Block m_expanded = ExpansionFunction(m); // Shift to left by 1 - m_expanded = Shiftl(m_expanded, 1); + //m_expanded = Shiftl(m_expanded, 1); + m_expanded = (m_expanded); // Matrix-mult with key - m_expanded = (BlockMatrix(m_expanded) * BlockMatrix(key)).ToBlock(); + m_expanded *= key; // Non-linearly apply subsitution boxes std::stringstream ss; - const std::string m_str = m_expanded.to_string(); + const std::string m_str = m_expanded.ToString(); for (std::size_t i = 0; i < BLOCK_SIZE; i += 4) { ss << SBox(m_str.substr(i, 4)); } m_expanded = Block(ss.str()); // Return the compressed version, shifted by 3 - return Shiftl(CompressionFunction(m_expanded), 3); + //return Shiftl(CompressionFunction(m_expanded), 3); + return (CompressionFunction(m_expanded)); } std::pair Feistel::FeistelSplit(const Block& block) { - const std::string bits = block.to_string(); + const std::string bits = block.ToString(); Halfblock l(bits.substr(0, bits.size() / 2)); Halfblock r(bits.substr(bits.size() / 2)); @@ -119,7 +121,7 @@ namespace Leonetienne::GCrypt { Halfblock Feistel::CompressionFunction(const Block& block) { std::stringstream ss; - const std::string bits = block.to_string(); + const std::string bits = block.ToString(); std::unordered_map compressionMap; compressionMap["0000"] = "10"; @@ -184,7 +186,8 @@ namespace Leonetienne::GCrypt { // Compress- substitute, and expand the seed key to form the initial and the second-initial round key // This action is non-linear and irreversible, and thus strenghtens security. Halfblock compressedSeed1 = CompressionFunction(seedKey); - Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression + //Halfblock compressedSeed2 = CompressionFunction(Shiftl(seedKey, 1)); // Shifting one key by 1 will result in a completely different compression + Halfblock compressedSeed2 = CompressionFunction((seedKey)); // Shifting one key by 1 will result in a completely different compression // To add further confusion, let's shift seed1 by 1 aswell (after compression, but before substitution) // but only if the total number of bits set are a multiple of 3 @@ -192,10 +195,11 @@ namespace Leonetienne::GCrypt { const std::size_t setBits1 = compressedSeed1.count(); if (setBits1 % 4 == 0) { - compressedSeed1 = Shiftr(compressedSeed1, 1); + //compressedSeed1 = Shiftr(compressedSeed1, 1); + compressedSeed1 = (compressedSeed1); } else if (setBits1 % 3 == 0) { - compressedSeed1 = Shiftl(compressedSeed1, 1); + compressedSeed1 = (compressedSeed1); } // Now apply substitution @@ -224,7 +228,8 @@ namespace Leonetienne::GCrypt { Block newKey = roundKeys[i - 1]; // Shift to left by how many bits are set, modulo 8 - newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible + //newKey = Shiftl(newKey, newKey.count() % 8); // This action is irreversible + newKey = (newKey); // This action is irreversible // Split into two halfblocks, // apply F() to one halfblock with rk[i-2], @@ -255,7 +260,7 @@ namespace Leonetienne::GCrypt { #endif void Feistel::ZeroKeyMemory() { for (Key& key : roundKeys) { - key.reset(); + key.Reset(); } return; diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index 371761d..a89b9cd 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -52,14 +52,14 @@ namespace Leonetienne::GCrypt { // Slurp up the rest of the current block std::stringstream ss; const std::size_t bitsLeft = BLOCK_SIZE - nextBit; - ss << hasher.GetHashsum().to_string().substr(nextBit, bitsLeft); + ss << hasher.GetHashsum().ToString().substr(nextBit, bitsLeft); // Now we have to advance to the next block AdvanceBlock(); // Now, grab the remaining bits const std::size_t remainingBits = BLOCK_SIZE - bitsLeft; - ss << hasher.GetHashsum().to_string().substr(0, remainingBits); + ss << hasher.GetHashsum().ToString().substr(0, remainingBits); // Assert that we have the correct number of bits assert(ss.str().length() == BLOCK_SIZE); diff --git a/GCryptLib/src/Key.cpp b/GCryptLib/src/Key.cpp index c353d9d..0356b0b 100644 --- a/GCryptLib/src/Key.cpp +++ b/GCryptLib/src/Key.cpp @@ -67,7 +67,7 @@ namespace Leonetienne::GCrypt { void Key::WriteToFile(const std::string& path) { // Transform key to bytes - const std::string keybytes = BitsToBytes(to_string()); + const std::string keybytes = BitsToBytes(ToString()); // Create an ofilestream std::ofstream ofs(path, std::ios::out | std::ios::binary); diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp index 21a98e0..9c315e5 100644 --- a/GCryptLib/src/Util.cpp +++ b/GCryptLib/src/Util.cpp @@ -53,7 +53,7 @@ namespace Leonetienne::GCrypt { std::string BitblockToBytes(const Block& bits) { std::stringstream ss; - const std::string bitstring = bits.to_string(); + const std::string bitstring = bits.ToString(); for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) { ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); @@ -97,7 +97,7 @@ namespace Leonetienne::GCrypt { std::string BitblockToHexstring(const Block& b) { std::stringstream ss; const std::string charset = "0123456789abcdef"; - const std::string bstr = b.to_string(); + const std::string bstr = b.ToString(); for (std::size_t i = 0; i < bstr.size(); i += 4) { ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; @@ -139,7 +139,7 @@ namespace Leonetienne::GCrypt { } // Append to our bits - ss << std::bitset<4>(value); + ss << std::bitset<4>(value).to_string(); } return Block(ss.str()); @@ -166,7 +166,7 @@ namespace Leonetienne::GCrypt { } // Append to our bits - ss << std::bitset<4>(value); + ss << std::bitset<4>(value).to_string(); } return ss.str(); diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp new file mode 100644 index 0000000..faa715e --- /dev/null +++ b/GCryptLib/test/Block.cpp @@ -0,0 +1,251 @@ +#include +#include "Catch2.h" +#include +#include +#include + +using namespace Leonetienne::GCrypt; + +// Tests that writing and retrieving data from a block works +TEST_CASE(__FILE__"/Write-read", "[Block]") { + + // Setup + Block block; + + // Exercise + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block.Get(i) == i * 1024); + } +} + +// Tests that the copy constructor works +TEST_CASE(__FILE__"/CCtor", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + // Exercise + Block block2(block); + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block2.Get(i) == i * 1024); + } +} + +// Tests that operator= works +TEST_CASE(__FILE__"/operator=", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + // Exercise + Block block2; + block2 = block; + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block2.Get(i) == i * 1024); + } +} + +// Tests that converting to, and from, strings works +TEST_CASE(__FILE__"/StringConversion", "[Block]") { + + // Setup + srand(time(0)); + std::stringstream ss; + + for (std::size_t i = 0; i < 512; i++) { + ss << (rand()%2 == 0 ? '1' : '0'); + } + + // Exercise + Block block(ss.str()); + + // Verify + REQUIRE(block.ToString() == ss.str()); +} + +// Tests that operator* is the same as *= +TEST_CASE(__FILE__"/operator*&=", "[Block]") { + + // Setup + Block block1; + for (std::size_t i = 0; i < 16; i++) { + block1.Get(i) = i * 1024; + } + + Block block2; + for (std::size_t i = 0; i < 16; i++) { + block2.Get(i) = i * 1024 * 2; + } + + // Exercise + Block block3 = block1 * block2; + block1 *= block2; + + // Verify + REQUIRE(block1 == block3); +} + +// Tests that operator^ (xor) works +TEST_CASE(__FILE__"/xor", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + Block xorRH; + for (std::size_t i = 0; i < 16; i++) { + xorRH.Get(i) = i * 5099; + } + + // Exercise + Block result = block ^ xorRH; + + Block manualResult; + for (std::size_t i = 0; i < 16; i++) { + manualResult.Get(i) = (i * 1024) ^ (i * 5099); + } + + // Verify + REQUIRE(result == manualResult); +} + +// Tests that operator^ is the same as ^= +TEST_CASE(__FILE__"/operator^&=", "[Block]") { + + // Setup + Block block1; + for (std::size_t i = 0; i < 16; i++) { + block1.Get(i) = i * 1024; + } + + Block block2; + for (std::size_t i = 0; i < 16; i++) { + block2.Get(i) = i * 5099 * 2; + } + + // Exercise + Block block3 = block1 ^ block2; + block1 ^= block2; + + // Verify + REQUIRE(block1 == block3); +} + +// Tests that operator== works correctly +TEST_CASE(__FILE__"/operator==", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + SECTION("Expected true") { + Block sameBlock; + for (std::size_t i = 0; i < 16; i++) { + sameBlock.Get(i) = i * 1024; + } + + REQUIRE(block == sameBlock); + } + + SECTION("Expected false") { + Block otherBlock; + for (std::size_t i = 0; i < 16; i++) { + otherBlock.Get(i) = i * 1024 + 1; + } + + REQUIRE_FALSE(block == otherBlock); + } +} + +// Tests that operator!= works correctly +TEST_CASE(__FILE__"/operator!=", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i * 1024; + } + + SECTION("Expected false") { + Block sameBlock; + for (std::size_t i = 0; i < 16; i++) { + sameBlock.Get(i) = i * 1024; + } + + REQUIRE_FALSE(block != sameBlock); + } + + SECTION("Expected true") { + Block otherBlock; + for (std::size_t i = 0; i < 16; i++) { + otherBlock.Get(i) = i * 1024 + 1; + } + + REQUIRE(block != otherBlock); + } +} + +// Tests that getting the data via the matrix accessor works +TEST_CASE(__FILE__"/matrix-accessor", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i; + } + + // Exercise + REQUIRE(block.Get(0,0) == 0); + REQUIRE(block.Get(1,0) == 1); + REQUIRE(block.Get(2,0) == 2); + REQUIRE(block.Get(3,0) == 3); + REQUIRE(block.Get(0,1) == 4); + REQUIRE(block.Get(1,1) == 5); + REQUIRE(block.Get(2,1) == 6); + REQUIRE(block.Get(3,1) == 7); + REQUIRE(block.Get(0,2) == 8); + REQUIRE(block.Get(1,2) == 9); + REQUIRE(block.Get(2,2) == 10); + REQUIRE(block.Get(3,2) == 11); + REQUIRE(block.Get(0,3) == 12); + REQUIRE(block.Get(1,3) == 13); + REQUIRE(block.Get(2,3) == 14); + REQUIRE(block.Get(3,3) == 15); +} + +// Tests that the reset method works +TEST_CASE(__FILE__"/reset", "[Block]") { + + // Setup + Block block; + for (std::size_t i = 0; i < 16; i++) { + block.Get(i) = i + 33; + } + + // Exercise + block.Reset(); + + // Verify + for (std::size_t i = 0; i < 16; i++) { + REQUIRE(block[i] == 0); + } +} diff --git a/GCryptLib/test/Password2Key_CollisionResistance.cpp b/GCryptLib/test/Password2Key_CollisionResistance.cpp index 19587c4..a2fe221 100644 --- a/GCryptLib/test/Password2Key_CollisionResistance.cpp +++ b/GCryptLib/test/Password2Key_CollisionResistance.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -59,7 +60,7 @@ TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key // This will take a LONG while to execute though (about 2.5hrs on my machine), hence why it's set so low. constexpr std::size_t NUM_RUN_TESTS = 10; - std::unordered_map, std::string> keys; // + std::unordered_map keys; // // Try NUM_RUN_TESTS passwords const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -69,23 +70,23 @@ TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key const std::string password = Base10_2_X(i, charset, 0); // Generate key - const std::bitset newKey = Key::FromPassword(password).Get(); + const std::string newKeyBits = Key::FromPassword(password).ToString(); // Check if this block is already in our map - if (keys.find(newKey) != keys.cend()) { + if (keys.find(newKeyBits) != keys.cend()) { std::cout << "Collision found between password \"" << password << "\" and \"" - << keys[newKey] + << keys[newKeyBits] << "\". The key is \"" - << newKey + << newKeyBits << "\"."; FAIL(); } // All good? Insert it into our map - keys[newKey] = password; + keys[newKeyBits] = password; } return;