Compare commits

..

No commits in common. "master" and "feature/relaunch" have entirely different histories.

16 changed files with 159 additions and 267 deletions

View File

@ -1,56 +0,0 @@
kind: pipeline
type: kubernetes
name: cicd-pipeline
steps:
- name: Build docs
image: ubuntu
commands:
- apt-get update
- >-
apt-get
install
make
doxygen
graphviz
-y
- cd "GCryptLib/doxygen"
- make
- name: Deploy docs to production
image: ubuntu
environment:
SSH_PRIV:
from_secret: ssh-priv
SSH_PUB:
from_secret: ssh-pub
KNOWN_HOSTS:
from_secret: known-hosts # this is just $(ssh-keyscan -p 2222 leonetienne.de)
commands:
- apt-get update
- >-
apt-get
install
openssh-client
rsync
-y
- eval "$(ssh-agent -s)"
- mkdir -p ~/.ssh
- echo "$SSH_PRIV" > ~/.ssh/id_ed25519
- echo "$SSH_PUB" > ~/.ssh/id_ed25519.pub
- echo "$KNOWN_HOSTS" > ~/.ssh/known_hosts
- chmod 600 ~/.ssh/id_ed25519
- chmod 644 ~/.ssh/id_ed25519.pub
- chmod 644 ~/.ssh/known_hosts
- ssh-add
- cd "GCryptLib/doxygen"
- >-
rsync
-avz
--recursive
--delete
--delete-excluded
-e
"ssh -o IdentitiesOnly=yes -p 2222"
./build/
doxygen-gcrypt@leonetienne.de:app

12
.gitmodules vendored
View File

@ -1,17 +1,15 @@
[submodule "StringTools"]
path = StringTools
url = https://code.ze.mawtrixx.net/leonetienne/StringTools.git
url = https://gitea.leonetienne.de/leonetienne/StringTools.git
[submodule "Hazelnupp"]
path = Hazelnupp
url = https://code.ze.mawtrixx.net/leonetienne/Hazelnupp.git
url = https://gitea.leonetienne.de/leonetienne/Hazelnupp.git
[submodule "GeneralUtility"]
path = GeneralUtility
url = https://code.ze.mawtrixx.net/leonetienne/GeneralUtility.git
url = https://gitea.leonetienne.de/leonetienne/GeneralUtility.git
[submodule "GCryptLib/exec/Eule"]
path = GCryptLib/exec/Eule
url = https://code.ze.mawtrixx.net/leonetienne/Eule.git
url = https://gitea.leonetienne.de/leonetienne/Eule.git
[submodule "GCryptLib/exec/BmpPP"]
path = GCryptLib/exec/BmpPP
url = https://code.ze.mawtrixx.net/leonetienne/BmpPP.git
[submodule "BmpPP"]
url = https://code.ze.mawtrixx.net/leonetienne/BmpPP.git
url = https://gitea.leonetienne.de/leonetienne/BmpPP.git

View File

@ -1 +0,0 @@
<mxfile host="app.diagrams.net" modified="2022-05-17T08:55:29.265Z" agent="5.0 (X11)" etag="82noNgqBrG7hiBNRM9Jy" version="18.0.6"><diagram id="ngb83caThQZh03zxjPih" name="Page-1">7VpNc+I4EP01VJHDUDYEkhwDJDvMMMXWcNjZuWwJq7G1sS2PLALk169alr9hQwhkApULltpS66Pfe2q5aHQGweoPQSLvG6fgN9oWXTU6w0a7bXdvLPVAyzqxXHdvEoMrGDWNcsOUPYExmn7uglGISw0l575kUdno8DAER5ZsRAi+LDebc788akRcqBmmDvHr1r8YlV66Ciu3fwbmeunItmXeBCRtbAyxRyhfFkydu0ZnIDiXSSlYDcDHzUv3Jel3v+VtNjEBodylw7/Bl88/u/F0YP9Yj9rf5uLrl+4n4+WR+Auz4Ea75yt/fcoeVdHF4pBIgo5CF2LJeKjKPlmDUM/mcDS+SLvMRNojtajZFPyUXFvEZ26ox+z9WuAm9H2Yy7xW7XUc79+B0Fi1748ng6//TEc/71RlxiTa5oIH6CrUi48WEhc8Zwoa7QEGVFIWJkUi3PjCFEOKzYMAKCMS/DU6AtCDSI/hY+Zz50EDWduUO2s4HLfU4ztEQPTYi1AyjN7d5B7doUkAcTyg2G5MYllwpF9LwvyIUAo4/pIp9LUtq3XKsbn1Y67XHUc8jNkMN14xGHFHnF8LJhQi0/hA6Ih1ZND5AOuTXvho3kAyJ11Zap0t5nMQowSI2WAsHyrBQa2fFIrbGzsMcvyNxho1WjFCLg1o9e6uFWz1RqeYhEcQmdEjmiosZLGnOyiYKl64+wXgpburhVWuU7UWfBEiATpDS71eekzCNCIOvl2q80nZPBn4qmarolqFZErpb01UJI8yn/gOVluV1s70Wx18wAOQAnmedrg0km/OPLtn6sv8BOmmJ4hXPD06xkjMqeVmvnNhVwWj7S/Q+c4LdJ6yTTo/zHX+gPHbix0hk0w1fgJEHs7YYZGnp6mRiaBmAaJ6iT8zcFGmrUhwB+LYaAbCHJYauVpWmrnXKbbi4UXrkJO+K88sU31NGAfYY7YYI+rITSZzUs4gC42mWdMoHlbuKeRlRUhFxF2CtfPkN59pNFHjJRG0cphNxnqCKwcimUk2zktv/kCjXmQBCo3QJMvE1ccX70a+T0JgOle7Cox1LIG5fIHA8IVMkqlcXSbvRl02E3XyQqIuBZMSwpQXoNIxvVKVM3JcOnZKEhkjQQcVm9+XnUxMaA+dnkxq6QnuMJTyk0EhRdEBMfGimRu/nDY373XWkuq9smyNwknIQEb5Z2XAPpYMdDfIQGXvIKS3eDFXNUcFJGZOebvKewsrJn9gudU1tb9NOywPV4Vmw7WpJEMCrd3sKxurpsUXwoHn78dSXfBAPpdf1QNVDMSGOKQ2AT6RCqnlrxcbYmNG+JOzUOY46FxXjoNqGpks0/QqfiKoOqoCql1xlOxDzZGGSrbs/dHTq6HnXuUGzT7y9aIOJBXgMZmBX8ZPKmOOCrbS3Dr/AkYp+uiriyV7IjPtD3ET4br0Srv9Rnf4fyQ1n5tM5/wjTxFj2wmyldGfrFan23sdKNImfD6P4Shhujolkv82UtplLrVv9iWlvSXZe4aUav/JutDMoHvnCacqkoMn8XhQKF3XoFS7hzUfYH0m5L86A/LffJD/efJnB+dryV91dCzy18Z5C/KnglM874sZefNMaH9zBrS3N31B/OB9hUaX9mXrqldi0mWVsbtSf4Ov7DL3Rvm4Xf+qc3YJub3l6nZa7Dype/d7Scn3pmbV0a68fG1K3rXf4lSu38LPOSe3z+FGbn9cyffIyvfmf9XRsfhfG+dN+F+/k59lVm6/79u4qub/DUua5/+w69z9Bw==</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,24 +0,0 @@
* Add a new iobase: bytes.
For cleartext:
Format is ALWAYS raw bytes. That works fine with text, and files.
The iobase ONLY affects ciphertext!
For ciphertext:
format depends..:
If none specified:
- raw bytes if an outputfile is given
- hex if output to stdout
If specified:
Just use the specified iobase. Even if it means dumping bytes to stdout, or writing base-2 to files.
* --intext or --infile should no longer be required. Default behaviour should be reading from stdin.
* No guessing where to output (like file-in got saved to another file beforehand.) Default behaviour should be stdout.
* --progress should output reports to stderr. This way it won't disturb piping the ciphertext to another program.
* Add a module to generate keyfiles.
Should seed a gcrypt prng with std::random_device, and then dump BLOCK_SIZE bits to the specified output.

