[Progress:] Completely re-done Block class to not use bitsets, and provide custom operators.

This commit is contained in:
Leonetienne 2022-05-24 01:02:06 +02:00
parent ed45b69342
commit 939df4731b
No known key found for this signature in database
GPG Key ID: C33879CD92E9708C
11 changed files with 619 additions and 191 deletions

View File

@ -1,12 +1,126 @@
#ifndef GCRYPT_BLOCK_H
#define GCRYPT_BLOCK_H
#include "GCrypt/SecureBitset.h"
#include "GCrypt/Config.h"
#include <cstdint>
#include <array>
#include <string>
#include <ostream>
namespace Leonetienne::GCrypt {
typedef SecureBitset<BLOCK_SIZE> 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<std::uint32_t, 16> data;
};
}
#endif

View File

@ -1,49 +0,0 @@
#ifndef GCRYPT_BLOCKMATRIX_H
#define GCRYPT_BLOCKMATRIX_H
#include "GCrypt/Block.h"
#include <cstdint>
#include <array>
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<std::uint32_t, 16> data;
};
}
#endif

View File

@ -1,7 +1,7 @@
#ifndef GCRYPT_VERSION_H
#define GCRYPT_VERSION_H
#define GCRYPT_VERSION 0.231
#define GCRYPT_VERSION 0.232
#endif

220
GCryptLib/src/Block.cpp Normal file
View File

@ -0,0 +1,220 @@
#include "GCrypt/Block.h"
#include "GCrypt/Config.h"
#include <sstream>
#include <bitset>
#include <cassert>
#include <cstring>
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<CHUNK_SIZE_BITS>(
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<CHUNK_SIZE_BITS>(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.CHUNK_SIZE_BITS>(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
}

View File

@ -1,114 +0,0 @@
#include "GCrypt/BlockMatrix.h"
#include <sstream>
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<cellSize>(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<cellSize>(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;
}
}

View File

@ -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<Halfblock, Halfblock> 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<std::string, std::string> 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;

View File

@ -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);

View File

@ -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);

View File

@ -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();

251
GCryptLib/test/Block.cpp Normal file
View File

@ -0,0 +1,251 @@
#include <GCrypt/Block.h>
#include "Catch2.h"
#include <cstdlib>
#include <time.h>
#include <sstream>
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);
}
}

View File

@ -1,4 +1,5 @@
#include <GCrypt/Util.h>
#include <GCrypt/Block.h>
#include <GCrypt/Config.h>
#include <unordered_map>
#include <sstream>
@ -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::bitset<BLOCK_SIZE>, std::string> keys; // <key, password>
std::unordered_map<std::string, std::string> keys; // <key, password>
// 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<BLOCK_SIZE> 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;