View File

@ -1,7 +1,7 @@
#ifndef GCRYPTCLI_VERSION_H
#define GCRYPTCLI_VERSION_H
#define GCRYPTCLI_VERSION 0.12512
#define GCRYPTCLI_VERSION 0.1251
#endif

View File

@ -23,14 +23,15 @@ Have these depencies installed:
6) Compile: `make`.
The executable `gcrypt` should now lie in `build/`.
If you want to use this globally, you could move it to `/usr/bin/`, or some other location in your $PATH. ### Options and flags
If you want to use this globally, you could move it to `/usr/bin/`, or some other location in your $PATH.
### All arguments and flags:
### Options and flags
All arguments and flags:
```
CLI for the GCrypt cipher/obfuscator
Copyright (c) 2022 Leon Etienne
GCryptLib v0.236
GCryptCLI v0.12511
GCrypt v0.236
GCrypt CLI v0.1241
THIS IS EXPERIMENTAL SOFTWARE AND MUST BE CONSIDERED INSECURE. DO NOT USE THIS TO ENCRYPT SENSITIVE DATA! READ THE README FILES ACCESSIBLE AT "https://gitea.leonetienne.de/leonetienne/GCrypt"
==== AVAILABLE PARAMETERS ====
@ -39,11 +40,7 @@ THIS IS EXPERIMENTAL SOFTWARE AND MUST BE CONSIDERED INSECURE. DO NOT USE THIS T
--iobase-16 VOID incompatibilities=[--iobase-bytes, --iobase-2, --iobase-8, --iobase-64, --iobase-uwu, --iobase-ugh] Interpret and format ciphertexts in base16 (hex)
--progress-interval INT default=['1000'] Print digestion progress reports every these many data blocks.
--buffer-input VOID Will read the entire input before beginning any digestion.
--progress -p VOID Print digestion progress to stderr. May be advisable for large files, as the cipher is rather slow.
--progress -p VOID Print digestion progress to stdout. May be advisable for large files, as the cipher is rather slow.
--cli-version -v VOID Will supply the version of GCryptCLI used.
@ -53,7 +50,19 @@ THIS IS EXPERIMENTAL SOFTWARE AND MUST BE CONSIDERED INSECURE. DO NOT USE THIS T
--iobase-10 VOID incompatibilities=[--iobase-bytes, --iobase-2, --iobase-8, --iobase-16, --iobase-64, --iobase-uwu, --iobase-ugh] Interpret and format ciphertexts in base10
--buffer-output VOID Will digest the entire data before initiating any output.
--ofile -o STRING incompatibilities=[--ostdout, --hash] Write output in this file.
--key -k STRING incompatibilities=[--keyfile, --keyask, --hash] Use this value as a password to extrapolate the encryption key. WARNING: Arguments may be logged by the system!
--keyask -ka VOID incompatibilities=[--key, --keyfile, --hash] Read the encryption key from stdin.
--no-newline VOID Don't postfix stdout output with a newline
--puffer-output VOID Will digest the entire data before initiating any output.
--puffer-input VOID Will read the entire input before beginning any digestion.
--decrypt -d VOID incompatibilities=[--encrypt, --hash, --generate-key] Use decryption module.
--lib-version VOID Will supply the version of GCryptLib used.
@ -71,16 +80,6 @@ THIS IS EXPERIMENTAL SOFTWARE AND MUST BE CONSIDERED INSECURE. DO NOT USE THIS T
--generate-key VOID incompatibilities=[--encrypt, --decrypt, --hash] Use the key generation module. Will generate a random key based on hardware events, output it, and exit.
--ofile -o STRING incompatibilities=[--ostdout, --hash] Write output in this file.
--key -k STRING incompatibilities=[--keyfile, --keyask, --hash] Use this value as a password to extrapolate the encryption key. WARNING: Arguments may be logged by the system!
--keyask -ka VOID incompatibilities=[--key, --keyfile, --hash] Read the encryption key from stdin.
--no-newline VOID Don't postfix stdout output with a newline
--decrypt -d VOID incompatibilities=[--encrypt, --hash, --generate-key] Use decryption module.
--hash -h VOID incompatibilities=[--encrypt, --decrypt, --generate-key] Use the GHash hash module to calculate a hashsum.
--intext -it STRING incompatibilities=[--infile] Encrypt this string.
@ -102,8 +101,9 @@ hello, world!
```
#### What about not using hex?
> :warning: Custom bases are super imperformant. Please only use them for text-based input...
> The larger the base, the exponentially longer it takes to recode.
> :warning: Custom bases are super imperformant.
> Encrypting all text in main.cpp took about two seconds.
> Outputting it in base-64 took just over ONE MINUTE. In base-2 over SEVEN MINUTES. The general trend seems to be, the larger the base, the better it performs.
```sh
$ gcrypt -e --keyask --intext "hello, world!" --iobase-2
@ -130,34 +130,44 @@ $ gcrypt -e --key "secretpassword" --intext "hello, world!"
```sh
$ gcrypt -e --keyfile "dog.jpg" --intext "hello, world!"
```
> :warning: Some operating systems will log cli arguments! One might find your keyfile!
#### Creating keyfiles
```sh
$ gcrypt --generate-key --ofile "my-keyfile.bin"
```
This will generate a random 512-bit keyfile from hardware events and other random sources, if available.
To see how this randomness gets sourced, see [std::random_device](https://en.cppreference.com/w/cpp/numeric/random/random_device).
This will generate a random 512-bit keyfile from hardware events
> :warning: Some operating systems will log cli arguments! One might find your keyfile!
#### Encrypting files
```sh
$ gcrypt -e --keyask --infile "cat.jpg" --ofile "cat.jpg.crypt"
$ gcrypt -e --keyask --infile "cat.jpg"
```
File `cat.jpg.crypt` will be created.
#### Encrypting files to a target file name
```sh
$ gcrypt -e --keyask --infile "cat.jpg" -o "encrypted_cat.jpg"
```
File `encrypted_cat.jpg` will be created.
#### Decrypting files
```sh
$ gcrypt -d --keyask --infile "cat.jpg.crypt" --ofile "decrypted_cat.jpg"
$ gcrypt -d --keyask --infile "cat.jpg.crypt"
```
File `decrypted_cat.jpg` will be created. You can now open it again. Its contents match `cat.jpg`.
File `cat.jpg.crypt.plain` will be created. Its contents match `cat.jpg`
> :warning: Since this is a block cipher, decrypted files may be tailpadded with a few nullbytes.
#### Decrypting files to a target file name
```sh
$ gcrypt -d --keyask --infile "cat.jpg.crypt" -o "decrypted_cat.jpg"
```
File `decrypted_cat.jpg` will be created. You can now open it again.
#### Encrypting large files takes time. How's the progress?
```sh
$ gcrypt -e --keyask --infile "cat.jpg" --buffer-input --progress
$ gcrypt -e --keyask --infile "cat.jpg" --progress
```
Something along the lines of `Encrypting... (Block 200 / 1148 - 17.4216%)` will be regularly, but not too often, printed to stderr.
Obviously, to print progress, we have to know the size of the input. Hence, it has to be buffered.
Something along the lines of `Encrypting... (Block 200 / 1148 - 17.4216%)` will be regularly, but not too often, printed to stdout.
#### Any cipher can also compute hashsums
```sh
@ -167,16 +177,15 @@ a96f42c9d97e46b9e1ed7de5182770170d4ef9b7b8264f3fbd89b38dc60c1fe06232653f58560133
$ gcrypt -h --infile "cat.jpg"
fe6bdfb6ec39771c4fdcdc40e52397bcd67fbfef0ad5a15ebbd8b9e4c2a815848b3984eda5ef6f727e9e420c23500c90c42ab80ac5659048be8969357741e3e5
```
The hashsum will always be of size BLOCK_SIZE. That is 512 bits.
The hashsum will always be of size BLOCK_SIZE. That is 512.
#### What version am i running?
Depending on whether you want to know the GCryptLib version or the CLI's version,
Depending on wether you want to know the GCrypt version or the CLI's version,
use either `--cli-version` or `--lib-version`.
It will print out a floating point number.
You can see both in the `--help`-page.
#### Streaming the output of file en/decryption.
Easily! If you do not supply any output or input, stdout and stdin will be used instead!
#### I want to stream the output of file en/decryption.
// Easily! If you do not supply any output or input, stdout and stdin will be used instead!
```sh
# mpv is a media player, as an example
$ gcrypt -d --key "123" --infile "music.mp3.crypt" | mpv -
@ -186,8 +195,8 @@ $ gcrypt -d --key "123" --infile "music.mp3.crypt" | mpv -
By default, gcrypt will read a block, digest it, and output the result immediately.
Sometimes you don't want that. Use these flags, respectively:
```
--buffer-input # Reads all input to memory before beginning to digest it
--buffer-output # Digests all input before beginning to write any
--puffer-input # Reads all input to memory before beginning to digest it
--puffer-output # Digests all input before beginning to write any
```
## Esoteric data formats
@ -203,14 +212,6 @@ $ gcrypt -e --keyask --intext "hello, world!" --iobase-ugh
Grr... Wha-? Aah! Aah! Uh-huh... Aah! Grr... Aah! Aah! Uh-huh... Ah... Ugh Grr... Ugh Pft! Nu-uh... Gah! Bah! Huh...? Ah... Uh-huh... Wha-? Pft! Nu-uh... Ugh Wha-? Psh! Agh! Ah... Aah! Nu-uh... Psh! Pft! Nu-uh... Psh! Shh! Gah! Ah... Pft! Gah! Shh! Bah! Gah! Uh-huh... Gah! Duh! Aah! Uh-huh... Er- Nu-uh... Gah! Wha-? Pft! Er- Shh! Ah... Huh...? Er- Wha-? Uh-huh... Ah... Shh! Ugh Bah! Wha-? Uaah! Ah... Nu-uh... Uh-huh... Ugh Pft! Pft! Gah! Shh! Shh! Wha-? Bah! Ugh Grr... Aah! Pft! Nu-uh... Ah... Aah! Agh! Er- Psh! Uaah! Nu-uh... Ugh Wha-? Uh-huh... Shh! Pft! Aah! Agh! Grr... Agh! Agh! Grr... Pft! Wha-? Wha-? Uh-huh... Aah! Ugh Aah! Pft! Gah! Bah! Huh...? Ugh Bah! Uaah! Gah! Bah! Duh! Duh! Uh-huh... Grr... Ah... Grr... Ugh Ah... Pft!
```
Yes, you can send these... *adventorous* texsts to your friends, and they can actually decipher them
back to the original message :). Almost going a bit into the steganography territory here, hehe.
These weird number bases don't impact security at all. This is because they are just that.
Number bases, to represent a bunch of bytes, that is our ciphertext.
These just bring a bit more fun into the big world of cryptography :).
## LICENSE
```
GNU GENERAL PUBLIC LICENSE

View File

@ -13,8 +13,8 @@ void CommandlineInterface::Init(int argc, const char* const* argv) {
std::stringstream ss;
ss << "CLI for the GCrypt cipher/obfuscator" << std::endl
<< "Copyright (c) 2022 Leon Etienne" << std::endl
<< "GCryptLib v" << GCRYPT_VERSION << std::endl
<< "GCryptCLI v" << GCRYPTCLI_VERSION << std::endl
<< "GCrypt v" << GCRYPT_VERSION << std::endl
<< "GCrypt CLI v" << GCRYPTCLI_VERSION << std::endl
<< "THIS IS EXPERIMENTAL SOFTWARE AND MUST BE CONSIDERED INSECURE. DO NOT USE THIS TO ENCRYPT SENSITIVE DATA! READ THE README FILES ACCESSIBLE AT \"https://gitea.leonetienne.de/leonetienne/GCrypt\"";
nupp.SetBriefDescription(ss.str());
ss.str("");
@ -102,11 +102,11 @@ void CommandlineInterface::Init(int argc, const char* const* argv) {
nupp.RegisterConstraint("--cli-version", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterAbbreviation("-v", "--cli-version");
nupp.RegisterDescription("--buffer-input", "Will read the entire input before beginning any digestion.");
nupp.RegisterConstraint("--buffer-input", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterDescription("--puffer-input", "Will read the entire input before beginning any digestion.");
nupp.RegisterConstraint("--puffer-input", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterDescription("--buffer-output", "Will digest the entire data before initiating any output.");
nupp.RegisterConstraint("--buffer-output", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterDescription("--puffer-output", "Will digest the entire data before initiating any output.");
nupp.RegisterConstraint("--puffer-output", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterDescription("--no-newline", "Don't postfix stdout output with a newline");
nupp.RegisterConstraint("--no-newline", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
@ -173,10 +173,10 @@ void CommandlineInterface::SpecialCompatibilityChecking() {
if (
(nupp.HasParam("--progress")) &&
(!nupp.HasParam("--buffer-input"))
(!nupp.HasParam("--puffer-input"))
) {
CrashWithMsg("--progress requires --buffer-input to work!");
CrashWithMsg("--progress requires --puffer-input to work!");
}
return;

View File

@ -57,7 +57,9 @@ void DataIngestionLayer::Init() {
}
// Derive from our the current module if we're reading ciphertext or not
if (Configuration::activeModule == Configuration::MODULE::DECRYPTION) {
if (
(Configuration::activeModule == Configuration::MODULE::DECRYPTION)
) {
isReadingCiphertext = true;
}
else {
@ -323,16 +325,16 @@ bool DataIngestionLayer::ReachedEOF() {
}
bool DataIngestionLayer::IsBlockReady() {
// We're not ready, if we haven't reached EOF, if we should buffer
// We're not ready, if we haven't reached EOF, if we should puffer
// the input.
if (
(CommandlineInterface::Get().HasParam("--buffer-input")) &&
(CommandlineInterface::Get().HasParam("--puffer-input")) &&
(!reachedEof)
) {
return false;
}
// If we're not buffering, just return whether or not
// If we're not puffering, just return whether or not
// we have any blocks...
return blocks.size() > 0;
}

View File

@ -65,13 +65,13 @@ void DataOutputLayer::WriteBlock() {
}
// Check if we have any block to write
// and if we should (output-buffering)
// and if we should (output-puffering)
// Basically: only output if we have anything to output, and
// if --buffer-output is given, only output once we have reachedEof.
// if --puffer-output is given, only output once we have reachedEof.
if (
(blocks.size() > 0) &&
(
(!CommandlineInterface::Get().HasParam("--buffer-output")) ||
(!CommandlineInterface::Get().HasParam("--puffer-output")) ||
(reachedEof)
)
) {

View File

@ -1,6 +1,6 @@
all:
# Copy all but the header of the readme here
tail ../../readme.md -n +9 > index.md
tail ../../readme.md -n +2 > index.md
#
# Run doxygen
doxygen doxyfig

View File

@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "Leonetienne/GCrypt"
PROJECT_NAME = "Leonetienne/GhettoCrypt"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version

View File

@ -4,7 +4,7 @@
#include <cstdint>
#include <array>
#include <string>
#include <iosfwd>
#include <ostream>
#include <bitset>
namespace Leonetienne::GCrypt {

View File

@ -9,11 +9,7 @@
// Just to be sure, the compiler will optimize this
// little formula out, let's do it in the preprocessor
namespace {
constexpr std::size_t MAT_INDEX(const std::size_t row, const std::size_t column) {
return column*4 + row;
}
}
#define MAT_INDEX(row, column) (column*4 + row)
namespace Leonetienne::GCrypt {
@ -152,25 +148,25 @@ namespace Leonetienne::GCrypt {
// Maybe pre-calculate the 1d-index...?
m.Get(MAT_INDEX(0, 0)) = (this->Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 0))) + (this->Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 0))) + (this->Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 0))) + (this->Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 0)));
m.Get(MAT_INDEX(0, 1)) = (this->Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 1))) + (this->Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 1))) + (this->Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 1))) + (this->Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 1)));
m.Get(MAT_INDEX(0, 2)) = (this->Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 2))) + (this->Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 2))) + (this->Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 2))) + (this->Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 2)));
m.Get(MAT_INDEX(0, 3)) = (this->Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 3))) + (this->Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 3))) + (this->Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 3))) + (this->Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 3)));
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(MAT_INDEX(1, 0)) = (this->Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 0))) + (this->Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 0))) + (this->Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 0))) + (this->Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(3, 0)));
m.Get(MAT_INDEX(1, 1)) = (this->Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 1))) + (this->Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 1))) + (this->Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 1))) + (this->Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(3, 1)));
m.Get(MAT_INDEX(1, 2)) = (this->Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 2))) + (this->Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 2))) + (this->Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 2))) + (this->Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(3, 2)));
m.Get(MAT_INDEX(1, 3)) = (this->Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 3))) + (this->Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 3))) + (this->Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 3))) + (this->Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(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(MAT_INDEX(2, 0)) = (this->Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 0))) + (this->Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 0))) + (this->Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 0))) + (this->Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(3, 0)));
m.Get(MAT_INDEX(2, 1)) = (this->Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 1))) + (this->Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 1))) + (this->Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 1))) + (this->Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(3, 1)));
m.Get(MAT_INDEX(2, 2)) = (this->Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 2))) + (this->Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 2))) + (this->Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 2))) + (this->Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(3, 2)));
m.Get(MAT_INDEX(2, 3)) = (this->Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 3))) + (this->Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 3))) + (this->Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 3))) + (this->Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(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(MAT_INDEX(3, 0)) = (this->Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 0))) + (this->Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 0))) + (this->Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 0))) + (this->Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(3, 0)));
m.Get(MAT_INDEX(3, 1)) = (this->Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 1))) + (this->Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 1))) + (this->Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 1))) + (this->Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(3, 1)));
m.Get(MAT_INDEX(3, 2)) = (this->Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 2))) + (this->Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 2))) + (this->Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 2))) + (this->Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(3, 2)));
m.Get(MAT_INDEX(3, 3)) = (this->Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 3))) + (this->Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 3))) + (this->Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 3))) + (this->Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(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;
}
@ -187,25 +183,25 @@ namespace Leonetienne::GCrypt {
// Maybe pre-calculate the 1d-index...?
this->Get(MAT_INDEX(0, 0)) = (m.Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 0))) + (m.Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 0))) + (m.Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 0))) + (m.Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 0)));
this->Get(MAT_INDEX(0, 1)) = (m.Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 1))) + (m.Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 1))) + (m.Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 1))) + (m.Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 1)));
this->Get(MAT_INDEX(0, 2)) = (m.Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 2))) + (m.Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 2))) + (m.Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 2))) + (m.Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 2)));
this->Get(MAT_INDEX(0, 3)) = (m.Get(MAT_INDEX(0, 0)) * o.Get(MAT_INDEX(0, 3))) + (m.Get(MAT_INDEX(0, 1)) * o.Get(MAT_INDEX(1, 3))) + (m.Get(MAT_INDEX(0, 2)) * o.Get(MAT_INDEX(2, 3))) + (m.Get(MAT_INDEX(0, 3)) * o.Get(MAT_INDEX(3, 3)));
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(MAT_INDEX(1, 0)) = (m.Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 0))) + (m.Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 0))) + (m.Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 0))) + (m.Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(3, 0)));
this->Get(MAT_INDEX(1, 1)) = (m.Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 1))) + (m.Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 1))) + (m.Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 1))) + (m.Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(3, 1)));
this->Get(MAT_INDEX(1, 2)) = (m.Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 2))) + (m.Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 2))) + (m.Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 2))) + (m.Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(3, 2)));
this->Get(MAT_INDEX(1, 3)) = (m.Get(MAT_INDEX(1, 0)) * o.Get(MAT_INDEX(0, 3))) + (m.Get(MAT_INDEX(1, 1)) * o.Get(MAT_INDEX(1, 3))) + (m.Get(MAT_INDEX(1, 2)) * o.Get(MAT_INDEX(2, 3))) + (m.Get(MAT_INDEX(1, 3)) * o.Get(MAT_INDEX(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(MAT_INDEX(2, 0)) = (m.Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 0))) + (m.Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 0))) + (m.Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 0))) + (m.Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(3, 0)));
this->Get(MAT_INDEX(2, 1)) = (m.Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 1))) + (m.Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 1))) + (m.Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 1))) + (m.Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(3, 1)));
this->Get(MAT_INDEX(2, 2)) = (m.Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 2))) + (m.Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 2))) + (m.Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 2))) + (m.Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(3, 2)));
this->Get(MAT_INDEX(2, 3)) = (m.Get(MAT_INDEX(2, 0)) * o.Get(MAT_INDEX(0, 3))) + (m.Get(MAT_INDEX(2, 1)) * o.Get(MAT_INDEX(1, 3))) + (m.Get(MAT_INDEX(2, 2)) * o.Get(MAT_INDEX(2, 3))) + (m.Get(MAT_INDEX(2, 3)) * o.Get(MAT_INDEX(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(MAT_INDEX(3, 0)) = (m.Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 0))) + (m.Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 0))) + (m.Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 0))) + (m.Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(3, 0)));
this->Get(MAT_INDEX(3, 1)) = (m.Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 1))) + (m.Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 1))) + (m.Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 1))) + (m.Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(3, 1)));
this->Get(MAT_INDEX(3, 2)) = (m.Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 2))) + (m.Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 2))) + (m.Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 2))) + (m.Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(3, 2)));
this->Get(MAT_INDEX(3, 3)) = (m.Get(MAT_INDEX(3, 0)) * o.Get(MAT_INDEX(0, 3))) + (m.Get(MAT_INDEX(3, 1)) * o.Get(MAT_INDEX(1, 3))) + (m.Get(MAT_INDEX(3, 2)) * o.Get(MAT_INDEX(2, 3))) + (m.Get(MAT_INDEX(3, 3)) * o.Get(MAT_INDEX(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;
}
@ -837,3 +833,6 @@ namespace Leonetienne::GCrypt {
template class Basic_Block<std::uint16_t>;
}
#undef MAT_INDEX

View File

@ -302,8 +302,8 @@ TEST_CASE(__FILE__"/operator-&=", "[Block]") {
// Tests that subtraction undoes addition, and vica versa
TEST_CASE(__FILE__"/subtraction-undoes-addition", "[Block]") {
// Setup
const Block a = Key::Random();
const Block b = Key::Random();
const Block a = Key::FromPassword("Halleluja");
const Block b = Key::FromPassword("Ananas");
// Exercise
const Block a_plus_b = a + b;
@ -441,7 +441,7 @@ TEST_CASE(__FILE__"/shift-rows-up", "[Block]") {
// Tests that ShiftRowsUpInplace() does the exact same thing as ShiftRowsUp()
TEST_CASE(__FILE__"/shift-rows-up-same-as-inplace", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise and verify
@ -475,7 +475,7 @@ TEST_CASE(__FILE__"/shift-rows-down", "[Block]") {
// Tests that ShiftRowsDownInplace() does the exact same thing as ShiftRowsDown()
TEST_CASE(__FILE__"/shift-rows-down-same-as-inplace", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise and verify
@ -509,7 +509,7 @@ TEST_CASE(__FILE__"/shift-columns-left", "[Block]") {
// Tests that ShiftColumnsLeftInplace()() does the exact same thing as ShiftColumnsLeft()
TEST_CASE(__FILE__"/shift-columns-left-same-as-inplace", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise and verify
@ -543,7 +543,7 @@ TEST_CASE(__FILE__"/shift-columns-right", "[Block]") {
// Tests that ShiftColumnsRightInplace()() does the exact same thing as ShiftColumnsRight()
TEST_CASE(__FILE__"/shift-columns-right-same-as-inplace", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise and verify
@ -576,7 +576,7 @@ TEST_CASE(__FILE__"/shift-cells-left", "[Block]") {
// Tests that ShiftCellsLeftInplace()() does the exact same thing as ShiftCellsLeft()
TEST_CASE(__FILE__"/shift-cells-left-same-as-inplace", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise and verify
@ -609,7 +609,7 @@ TEST_CASE(__FILE__"/shift-cells-right", "[Block]") {
// Tests that ShiftCellsRightInplace()() does the exact same thing as ShiftCellsRight()
TEST_CASE(__FILE__"/shift-cells-right-same-as-inplace", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise and verify
@ -620,7 +620,7 @@ TEST_CASE(__FILE__"/shift-cells-right-same-as-inplace", "[Block]") {
// Tests that shifting down undoes shifting up, and vica versa
TEST_CASE(__FILE__"/shift-down-undoes-shift-up", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise
@ -634,7 +634,7 @@ TEST_CASE(__FILE__"/shift-down-undoes-shift-up", "[Block]") {
// Tests that shifting left undoes shifting right, and vica versa
TEST_CASE(__FILE__"/shift-left-undoes-shift-right", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise
@ -648,7 +648,7 @@ TEST_CASE(__FILE__"/shift-left-undoes-shift-right", "[Block]") {
// Tests that shifting cells left undoes shifting cells right, and vica versa
TEST_CASE(__FILE__"/cellshift-left-undoes-cellshift-right", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;
// Exercise
@ -662,7 +662,7 @@ TEST_CASE(__FILE__"/cellshift-left-undoes-cellshift-right", "[Block]") {
// Tests that multiple, combined shifts and additions can be undone
TEST_CASE(__FILE__"/multiple-combined-shifts-and-additions-can-be-undone", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
Block key = Key::FromPassword("Papaya");
const Block initial_a = a;
@ -689,42 +689,23 @@ TEST_CASE(__FILE__"/multiple-combined-shifts-and-additions-can-be-undone", "[Blo
// Tests that the get-bit method works
TEST_CASE(__FILE__"/get-bit", "[Block]") {
for (std::size_t i = 0; i < 100; i++) {
// Setup
Block a = Key::Random();
// Setup
Block a = Key::FromPassword("Halleluja");
// Exercise
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << a.GetBit(i);
}
// Verify
REQUIRE(ss.str() == a.ToBinaryString());
// Exercise
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << a.GetBit(i);
}
}
// Tests that the set-bit method works
TEST_CASE(__FILE__"/set-bit", "[Block]") {
for (std::size_t i = 0; i < 100; i++) {
// Setup
const std::string a_bits = Key::Random().ToBinaryString();
// Exercise
Block a;
for (std::size_t i = 0; i < 512; i++) {
a.SetBit(i, a_bits[i] == '1');
}
// Verify
REQUIRE(a_bits == a.ToBinaryString());
}
// Verify
REQUIRE(ss.str() == a.ToBinaryString());
}
// Tests that the set-bit to-false method works
TEST_CASE(__FILE__"/set-bit-to-false", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
// Exercise
a.SetBit(5, 0);
@ -742,7 +723,7 @@ TEST_CASE(__FILE__"/set-bit-to-false", "[Block]") {
// Tests that the set-bit to-true method works
TEST_CASE(__FILE__"/set-bit-to-true", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
// Exercise
a.SetBit(5, 1);
@ -760,7 +741,7 @@ TEST_CASE(__FILE__"/set-bit-to-true", "[Block]") {
// Tests that the flip-bit method works
TEST_CASE(__FILE__"/flip-bit", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
std::string compare = a.ToBinaryString();
compare[5] = compare[5] == '1' ? '0' : '1';
@ -882,7 +863,7 @@ TEST_CASE(__FILE__"/bitshift-right-inplace", "[Block]") {
TEST_CASE(__FILE__"/bitshifting-undoes-itself", "[Block]") {
// Setup
Block a = Key::Random();
Block a = Key::FromPassword("Halleluja");
const Block initial_a = a;

View File

@ -1,12 +1,7 @@
[![Build Status](https://drone.leonetienne.de/api/badges/leonetienne/GCrypt/status.svg)](https://drone.leonetienne.de/leonetienne/GCrypt)
# GCrypt
# GCrypt
*(GhettoCrypt), because frankly I have no idea what the fuck I'm doing*
<sub>*Please don't use this for anything critical*</sub>
## [Documentation](https://gcrypt.rtfm.leonetienne.de/)
## What the hell is this?
An educational project on implementing a block cipher using a feistel network.
This block cipher employs a few modes of operation. Read more about them [here](#modes-of-operation).
@ -14,15 +9,15 @@ This block cipher employs a few modes of operation. Read more about them [here](
## Features
* It has very easy syntax
* It's slow
* It absolutely tanks your ram when working with files
* Even leaves some key fragments in there✨
* It's probably super insecure
* But the syntax is pythonlike easy🙇
* 512-bit keys
It's pretty ghetto, you know?
## What are the actual advantages?
* It's two files to import into your project
* No dependencies
* 1 Line to use
* 100% cross plattform
@ -32,7 +27,7 @@ It's pretty ghetto, you know?
### I am not kidding, don't use this for critical stuff! Homebrew ciphers tend to be shit!
Especially mine!🗡️
Even assumed it's a good cipher, it's implementation leaves a lot to be desired in terms of being cryptographically secure.
Even assumed it's a good cipher, it's implementation leaves a lot to be desired in terms of being cryptographically secure. The whole leaving partial keys in ram- thingy...
## How do I use this?
### *"I don't care about the library. Just let me use it from the command line!"*
@ -107,8 +102,6 @@ This way you can cipher on bitlevel. Examples on how to do this are in [GWrapper
This way you could, for example, decrypt an ecrypted file directly into memory.
Without saying, this is more advanced and not as-easy as the methods supplied in the wrapper.
Want more documentation? See the [doxygen page](https://gcrypt.rtfm.leonetienne.de/).
---
## The deets 🍝
@ -117,26 +110,25 @@ Want more documentation? See the [doxygen page](https://gcrypt.rtfm.leonetienne.
* [CBC] This block cipher makes use of cipher block chaining. Nothing special.
* [IV] The initialization vector is indeed a bit of special sauce, as it depends on your key instead of being static. It is generated by running the feistel network on *E(m=seed, k=seed)*, which is a one-way function, because *m=k*.
* [RRKM] Never heard of a mode like this, so i've named it **R**olling**R**ound**K**ey**M**ode. This basically means that the round key extrapolation is carried out continously over EVERY round on EVERY block. So in addition to *M<sub>i</sub>* being dependent on *E(M<sub>i-1</sub>,K<sub>i-1,0</sub>)* due to CBC, so is now *K<sub>i</sub>* dependent on *K<sub>i-1,r</sub>* with *r* being the maximum number of extrapolated keys within a call of *E()*. This is handled within the feistel network class, as an instance lifecycle sees all blocks. Just in case you want to take a peek.
* [I-don't-even-know-any-more] Inspired by Rijndael, it does some monkey tricks with reversible matrix-mutators after each feistel round.
### Password to key
How does GCrypt transform a password to a key?..
Well, it uses the included hash function [GHash](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/GHash.h).
Well, it uses the included hash function [GHash](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GHash.h).
### Hashing with GHash
GHash is a streaming hash function based on the GCipher.
For all intents and purposes, it does the following:
You have a *Block b*, which is initialized with a static random distribution.
Once you give the GHash instance a data block to digest, it will use the GCipher to encrypt it, with itself as a key, and xor that onto *b*.
(*b<sub>i</sub> = b<sub>i-1</sub> &#8853; E(key=b<sub>new</sub>, data=b<sub>new</sub>)*)
(*b<sub>i</sub> = b<sub>i-1</sub> &#8853; E(key=b, data=b)*)
The lastest *b* represents the current result of the hash function.
GHash also supports a do-it-all wrapper method that takes a vector of blocks, and returns a hashsum for it.
This wrapper function adds an additional block including the length of the input, if provided. This wrapper function is used to transform Passwords to Keys.
GHash also supports a do-it-all wrapper method that takes a Flexblock (A block of arbitrary length), and returns a hashsum for it.
This wrapper function adds an additional block including the length of the input. This wrapper function is used to transform Passwords to Keys.
### GPrng...?
Whilst we're at it, why not implement a pseudo-random number generator based on GHash aswell. So here it is, [GPrng](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/master/GCryptLib/include/GCrypt/GPrng.h).
Whilst we're at it, why not implement a pseudo-random number generator based on GHash aswell. So here it is, [GPrng](https://gitea.leonetienne.de/leonetienne/GCrypt/src/branch/feature/relaunch/GCryptLib/include/GCrypt/GPrng.h).
GPrng is really nothing special. I just wanted to implement it, mainly to visualize the GCiphers entropy.
GPrng basically does the following: It creates a GHash instance, which initially digests the prng's seed. This produces a hash result, which is one block in size.
@ -148,30 +140,30 @@ future output.
#### Single-block diffusion
`"Hello :3"` in binary, and it's ciphertext:
![Hello :3 in binary](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-singleblock-diffusion-input.bmp.png)
!["Hello :3" in binary](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-singleblock-diffusion-input.bmp.png)
&nbsp;&nbsp;&nbsp;
![Ciphertext 1](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-singleblock-diffusion-output.bmp.png)
![Ciphertext 1](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-singleblock-diffusion-output.bmp.png)
Now, let's flip a single bit in the input:
One bit flipped, and again the corresponding ciphertext:
![One bit flipped](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-singleblock-diffusion-input-flip.bmp.png)
![One bit flipped](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-singleblock-diffusion-input-flip.bmp.png)
&nbsp;&nbsp;&nbsp;
![Ciphertext for flipped bit](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-singleblock-diffusion-output-flip.bmp.png)
![Ciphertext for flipped bit](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-singleblock-diffusion-output-flip.bmp.png)
Let's gif them together, to better see the difference:
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-singleblock-diffusion-input.gif)
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-singleblock-diffusion-input.gif)
&nbsp;&nbsp;&nbsp;
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-singleblock-diffusion-output.gif)
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-singleblock-diffusion-output.gif)
As shown, flipping even a single bit, affects the entire ciphertext.
#### What about input longer than a single block?
Input, and ciphertext:
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-multiblock-diffusion-input.gif)
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-multiblock-diffusion-input.gif)
&nbsp;&nbsp;&nbsp;
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-multiblock-diffusion-output.gif)
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-multiblock-diffusion-output.gif)
Notice how the ciphertext doesn't change until the block containing the bitflip is reached? This is a limitation of cipher block chaining.
@ -179,11 +171,11 @@ Notice how the ciphertext doesn't change until the block containing the bitflip
How non-transparent is the cipher with extreme inputs? Even with a super problematic key?:
Input, key, and ciphertext:
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-extreme-input-diffusion-input.gif)
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-extreme-input-diffusion-input.gif)
&nbsp;&nbsp;&nbsp;
![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-extreme-input-diffusion-key.bmp.png)
![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-extreme-input-diffusion-key.bmp.png)
&nbsp;&nbsp;&nbsp;
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-extreme-input-diffusion-output.gif)
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-extreme-input-diffusion-output.gif)
Notice how even cleartexts that are completely uniform, with a key that is almost just zeores, will still produce ambiguous ciphertexts.
@ -191,18 +183,18 @@ Notice how even cleartexts that are completely uniform, with a key that is almos
Check it out, here are the distributions of a few different getter-methods, some in black/white, some in grayscale, some in color.
Blackwhite - GetBit(), Grayscale - GetRandom<T>(), and Grayscale - operator():
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-prng-distribution-blackwhite.bmp.png)
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-prng-distribution-blackwhite.bmp.png)
&nbsp;&nbsp;&nbsp;
![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-prng-distribution-getrandom-grayscale.bmp.png)
![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-prng-distribution-getrandom-grayscale.bmp.png)
&nbsp;&nbsp;&nbsp;
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-prng-distribution-operator-grayscale.bmp.png)
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-prng-distribution-operator-grayscale.bmp.png)
Color - GetRandom<T>(), Color - operator(), and Color - GetBlock():
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-prng-distribution-getrandom-color.bmp.png)
![Input](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-prng-distribution-getrandom-color.bmp.png)
&nbsp;&nbsp;&nbsp;
![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-prng-distribution-operator-color.bmp.png)
![Key](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-prng-distribution-operator-color.bmp.png)
&nbsp;&nbsp;&nbsp;
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/master/GCryptLib/visualizations/visualize-prng-distribution-getblock-color.bmp.png)
![Ciphertext](https://gitea.leonetienne.de/leonetienne/GCrypt/raw/branch/feature/relaunch/GCryptLib/visualizations/visualize-prng-distribution-getblock-color.bmp.png)
## Noteworthy:
* This is no fixed algorithm. Newer versions may very well be unable to decrypt ciphertexts encrypted with earlier versions.