Compare commits

...

209 Commits

Author SHA1 Message Date
521ec2bc2e
fix git remote ids 2024-09-26 10:26:48 +02:00
Leon Etienne
88a1295383 Install graphviz for doxygen pipelione
All checks were successful
continuous-integration/drone/push Build is passing
2022-10-25 22:18:42 +00:00
Leon Etienne
626ca33536 Fix readme cropping for doxygen
All checks were successful
continuous-integration/drone/push Build is passing
2022-10-25 22:15:33 +00:00
Leon Etienne
535c90b92c Add build status to readme
All checks were successful
continuous-integration/drone/push Build is passing
2022-10-25 21:47:43 +00:00
Leon Etienne
b1abc77f32 Import working drone config
All checks were successful
continuous-integration/drone/push Build is passing
2022-10-25 21:44:05 +00:00
Leon Etienne
827622a0b7 Cicd-test
Some checks failed
continuous-integration/drone/push Build is failing
2022-10-25 20:10:42 +00:00
Leonetienne
d507bd1b2f
Merge branch 'master' of gitea.leonetienne.de:leonetienne/GCrypt 2022-08-12 09:13:10 +02:00
Leonetienne
4561620eac
CLI: Fix typo in option name 2022-08-12 09:12:44 +02:00
Leonetienne
f6b8e9fbad
typo readme 2022-07-07 14:09:26 +02:00
Leonetienne
e5d4211761
Improved tests for block class 2022-06-04 00:01:21 +02:00
Leonetienne
f0456193a9
Adjust makefile doxygen 2022-06-01 21:35:46 +02:00
Leonetienne
656934634b
Fix image alt tag in readme, that screwed with doxygen 2022-06-01 21:01:38 +02:00
Leonetienne
573674a0b7
Update project name in doxygen config 2022-06-01 20:59:26 +02:00
Leonetienne
7410bc1b54
Add docs link to readme 2022-06-01 20:58:31 +02:00
Leonetienne
377099907b
Readme 2022-06-01 19:57:55 +02:00
Leonetienne
9a02c37a68
Readme 2022-06-01 19:56:08 +02:00
Leonetienne
fc6208f08a
Update readme 2022-06-01 19:55:06 +02:00
Leonetienne
afa07d0aca
Merge branch 'master' of gitea.leonetienne.de:leonetienne/GCrypt 2022-06-01 16:54:25 +02:00
Leonetienne
2f5e65b334
A bit of code cleanup 2022-06-01 16:54:14 +02:00
Leonetienne
00d0f81bd9
Fix compiler warning on macos 2022-06-01 15:28:17 +02:00
Leonetienne
f0db047316
Typo readme 2022-06-01 04:01:12 +02:00
Leonetienne
27ebdb8d63
Fixes in cli readme 2022-06-01 03:58:48 +02:00
Leonetienne
4f73996d79
Update help page in cli readme 2022-06-01 03:47:58 +02:00
Leonetienne
35a5c9496d
Wording in help page 2022-06-01 03:46:27 +02:00
Leonetienne
309dacadc8
Adjust links in readme 2022-06-01 03:32:01 +02:00
Leonetienne
74883458ba
Merge branch 'feature/relaunch' into master 2022-06-01 03:30:55 +02:00
Leonetienne
08f6e7d907
Add parameter to control progress report interval 2022-06-01 03:30:18 +02:00
Leonetienne
e8d81af6f2
Implement progress output 2022-06-01 03:29:05 +02:00
Leonetienne
fb1e6a9e8c
Update CLI readme 2022-06-01 02:49:49 +02:00
Leonetienne
855ecaaa2f
Fix docs 2022-06-01 02:34:16 +02:00
Leonetienne
136e03e65e
Doxygen now using makefile 2022-06-01 02:34:11 +02:00
Leonetienne
834b799849
Fix outdated information in readme 2022-06-01 02:29:20 +02:00
Leonetienne
b87ba395e3
Docs 2022-06-01 02:23:51 +02:00
Leonetienne
70111f906c
Bump version 2022-06-01 02:10:08 +02:00
Leonetienne
ffea2bfb5b
Added module for hashing 2022-06-01 02:09:49 +02:00
Leonetienne
bf8a6454ae
Implemented low space-complexity stream decoding for all ioformats 2022-06-01 01:53:52 +02:00
Leonetienne
4c8c45ad04
Fix wrong minlen for base ugh 2022-06-01 01:49:10 +02:00
Leonetienne
0917e9c6cb
Fix wrong minlen for base uwu 2022-05-31 22:19:01 +02:00
Leonetienne
a93b3b3fe5
Sophisticated and bug-fixed DataOutput/InputLayer, and added ModuleDecryption 2022-05-31 21:40:13 +02:00
Leonetienne
d9fb90a01e
Now by-default prepending a newline to stdout 2022-05-31 18:26:02 +02:00
Leonetienne
ba37b4325c
Integrated DataOutputLayer to ModuleGenerateKey 2022-05-31 18:19:12 +02:00
Leonetienne
0ab87de23c
More streamlined handling of io bases 2022-05-31 18:17:29 +02:00
Leonetienne
fd75678ea3
Added encryption module, and data output layer 2022-05-31 17:35:05 +02:00
Leonetienne
a00b8cc310
Fix Indentation 2022-05-31 17:07:45 +02:00
Leonetienne
f979b9c187
Add additional methods to data ingestion layer 2022-05-31 15:32:17 +02:00
Leonetienne
6a14b7b428
Forbid instanciation of static classes 2022-05-31 14:28:17 +02:00
Leonetienne
2f6df42696
Implement relevant methods for DataIngestionLayer 2022-05-31 14:25:23 +02:00
Leonetienne
3823eb6cc7
Fix typo in comment 2022-05-31 10:44:05 +02:00
Leonetienne
87987f6fe2
Implement unified istream for ingestion layer 2022-05-27 18:26:48 +02:00
Leonetienne
5df625e610
Rename cmake cli target name 2022-05-27 17:21:30 +02:00
Leonetienne
b9d81d1425
Change module GenerateKeyfile to more versatile GenerateKey, which doesnt have to output to a file 2022-05-27 17:21:10 +02:00
Leonetienne
93be4d9cdc
Implement GenerateKeyfile module 2022-05-27 17:04:16 +02:00
Leonetienne
191b17c631
Fix Key::WriteToFile method being not const qualified 2022-05-27 17:04:05 +02:00
Leonetienne
5365233b43
A bit of cleanup 2022-05-27 16:50:18 +02:00
Leonetienne
b0d0f831d9
Removed bunch of garbage from main.cpp 2022-05-27 16:14:24 +02:00
Leonetienne
186fea1383
More tests on data formatter 2022-05-27 16:08:24 +02:00
Leonetienne
cf22f8c569
Added tests for recoding single blocks to all formats 2022-05-27 15:56:28 +02:00
Leonetienne
2fa67b6860
Renamed method, and added first test to cli 2022-05-27 15:34:16 +02:00
Leonetienne
612157bcac
Added test project 2022-05-27 15:27:33 +02:00
Leonetienne
b888585f75
A bit of error handling and better comments 2022-05-27 14:47:26 +02:00
Leonetienne
2eb0754b4e
Remove unused code 2022-05-27 03:34:02 +02:00
Leonetienne
0a248b6d86
Fix multiple definition issue 2022-05-27 03:30:11 +02:00
Leonetienne
0e47b11a2c
Proper include guard 2022-05-27 03:29:51 +02:00
Leonetienne
6834ea4ad8
Move blocklenght lookup table to Bases.h 2022-05-27 03:27:43 +02:00
Leonetienne
407c0ad5bc
Better comment. 2022-05-27 03:01:47 +02:00
Leonetienne
2ecf0cc427
Added multiblocks methods to data formatter 2022-05-27 03:00:34 +02:00
Leonetienne
8e04e91e88
Got block conversions working... 2022-05-27 02:13:05 +02:00
Leonetienne
f6d646da55
Implemented to-block methods of dataformatter 2022-05-26 23:22:04 +02:00
Leonetienne
6ac775105b
Implement output formatting module 2022-05-26 22:30:59 +02:00
Leonetienne
fad87e9944
Add exceptoins 2022-05-26 22:06:04 +02:00
Leonetienne
dddc2d16f6
Added module PrepareKey 2022-05-26 21:56:15 +02:00
Leonetienne
8b9221e2e0
Add Configuration class to intelligently decide default settings 2022-05-26 21:32:55 +02:00
Leonetienne
f28e510dba
Adjust cli parameter definitions 2022-05-26 20:19:15 +02:00
Leonetienne
0f46ed7115
GCryptLib version bump 2022-05-26 19:59:16 +02:00
Leonetienne
75c4b0a0d9
More streamlined naming scheme for digestion method of ghash 2022-05-26 19:57:14 +02:00
Leonetienne
f246e3a5ef
Fix dangling hint 2022-05-26 19:34:58 +02:00
Leonetienne
2194ad1ce3
Fix apple linker problem 2022-05-26 19:25:40 +02:00
Leonetienne
876129f05f
Added how2compile to readme 2022-05-26 19:05:35 +02:00
Leonetienne
849d34613e
Add new visualizations 2022-05-26 18:59:59 +02:00
Leonetienne
cad96a19a2
Fix bad filename in visualization 2022-05-26 18:59:05 +02:00
Leonetienne
c0418766d9
Tidied up example/static test executables 2022-05-26 18:24:44 +02:00
Leonetienne
e7c1e17e2c
Got rid of flexblocks 2022-05-26 15:47:24 +02:00
Leonetienne
143ec19bf3
Many methods now using vectors of blocks instead of flexblocks 2022-05-26 15:04:39 +02:00
Leonetienne
800140bafa
Added a method to GPrng to get a random uint32, which is about twice as fast as GetRandom<uint32_t> 2022-05-26 12:52:04 +02:00
Leonetienne
e9377699f2
Made GPrng::GetBlock() faster by a factor of 100 2022-05-26 12:23:27 +02:00
Leonetienne
660ab5e999
Unstupided mathematical expression 2022-05-26 04:40:23 +02:00
Leonetienne
c3ff7a1326
Fix markup in artifacts 2022-05-26 04:25:02 +02:00
Leonetienne
8cf8ad2628
Add artifact directory 2022-05-26 04:23:32 +02:00
Leonetienne
81a9570673
Implement direct file i/o to- and from blocks. 2022-05-26 04:22:42 +02:00
Leonetienne
101a1e0fd6
Add additional jumbling-up in feistel rounds 2022-05-26 02:44:22 +02:00
Leonetienne
bc3dae96a3
Implement new sbox, reduction, and expansion function 2022-05-26 02:30:16 +02:00
Leonetienne
8ddd9d6bfb
Replaced halfblock with instanciation of Basic_Block 2022-05-26 00:55:24 +02:00
Leonetienne
1f913b3a54
Typo in comment 2022-05-25 16:51:38 +02:00
Leonetienne
f7d8093668
Templatified block class 2022-05-25 16:38:16 +02:00
Leonetienne
21cbd80488
Merge origin feature/relaunch into feature/relaunch 2022-05-25 14:58:40 +02:00
Leonetienne
3630243d8d
Fix macos compile issue 2022-05-25 14:57:40 +02:00
Leonetienne
edbf36eb6d
Cipher now using new block class 2022-05-25 13:05:25 +02:00
Leonetienne
b5369a3c32
Added bitshift methods to block class 2022-05-25 12:54:26 +02:00
Leonetienne
9a9cd05bed
Add SetBit, and FlipBit methods to block 2022-05-24 23:51:17 +02:00
Leonetienne
e552e1a6f8
Add GetBit() method to Block 2022-05-24 23:18:39 +02:00
Leonetienne
db0add6e6e
Implemented remaining operands for block class 2022-05-24 22:09:06 +02:00
Leonetienne
83854e42cb
Fix blanklines in block.cpp 2022-05-24 01:07:00 +02:00
Leonetienne
fa47a48dae
Add comment 2022-05-24 01:05:45 +02:00
Leonetienne
939df4731b
[Progress:] Completely re-done Block class to not use bitsets, and provide custom operators. 2022-05-24 01:02:06 +02:00
Leonetienne
ed45b69342
Experimentally implement matrix-mult 2022-05-23 22:42:14 +02:00
Leonetienne
3819fbe693
Typo readme 2022-05-22 23:27:23 +02:00
Leonetienne
2815be238b
Merge branch 'feature/relaunch' of gitea.leonetienne.de:leonetienne/GCrypt into feature/relaunch 2022-05-22 23:23:31 +02:00
Leonetienne
7cf55414b5
Wording readme 2022-05-22 23:22:54 +02:00
Leonetienne
b873c13bf2
Fix typo in readme 2022-05-22 23:16:57 +02:00
Leonetienne
12b0f6b031
Fix typo in readme 2022-05-22 22:39:25 +02:00
Leonetienne
3978bb6b18
Fix invalid html in readme 2022-05-22 21:25:53 +02:00
Leonetienne
8c7506297f
Added another visualization to readme 2022-05-22 21:22:02 +02:00
Leon Etienne
17dece8daf Put images in readme next to each other 2022-05-22 20:55:04 +02:00
Leonetienne
1e479986fc
Readme and visualizations 2022-05-22 20:40:56 +02:00
Leonetienne
5677d94e6a
Improved security 2022-05-22 20:13:41 +02:00
Leonetienne
19660fc696
Add method to load and save keyfiles 2022-05-22 17:54:26 +02:00
Leonetienne
88cb36fd7b
Fix include guard 2022-05-22 17:54:04 +02:00
Leonetienne
cd119f21bb
Indentation 2022-05-22 17:32:54 +02:00
Leonetienne
91819c9723
Bump gcryptlib version 2022-05-22 17:30:15 +02:00
Leonetienne
cb6c50b684
Now using actual include guards 2022-05-22 17:29:38 +02:00
Leonetienne
a3c04b957f
Implemented a Key::Random() method 2022-05-22 17:24:56 +02:00
Leonetienne
04c67436c4
Implemented GPrng pnrg 2022-05-22 16:54:40 +02:00
Leonetienne
bedfc91e04
GHash now uses a full-size key for the cipher 2022-05-22 14:30:24 +02:00
Leonetienne
fe6ec11672
Adjusted tests 2022-05-22 14:29:21 +02:00
Leonetienne
967eba2f03
Cmake make colored output 2022-05-22 14:21:21 +02:00
Leonetienne
b0e0c0cd99
Moved utility functions to cpp file 2022-05-22 14:13:10 +02:00
Leonetienne
fedb30bb43
Added padding direction option for Util::StringToBitblock 2022-05-22 13:54:03 +02:00
Leonetienne
9fdc642bd6
Implemented a key class 2022-05-22 13:45:40 +02:00
Leonetienne
bb76cbb2d7
Renamed class GCryptWrapper to GWrapper 2022-05-22 13:07:40 +02:00
Leonetienne
cf784ca8ac
Renamed method DigestFlexblock to CipherFlexblock, and made it public 2022-05-22 13:04:20 +02:00
Leonetienne
734324ec10
Renamed class Hasher to GHash 2022-05-22 12:55:39 +02:00
Leonetienne
4e2f99c28e
Renamed class Cipher to GCipher 2022-05-22 12:51:58 +02:00
Leonetienne
1cc01a840d
Cmake specify color output as always 2022-05-22 12:51:29 +02:00
Leonetienne
29f0efbba5
Fix warning 2022-05-22 12:31:48 +02:00
Leonetienne
201917d385
Warnings are now treated as errors 2022-05-22 12:31:33 +02:00
Leonetienne
6dce12b6ee
Added class for hashing, that is now used for password to key transformation 2022-05-22 00:23:10 +02:00
Leonetienne
f3b6dc155c
Implemented digestion (feeding one block at a time) 2022-05-21 20:41:09 +02:00
Leonetienne
71de8270d8
Added warning to readme 2022-05-21 20:40:44 +02:00
Leonetienne
985aca1ef0
Merge branch 'master' of gitea.leonetienne.de:leonetienne/GCrypt 2022-05-20 10:19:45 +02:00
Leon Etienne
baf3190665 Fix typo in code samples in readme 2022-05-17 14:16:17 +02:00
Leonetienne
61577acd9e
Add ideas for cli relaunch 2022-05-17 12:32:30 +02:00
Leonetienne
4015ee5dda
Switch to https-based git submodules 2022-05-17 01:31:26 +02:00
Leonetienne
9faea67af3
Version bump gcryptlib 2022-05-17 01:18:00 +02:00
Leonetienne
7a61d2e6c3
Step 2: fix broken submodule config 2022-05-17 01:17:48 +02:00
Leonetienne
e416fe05cb
Step 1: fix broken submodule config 2022-05-17 01:16:25 +02:00
Leonetienne
a8230086d3
Streamlined workflow of GCryptCLI 2022-05-17 01:13:42 +02:00
Leonetienne
845c77a985
unbloated readme 2022-05-16 23:49:08 +02:00
Leonetienne
e8305399ea
Fix dangling var in cmakelist of gcryptlib 2022-05-16 23:47:36 +02:00
Leonetienne
5fb38e1ed3
Update readme 2022-05-16 23:37:14 +02:00
Leonetienne
f75a41d8dc
Translated encryption/decryption consistency tests to catch2 2022-05-16 23:26:29 +02:00
Leonetienne
14e1fbe32c
Translated password2key transformation collision resistance tests to catch2 2022-05-16 23:03:55 +02:00
Leonetienne
b998a51e11
Renamed ghettocryptwrapper class to gcryptwrapper 2022-05-16 22:50:52 +02:00
Leonetienne
13a7abd82d
Translated gcrypt wrapper tests to catch2 2022-05-16 22:47:41 +02:00
Leonetienne
7fe9dcc6dc
GCryptLib: Fix include paths 2022-05-16 22:35:28 +02:00
Leonetienne
9432325b4a
Fix directory structure for include dir 2022-05-16 22:22:42 +02:00
Leonetienne
7c556e5b3d
Doxygen adjustment, and better directory name for GCryptLib 2022-05-16 22:19:20 +02:00
Leonetienne
acf9dea387
Gcryptlib: new brace style, and moved to Leonetienne namespace 2022-05-16 22:15:34 +02:00
Leonetienne
c551f5fa64
retabbed gcryptlib 2022-05-16 22:01:52 +02:00
Leonetienne
ae276e49af
New directory structure for libghettocrypt 2022-05-16 21:43:22 +02:00
Leon Etienne
9772c5fcf8 Added comment 2022-05-16 00:21:01 +02:00
Leonetienne
a29e199125
Remove bunch of microsoft crap 2022-05-13 22:28:01 +02:00
Leon Etienne
b8d6be8f4c Typos 2022-05-13 22:12:59 +02:00
Leon Etienne
ec3dd1ab07 Rename header in cli/readme 2022-05-13 12:46:56 +02:00
Leon Etienne
518fc054ed Update readme.md 2022-05-13 11:58:34 +02:00
Leon Etienne
5afd772a84 Update documentation for PasswordToKey function 2022-05-13 11:37:08 +02:00
Leon Etienne
754db08e7d Update 'readme.md' 2022-04-13 18:56:56 +02:00
Leonetienne
17ba2a373e Rename cli cmake target 2022-03-18 17:10:32 +01:00
Leon Etienne
c7b13ca7ab
Fix filename 2022-03-16 22:45:56 +01:00
Leonetienne
698647f7af readme 2022-03-16 01:42:19 +01:00
Leonetienne
4a40dfbba4 Update readme 2022-03-16 01:37:53 +01:00
Leonetienne
117798d0fb Implemented hashsum mode 2022-03-16 01:31:28 +01:00
Leonetienne
cdad33c738 Updated hazelnupp 2022-03-13 19:48:29 +01:00
Leonetienne
6e13a5196a fix broken base uwu 2022-03-13 19:36:29 +01:00
Leonetienne
6f08848aed more digits for uwu base 2022-03-13 19:23:13 +01:00
Leonetienne
3359fdab17 Fix build command 2022-03-13 19:15:43 +01:00
Leonetienne
ea0778e203 Fix build command 2022-03-13 19:15:29 +01:00
Leonetienne
29117aff0c Updated installation instructions, and removed useless non-crossplatform binary 2022-03-13 19:13:54 +01:00
Leonetienne
f250f77557 readme 2022-03-13 19:08:09 +01:00
Leonetienne
09e6dff9d3 more uwu digits and readme 2022-03-13 19:06:14 +01:00
Leonetienne
c9953a1078 readme 2022-03-13 18:56:55 +01:00
Leonetienne
829de7c1f4 More uwu digits, and included warning in readme 2022-03-13 18:55:56 +01:00
Leonetienne
bfe7152f1f readme 2022-03-13 18:26:24 +01:00
Leonetienne
a64c0541ed readme 2022-03-13 18:25:20 +01:00
Leonetienne
aa860bad76 readme 2022-03-13 18:24:11 +01:00
Leonetienne
6eae039c37 readme 2022-03-13 18:23:16 +01:00
Leonetienne
5722110bce Merge branch 'master' of github.com:Leonetienne/GhettoCrypt 2022-03-13 18:22:30 +01:00
Leonetienne
078ceb287c readme 2022-03-13 18:22:23 +01:00
Leonetienne
5fc0e190b9 Implemented useful custom bases, fun bases, also with support to decipher them 2022-03-13 18:21:45 +01:00
Leonetienne
cdbb52b24c Added support for a variety of output base formats 2022-03-13 15:08:29 +01:00
Leonetienne
de84fba0b6 Added cmakelist for cli project 2022-03-13 13:51:13 +01:00
Leonetienne
254453cef8 Added doxygen 2022-02-28 00:26:28 +01:00
Leonetienne
9bac50271e Fix: Issue #1 ([CLI] --ostdout uses BitsToString instead of BitsToBytes) 2022-02-19 22:40:23 +01:00
Leonetienne
01f8eddcac readme 2022-02-08 01:23:15 +01:00
Leonetienne
2b317f04ec readme 2022-02-08 01:19:53 +01:00
Leonetienne
ecf4381cda readme 2022-02-08 01:17:56 +01:00
Leonetienne
986b5d870f readme 2022-02-08 01:13:59 +01:00
Leonetienne
bb86c85d68 Readme 2022-02-07 23:51:09 +01:00
Leonetienne
4d083e6acf Updated readme 2022-02-07 23:43:53 +01:00
Leonetienne
9413e686f3 Include-statement cleanup 2022-02-06 23:00:34 +01:00
Leonetienne
0b800f988a compiled single-header 2022-02-06 22:59:24 +01:00
Leonetienne
730e2b00e0 Fixed issue that caused identical (m,k) to cause different ciphertexts on different platforms 2022-02-06 22:58:53 +01:00
Leonetienne
c621357097 Include-statement cleanup 2022-02-06 22:06:46 +01:00
Leonetienne
653f647fc6 Added nice tip to config.h 2022-02-06 22:04:22 +01:00
Leonetienne
09ad0af688 compiled cli version 0.12 (gc version 0.2) 2022-02-06 21:59:55 +01:00
Leonetienne
f5a9678862 Fix compiler error on g++ 2022-02-06 21:58:57 +01:00
Leonetienne
8678d3cb1b Made the whole thing MUCH more secure, by adding an IV (initialization vector), implemeted RRKM (rolling round key mode) and redone key extrapolation 2022-02-06 21:56:04 +01:00
Leonetienne
e57456e9ae Integrated initialization vector 2022-02-06 18:46:07 +01:00
Leonetienne
40a6b0c4ea Implemented initialization vector 2022-02-06 18:38:09 +01:00
Leonetienne
4064483cad Added a simple unit test to ensure E(D(M)) = M 2022-02-06 17:59:08 +01:00
157 changed files with 47769 additions and 6316 deletions

56
.drone.yml Normal file
View File

@ -0,0 +1,56 @@
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

362
.gitignore vendored
View File

@ -1,360 +1,4 @@
## Ignore Visual Studio temporary files, build results, and build/
## files generated by popular Visual Studio add-ons. *.swp
## *_/
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
#infilename-tag
*_gitignore_*
*.jpg
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Visual Paradigm Shitfiles
*tornado.vpp.bak*
*tornado.*lck*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

17
.gitmodules vendored Normal file
View File

@ -0,0 +1,17 @@
[submodule "StringTools"]
path = StringTools
url = https://code.ze.mawtrixx.net/leonetienne/StringTools.git
[submodule "Hazelnupp"]
path = Hazelnupp
url = https://code.ze.mawtrixx.net/leonetienne/Hazelnupp.git
[submodule "GeneralUtility"]
path = GeneralUtility
url = https://code.ze.mawtrixx.net/leonetienne/GeneralUtility.git
[submodule "GCryptLib/exec/Eule"]
path = GCryptLib/exec/Eule
url = https://code.ze.mawtrixx.net/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

View File

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{b9a390ac-f382-42e6-92dd-3321293e7c27}</ProjectGuid>
<RootNamespace>ExampleApp</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GhettoCrypt\GhettoCrypt.vcxproj">
<Project>{2b2cf665-f5e6-44db-961f-fc81c88a356d}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Quelldateien">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headerdateien">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Ressourcendateien">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,46 +0,0 @@
#pragma once
#include <iostream>
#include <GhettoCryptWrapper.h>
#include <SecureBitset.h>
using namespace GhettoCipher;
void ExampleString()
{
std::cout << "Example on how to encrypt & decrypt a string:" << std::endl;
// Get some string
const std::string input = "I am a super secret message!";
std::cout << input << std::endl;
// Encrypt
const std::string encrypted = GhettoCryptWrapper::EncryptString(input, "password1");
std::cout << encrypted << std::endl;
// Decrypt
const std::string decrypted = GhettoCryptWrapper::DecryptString(encrypted, "password1");
std::cout << decrypted << std::endl;
return;
}
void ExampleFiles()
{
std::cout << "Example on how to encrypt & decrypt any file:" << std::endl;
// Encrypt
GhettoCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1");
// Decrypt
GhettoCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1");
return;
}
int main()
{
ExampleString();
//ExampleFiles();
return 0;
}

78
GCryptCLI/CMakeLists.txt Normal file
View File

@ -0,0 +1,78 @@
cmake_minimum_required(VERSION 3.16)
project(gcrypt)
set(CMAKE_CXX_STANDARD 17)
# Add library StringTools
SET(stringtools_dir ../StringTools/StringTools)
SET(stringtools_include ${stringtools_dir}/include)
FILE(GLOB stringtools_src ${stringtools_dir}/src/*.cpp)
# Add library GeneralUtility
SET(generalutility_dir ../GeneralUtility/GeneralUtility)
SET(generalutility_include ${generalutility_dir}/include)
FILE(GLOB generalutility_src ${generalutility_dir}/src/*.cpp)
# Add library Hazelnupp
SET(hazelnupp_dir ../Hazelnupp/Hazelnupp)
SET(hazelnupp_include ${hazelnupp_dir}/include)
FILE(GLOB hazelnupp_src ${hazelnupp_dir}/src/*.cpp)
# Add library GCrypt
SET(gcrypt_dir ../GCryptLib)
SET(gcrypt_include ${gcrypt_dir}/include)
FILE(GLOB gcrypt_src ${gcrypt_dir}/src/*.cpp)
FILE(GLOB main_src src/*.cpp)
add_executable(${PROJECT_NAME}
${main_src}
${stringtools_src}
${generalutility_src}
${hazelnupp_src}
${gcrypt_src}
)
target_include_directories(${PROJECT_NAME} PRIVATE
include
${stringtools_include}
${generalutility_include}
${hazelnupp_include}
${gcrypt_include}
)
target_compile_options(${PROJECT_NAME} PRIVATE
-Werror
-fdiagnostics-color=always
)
#########
# Tests #
#########
LIST(FILTER main_src EXCLUDE REGEX ".*/main.cpp")
FILE(GLOB test_src test/*.cpp)
add_executable(test
test/Catch2.h
${test_src}
${main_src}
${stringtools_src}
${generalutility_src}
${hazelnupp_src}
${gcrypt_src}
)
target_include_directories(test PRIVATE
include
${stringtools_include}
${generalutility_include}
${hazelnupp_include}
${gcrypt_include}
)
target_compile_options(test PRIVATE
-Werror
-fdiagnostics-color=always
)

View File

@ -0,0 +1 @@
<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.

After

Width:  |  Height:  |  Size: 25 KiB

24
GCryptCLI/idea/notes.md Normal file
View File

@ -0,0 +1,24 @@
* 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.

143
GCryptCLI/include/Bases.h Normal file
View File

@ -0,0 +1,143 @@
#ifndef GCRYPTCLI_BASES_H
#define GCRYPTCLI_BASES_H
#include <vector>
#include <string>
#include <map>
// This lookup table holds how many digits a block is long
// in any iobase.
// This cannot be calculated on the fly, as it involves
// arithmetic with involving REALLY big numbers (like, 2^512).
// Here's how to calculate these numbers:
// Print an all 1's block in this format, and check the string size.
// That's it.
static auto blockLengthByBase =
std::map<Configuration::IOBASE_FORMAT, std::size_t>({
std::make_pair(Configuration::IOBASE_FORMAT::BASE_BYTES, 64),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_2, 512),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_8, 171),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_10, 155),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_16, 128),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_64, 86),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_UWU, 81),
std::make_pair(Configuration::IOBASE_FORMAT::BASE_UGH, 126)
});
// Actually useful bases
static const std::vector<std::string> BASE_2 = { "0","1" };
static const std::vector<std::string> BASE_8 = { "0","1","2","3","4","5","6","7"};
static const std::vector<std::string> BASE_10 = { "0","1","2","3","4","5","6","7","8","9" };
static const std::vector<std::string> BASE_64 = { "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/" };
// Fun bases
static const std::vector<std::string> BASE_UWU = {
"uwu",
"UwU",
"<3",
":P",
":p",
":o",
":O",
":3",
":)",
"^.^",
"^_^",
"^^",
"XD",
"XDD",
"XDDD",
"xD",
"xDD",
"xDDD",
"(*^.^*)",
"(*^_^*)",
"devewopa",
"cutieee",
"cutieees",
"cutewr",
"whiiiich",
"masta",
"mastaaaa",
"hiiiii",
"hewwo",
"soopa",
"doopa",
"favowite",
"kawaii",
"rawr",
"keewl",
"keeeewl",
"Owww",
"Awww",
"haaaai",
"haaaay",
"heeeey",
"heeeei",
"senpaiiii",
"i",
"nyeed",
"awe",
"youuu",
"twe",
"best",
"ruff",
"me",
"nyeko",
"eughh",
"snaffle",
"toot",
"whiffle",
"nappies",
"chiffchaff",
"kawaiisu",
"*winks*",
"*bites-lip*",
"*blushes*",
"*stutters*",
"*sweats*",
"uhh?!",
"uhh..?",
"nu-uh...",
"sweatr",
"comfy-womfy",
"oopsie-whoopsie",
"dewicious",
"tastieee",
"tasties",
"boop",
"smoochies",
"whiffskaws",
"chomp",
"toesy-woesies",
"smush",
"snuff",
"sniff",
"snaff",
"nyoo!",
"nyah!",
};
// Source: https://lakinkonieczny.wordpress.com/2012/12/06/dialogue-noises-agh-ugh-shh-and-so-much-more/
static const std::vector<std::string> BASE_UGH = {
"Agh!",
"Ugh",
"Shh!",
"Pft!",
"Aah!",
"Uaah!",
"Gah!",
"Grr...",
"Duh!",
"Psh!",
"Ah...",
"Er-",
"Huh...?",
"Uh-huh...",
"Nu-uh...",
"Bah!",
"Wha-?"
};
#endif

View File

@ -0,0 +1,26 @@
#ifndef GCRYPTCLI_CLIINTERFACE_H
#define GCRYPTCLI_CLIINTERFACE_H
#include <Hazelnupp/CmdArgsInterface.h>
class CommandlineInterface
{
public:
static void Init(const int argc, const char* const* argv);
static Hazelnp::CmdArgsInterface& Get();
private:
//! Special command compatibility checking unique to this app
static void SpecialCompatibilityChecking();
static void CrashWithMsg(const std::string& msg);
static void CatchVersionQueries();
static Hazelnp::CmdArgsInterface nupp;
// No instanciation! >:(
CommandlineInterface() {};
};
#endif

View File

@ -0,0 +1,61 @@
#ifndef GCRYPTCLI_CONFIGURATION_H
#define GCRYPTCLI_CONFIGURATION_H
#include <string>
class Configuration {
public:
static enum class INPUT_FROM {
STDIN,
FILE,
PARAMETER
} inputFrom;
static enum class OUTPUT_TO {
STDOUT,
FILE
} outputTo;
static enum class IOBASE_FORMAT {
BASE_BYTES,
BASE_2,
BASE_8,
BASE_10,
BASE_16,
BASE_64,
BASE_UWU,
BASE_UGH
}
formatIn,
formatOut;
static std::string inputFilename;
static std::string outputFilename;
static enum class MODULE {
ENCRYPTION,
DECRYPTION,
HASH,
GENERATE_KEY
} activeModule;
//! Will analyze the supplied cli parameters,
//! and decide what the configuration will be.
static void Parse();
private:
static void DecideInputFrom();
static void DecideOutputTo();
static void DecideCiphertextFormat();
static void MapCiphertextFormatToIOBases();
static void DecideModule();
// This is just an intermediary value, used between methods
static IOBASE_FORMAT ciphertextFormat;
// No instanciation! >:(
Configuration() {};
};
#endif

View File

@ -0,0 +1,58 @@
#ifndef GCRYPTCLI_DATAFORMATTER_H
#define GCRYPTCLI_DATAFORMATTER_H
#include <GCrypt/Block.h>
#include <string>
#include <vector>
#include "Configuration.h"
using namespace Leonetienne::GCrypt;
// This class has the task to format Blocks to various formats.
class DataFormatter {
public:
//! Will format a single block to a given iobase
static std::string FormatBlock(
const Block& block,
const Configuration::IOBASE_FORMAT base
);
//! Will parse a string of a given iobase to a block
static Block DecodeFormat(
const std::string& str,
const Configuration::IOBASE_FORMAT base
);
//! Will format a vector of blocks to a given iobase
static std::string FormatBlocks(
const std::vector<Block>& blocks,
const Configuration::IOBASE_FORMAT base
);
//! Will format a string making up multiple block in a given iobase into a vector of block
static std::vector<Block> DecodeFormatMultiblock(
const std::string& str,
const Configuration::IOBASE_FORMAT base
);
private:
static std::string Bin2CustomBase(
const std::string& bin,
const std::vector<std::string>& customSet,
const std::size_t minLen,
const std::string& seperator = ""
);
static std::string CustomBase2Bin(
const std::string& in,
const std::vector<std::string>& customSet,
const std::string& seperator = ""
);
// No instanciation! >:(
DataFormatter() {};
};
#endif

View File

@ -0,0 +1,75 @@
#ifndef GCRYPTCLI_DATAINGESTIONLAYER_H
#define GCRYPTCLI_DATAINGESTIONLAYER_H
#include <iosfwd>
#include <queue>
#include <GCrypt/Block.h>
#include "Configuration.h"
using namespace Leonetienne::GCrypt;
namespace IO {
// This class is used to read in data.
class DataIngestionLayer {
public:
//! Will initialize the ingestion
static void Init();
//! Will destruct the ingestion layer (like, closing file handles)
static void Destruct();
//! Will attempt to read a data block.
//! Requires Init() to have been called
static void ReadBlock();
//! Have we read in all available blocks?
static bool ReachedEOF();
//! Returns true if there are blocks to be fetched (GetNextBlock())
static bool IsBlockReady();
//! Will return the next block in the queue
static Block GetNextBlock();
//! Returns true, if EOF is reached, and there are no more blocks to fetch (GetNextBlock())
static bool IsFinished();
//! Returns how many blocks have been read, in total
static std::size_t NBlocksRead();
private:
static std::istream* in;
// Will read n bytes from the input.
// If EOF is reached, it will return a string of length <= 5
// and will set the approriate flags.
static std::string ReadBytes(const std::size_t n, std::size_t& out_bytes_read);
// We have to hold on to a reference to a filestream,
// even if we're always just reading from in.
// We still have to CLOSE the file handle afterwards!
static std::ifstream ifs;
static std::istringstream iss;
// Indicates whether EOF has been reached
static bool reachedEof;
// Indicates whether this class has been initialized
static bool initialized;
// Are we reading ciphertext or regular text?
static bool isReadingCiphertext;
// How many blocks have been read in total
static std::size_t nBlocksRead;
// All read blocks, that haven't been given out yet
static std::queue<Block> blocks;
// No instanciation! >:(
DataIngestionLayer();
};
}
#endif

View File

@ -0,0 +1,61 @@
#ifndef GCRYPTCLI_DATAOUTPUTLAYER_H
#define GCRYPTCLI_DATAOUTPUTLAYER_H
#include <iosfwd>
#include <queue>
#include <GCrypt/Block.h>
#include "Configuration.h"
using namespace Leonetienne::GCrypt;
namespace IO {
// This class is used to read in data.
class DataOutputLayer {
public:
//! Will initialize the output
static void Init();
//! Will destruct the output layer (like, closing file handles)
static void Destruct();
//! Will queue a block for writing
static void Enqueue(const Block& block);
//! Will attempt to write the next block
static void WriteBlock();
//! Indicates that no more blocks will be enqueued
static void ReachedEOF();
//! Returns true, if all blocks have been written, and an EOF signal as been received
static bool IsFinished();
private:
//! If we are finished, and are outputting to stdout,
//! and the user didn't specifically opt out, print a newline
static void AddTrailingLinebreakIfRequired();
static std::ostream* out;
// We have to hold on to a reference to a filestream,
// even if we're always just reading from in.
// We still have to CLOSE the file handle afterwards!
static std::ofstream ofs;
// Indicates whether EOF has been reached
static bool reachedEof;
// Indicates whether this class has been initialized
static bool initialized;
// All blocks, that haven't been written yet
static std::queue<Block> blocks;
//! No instanciation >:(
DataOutputLayer() {};
};
}
#endif

View File

@ -0,0 +1,30 @@
#ifndef GCRYPTCLI_KEYMANAGER_H
#define GCRYPTCLI_KEYMANAGER_H
#include <GCrypt/Key.h>
using namespace Leonetienne::GCrypt;
// This class has the task to prepare and supply the encryption key.
class KeyManager {
public:
//! Will prepare the key. Be it from cli, a file, or, random, or whatever.
static void PrepareKey();
//! Will return the key, if prepared.
static const Key& GetKey();
private:
//! Will ask for a password on stdin,
//! hiding the input.
static std::string PasswordPrompt();
//! The encryption key
static Key key;
// No instanciation! >:(
KeyManager() {};
};
#endif

View File

@ -0,0 +1,18 @@
#ifndef GCRYPTCLI_MODULE_DECRYPTION_H
#define GCRYPTCLI_MODULE_DECRYPTION_H
namespace Module {
//! This module will decrypt supplied input
class Decryption {
public:
//! Will run the module
static void Run();
private:
// No instanciation! >:(
Decryption() {};
};
}
#endif

View File

@ -0,0 +1,18 @@
#ifndef GCRYPTCLI_MODULE_ENCRYPTION_H
#define GCRYPTCLI_MODULE_ENCRYPTION_H
namespace Module {
//! This module will encrypt supplied input
class Encryption {
public:
//! Will run the module
static void Run();
private:
// No instanciation! >:(
Encryption() {};
};
}
#endif

View File

@ -0,0 +1,19 @@
#ifndef GCRYPTCLI_MODULE_GENERATEKEY_H
#define GCRYPTCLI_MODULE_GENERATEKEY_H
namespace Module {
// This module just generates a key, and outputs it.
// Can be used to create a keyfiles.
class GenerateKey {
public:
//! Will write the key to a file
static void Run();
private:
// No instanciation! >:(
GenerateKey() {};
};
}
#endif

View File

@ -0,0 +1,18 @@
#ifndef GCRYPTCLI_MODULE_HASHING_H
#define GCRYPTCLI_MODULE_HASHING_H
namespace Module {
//! This module will hash supplied input
class Hashing {
public:
//! Will run the module
static void Run();
private:
// No instanciation! >:(
Hashing() {};
};
}
#endif

View File

@ -0,0 +1,23 @@
#ifndef GCRYPTCLI_PROGRESSPRINTER_H
#define GCRYPTCLI_PROGRESSPRINTER_H
#include <iostream>
#include "CommandlineInterface.h"
// This class has the task to output progress to stderr, if requested
class ProgressPrinter {
public:
//! Will print progress to stderr, if requested, and the interval matches
static void PrintIfAppropriate(
const std::string& message,
const std::size_t current,
const std::size_t target
);
private:
// No instanciation! >:(
ProgressPrinter() {};
};
#endif

View File

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

890
GCryptCLI/readme.md Normal file
View File

@ -0,0 +1,890 @@
# GCrypt CLI
Easy text and file encryption via the command line using GCrypt. Now supporting [*esoteric data formats*](#esoteric-data-formats)... :)
Again, please only use this as an obfuscator or if the only other option would be no encryption at all.
Do you want to quickly and securely encrypt stuff via the command line? Use openssl-cli with the aes cipher. It's a bit more wordy but much faster and more secure.
Still want to use GCrypt cli? Here ya go!
Just clone this repository, navigate into this directory and compile it:
## How do i use this?
### Prerequsities:
Have these depencies installed:
* git
* make
* cmake
* build-essentials (c++ >= 17) (might work with 11, if you're lucky)
### How2compile
1) Clone this repository.
2) Download all submodules: `git submodule update --init --recursive`.
3) Cd into /GCryptCLI: `cd GCryptCLI`.
4) Create a build directory: `cmake -B build`.
5) Cd into the build directory: `cd build`.
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
### All arguments and flags:
```
CLI for the GCrypt cipher/obfuscator
Copyright (c) 2022 Leon Etienne
GCryptLib v0.236
GCryptCLI v0.12511
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 ====
--iobase-bytes VOID incompatibilities=[--iobase-2, --iobase-8, --iobase-10, --iobase-16, --iobase-64, --iobase-uwu, --iobase-ugh] Interpret and output ciphertexts as raw bytes.
--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.
--cli-version -v VOID Will supply the version of GCryptCLI used.
--keyfile -kf STRING incompatibilities=[--key, --keyask, --hash] Read in the first {KEYSIZE}(=512) bits of this file and use that as an encryption key. WARNING: Arguments may be logged by the system!
--iobase-2 VOID incompatibilities=[--iobase-bytes, --iobase-8, --iobase-10, --iobase-16, --iobase-64, --iobase-uwu, --iobase-ugh] Interpret and format ciphertexts in base2
--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.
--lib-version VOID Will supply the version of GCryptLib used.
--iobase-ugh VOID incompatibilities=[--iobase-bytes, --iobase-2, --iobase-8, --iobase-10, --iobase-16, --iobase-64, --iobase-uwu] Interpret and format ciphertexts in base ugh
--infile -if STRING incompatibilities=[--intext] Encrypt this file.
--iobase-uwu VOID incompatibilities=[--iobase-bytes, --iobase-2, --iobase-8, --iobase-10, --iobase-16, --iobase-64, --iobase-ugh] Interpret and format ciphertexts in base uwu
--iobase-64 VOID incompatibilities=[--iobase-bytes, --iobase-2, --iobase-8, --iobase-10, --iobase-16, --iobase-uwu, --iobase-ugh] Interpret and format ciphertexts in base64
--iobase-8 VOID incompatibilities=[--iobase-bytes, --iobase-2, --iobase-10, --iobase-16, --iobase-64, --iobase-uwu, --iobase-ugh] Interpret and format ciphertexts in base8
--encrypt -e VOID incompatibilities=[--decrypt, --hash] Use the encryption module.
--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.
```
### Examples
Please note that commonly used arguments are supplied in their short form (`-e` in place of `--encrypt`).
#### I want to encrypt text!
```sh
$ gcrypt -e --keyask --intext "hello, world!"
efbebc429c8370bf84f00b0d8ccbaf7858b3b87d71ff58cb1cfefa8fb0c68094c0865565873aa8a5254ede59be46e81a4d4917e679b18cb290dbd6669cb6207a
```
#### Now decrypt it
```sh
$ gcrypt -d --keyask --intext "efbebc429c8370bf84f00b0d8ccbaf7858b3b87d71ff58cb1cfefa8fb0c68094c0865565873aa8a5254ede59be46e81a4d4917e679b18cb290dbd6669cb6207a"
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.
```sh
$ gcrypt -e --keyask --intext "hello, world!" --iobase-2
111001001011100000011111000100010100110011100110000100100101001001110001001000101011110000000011011100001010111010001000110111110110011011100000001100110001001000100111011000101010010001011011111011001000011111100100101001011110011101110001010011000101011001111010000001001100101110000101101101101001110100100001101010111101010000100111101110000110011101100101101011000011101001000011010010011001111010001001101000101001100101010000100010111101101100010000000001001110010001001011001001011011010111001101000100
$ gcrypt -e --keyask --intext "hello, world!" --iobase-8
71134037042463460445116110536003341272106766334014611047305221337310374451363561230531720114560555516441527520475606354553035103223172115051452042755420011621131133271504
$ gcrypt -e --keyask --intext "hello, world!" --iobase-10
2994749439449970047518881970731547473115480925772565399786126223459744370490386223437520234266936877059618216185983047971748564015130703048737306773910340
$ gcrypt -e --keyask --intext "hello, world!" --iobase-64
Co/WjpV5nPrCaz0QMdrXAXzzOH5HODRsBNL22KZowmGMcTLwfmsQpzt7Ik+ViR5vOhUXowFQeR5x2vbcj1X5ae
```
I won't be pasting in stdout for every example. It would become too cluttered.
#### Passing the key as an argument
```sh
$ gcrypt -e --key "secretpassword" --intext "hello, world!"
```
> :warning: Some operating systems will log cli arguments! THIS WOULD BE THE ENTIRE KEY!
#### Using keyfiles
```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).
#### Encrypting files
```sh
$ gcrypt -e --keyask --infile "cat.jpg" --ofile "cat.jpg.crypt"
```
File `cat.jpg.crypt` will be created.
#### Decrypting files
```sh
$ gcrypt -d --keyask --infile "cat.jpg.crypt" --ofile "decrypted_cat.jpg"
```
File `decrypted_cat.jpg` will be created. You can now open it again. Its contents match `cat.jpg`.
> :warning: Since this is a block cipher, decrypted files may be tailpadded with a few nullbytes.
#### Encrypting large files takes time. How's the progress?
```sh
$ gcrypt -e --keyask --infile "cat.jpg" --buffer-input --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.
#### Any cipher can also compute hashsums
```sh
$ gcrypt -h --intext "hello, world!"
a96f42c9d97e46b9e1ed7de5182770170d4ef9b7b8264f3fbd89b38dc60c1fe06232653f5856013307fc020fb1d35f2bea26bc0f373c5ac35a722c6b03d8254d
$ gcrypt -h --infile "cat.jpg"
fe6bdfb6ec39771c4fdcdc40e52397bcd67fbfef0ad5a15ebbd8b9e4c2a815848b3984eda5ef6f727e9e420c23500c90c42ab80ac5659048be8969357741e3e5
```
The hashsum will always be of size BLOCK_SIZE. That is 512 bits.
#### What version am i running?
Depending on whether you want to know the GCryptLib 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!
```sh
# mpv is a media player, as an example
$ gcrypt -d --key "123" --infile "music.mp3.crypt" | mpv -
```
#### Don't want to stream input and output?
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
```
## Esoteric data formats
#### Base *UwU*
```sh
$ gcrypt -e --keyask --intext "hello, world!" --iobase-uwu
:) sewnpaiii tastieee uhh?! nappies cutewr twe best cutieee :O tastieee senpaiiiw favowite toesy-woesies ^.^ :3 best chomp whiffle uwu Awww sewnpaiii comfy-womfy :p keewl Awww youuu nyeko :O tasties hiiiii heeeey (*^_^*) youuu toot uhh..? smush (*^_^*) *bites-lip* whiffle haaaay nyah! comfy-womfy :) cutsie Owww haaaay snaffle haaaai haaaai nyeko *sweats* :) uhh..? boop toot *bites-lip* <3 whiiiich whiffskaws ^.^ twe whiffskaws hiiiii *sweats* Owww dewicious i tasties :P awe hewwo boop rawr uwu dewicious eughh twe cutsie xD
```
#### Base **UGH!**
```sh
$ 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
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
```

View File

@ -0,0 +1,213 @@
#include "CommandlineInterface.h"
#include <iostream>
#include <sstream>
#include <GCrypt/Version.h>
#include <GCrypt/Block.h>
#include "Version.h"
using namespace Hazelnp;
using namespace Leonetienne::GCrypt;
void CommandlineInterface::Init(int argc, const char* const* argv) {
/* General information */
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
<< "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("");
nupp.SetCatchHelp("true");
nupp.SetCrashOnFail("true");
/* Builtin documentation */
nupp.RegisterDescription("--encrypt", "Use the encryption module.");
nupp.RegisterConstraint("--encrypt", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {"--decrypt", "--hash" }));
nupp.RegisterAbbreviation("-e", "--encrypt");
nupp.RegisterDescription("--decrypt", "Use decryption module.");
nupp.RegisterConstraint("--decrypt", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--encrypt", "--hash", "--generate-key" }));
nupp.RegisterAbbreviation("-d", "--decrypt");
nupp.RegisterDescription("--hash", "Use the GHash hash module to calculate a hashsum.");
nupp.RegisterConstraint("--hash", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--encrypt", "--decrypt", "--generate-key" }));
nupp.RegisterAbbreviation("-h", "--hash");
nupp.RegisterDescription("--generate-key", "Use the key generation module. Will generate a random key based on hardware events, output it, and exit.");
nupp.RegisterConstraint("--generate-key", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--encrypt", "--decrypt", "--hash" }));
nupp.RegisterDescription("--intext", "Encrypt this string.");
nupp.RegisterConstraint("--intext", ParamConstraint(true, DATA_TYPE::STRING, {}, false, { "--infile" }));
nupp.RegisterAbbreviation("-it", "--intext");
nupp.RegisterDescription("--infile", "Encrypt this file.");
nupp.RegisterConstraint("--infile", ParamConstraint(true, DATA_TYPE::STRING, {}, false, { "--intext" }));
nupp.RegisterAbbreviation("-if", "--infile");
nupp.RegisterDescription("--ofile", "Write output in this file.");
nupp.RegisterConstraint("--ofile", ParamConstraint(true, DATA_TYPE::STRING, {}, false, { "--ostdout", "--hash" }));
nupp.RegisterAbbreviation("-of", "--ofile");
nupp.RegisterAbbreviation("-o", "--ofile");
nupp.RegisterDescription("--key", "Use this value as a password to extrapolate the encryption key. WARNING: Arguments may be logged by the system!");
nupp.RegisterConstraint("--key", ParamConstraint(true, DATA_TYPE::STRING, {}, false, { "--keyfile", "--keyask", "--hash" }));
nupp.RegisterAbbreviation("-k", "--key");
ss << "Read in the first {KEYSIZE}(=" << Block::BLOCK_SIZE_BITS << ") bits of this file and use that as an encryption key. WARNING: Arguments may be logged by the system!";
nupp.RegisterDescription("--keyfile", ss.str());
ss.str("");
nupp.RegisterConstraint("--keyfile", ParamConstraint(true, DATA_TYPE::STRING, {}, false, { "--key", "--keyask", "--hash" }));
nupp.RegisterAbbreviation("-kf", "--keyfile");
nupp.RegisterDescription("--keyask", "Read the encryption key from stdin.");
nupp.RegisterConstraint("--keyask", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--key", "--keyfile", "--hash" }));
nupp.RegisterAbbreviation("-ka", "--keyask");
nupp.RegisterDescription("--progress", "Print digestion progress to stderr. May be advisable for large files, as the cipher is rather slow.");
nupp.RegisterConstraint("--progress", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterAbbreviation("-p", "--progress");
nupp.RegisterDescription("--progress-interval", "Print digestion progress reports every these many data blocks.");
nupp.RegisterConstraint("--progress-interval", ParamConstraint(true, DATA_TYPE::INT, { "1000" }, true, {}));
nupp.RegisterDescription("--iobase-bytes", "Interpret and output ciphertexts as raw bytes.");
nupp.RegisterConstraint("--iobase-bytes", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-2", "--iobase-8", "--iobase-10", "--iobase-16", "--iobase-64", "--iobase-uwu", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-2", "Interpret and format ciphertexts in base2");
nupp.RegisterConstraint("--iobase-2", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-8", "--iobase-10", "--iobase-16", "--iobase-64", "--iobase-uwu", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-8", "Interpret and format ciphertexts in base8");
nupp.RegisterConstraint("--iobase-8", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-2", "--iobase-10", "--iobase-16", "--iobase-64", "--iobase-uwu", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-10", "Interpret and format ciphertexts in base10");
nupp.RegisterConstraint("--iobase-10", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-2", "--iobase-8", "--iobase-16", "--iobase-64", "--iobase-uwu", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-16", "Interpret and format ciphertexts in base16 (hex)");
nupp.RegisterConstraint("--iobase-16", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-2", "--iobase-8", "--iobase-64", "--iobase-uwu", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-64", "Interpret and format ciphertexts in base64");
nupp.RegisterConstraint("--iobase-64", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-2", "--iobase-8", "--iobase-10", "--iobase-16", "--iobase-uwu", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-uwu", "Interpret and format ciphertexts in base uwu");
nupp.RegisterConstraint("--iobase-uwu", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-2", "--iobase-8", "--iobase-10", "--iobase-16", "--iobase-64", "--iobase-ugh" }));
nupp.RegisterDescription("--iobase-ugh", "Interpret and format ciphertexts in base ugh");
nupp.RegisterConstraint("--iobase-ugh", ParamConstraint(true, DATA_TYPE::VOID, {}, false, { "--iobase-bytes", "--iobase-2", "--iobase-8", "--iobase-10", "--iobase-16", "--iobase-64", "--iobase-uwu" }));
nupp.RegisterDescription("--lib-version", "Will supply the version of GCryptLib used.");
nupp.RegisterConstraint("--lib-version", ParamConstraint(true, DATA_TYPE::VOID, {}, false, {}));
nupp.RegisterDescription("--cli-version", "Will supply the version of GCryptCLI used.");
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("--buffer-output", "Will digest the entire data before initiating any output.");
nupp.RegisterConstraint("--buffer-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, {}));
/* Now parse */
nupp.Parse(argc, argv);
CatchVersionQueries();
SpecialCompatibilityChecking();
return;
}
Hazelnp::CmdArgsInterface& CommandlineInterface::Get() {
return nupp;
}
void CommandlineInterface::SpecialCompatibilityChecking() {
// Active module
// Do we have EITHER --encrypt or --decrypt or --hash?
if (
(!nupp.HasParam("--generate-key")) &&
(!nupp.HasParam("--hash")) &&
(!nupp.HasParam("--encrypt")) &&
(!nupp.HasParam("--decrypt"))
) {
CrashWithMsg("No module supplied! Please supply either --encrypt, --decrypt, --hash, or --generate-key!");
}
// Encryption key
// Do we have EITHER --hash (no key required), --generate-key (no key required), --key, --keyask or --keyfile given?
if (
(!nupp.HasParam("--hash")) &&
(!nupp.HasParam("--generate-key")) &&
(!nupp.HasParam("--key")) &&
(!nupp.HasParam("--keyfile")) &&
(!nupp.HasParam("--keyask"))
) {
CrashWithMsg("No encryption key supplied! Please supply either --key, --keyfile, or --keyask!");
}
// Check that, if supplied, filename strings are not empty.
if (
(nupp.HasParam("--ofile")) &&
(nupp["--ofile"].GetString().length() == 0)
) {
CrashWithMsg("Length of --ofile is zero! That can't be a valid path!");
}
if (
(nupp.HasParam("--ifile")) &&
(nupp["--ifile"].GetString().length() == 0)
) {
CrashWithMsg("Length of --ifile is zero! That can't be a valid path!");
}
if (
(nupp.HasParam("--keyfile")) &&
(nupp["--keyfile"].GetString().length() == 0)
) {
CrashWithMsg("Length of --keyfile is zero! That can't be a valid path!");
}
if (
(nupp.HasParam("--progress")) &&
(!nupp.HasParam("--buffer-input"))
) {
CrashWithMsg("--progress requires --buffer-input to work!");
}
return;
}
void CommandlineInterface::CrashWithMsg(const std::string& msg) {
std::cerr
<< nupp.GetBriefDescription()
<< std::endl
<< "Fatal error! Unable to continue! More information:" << std::endl
<< msg << std::endl;
exit(-1);
}
void CommandlineInterface::CatchVersionQueries() {
if (
(nupp.HasParam("--version")) ||
(nupp.HasParam("--cli-version"))
) {
std::cout << GCRYPTCLI_VERSION << std::endl;
exit(0);
}
else if (nupp.HasParam("--lib-version"))
{
std::cout << GCRYPT_VERSION << std::endl;
exit(0);
}
return;
}
CmdArgsInterface CommandlineInterface::nupp;

View File

@ -0,0 +1,186 @@
#include "Configuration.h"
#include "CommandlineInterface.h"
void Configuration::Parse() {
DecideModule();
DecideInputFrom();
DecideOutputTo();
DecideCiphertextFormat();
MapCiphertextFormatToIOBases();
return;
}
void Configuration::DecideModule() {
if (CommandlineInterface::Get().HasParam("--encrypt")) {
activeModule = MODULE::ENCRYPTION;
return;
}
else if (CommandlineInterface::Get().HasParam("--decrypt")) {
activeModule = MODULE::DECRYPTION;
return;
}
else if (CommandlineInterface::Get().HasParam("--hash")) {
activeModule = MODULE::HASH;
return;
}
else if (CommandlineInterface::Get().HasParam("--generate-key")) {
activeModule = MODULE::GENERATE_KEY;
return;
}
throw std::runtime_error("No module option found. Is the CLI parser configuration correct?.");
return;
}
void Configuration::DecideInputFrom() {
if (CommandlineInterface::Get().HasParam("--intext")) {
inputFrom = INPUT_FROM::PARAMETER;
}
else if (CommandlineInterface::Get().HasParam("--infile")) {
inputFrom = INPUT_FROM::FILE;
inputFilename = CommandlineInterface::Get()["--infile"].GetString();
}
else {
inputFrom = INPUT_FROM::STDIN;
}
return;
}
void Configuration::DecideOutputTo() {
if (CommandlineInterface::Get().HasParam("--ofile")) {
outputTo = OUTPUT_TO::FILE;
outputFilename = CommandlineInterface::Get()["--ofile"].GetString();
}
else {
outputTo = OUTPUT_TO::STDOUT;
}
return;
}
void Configuration::DecideCiphertextFormat() {
// Do we have any iobase explicitly specified?
if (CommandlineInterface::Get().HasParam("--iobase-bytes")) {
ciphertextFormat = IOBASE_FORMAT::BASE_BYTES;
}
else if (CommandlineInterface::Get().HasParam("--iobase-2")) {
ciphertextFormat = IOBASE_FORMAT::BASE_2;
}
else if (CommandlineInterface::Get().HasParam("--iobase-8")) {
ciphertextFormat = IOBASE_FORMAT::BASE_8;
}
else if (CommandlineInterface::Get().HasParam("--iobase-10")) {
ciphertextFormat = IOBASE_FORMAT::BASE_10;
}
else if (CommandlineInterface::Get().HasParam("--iobase-16")) {
ciphertextFormat = IOBASE_FORMAT::BASE_16;
}
else if (CommandlineInterface::Get().HasParam("--iobase-64")) {
ciphertextFormat = IOBASE_FORMAT::BASE_64;
}
else if (CommandlineInterface::Get().HasParam("--iobase-uwu")) {
ciphertextFormat = IOBASE_FORMAT::BASE_UWU;
}
else if (CommandlineInterface::Get().HasParam("--iobase-ugh")) {
ciphertextFormat = IOBASE_FORMAT::BASE_UGH;
}
// So we have no iobase explicitly specified.. Let's default..
// If we are encrypting,
else if (activeModule == MODULE::ENCRYPTION) {
// and input comes from a parameter,
// and output goes to stdout,
// let's assume base-16.
if (
(inputFrom == INPUT_FROM::PARAMETER) &&
(outputTo == OUTPUT_TO::STDOUT)
) {
ciphertextFormat = IOBASE_FORMAT::BASE_16;
}
// Any other case whilst encrypting, we'll assume base-bytes.
else {
ciphertextFormat = IOBASE_FORMAT::BASE_BYTES;
return;
}
}
// Else, if we are hashing,
else if (activeModule == MODULE::HASH) {
// output is always defaults to base 16
ciphertextFormat = IOBASE_FORMAT::BASE_16;
}
// Else, if we are decrypting,
else if (activeModule == MODULE::DECRYPTION) {
// and input comes from a parameter, we'll assume base-16.
if (inputFrom == INPUT_FROM::PARAMETER) {
ciphertextFormat = IOBASE_FORMAT::BASE_16;
}
// Any other case whilst decrypting, we'll assume base-bytes.
else {
ciphertextFormat = IOBASE_FORMAT::BASE_BYTES;
}
}
// Else, if we are generating a key,
else if (activeModule == MODULE::GENERATE_KEY) {
// and we're outputting to stdout, we'll use base-16.
if (outputTo == OUTPUT_TO::STDOUT) {
ciphertextFormat = IOBASE_FORMAT::BASE_16;
}
// else, we're outputting to a file, use base-bytes.
else {
ciphertextFormat = IOBASE_FORMAT::BASE_BYTES;
}
}
// Fallback: Bytes
else {
ciphertextFormat = IOBASE_FORMAT::BASE_BYTES;
}
return;
}
void Configuration::MapCiphertextFormatToIOBases() {
// Now, map the ciphertextFormat to either formatIn or formatOut.
switch (activeModule) {
// For encryption, keygen, and hashing:
// input is bytes and output is ciphertext
case MODULE::ENCRYPTION:
case MODULE::HASH:
case MODULE::GENERATE_KEY:
formatIn = IOBASE_FORMAT::BASE_BYTES;
formatOut = ciphertextFormat;
break;
// For decryption:
// input is ciphertext and output is bytes
case MODULE::DECRYPTION:
formatIn = ciphertextFormat;
formatOut = IOBASE_FORMAT::BASE_BYTES;
break;
}
return;
}
std::string Configuration::inputFilename;
std::string Configuration::outputFilename;
Configuration::MODULE Configuration::activeModule;
Configuration::IOBASE_FORMAT Configuration::formatIn;
Configuration::IOBASE_FORMAT Configuration::formatOut;
Configuration::IOBASE_FORMAT Configuration::ciphertextFormat;
Configuration::INPUT_FROM Configuration::inputFrom;
Configuration::OUTPUT_TO Configuration::outputTo;

View File

@ -0,0 +1,299 @@
#include "DataFormatter.h"
#include "Bases.h"
#include <GeneralUtility/BaseConversion.h>
#include <StringTools/StringTools.h>
#include <GCrypt/Util.h>
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::StringTools;
using namespace Leonetienne::GeneralUtility;
std::string DataFormatter::FormatBlock(
const Block& block,
const Configuration::IOBASE_FORMAT base
) {
switch (base) {
case Configuration::IOBASE_FORMAT::BASE_BYTES:
return block.ToByteString();
case Configuration::IOBASE_FORMAT::BASE_2:
return block.ToBinaryString();
case Configuration::IOBASE_FORMAT::BASE_8:
return Bin2CustomBase(
block.ToBinaryString(),
BASE_8,
blockLengthByBase[base]
);
case Configuration::IOBASE_FORMAT::BASE_10:
return Bin2CustomBase(
block.ToBinaryString(),
BASE_10,
blockLengthByBase[base]
);
case Configuration::IOBASE_FORMAT::BASE_16:
return block.ToHexString();
case Configuration::IOBASE_FORMAT::BASE_64:
return Bin2CustomBase(
block.ToBinaryString(),
BASE_64,
blockLengthByBase[base]
);
case Configuration::IOBASE_FORMAT::BASE_UWU:
return Bin2CustomBase(
block.ToBinaryString(),
BASE_UWU,
blockLengthByBase[base],
" "
);
case Configuration::IOBASE_FORMAT::BASE_UGH:
return Bin2CustomBase(
block.ToBinaryString(),
BASE_UGH,
blockLengthByBase[base],
" "
);
default:
throw std::invalid_argument("FormatBlock(): Iobase not found! Oh no. Anyway.");
}
}
std::string DataFormatter::FormatBlocks(
const std::vector<Block>& blocks,
const Configuration::IOBASE_FORMAT base
) {
std::stringstream ss;
std::size_t i = 0;
for (const Block& block : blocks) {
ss << FormatBlock(block, base);
// If we are dealing with a multichar base, we must append a
// seperator (space), but only if its not the last block.
if (
(base == Configuration::IOBASE_FORMAT::BASE_UWU) ||
(base == Configuration::IOBASE_FORMAT::BASE_UGH)
) {
if (i++ != blocks.size()) {
ss << " ";
}
}
}
return ss.str();
}
Block DataFormatter::DecodeFormat(
const std::string& str,
const Configuration::IOBASE_FORMAT base
) {
Block b;
switch (base) {
case Configuration::IOBASE_FORMAT::BASE_BYTES:
b.FromByteString(str);
break;
case Configuration::IOBASE_FORMAT::BASE_2:
b.FromBinaryString(str);
break;
case Configuration::IOBASE_FORMAT::BASE_8:
b.FromBinaryString(
CustomBase2Bin(
str,
BASE_8
)
);
break;
case Configuration::IOBASE_FORMAT::BASE_10:
b.FromBinaryString(
CustomBase2Bin(
str,
BASE_10
)
);
break;
case Configuration::IOBASE_FORMAT::BASE_16:
b.FromHexString(str);
break;
case Configuration::IOBASE_FORMAT::BASE_64:
b.FromBinaryString(
CustomBase2Bin(
str,
BASE_64
)
);
break;
case Configuration::IOBASE_FORMAT::BASE_UWU:
b.FromBinaryString(
CustomBase2Bin(
str,
BASE_UWU,
" "
)
);
break;
case Configuration::IOBASE_FORMAT::BASE_UGH:
b.FromBinaryString(
CustomBase2Bin(
str,
BASE_UGH,
" "
)
);
break;
default:
throw std::invalid_argument("StringToBlock(): Iobase now found! Oh no. Anyway.");
}
return b;
}
std::vector<Block> DataFormatter::DecodeFormatMultiblock(
const std::string& str,
const Configuration::IOBASE_FORMAT base
) {
std::vector<Block> blocks;
// A block is this many digits wide, in encoding
const std::size_t blockWidth = blockLengthByBase[base];
// How many blocks are we dealing with here?
const std::size_t n_blocks = (str.length() / blockWidth) + 1;
blocks.reserve(n_blocks);
// Iterate over the string, and parse all blocks
// We now have to differentiate between single-char digit sets (like hex),
// and multi-char digit sets (like uwu):
switch (base) {
case Configuration::IOBASE_FORMAT::BASE_BYTES:
case Configuration::IOBASE_FORMAT::BASE_2:
case Configuration::IOBASE_FORMAT::BASE_8:
case Configuration::IOBASE_FORMAT::BASE_10:
case Configuration::IOBASE_FORMAT::BASE_16:
case Configuration::IOBASE_FORMAT::BASE_64:
// Easy case: Each digit is exactly one char in size.
// We can just calculate how many bytes we should read.
for (std::size_t i = 0; i < str.length(); i += blockWidth) {
const std::string subs = str.substr(i, blockWidth);
Block newBlock = DecodeFormat(
subs,
base
);
blocks.emplace_back(newBlock);
}
break;
case Configuration::IOBASE_FORMAT::BASE_UWU:
case Configuration::IOBASE_FORMAT::BASE_UGH: {
// Hard case: Each digit is n digits long. Digits may vary in length.
// They are seperated by spaces.
// We have to parse them...
std::size_t digitsPassed = 0;
std::size_t blockStart = 0;
for (std::size_t i = 0; i < str.length(); i++) {
if (str[i] == ' ') {
digitsPassed++;
if (digitsPassed == blockWidth) {
const std::string subs = str.substr(
blockStart,
i - blockStart
);
Block newBlock = DecodeFormat(
subs,
base
);
blocks.emplace_back(newBlock);
digitsPassed = 0;
blockStart = i+1;
}
}
}
// Here should never be any digits left. A formatted block should ALWAYS be full length.
break;
}
default:
throw std::invalid_argument("DataFormatter::StringToBlocks() has been passed an unknown base! No switch-case matched!");
break;
}
return blocks;
}
std::string DataFormatter::Bin2CustomBase(
const std::string& bin,
const std::vector<std::string>& customSet,
const std::size_t minLen,
const std::string& seperator
) {
std::stringstream ss;
// Translate to custom set
const std::vector<std::string> vec_base_custom =
Leonetienne::GeneralUtility::BaseConversion::BaseX_2_Y<std::string, std::vector<std::string>>(
bin,
"01",
customSet,
minLen
);
// Convert to string
for (std::size_t i = 0; i < vec_base_custom.size(); i++) {
ss << vec_base_custom[i];
if (i != vec_base_custom.size() - 1) {
ss << seperator;
}
}
return ss.str();
}
std::string DataFormatter::CustomBase2Bin(
const std::string& in,
const std::vector<std::string>& customSet,
const std::string& seperator
) {
// Split input into symbols
const std::vector<std::string> in_symbols = StringTools::Split(in, seperator);
// Translate to binary
std::string binary =
Leonetienne::GeneralUtility::BaseConversion::BaseX_2_Y<std::vector<std::string>, std::string>(
in_symbols,
customSet,
std::string("01"),
Block::BLOCK_SIZE_BITS
);
if (binary.length() != Block::BLOCK_SIZE_BITS) {
throw std::invalid_argument("DataFormatter::CustomBase2Bin() received input that doesn't translate to a bitstring of length 512!");
}
return binary;
}

View File

@ -0,0 +1,367 @@
#include "DataIngestionLayer.h"
#include "CommandlineInterface.h"
#include "DataFormatter.h"
#include "Bases.h"
#include <StringTools/StringTools.h>
#include <iostream>
#include <istream>
#include <fstream>
#include <sstream>
#include <cstring>
using namespace IO;
using namespace Leonetienne::StringTools;
void DataIngestionLayer::Init() {
// Set our istream
switch (Configuration::inputFrom) {
// Are we reading from stdin?
case Configuration::INPUT_FROM::STDIN:
// Redirect our istream to stdin
in = &std::cin;
break;
// Are we reading from a file?
case Configuration::INPUT_FROM::FILE:
// Open the file
ifs.open(
Configuration::inputFilename,
std::ios::in | std::ios::binary
);
// A little bit of error handling
if (!ifs.good()) {
throw std::runtime_error("Unable to open infilestream!");
}
// Redirect our istream to this infilestream
in = &ifs;
break;
// Are we reading from a parameter?
case Configuration::INPUT_FROM::PARAMETER:
// Create an instringstream with our parameter
iss = std::istringstream(
CommandlineInterface::Get()["--intext"].GetString()
);
// Redirect our istream to this instringstream
in = &iss;
break;
}
// Derive from our the current module if we're reading ciphertext or not
if (Configuration::activeModule == Configuration::MODULE::DECRYPTION) {
isReadingCiphertext = true;
}
else {
isReadingCiphertext = false;
}
initialized = true;
reachedEof = false;
nBlocksRead = 0;
return;
}
void DataIngestionLayer::Destruct() {
if (Configuration::inputFrom == Configuration::INPUT_FROM::FILE) {
ifs.close();
}
return;
}
void DataIngestionLayer::ReadBlock() {
if (!initialized) {
throw std::runtime_error("Attempted to read on uninitialized DataIngestionLayer!");
}
if (!reachedEof) {
// A block is this many digits wide, in encoding
const std::size_t blockWidth = blockLengthByBase[Configuration::formatIn];
// Iterate over the string, and parse all blocks
// We now have to differentiate between single-char digit sets (like hex),
// and multi-char digit sets (like uwu):
switch (Configuration::formatIn) {
case Configuration::IOBASE_FORMAT::BASE_BYTES:
case Configuration::IOBASE_FORMAT::BASE_2:
case Configuration::IOBASE_FORMAT::BASE_8:
case Configuration::IOBASE_FORMAT::BASE_10:
case Configuration::IOBASE_FORMAT::BASE_16:
case Configuration::IOBASE_FORMAT::BASE_64: {
// Easy case: Each digit is exactly one char in size.
// We can just calculate how many bytes we have to read.
// bytesRead is always of the correct length, 0-padded.
std::size_t n_bytes_read;
const std::string dataRead = ReadBytes(blockWidth, n_bytes_read);
// If we've read 0 bytes, this was the last block
// and it's completely empty. We can abort without doing anything.
// The ReadBytes function takes care of setting the reachedEof flag.
if (n_bytes_read == 0) {
return;
}
// If we are reading ciphertext
// make sure we've read enough bytes to compose a block.
if (
(isReadingCiphertext) &&
(n_bytes_read < blockWidth)
) {
throw std::runtime_error("DataIngestionLayer::ReadBlock() read an input-data fragment that is smaller than a data block should be. Is your cipher text incomplete?");
}
// This should decode to a block just like this.
Block newBlock;
// Special-case: We are reading cleartext (no ciphertext)
// cleartext is always base_bytes
if (!isReadingCiphertext) {
// When just reading cleartext-bytes, we also allow shorter strings
// than BLOCK_SIZE. These will just get zero-padded.
newBlock.FromTextString(dataRead);
}
else {
// Else: recode to a block.
newBlock = DataFormatter::DecodeFormat(
dataRead,
Configuration::formatIn
);
}
blocks.emplace(newBlock);
nBlocksRead++;
break;
}
case Configuration::IOBASE_FORMAT::BASE_UWU:
case Configuration::IOBASE_FORMAT::BASE_UGH: {
// The whole of Italy doesn't have as much spaghetti as this is...
// Hard case: Each digit is n digits long. Digits may vary in length.
// They are seperated by spaces.
// We have to parse them...
std::string overshoot = ""; // this is how much we've read too much in the last iteration
// Gets terminated by a break statement
while (1) {
// We'll read chunks of 64 bytes... This should be a good
// median, to also support small multi-byte-digit sets
std::size_t n_bytes_read = 0;
int lastDigitPos = -1; // Should point the the space BEFORE it. Relative to chunk.
std::size_t digitsCollected = 0;
std::stringstream digits;
bool foundBlock = false;
// Remember to prepend our overshoot from the previous iteration this chunk
std::string chunk = overshoot + ReadBytes(64, n_bytes_read);
// We should also strip all linebreaks from the chunk, that may be a result of manual stdin input.
chunk = StringTools::Replace(chunk, '\n', "");
// We can't just check for completeness by n_bytes_read...
// It can be any number of bytes, since any digit is n bytes long...
// Parse the 64-byte chunk string we've just fetched:
for (std::size_t i = 0; i < chunk.size(); i++) {
// If we are near the end, and have still not found a complete block, let's load an additional chunk
if (i == chunk.size() - 2) {
const std::string nextChunk = ReadBytes(64, n_bytes_read);
if (n_bytes_read != 0) {
chunk += StringTools::Replace(nextChunk, '\n', "");
}
}
// If i is on a space, or at the end of the chunk,
// and, at least one of i, or lastDigitPos is on a space,
if (
(
(chunk[i] == ' ') ||
(i == chunk.size() - 1)
) &&
(
(chunk[i] == ' ') ||
lastDigitPos >= 0 // This basically does the same as discribed, but safer, as its default value is -1.
)
){
digitsCollected++;
// We have found a digit. Let's store it away...
// We're putting them in a stringstream, to fit the format required by the data formatter...
// We have a slight edgecase if we're currently on the last char. Then we do NOT want to read one short.
// This is because we ususally stand on a seperator char (' '), which we do not want to extract. But in that case,
// in which we're standing on the last char, it could be not a seperator char.
// note: chunk[i] != ' ' can only be true if we're on the last char.
if (chunk[i] == ' ') {
digits <<
chunk.substr(
lastDigitPos + 1,
(int)i - lastDigitPos - 1
)
;
} else {
digits <<
chunk.substr(
lastDigitPos + 1,
(int)i - lastDigitPos
)
;
}
// Add a seperator, if its not the last
if (digitsCollected != blockWidth) {
digits << ' ';
}
lastDigitPos = i;
// Do we have enough digits to form a block?
if (digitsCollected == blockWidth) {
// We've found a complete block!
// Trim excess nullbytes off out digit string
const std::string digitString = std::string(
digits.str().data(),
strlen(digits.str().data())
);
// Decode it to a block object
const Block newBlock = DataFormatter::DecodeFormat(
digitString,
Configuration::formatIn
);
// Enqueue it to be processed by some module
blocks.emplace(newBlock);
nBlocksRead++;
foundBlock = true;
// Now we have to calculate how many bytes we've read TOO MANY.
// We have to trim this current chunk to be our new overshoot.
// If we still have more than a byte left, leave out the current seperator char
if (i < chunk.size() - 1) {
overshoot = chunk.substr(i+1); // Take all bytes from the next iterator, to the end
}
// Else: we are on the last char: there is no overshoot
else {
overshoot = "";
}
// Stop the for loop
break;
}
}
}
// Exit-condition:
// We have not found any block, not even any digit.
if ((!foundBlock) && (digitsCollected == 0)) {
break;
}
// Hard-abort: We have not finished reading a block
if (!foundBlock) {
throw std::runtime_error("DataIngestionLayer reached EOF whilst parsing multi-byte-digit block...");
}
}
break;
}
default:
throw std::invalid_argument("DataFormatter::StringToBlocks() has been passed an unknown base! No switch-case matched!");
}
}
return;
}
std::string DataIngestionLayer::ReadBytes(const std::size_t n, std::size_t& out_bytes_read) {
// Prepare a buffer to read to
char* buf = new char[n+1];
memset(buf, 0, (n+1) * sizeof(buf[0]));
// Read
in->read(buf, n * sizeof(buf[0]));
// Fetch how much we've read
out_bytes_read = in->gcount();
// Is this fewer bytes than got requested?
if (out_bytes_read < n) {
// Yes: EOF reached.
reachedEof = true;
}
// Translate buffer to a standard string
const std::string sbuf(buf, n);
delete[] buf;
// Return our buffer
return sbuf;
}
bool DataIngestionLayer::ReachedEOF() {
return reachedEof;
}
bool DataIngestionLayer::IsBlockReady() {
// We're not ready, if we haven't reached EOF, if we should buffer
// the input.
if (
(CommandlineInterface::Get().HasParam("--buffer-input")) &&
(!reachedEof)
) {
return false;
}
// If we're not buffering, just return whether or not
// we have any blocks...
return blocks.size() > 0;
}
bool DataIngestionLayer::IsFinished() {
return (reachedEof) && (blocks.size() == 0);
}
Block DataIngestionLayer::GetNextBlock() {
if (!IsBlockReady()) {
throw std::runtime_error("Attempted to get the next block, but there are none left!");
}
// Why... why not just return a T in pop()???
const Block popped = blocks.front();
blocks.pop();
return popped;
}
std::size_t DataIngestionLayer::NBlocksRead() {
return nBlocksRead;
}
std::istream* DataIngestionLayer::in;
std::ifstream DataIngestionLayer::ifs;
std::istringstream DataIngestionLayer::iss;
bool DataIngestionLayer::reachedEof = false;
bool DataIngestionLayer::initialized = false;
bool DataIngestionLayer::isReadingCiphertext;
std::size_t DataIngestionLayer::nBlocksRead = 0;
std::queue<Block> DataIngestionLayer::blocks;

View File

@ -0,0 +1,149 @@
#include "DataOutputLayer.h"
#include "DataFormatter.h"
#include "CommandlineInterface.h"
#include <ostream>
#include <fstream>
#include <iostream>
using namespace IO;
void DataOutputLayer::Init() {
// Set our ostream
switch (Configuration::outputTo) {
// Are we writing to stdout?
case Configuration::OUTPUT_TO::STDOUT:
// Redirect our ostream to stdout
out = &std::cout;
break;
// Are we writing to a file?
case Configuration::OUTPUT_TO::FILE:
// Open the file
ofs.open(
Configuration::outputFilename,
std::ios::out | std::ios::binary
);
// A little bit of error handling
if (!ofs.good()) {
throw std::runtime_error("Unable to open outfilestream!");
}
// Redirect our ostream to this outfilestream
out = &ofs;
break;
}
initialized = true;
reachedEof = false;
return;
}
void DataOutputLayer::Destruct() {
if (Configuration::outputTo == Configuration::OUTPUT_TO::FILE) {
ofs.close();
}
return;
}
void DataOutputLayer::Enqueue(const Block& block) {
blocks.emplace(block);
return;
}
void DataOutputLayer::WriteBlock() {
// Some error checking
if (!initialized) {
throw std::runtime_error("Attempted to write on uninitialized DataOutputLayer!");
}
// Check if we have any block to write
// and if we should (output-buffering)
// Basically: only output if we have anything to output, and
// if --buffer-output is given, only output once we have reachedEof.
if (
(blocks.size() > 0) &&
(
(!CommandlineInterface::Get().HasParam("--buffer-output")) ||
(reachedEof)
)
) {
// Fetch the block to write
const Block block = blocks.front();
blocks.pop();
// Recode it to our output format
const std::string formattedBlock =
DataFormatter::FormatBlock(
block,
Configuration::formatOut
);
// Dump it
// This way we avoid zerobytes getting trimmed off...
out->write(formattedBlock.data(), formattedBlock.length());
// If this is not the last block, and the used iobase set
// requires it, append a seperator
if (
(!IsFinished()) &&
(
(Configuration::formatOut == Configuration::IOBASE_FORMAT::BASE_UWU) ||
(Configuration::formatOut == Configuration::IOBASE_FORMAT::BASE_UGH)
)
) {
*out << " ";
}
AddTrailingLinebreakIfRequired();
out->flush();
}
return;
}
void DataOutputLayer::ReachedEOF() {
reachedEof = true;
// Add the trailing linebreak here aswell, as, if input is ciphertext,
// ReachedEOF() may only be called after all blocks are already written
AddTrailingLinebreakIfRequired();
return;
}
bool DataOutputLayer::IsFinished() {
return (reachedEof) && (blocks.size() == 0);
}
void DataOutputLayer::AddTrailingLinebreakIfRequired() {
// If we are finished, and are outputting to stdout,
// and input format is not bytes,
// and the user didn't specifically opt out, print a newline
if (
(IsFinished()) &&
(Configuration::outputTo == Configuration::OUTPUT_TO::STDOUT) &&
(Configuration::formatOut != Configuration::IOBASE_FORMAT::BASE_BYTES) &&
(!CommandlineInterface::Get().HasParam("--no-newline"))
) {
*out << std::endl;
out->flush();
}
return;
}
std::ostream* DataOutputLayer::out;
std::ofstream DataOutputLayer::ofs;
bool DataOutputLayer::reachedEof = false;
bool DataOutputLayer::initialized = false;
std::queue<Block> DataOutputLayer::blocks;

View File

@ -0,0 +1,107 @@
#include "KeyManager.h"
#include "CommandlineInterface.h"
#include "Configuration.h"
#include <cstring>
#include <iostream>
// Required for hidden password input
#if defined _WIN32 || defined _WIN64
#include <Windows.h>
#elif defined __GNUG__
#include <termios.h>
#include <unistd.h>
#endif
void KeyManager::PrepareKey() {
// Special-case: We are hashing:
// no key needed.
if (Configuration::activeModule == Configuration::MODULE::HASH) {
return;
}
// Special-case: We are generating a keyfile:
// generate a random key from hardware events.
else if (Configuration::activeModule == Configuration::MODULE::GENERATE_KEY) {
key = Key::Random();
return;
}
// Else:
// Is a password passed on the command line?
else if (CommandlineInterface::Get().HasParam("--key")) {
// Fetch it, and hash it to a key
std::string password = CommandlineInterface::Get()["--key"].GetString();
key = Key::FromPassword(password);
// Don't forget to zero string memory.
memset(password.data(), 0, password.size());
return;
}
// Should we prompt for a password on stdin?
else if (CommandlineInterface::Get().HasParam("--keyask")) {
// Create a password prompt
std::string password = PasswordPrompt();
key = Key::FromPassword(password);
// Don't forget to zero string memory.
memset(password.data(), 0, password.size());
return;
}
// Else:
// Should we read from a keyfile?
else if (CommandlineInterface::Get().HasParam("--keyfile")) {
// Fetch the filename, and read it
const std::string filepath = CommandlineInterface::Get()["--keyfile"].GetString();
key = Key::LoadFromFile(filepath);
return;
}
throw std::runtime_error("No key option found. Is the CLI parser configuration correct?.");
return;
}
const Key& KeyManager::GetKey() {
return key;
}
std::string KeyManager::PasswordPrompt() {
// Disable stdin-echo
#if defined _WIN32 || defined _WIN64
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
#elif defined __GNUG__
termios oldt;
tcgetattr(STDIN_FILENO, &oldt);
termios newt = oldt;
newt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
#endif
// Prompt stdin
std::string password;
std::cin >> password;
// Restore previous config
#if defined _WIN32 || defined _WIN64
SetConsoleMode(hStdin, mode);
#elif defined __GNUG__
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#endif
return password;
}
Key KeyManager::key;

View File

@ -0,0 +1,67 @@
#include "ModuleDecryption.h"
#include "DataIngestionLayer.h"
#include "DataOutputLayer.h"
#include "ProgressPrinter.h"
#include "KeyManager.h"
#include <GCrypt/GCipher.h>
using namespace Module;
using namespace Leonetienne::GCrypt;
void Decryption::Run() {
// Initialize the data ingestion layer
IO::DataIngestionLayer::Init();
// Initialize the data output layer
IO::DataOutputLayer::Init();
// Initialize a cipher
GCipher cipher(
KeyManager::GetKey(),
GCipher::DIRECTION::DECIPHER
);
std::size_t nBlocksDigested = 0;
while (!IO::DataOutputLayer::IsFinished()) {
// Read in new blocks, if not reached eof
if (!IO::DataIngestionLayer::ReachedEOF()) {
IO::DataIngestionLayer::ReadBlock();
}
// Process a block, if one is ready
if (IO::DataIngestionLayer::IsBlockReady()) {
// Print progress, if appropriate
ProgressPrinter::PrintIfAppropriate(
"Decrypting",
nBlocksDigested,
IO::DataIngestionLayer::NBlocksRead()
);
const Block cleartext = IO::DataIngestionLayer::GetNextBlock();
const Block ciphertext = cipher.Digest(cleartext);
nBlocksDigested++;
// Enqueue the block for output
IO::DataOutputLayer::Enqueue(ciphertext);
}
// Tell the data output layer that it received the
// last block, if it did
if (IO::DataIngestionLayer::IsFinished()) {
IO::DataOutputLayer::ReachedEOF();
}
// Attempt to write a block
IO::DataOutputLayer::WriteBlock();
}
// Destruct the data ingestion layer
IO::DataIngestionLayer::Destruct();
// Destruct the data output layer
IO::DataOutputLayer::Destruct();
return;
}

View File

@ -0,0 +1,68 @@
#include "ModuleEncryption.h"
#include "DataIngestionLayer.h"
#include "DataOutputLayer.h"
#include "KeyManager.h"
#include "ProgressPrinter.h"
#include <GCrypt/GCipher.h>
#include <iostream>
using namespace Module;
using namespace Leonetienne::GCrypt;
void Encryption::Run() {
// Initialize the data ingestion layer
IO::DataIngestionLayer::Init();
// Initialize the data output layer
IO::DataOutputLayer::Init();
// Initialize a cipher
GCipher cipher(
KeyManager::GetKey(),
GCipher::DIRECTION::ENCIPHER
);
std::size_t nBlocksDigested = 0;
while (!IO::DataOutputLayer::IsFinished()) {
// Read in new blocks, if not reached eof
if (!IO::DataIngestionLayer::ReachedEOF()) {
IO::DataIngestionLayer::ReadBlock();
}
// Process a block, if one is ready
if (IO::DataIngestionLayer::IsBlockReady()) {
// Print progress, if appropriate
ProgressPrinter::PrintIfAppropriate(
"Encrypting",
nBlocksDigested,
IO::DataIngestionLayer::NBlocksRead()
);
const Block cleartext = IO::DataIngestionLayer::GetNextBlock();
const Block ciphertext = cipher.Digest(cleartext);
nBlocksDigested++;
// Enqueue the block for output
IO::DataOutputLayer::Enqueue(ciphertext);
}
// Tell the data output layer that it just received the
// last block, if it did
if (IO::DataIngestionLayer::IsFinished()) {
IO::DataOutputLayer::ReachedEOF();
}
// Attempt to write a block
IO::DataOutputLayer::WriteBlock();
}
// Destruct the data ingestion layer
IO::DataIngestionLayer::Destruct();
// Destruct the data output layer
IO::DataOutputLayer::Destruct();
return;
}

View File

@ -0,0 +1,32 @@
#include "ModuleGenerateKey.h"
#include "DataOutputLayer.h"
#include "KeyManager.h"
#include "CommandlineInterface.h"
using namespace Leonetienne::GCrypt;
using namespace Module;
void GenerateKey::Run() {
// Initialize the data output layer
IO::DataOutputLayer::Init();
// Enqueue our single block of data
IO::DataOutputLayer::Enqueue(KeyManager::GetKey());
// Tell the data output layer, that is has received all blocks
IO::DataOutputLayer::ReachedEOF();
// Tell it to write all blocks
// (a single call should suffice, but a while-loop is the proper
// way to do it)
while (!IO::DataOutputLayer::IsFinished()) {
IO::DataOutputLayer::WriteBlock();
}
// Destruct the data output layer
IO::DataOutputLayer::Destruct();
return;
}

View File

@ -0,0 +1,64 @@
#include "ModuleHashing.h"
#include "DataIngestionLayer.h"
#include "DataOutputLayer.h"
#include "ProgressPrinter.h"
#include "KeyManager.h"
#include <GCrypt/GHash.h>
using namespace Module;
using namespace Leonetienne::GCrypt;
void Hashing::Run() {
// Initialize the data ingestion layer
IO::DataIngestionLayer::Init();
// Initialize the data output layer
IO::DataOutputLayer::Init();
// Initialize a ghasher
GHash hasher;
// Read in new blocks, if not reached eof
std::size_t nBlocksDigested = 0;
while (!IO::DataIngestionLayer::IsFinished()) {
if (!IO::DataIngestionLayer::ReachedEOF()) {
IO::DataIngestionLayer::ReadBlock();
}
// Process a block, if one is ready
if (IO::DataIngestionLayer::IsBlockReady()) {
// Print progress, if appropriate
ProgressPrinter::PrintIfAppropriate(
"Hashing",
nBlocksDigested,
IO::DataIngestionLayer::NBlocksRead()
);
const Block cleartext = IO::DataIngestionLayer::GetNextBlock();
hasher.Digest(cleartext);
nBlocksDigested++;
}
}
// Wait until we've finished digesting all blocks
// Enqueue that single block (the hash result) to the output layer
IO::DataOutputLayer::Enqueue(hasher.GetHashsum());
// Tell the data output layer that that was the last block
IO::DataOutputLayer::ReachedEOF();
// Dump it
while (!IO::DataOutputLayer::IsFinished()) {
IO::DataOutputLayer::WriteBlock();
}
// Destruct the data ingestion layer
IO::DataIngestionLayer::Destruct();
// Destruct the data output layer
IO::DataOutputLayer::Destruct();
return;
}

View File

@ -0,0 +1,28 @@
#include "ProgressPrinter.h"
#include "CommandlineInterface.h"
#include <iostream>
void ProgressPrinter::PrintIfAppropriate(
const std::string& message,
const std::size_t current,
const std::size_t target
) {
if (
(CommandlineInterface::Get().HasParam("--progress")) &&
(current % CommandlineInterface::Get()["--progress-interval"].GetInt32() == 0)
) {
std::cerr
<< message
<< "... (Block "
<< current + 1
<< " / "
<< target
<< " - " << ((float)(current+1)*100 / target)
<< "%)"
<< std::endl
;
}
return;
}

41
GCryptCLI/src/main.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "CommandlineInterface.h"
#include "Configuration.h"
#include "KeyManager.h"
#include "ModuleGenerateKey.h"
#include "ModuleEncryption.h"
#include "ModuleDecryption.h"
#include "ModuleHashing.h"
int main(int argc, char* const* argv) {
// Init cli args
CommandlineInterface::Init(argc, argv);
// Parse configuration
Configuration::Parse();
// Prepare the key
KeyManager::PrepareKey();
// Launch our module
switch (Configuration::activeModule) {
case Configuration::MODULE::ENCRYPTION:
Module::Encryption::Run();
break;
case Configuration::MODULE::DECRYPTION:
Module::Decryption::Run();
break;
case Configuration::MODULE::GENERATE_KEY:
Module::GenerateKey::Run();
break;
case Configuration::MODULE::HASH:
Module::Hashing::Run();
break;
}
return 0;
}

17965
GCryptCLI/test/Catch2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
#include <DataFormatter.h>
#include <GCrypt/Key.h>
#include <GCrypt/GPrng.h>
#include "Catch2.h"
using namespace Leonetienne::GCrypt;
// Tests that recoding iobase formats works for individual blocks, with random data
TEMPLATE_TEST_CASE_SIG(
__FILE__"Data formats can be converted, without changing in value, with indivudual blocks, with random data",
"[DataFormatter]",
((Configuration::IOBASE_FORMAT formatUnderTest), formatUnderTest),
Configuration::IOBASE_FORMAT::BASE_BYTES,
Configuration::IOBASE_FORMAT::BASE_2,
Configuration::IOBASE_FORMAT::BASE_8,
Configuration::IOBASE_FORMAT::BASE_10,
Configuration::IOBASE_FORMAT::BASE_16,
Configuration::IOBASE_FORMAT::BASE_64,
Configuration::IOBASE_FORMAT::BASE_UWU,
Configuration::IOBASE_FORMAT::BASE_UGH
) {
// Let's use a GPrng instead of Key::Random,
// because Key::Random is rather slow (because it's using hardware events).
// We just want randomized data for tests...
GPrng prng(Key::Random());
// Let's try 10 different random blocks per test
for (std::size_t i = 0; i < 10; i++) {
// Setup
const Block b_initial = prng.GetBlock();
// Exercise
// Convert to a custom base
const std::string b_format = DataFormatter::FormatBlock(
b_initial,
formatUnderTest
);
// Convert back to a block
const Block b_retrieved = DataFormatter::DecodeFormat(
b_format,
formatUnderTest
);
// Verify
// Do b_initial and b_retrieved match?
REQUIRE(b_initial == b_retrieved);
}
}
// Tests that recoding iobase format works
TEMPLATE_TEST_CASE_SIG(
__FILE__"Data formats can be converted, without changing in value, with indivudual blocks, with very little data (lots of nullbytes)",
"[DataFormatter]",
((Configuration::IOBASE_FORMAT formatUnderTest), formatUnderTest),
Configuration::IOBASE_FORMAT::BASE_BYTES,
Configuration::IOBASE_FORMAT::BASE_2,
Configuration::IOBASE_FORMAT::BASE_8,
Configuration::IOBASE_FORMAT::BASE_10,
Configuration::IOBASE_FORMAT::BASE_16,
Configuration::IOBASE_FORMAT::BASE_64,
Configuration::IOBASE_FORMAT::BASE_UWU,
Configuration::IOBASE_FORMAT::BASE_UGH
) {
// Setup
Block b_initial;
b_initial.FromTextString("Heyu");
// Exercise
// Convert to a custom base
const std::string b_format = DataFormatter::FormatBlock(
b_initial,
formatUnderTest
);
// Convert back to a block
const Block b_retrieved = DataFormatter::DecodeFormat(
b_format,
formatUnderTest
);
// Verify
// Do b_initial and b_retrieved match?
REQUIRE(b_initial == b_retrieved);
}

2
GCryptCLI/test/main.cpp Normal file
View File

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "Catch2.h"

86
GCryptLib/CMakeLists.txt Normal file
View File

@ -0,0 +1,86 @@
cmake_minimum_required(VERSION 3.16)
project(GCrypt)
###################
# Library project #
###################
set(CMAKE_CXX_STANDARD 17)
FILE(GLOB main_src src/*.cpp)
add_library(${PROJECT_NAME}
${main_src}
)
target_include_directories(${PROJECT_NAME} PRIVATE
include
)
target_compile_options(${PROJECT_NAME} PRIVATE
-Werror
-fdiagnostics-color=always
)
#########
# Tests #
#########
FILE(GLOB test_src test/*.cpp)
add_executable(test
test/Catch2.h
${test_src}
)
target_link_libraries(test ${PROJECT_NAME})
target_include_directories(test PRIVATE
include
)
target_compile_options(test PRIVATE
-Werror
-fdiagnostics-color=always
)
## Move test assest to build dir
ADD_CUSTOM_COMMAND(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/test/testAssets/ $<TARGET_FILE_DIR:${PROJECT_NAME}>/testAssets/
)
###############
# Executables #
###############
FILE(GLOB bmpp_src exec/BmpPP/BmpPP/src/*.cpp)
FILE(GLOB eule_src exec/Eule/Eule/src/*.cpp)
add_compile_definitions(_EULE_NO_INTRINSICS_)
include_directories(
include
exec/BmpPP/BmpPP/include
exec/Eule/Eule/include
)
## Move exec assets to build dir
ADD_CUSTOM_COMMAND(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/exec/execAssets/ $<TARGET_FILE_DIR:${PROJECT_NAME}>/execAssets/
)
function(DECLARE_EXEC_EXAMPLE name)
add_executable(example-${name} exec/${name}.cpp ${bmpp_src} ${eule_src})
target_link_libraries(example-${name} ${PROJECT_NAME})
target_compile_options(example-${name} PRIVATE -Werror -fdiagnostics-color=always)
endfunction()
# These are the names of the cpp files in /exec/, without the ".cpp".
DECLARE_EXEC_EXAMPLE(encrypt-decrypt-files)
DECLARE_EXEC_EXAMPLE(encrypt-decrypt-strings)
DECLARE_EXEC_EXAMPLE(benchmark-encryption)
DECLARE_EXEC_EXAMPLE(benchmark-prng)
DECLARE_EXEC_EXAMPLE(visualize-singleblock-diffusion)
DECLARE_EXEC_EXAMPLE(visualize-multiblock-diffusion)
DECLARE_EXEC_EXAMPLE(visualize-extreme-input-diffusion)
DECLARE_EXEC_EXAMPLE(visualize-prng-distribution)
DECLARE_EXEC_EXAMPLE(visualize-hashing-distribution)

View File

@ -0,0 +1,21 @@
Old way (400 rounds, no matrix mult): 38.01s
- 400 was the minimum for good diffusion
New way (10 rounds, with matrix mult): 1.16s
- 10 rounds now give sufficient diffusion
- still using bitsets and strings
With new block class (instead of bitsets) (10 rounds): 0.35s
- still partially using bitsets and strings
With new block class (6 rounds, still good diffusion): 0.21s
With new templated block class (full block and half block): 0.14s
- finally no more bitsets
With new sbox, reduction, and expansion function: 0.03s
With additional jumbling in feistel rounds: 0.03s
With direct file reading/writing from data blocks: 0.02s

1
GCryptLib/doxygen/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

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

2579
GCryptLib/doxygen/doxyfig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
#ifndef GCRYPTEXAMPLE_BENCHMARK_H
#define GCRYPTEXAMPLE_BENCHMARK_H
#include <functional>
#include <chrono>
#include <iostream>
void Benchmark(const std::string& brief, std::function<void()> toBenchmark) {
std::cout << "Benchmarking " << brief << "..." << std::endl;
auto start = std::chrono::steady_clock::now();
toBenchmark();
auto end = std::chrono::steady_clock::now();
double seconds = (double)std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() / 1000.0;
std::cout << seconds << " seconds." << std::endl << std::endl;
return;
}
#endif

1
GCryptLib/exec/BmpPP Submodule

@ -0,0 +1 @@
Subproject commit 522f9551ae31215cf63fcad88cacbfc8c818ccaf

1
GCryptLib/exec/Eule Submodule

@ -0,0 +1 @@
Subproject commit 1bfd756aa8bd1d484857735d63b4fdf8a15bbed5

View File

@ -0,0 +1,58 @@
#ifndef GCRYPTEXAMPLE_VISUALIZE_H
#define GCRYPTEXAMPLE_VISUALIZE_H
#include <GCrypt/Block.h>
#include <BmpPP/Bmp.h>
#include <string>
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::Eule;
using namespace Leonetienne::BmpPP;
void VisualizeBlock(const Block& block, const std::string& name) {
BMP bmp(Vector2i(32, 16), Colormode::RGB);
std::size_t i = 0;
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::uint8_t pixel = block.GetBit(i) == false ? 255 : 0;
bmp.SetPixel(Vector2i(x, y), pixel);
i++;
}
bmp.Write(name);
return;
}
// size.x*size.y MUST equal blocks.size() * Block::BLOCK_SIZE_BITS. That should be, by defalt blocks.size * 512.
void VisualizeBlocks(const std::vector<Block>& blocks, const Vector2i& size, const std::string& name) {
//! A bit of error checking...
if (size.x*size.y != blocks.size() * Block::BLOCK_SIZE_BITS) {
throw std::invalid_argument("Supplied unfitting widht/height for visualization. Does not fit bits!");
}
BMP bmp(size, Colormode::RGB);
std::size_t i = 0;
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::size_t blockIndex = i / Block::BLOCK_SIZE_BITS;
const std::size_t relBitIndex = i - blockIndex * Block::BLOCK_SIZE_BITS;
const std::uint8_t pixel = blocks[blockIndex].GetBit(relBitIndex) == false ? 255 : 0;
bmp.SetPixel(Vector2i(x, y), pixel);
i++;
}
bmp.Write(name);
return;
}
#endif

View File

@ -0,0 +1,21 @@
#include <GCrypt/GWrapper.h>
#include "Benchmark.h"
using namespace Leonetienne::GCrypt;
int main() {
Benchmark(
"file encryption",
[]() {
GWrapper::EncryptFile(
"./execAssets/big-testfile.bmp",
"./execAssets/testimage.bmp.crypt",
Key::FromPassword("password1")
);
}
);
return 0;
}

View File

@ -0,0 +1,42 @@
#include <GCrypt/GPrng.h>
#include <iostream>
#include "Benchmark.h"
using namespace Leonetienne::GCrypt;
int main() {
Benchmark(
"generating 1.000.000 32-bit uints using prng.GetRandom<uint32_t>()",
[]() {
GPrng prng(Key::Random());
for (int i = 0; i < 1000000; i++) {
prng.GetRandom<std::uint32_t>();
}
}
);
Benchmark(
"generating 1.000.000 uint32_t using prng()",
[]() {
GPrng prng(Key::Random());
for (int i = 0; i < 1000000; i++) {
prng();
}
}
);
Benchmark(
"generating 100.000 data blocks using prng.GetBlock()",
[]() {
GPrng prng(Key::Random());
for (int i = 0; i < 100000; i++) {
prng.GetBlock();
}
}
);
return 0;
}

View File

@ -0,0 +1,25 @@
#include <GCrypt/GWrapper.h>
#include <iostream>
using namespace Leonetienne::GCrypt;
int main() {
std::cout << "Example on how to encrypt & decrypt any file:" << std::endl;
// Encrypt
GWrapper::EncryptFile(
"./execAssets/testimage.bmp",
"./execAssets/testimage.bmp.crypt",
Key::FromPassword("password1")
);
// Decrypt
GWrapper::DecryptFile(
"./execAssets/testimage.bmp.crypt",
"./execAssets/testimage.bmp.clear.bmp",
Key::FromPassword("password1"
));
return 0;
}

View File

@ -0,0 +1,30 @@
#include <GCrypt/GWrapper.h>
#include <iostream>
using namespace Leonetienne::GCrypt;
int main() {
std::cout << "Example on how to encrypt & decrypt strings:" << std::endl;
const std::string cleartext = "Hello, World :3";
std::cout << "Cleartext: " << cleartext << std::endl;
// Encrypt
const std::string ciphertext = GWrapper::EncryptString(
cleartext,
Key::FromPassword("password1")
);
std::cout << "Ciphertext: " << ciphertext << std::endl;
// Decrypt
const std::string decrypted = GWrapper::DecryptString(
ciphertext,
Key::FromPassword("password1")
);
std::cout << "Decrypted: " << decrypted << std::endl;
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -0,0 +1,54 @@
#include <iostream>
#include <GCrypt/GWrapper.h>
#include <GCrypt/Key.h>
#include <GCrypt/Util.h>
#include <BmpPP/Bmp.h>
#include "Visualize.h"
const std::string execName = "visualize-extreme-input-diffusion";
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::BmpPP;
using namespace Leonetienne::Eule;
int main() {
// These are magic values, which work for this specific input string.
// If you want to try another string, get the size of all blocks in bits (it gets printed),
// and find two integer factors which factor up to it. These are your images width, and height.
const Vector2i visualizationDimension = Vector2i(56, 64);
// Create a key
// The key is almost just zeores (it doesn't have an IV, so what you see is what goes in the cipher.)
// In case you're wondering, I can tell you right now that an all-zero input with an all-zero key will result in an all-zero ciphertext.
Key key;
key.Reset();
key.SetBit(199, true);
VisualizeBlock(key, execName+"-key.bmp");
// Create our input blocks
// All the input blocks are just zeroes!
std::vector<Block> input_blocks;
input_blocks.resize(7);
for (Block& block : input_blocks) {
block.Reset();
}
std::cout << "Input size is " << input_blocks.size() * Block::BLOCK_SIZE_BITS << " bits long." << std::endl;
VisualizeBlocks(input_blocks, visualizationDimension, execName+"-input.bmp");
// Encrypt it
std::vector<Block> ciphertext_blocks = GWrapper::CipherBlocks(input_blocks, key, GCipher::DIRECTION::ENCIPHER);
VisualizeBlocks(ciphertext_blocks, visualizationDimension, execName+"-output.bmp");
// Now flip a single bit in the input
input_blocks[3].FlipBit(156);
VisualizeBlocks(input_blocks, visualizationDimension, execName+"-input-flip.bmp");
// Encrypt it again
ciphertext_blocks = GWrapper::CipherBlocks(input_blocks, key, GCipher::DIRECTION::ENCIPHER);
VisualizeBlocks(ciphertext_blocks, visualizationDimension, execName+"-output-flip.bmp");
return 0;
}

View File

@ -0,0 +1,34 @@
#include <iostream>
#include <GCrypt/GHash.h>
#include <BmpPP/Bmp.h>
#include "Visualize.h"
const std::string execName = "visualize-hashing-distribution";
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::BmpPP;
using namespace Leonetienne::Eule;
void HashAndVisualize(const Block& b, const std::string filename) {
GHash hasher;
hasher.Digest(b);
VisualizeBlock(hasher.GetHashsum(), filename);
}
int main() {
// Get some random input
Block a;
a.FromTextString("Hello, World :3");
VisualizeBlock(a, execName+"-input-a.bmp");
HashAndVisualize(a, execName+"-output-a.bmp");
// Now flip a bit
Block b = a;
b.FlipBit(4);
VisualizeBlock(b, execName+"-input-b.bmp");
HashAndVisualize(b, execName+"-output-b.bmp");
return 0;
}

View File

@ -0,0 +1,45 @@
#include <iostream>
#include <GCrypt/GWrapper.h>
#include <GCrypt/Key.h>
#include <GCrypt/Util.h>
#include <BmpPP/Bmp.h>
#include "Visualize.h"
const std::string execName = "visualize-multiblock-diffusion";
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::BmpPP;
using namespace Leonetienne::Eule;
int main() {
// These are magic values, which work for this specific input string.
// If you want to try another string, get the size of all blocks in bits (it gets printed),
// and find two integer factors which factor up to it. These are your images width, and height.
const Vector2i visualizationDimension = Vector2i(56, 64);
// Create a key
const Key key = Key::Random();
VisualizeBlock(key, execName+"-key.bmp");
// Create our input blocks
const std::string input = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
std::vector<Block> input_blocks = StringToBitblocks(input);
std::cout << "Input size is " << input_blocks.size() * Block::BLOCK_SIZE_BITS << " bits long." << std::endl;
VisualizeBlocks(input_blocks, visualizationDimension, execName+"-input.bmp");
// Encrypt it
std::vector<Block> ciphertext_blocks = GWrapper::CipherBlocks(input_blocks, key, GCipher::DIRECTION::ENCIPHER);
VisualizeBlocks(ciphertext_blocks, visualizationDimension, execName+"-output.bmp");
// Now flip a single bit in the input
input_blocks[3].FlipBit(156);
VisualizeBlocks(input_blocks, visualizationDimension, execName+"-input-flip.bmp");
// Encrypt it again
ciphertext_blocks = GWrapper::CipherBlocks(input_blocks, key, GCipher::DIRECTION::ENCIPHER);
VisualizeBlocks(ciphertext_blocks, visualizationDimension, execName+"-output-flip.bmp");
return 0;
}

View File

@ -0,0 +1,146 @@
#include <iostream>
#include <GCrypt/Key.h>
#include <GCrypt/GPrng.h>
#include <BmpPP/Bmp.h>
#include "Benchmark.h"
const std::string execName = "visualize-prng-distribution";
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::BmpPP;
using namespace Leonetienne::Eule;
int main() {
// Black/white
Benchmark(
"black/white - GetBit()",
[]() {
Key seed = Key::Random();
BMP bmp(Vector2i(800, 800), Colormode::RGB);
GPrng prng(seed);
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::uint8_t pixel = prng.GetBit() ? 255 : 0;
bmp.SetPixel(Vector2i(x, y), pixel);
}
bmp.Write(execName+"-blackwhite.bmp");
}
);
// Grayscale (using GetRandom<>)
Benchmark(
"grayscale - GetRandom<std::uint8_t>()",
[]() {
Key seed = Key::Random();
BMP bmp(Vector2i(800, 800), Colormode::RGB);
GPrng prng(seed);
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::uint8_t pixel = prng.GetRandom<std::uint8_t>();
bmp.SetPixel(Vector2i(x, y), pixel);
}
bmp.Write(execName+"-getrandom-grayscale.bmp");
}
);
// Grayscale (using operator()) (this one returns a whole uint32)
Benchmark(
"grayscale - operator()",
[]() {
Key seed = Key::Random();
BMP bmp(Vector2i(800, 800), Colormode::RGB);
GPrng prng(seed);
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::uint8_t pixel = prng() % 256;
bmp.SetPixel(Vector2i(x, y), pixel);
}
bmp.Write(execName+"-operator-grayscale.bmp");
}
);
// Color (using GetRandom<>)
Benchmark(
"color - GetRandom<uint8_t>()",
[]() {
Key seed = Key::Random();
BMP bmp(Vector2i(800, 800), Colormode::RGB);
GPrng prng(seed);
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::uint8_t r = prng.GetRandom<std::uint8_t>();
const std::uint8_t g = prng.GetRandom<std::uint8_t>();
const std::uint8_t b = prng.GetRandom<std::uint8_t>();
bmp.SetPixel(Vector2i(x, y), r, g, b);
}
bmp.Write(execName+"-getrandom-color.bmp");
}
);
// Color (using operator()) (this one returns a whole uint32)
Benchmark(
"color - operator()",
[]() {
Key seed = Key::Random();
BMP bmp(Vector2i(800, 800), Colormode::RGB);
GPrng prng(seed);
for (std::size_t x = 0; x < bmp.GetDimensions().x; x++)
for (std::size_t y = 0; y < bmp.GetDimensions().y; y++) {
const std::uint8_t r = prng() % 256;
const std::uint8_t g = prng() % 256;
const std::uint8_t b = prng() % 256;
bmp.SetPixel(Vector2i(x, y), r, g, b);
}
bmp.Write(execName+"-operator-color.bmp");
}
);
// Color (using GetBlock())
//(this one returns a derivation of the current hashsum, without using up randomness)
Benchmark(
"color - GetBlock()",
[]() {
Key seed = Key::Random();
BMP bmp(Vector2i(800, 800), Colormode::RGB);
GPrng prng(seed);
std::size_t bytes_written = 0;
while (bytes_written < bmp.GetPixelbufferSize()) {
const Block block = prng.GetBlock();
std::size_t bytesToCopy = 0;
if (bmp.GetPixelbufferSize() - bytes_written < Block::BLOCK_SIZE) {
bytesToCopy = bmp.GetPixelbufferSize() - bytes_written;
}
else {
bytesToCopy = Block::BLOCK_SIZE;
}
memcpy(
(char*)bmp.GetPixelbuffer().data() + bytes_written,
(char*)block.Data(),
bytesToCopy
);
bytes_written += bytesToCopy;
}
bmp.Write(execName+"-getblock-color.bmp");
}
);
return 0;
}

View File

@ -0,0 +1,45 @@
#include <iostream>
#include <GCrypt/GWrapper.h>
#include <GCrypt/Key.h>
#include <BmpPP/Bmp.h>
#include "Visualize.h"
const std::string execName = "visualize-singleblock-diffusion";
using namespace Leonetienne::GCrypt;
using namespace Leonetienne::BmpPP;
using namespace Leonetienne::Eule;
int main() {
// Create input block
const std::string input_str = "Hello :3";
Block input;
input.FromTextString(input_str);
VisualizeBlock(input, execName+"-input.bmp");
// Create a key
const Key key = Key::Random();
VisualizeBlock(key, execName+"-key.bmp");
// Create a cipher
GCipher cipher(key, GCipher::DIRECTION::ENCIPHER);
// Encipher our block
Block cipherblock = cipher.Digest(input);
VisualizeBlock(cipherblock, execName+"-output.bmp");
// Now flip a bit in the input
input.FlipBit(35);
VisualizeBlock(input, execName+"-input-flip.bmp");
// Reset our cipher, and encipher the input with a flipped bit
cipher.Initialize(key, GCipher::DIRECTION::ENCIPHER);
// Encipher our block
cipherblock = cipher.Digest(input);
VisualizeBlock(cipherblock, execName+"-output-flip.bmp");
return 0;
}

View File

@ -0,0 +1,216 @@
#ifndef GCRYPT_BLOCK_H
#define GCRYPT_BLOCK_H
#include <cstdint>
#include <array>
#include <string>
#include <iosfwd>
#include <bitset>
namespace Leonetienne::GCrypt {
/** This class represents a block of data,
* and provides functions to manipulate it
*/
template <typename T>
class Basic_Block {
public:
//! Will constuct an uninitialized data block
Basic_Block();
//! Will construct this block from a string like "101010".. Length MUST be 512.
Basic_Block(const std::string& other);
//! Copy-ctor
Basic_Block(const Basic_Block<T>& other);
~Basic_Block();
//! Will construct this block from a string like "011101..".
void FromBinaryString(const std::string& str);
//! Will construct this block from a hexstring
void FromHexString(const std::string& str);
//! Will construct this block from a bytestring (any characters)
void FromByteString(const std::string& str);
//! Will construct this block from a textstring (any length)
void FromTextString(const std::string& str);
//! Will create a bitset-compatible string ("0101110..") representation
//! of this block. Length will always be 512.
std::string ToBinaryString() const;
//! Will create a hexstring representation of this block.
std::string ToHexString() const;
//! Will create a bytestring representation of this block.
std::string ToByteString() const;
//! Will create a textstring representation of this block.
//! The difference to a bytestring is that it gets trimmed after a nullterminator.
std::string ToTextString() 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.
[[nodiscard]] Basic_Block<T> MMul(const Basic_Block<T>& other) const;
[[nodiscard]] Basic_Block<T> operator*(const Basic_Block<T>& 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 Basic_Block<T>& other);
Basic_Block<T>& operator*=(const Basic_Block<T>& other);
//! Will xor two blocks together
[[nodiscard]] Basic_Block<T> Xor(const Basic_Block<T>& other) const;
//! Will xor two blocks together
[[nodiscard]] Basic_Block<T> operator^(const Basic_Block<T>& other) const;
//! Will xor two blocks together, inplace
void XorInplace(const Basic_Block<T>& other);
//! Will xor two blocks together, inplace
Basic_Block<T>& operator^=(const Basic_Block<T>& other);
//! Will add all the integer making up this block, one by one
[[nodiscard]] Basic_Block<T> Add(const Basic_Block<T>& other) const;
//! Will add all the integer making up this block, one by one
[[nodiscard]] Basic_Block<T> operator+(const Basic_Block<T>& other) const;
//! Will add all the integer making up this block, one by one, inplace
void AddInplace(const Basic_Block<T>& other);
//! Will add all the integer making up this block, one by one, inplace
Basic_Block<T>& operator+=(const Basic_Block<T>& other);
//! Will subtract all the integer making up this block, one by one
[[nodiscard]] Basic_Block<T> Sub(const Basic_Block<T>& other) const;
//! Will subtract all the integer making up this block, one by one
[[nodiscard]] Basic_Block<T> operator-(const Basic_Block<T>& other) const;
//! Will subtract all the integer making up this block, one by one, inplace
void SubInplace(const Basic_Block<T>& other);
//! Will subtract all the integer making up this block, one by one, inplace
Basic_Block<T>& operator-=(const Basic_Block<T>& other);
//! Will shift rows upwards by 1
[[nodiscard]] Basic_Block<T> ShiftRowsUp() const;
//! Will shift rows upwards by 1
void ShiftRowsUpInplace();
//! Will shift matrix rows downwards by 1
[[nodiscard]] Basic_Block<T> ShiftRowsDown() const;
//! Will shift matrix rows downwards by 1
void ShiftRowsDownInplace();
//! Will shift matrix columns to the left by 1
[[nodiscard]] Basic_Block<T> ShiftColumnsLeft() const;
//! Will shift matrix columns to the left by 1
void ShiftColumnsLeftInplace();
//! Will shift matrix columns to the right by 1
[[nodiscard]] Basic_Block<T> ShiftColumnsRight() const;
//! Will shift matrix columns to the right by 1
void ShiftColumnsRightInplace();
//! Will shift array cells to the left by 1
[[nodiscard]] Basic_Block<T> ShiftCellsLeft() const;
//! Will shift array cells to the left by 1
void ShiftCellsLeftInplace();
//! Will shift array cells to the right by 1
[[nodiscard]] Basic_Block<T> ShiftCellsRight() const;
//! Will shift array cells to the right by 1
void ShiftCellsRightInplace();
//! Will copy a block
Basic_Block<T>& operator=(const Basic_Block<T>& other);
//! Will compare whether or not two blocks are equal
[[nodiscard]] bool operator==(const Basic_Block<T>& other) const;
//! Will compare whether or not two blocks are unequal
[[nodiscard]] bool operator!=(const Basic_Block<T>& other) const;
//! Will zero all data
void Reset();
//! Will return the state of any given bit
[[nodiscard]] bool GetBit(const std::size_t index) const;
//! Will set the state of any given bit
void SetBit(const std::size_t index, const bool state);
//! Will flip the state of any given bit
void FlipBit(const std::size_t index);
//! Will shift all bits to the left by 1
[[nodiscard]] Basic_Block<T> ShiftBitsLeft() const;
//! Will shift all bits to the left by 1, inplace
void ShiftBitsLeftInplace();
//! Will shift all bits to the right by 1
[[nodiscard]] Basic_Block<T> ShiftBitsRight() const;
//! Will shift all bits to the right by 1, inplace
void ShiftBitsRightInplace();
//! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3)
[[nodiscard]] T& Get(const std::uint8_t row, const std::uint8_t column);
//! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3)
[[nodiscard]] const 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)
[[nodiscard]] T& Get(const std::uint8_t index);
//! Returns 32-bit chunks of data, indexed by a 1d-index (0-16)
[[nodiscard]] const T& Get(const std::uint8_t index) const;
//! Returns 32-bit chunks of data, indexed by a 1d-index (0-16)
[[nodiscard]] T& operator[](const std::uint8_t index);
//! Returns 32-bit chunks of data, indexed by a 1d-index (0-16)
[[nodiscard]] const T& operator[](const std::uint8_t index) const;
//! Will return a reference to the data array
T* Data() noexcept;
//! Will return a reference to the data array
const T* Data() const noexcept;
static constexpr std::size_t CHUNK_SIZE = sizeof(T);
static constexpr std::size_t CHUNK_SIZE_BITS = CHUNK_SIZE * 8;
static constexpr std::size_t BLOCK_SIZE = CHUNK_SIZE * 16;
static constexpr std::size_t BLOCK_SIZE_BITS = CHUNK_SIZE_BITS * 16;
friend std::ostream& operator<<(std::ostream& os, const Basic_Block<T>& b) {
for (std::size_t i = 0; i < b.data.size(); i++) {
os << std::bitset<Basic_Block<T>::CHUNK_SIZE_BITS>(b.data[i]).to_string();
}
return os;
}
private:
std::array<T, 16> data;
};
//! This a full-sized 512-bit block
typedef Basic_Block<std::uint32_t> Block;
//! This is a half-block used within the feistel class
typedef Basic_Block<std::uint16_t> Halfblock;
}
#endif

View File

@ -0,0 +1,12 @@
#ifndef GCRYPT_CONFIG_H
#define GCRYPT_CONFIG_H
#include <cstddef>
namespace Leonetienne::GCrypt {
// MUST BE > 2
constexpr std::size_t N_ROUNDS = 6;
}
#endif

View File

@ -0,0 +1,72 @@
#ifndef GCRYPT_FEISTEL_H
#define GCRYPT_FEISTEL_H
#include "GCrypt/Keyset.h"
#include "GCrypt/Block.h"
#include "GCrypt/Key.h"
namespace Leonetienne::GCrypt {
/** Class to perform a feistel block chipher
*/
class Feistel {
public:
//! Empty initializer. If you use this, you must call SetKey()!
Feistel();
//! Will initialize the feistel cipher with a key
explicit Feistel(const Key& key);
Feistel(const Feistel& other) = delete;
Feistel(Feistel&& other) noexcept = delete;
~Feistel();
//! Will set the seed-key for this feistel network.
//! Roundkeys will be derived from this.
void SetKey(const Key& key);
//! Will encipher a data block via the set seed-key
Block Encipher(const Block& data);
//! Will decipher a data block via the set seed-key
Block Decipher(const Block& data);
void operator=(const Feistel& other);
private:
//! Will run the feistel rounds, with either regular key
//! order or reversed key order
Block Run(const Block& data, bool modeEncrypt);
//! Arbitrary cipher function
static Halfblock F(Halfblock m, const Key& key);
//! Split a data block into two half blocks (into L and R)
static std::pair<Halfblock, Halfblock> FeistelSplit(const Block& block);
//! Combine two half blocks (L and R) into a regular data block
static Block FeistelCombine(const Halfblock& l, const Halfblock& r);
//! Will expand a halfblock to a fullblock
static Block ExpansionFunction(const Halfblock& block);
//! Will reduce a fullblock to a halfblock
static Halfblock ReductionFunction(const Block& block);
//! Substitutes eight bits by static random others, inplace
static void SBox(Block& block);
//! Will generate a the round keys
void GenerateRoundKeys(const Key& seedKey);
//! Will zero the memory used by the keyset
void ZeroKeyMemory();
Keyset roundKeys;
bool isInitialized = false;
};
}
#endif

View File

@ -0,0 +1,54 @@
#ifndef GCRYPT_GCIPHER_H
#define GCRYPT_GCIPHER_H
#include "GCrypt/Feistel.h"
namespace Leonetienne::GCrypt {
/** Class to apply a block/-stream cipher to messages of arbitrary length in a distributed manner
*/
class GCipher {
public:
//! Describes the direction the cipher runs in
enum class DIRECTION {
ENCIPHER,
DECIPHER
};
//! Empty initializer. If you use this, you must call Initialize()!
GCipher();
//! Will initialize this cipher with a key
explicit GCipher(const Key& key, const DIRECTION direction);
// Disable copying
GCipher(const GCipher& other) = delete;
GCipher(GCipher&& other) noexcept = delete;
//! Will digest a data block, and return it
Block Digest(const Block& input);
//! Will update the base key used
void SetKey(const Key& key);
void operator=(const GCipher& other);
//! Will initialize the cipher with a key, and a mode.
//! If called on an existing object, it will reset its state.
void Initialize(const Key& key, const DIRECTION direction);
private:
DIRECTION direction;
//! The feistel instance to be used
Feistel feistel;
//! The last block, required for CBC.
Block lastBlock;
bool isInitialized = false;
};
}
#endif

View File

@ -0,0 +1,45 @@
#ifndef GCRYPT_GHASH_H
#define GCRYPT_GHASH_H
#include "GCrypt/Block.h"
#include "GCrypt/GCipher.h"
#include <vector>
namespace Leonetienne::GCrypt {
/** This class implements a hash function, based on the GCrypt cipher
*/
class GHash {
public:
GHash();
//! Will add the hash value of the block `data` to the hashsum.
//! WARNING: If you compute hashes using this digestive method,
//! you REALLY REALLY should add a trailing block just containing the cleartext size!
//! You MOST LIKELY just want to use the wrapper function GHash::CalculateHashsum(Flexblock const&) instead!
void Digest(const Block& data);
//! Will return the current hashsum
const Block& GetHashsum() const;
//! Will calculate a hashsum for `blocks`.
//! Whilst n_bytes is optional, it is HIGHLY recommended to supply.
//! Without specifying the size of the input (doesn't always have to be 512*n bits)
//! b'293eff' would hash to the exact same values as b'293eff0000'
static Block CalculateHashsum(const std::vector<Block>& blocks, std::size_t n_bytes = std::string::npos);
//! Will calculate a hashsum for a string
static Block HashString(const std::string& str);
void operator=(const GHash& other);
private:
//! The cipher to use
GCipher cipher;
//! The current state of the hashsum
Block block;
};
}
#endif

View File

@ -0,0 +1,71 @@
#ifndef GCRYPT_GPRNG_H
#define GCRYPT_GPRNG_H
#include "GCrypt/GHash.h"
#include "GCrypt/Util.h"
#include <string.h>
#include <sstream>
#include <type_traits>
namespace Leonetienne::GCrypt {
/** This class implements a pseudo random number generator, based on the GCrypt hash function
*/
class GPrng {
public:
//! Will instanciate the prng with a seed. Seed could also be a GCrypt::Key.
GPrng(const Block& seed);
//! Will instanciate the GPrng with no seed. You should really seed it later.
GPrng();
//! Will reset and seed the prng. Seed could also be a GCrypt::Key.
void Seed(const Block& seed);
//! Will return a random bit.
bool GetBit();
//! Will return a randomized instance of any primitive.
template <typename T>
T GetRandom() {
static_assert(std::is_fundamental<T>::value, "Leonetienne::GCrypt::GPrng::GetRandom() may only be used with primitive types!");
// Pull the required amount of bits
std::stringstream ss;
for (std::size_t i = 0; i < sizeof(T)*8; i++) {
ss << (GetBit() ? '1' : '0');
}
// Transform to bytes
const std::string bits = ss.str();
ss.str("");
for (std::size_t i = 0; i < bits.size(); i += 8) {
ss << (char)std::bitset<8>(bits.substr(i, 8)).to_ulong();
}
const std::string bytes = ss.str();
// Cram bytes into type
T t;
memcpy(&t, bytes.data(), sizeof(T));
// Return our randomized primitive
return t;
}
//! Will return a random unsigned 32-bit integer
std::uint32_t operator()();
//! Will return a random block
Block GetBlock();
private:
//! Will generate the next block of random bits
void AdvanceBlock();
GHash hasher;
Block seed;
std::size_t nextBit = 0;
};
}
#endif

View File

@ -0,0 +1,45 @@
#ifndef GCRYPT_GWRAPPER_H
#define GCRYPT_GWRAPPER_H
#include "GCrypt/Block.h"
#include "GCrypt/GCipher.h"
#include "GCrypt/Key.h"
#include <string>
#include <vector>
namespace Leonetienne::GCrypt {
/** This class is a wrapper to make working with the GCipher
* super easy with a python-like syntax
*/
class GWrapper {
public:
//! Will encrypt a string and return it hexadecimally encoded.
static std::string EncryptString(const std::string& cleartext, const Key& key);
//! Will decrypt a hexadecimally encoded string.
static std::string DecryptString(const std::string& ciphertext, const Key& key);
//! Will encrypt a file.
//! Returns false if anything goes wrong (like, file-access).
//! @filename_in The file to be read.
//! @filename_out The file the encrypted version should be saved in.
static bool EncryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false);
//! Will decrypt a file.
//! Returns false if anything goes wrong (like, file-access).
//! @filename_in The file to be read.
//! @filename_out The file the decrypted version should be saved in.
static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const Key& key, bool printProgressReport = false);
//! Will enncrypt or decrypt an entire flexblock of binary data, given a key.
static std::vector<Block> CipherBlocks(const std::vector<Block>& data, const Key& key, const GCipher::DIRECTION direction);
private:
// No instanciation! >:(
GWrapper();
};
}
#endif

View File

@ -0,0 +1,17 @@
#pragma once
#include "GCrypt/Config.h"
#include "GCrypt/Block.h"
namespace Leonetienne::GCrypt {
/** Will create a sudo-random Block based on a seed
*/
class InitializationVector {
public:
InitializationVector(const Block& seed);
operator Block() const;
private:
Block iv;
};
}

View File

@ -0,0 +1,37 @@
#ifndef GCRYPT_KEY_H
#define GCRYPT_KEY_H
#include "GCrypt/Block.h"
#include <string>
namespace Leonetienne::GCrypt {
/** This class represents encryption keys.
* You can copy them, create them from data blocks,
* or even read from files.
*/
class Key : public Block {
public:
//! Will generate a key from a password
static Key FromPassword(const std::string& password);
//! Will generate a random key from actual randomness (std::random_device)
static Key Random();
//! Loads a keyfile
static Key LoadFromFile(const std::string& path);
//! Will save a keyfile
void WriteToFile(const std::string& path) const;
Key();
Key(const Key& k);
Key(const Block& b);
private:
};
}
#endif

View File

@ -0,0 +1,13 @@
#ifndef GCRYPT_KEYSET_H
#define GCRYPT_KEYSET_H
#include <array>
#include "GCrypt/Key.h"
#include "GCrypt/Config.h"
namespace Leonetienne::GCrypt {
typedef std::array<Key, N_ROUNDS> Keyset;
}
#endif

View File

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

View File

@ -0,0 +1,44 @@
#ifndef GCRYPT_UTIL_H
#define GCRYPT_UTIL_H
#include <bitset>
#include <sstream>
#include <fstream>
#include <cstring>
#include <vector>
#include "GCrypt/Block.h"
#include "GCrypt/Config.h"
#include "GCrypt/GCipher.h"
#include "GCrypt/InitializationVector.h"
namespace Leonetienne::GCrypt {
//! Mod-operator that works with negative values
inline int Mod(const int numerator, const int denominator) {
return (denominator + (numerator % denominator)) % denominator;
}
//! Will pad a string to a set length with a certain character
std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true);
//! Will convert a string to a vector of blocks
std::vector<Block> StringToBitblocks(const std::string& str);
//! Will convert an array of data blocks to a bytestring
std::string BitblocksToBytes(const std::vector<Block>& bits);
//! Will convert an array of blocks to a character-string
//! The difference to BitblocksToBytes() is, that it strips excess nullbytes
std::string BitblocksToString(const std::vector<Block>& blocks);
//! Will read a file directly to data blocks, and yield the amount of bytes read
std::vector<Block> ReadFileToBlocks(const std::string& filepath, std::size_t& bytes_read);
//! Will read a file directly to data blocks
std::vector<Block> ReadFileToBlocks(const std::string& filepath);
//! Will write data blocks directly to a file
void WriteBlocksToFile(const std::string& filepath, const std::vector<Block>& blocks);
}
#endif

View File

@ -0,0 +1,7 @@
#ifndef GCRYPT_VERSION_H
#define GCRYPT_VERSION_H
#define GCRYPT_VERSION 0.236
#endif

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

@ -0,0 +1,839 @@
#include "GCrypt/Block.h"
#include "GCrypt/Config.h"
#include "GCrypt/Util.h"
#include <sstream>
#include <cassert>
#include <cstring>
#include <iomanip>
#include <ios>
// 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;
}
}
namespace Leonetienne::GCrypt {
template <typename T>
Basic_Block<T>::Basic_Block() {
}
template <typename T>
Basic_Block<T>::Basic_Block(const std::string& str) {
FromBinaryString(str);
}
template <typename T>
Basic_Block<T>::Basic_Block(const Basic_Block<T>& other) {
data = other.data;
}
template <typename T>
void Basic_Block<T>::FromBinaryString(const std::string& str) {
if (str.length() != BLOCK_SIZE_BITS) {
throw std::invalid_argument(
std::string("Unable to read binary block: \"") + str + "\": Length is not BLOCK_SIZE_BITS."
);
}
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;
}
template <typename T>
void Basic_Block<T>::FromHexString(const std::string& str) {
if (str.length() != BLOCK_SIZE*2) {
throw std::invalid_argument(
std::string("Unable to read hex block: \"") + str + "\": Length is not BLOCK_SIZE*2."
);
}
for (std::size_t i = 0; i < str.length(); i += CHUNK_SIZE*2) {
const std::string hexChunk = str.substr(i, CHUNK_SIZE*2);
try {
data[i / (CHUNK_SIZE*2)] = std::stoul(hexChunk, NULL, 16);
}
catch (std::invalid_argument&) {
throw std::invalid_argument(
std::string("Unable to read hex block: \"") + hexChunk + "\"."
);
}
}
return;
}
template <typename T>
void Basic_Block<T>::FromByteString(const std::string& str) {
if (str.length() != BLOCK_SIZE) {
throw std::invalid_argument(
std::string("Unable to read byte block: \"") + str + "\": Length is not BLOCK_SIZE."
);
}
// Iterate over all bytes in the block
std::uint8_t* curByte = (std::uint8_t*)(void*)Data();
const char* strIt = 0;
for (std::size_t i = 0; i < BLOCK_SIZE; i++) {
*curByte++ = str[i];
}
return;
}
template <typename T>
void Basic_Block<T>::FromTextString(const std::string& str) {
// Just pad the input string to lenght, and treat it as a byte string
FromByteString(
PadStringToLength(str, BLOCK_SIZE, '\0', false)
);
}
template <typename T>
std::string Basic_Block<T>::ToBinaryString() 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();
}
template <typename T>
std::string Basic_Block<T>::ToHexString() const {
std::stringstream ss;
for (std::size_t i = 0; i < data.size(); i++) {
ss
<< std::setfill('0')
<< std::setw(CHUNK_SIZE*2)
<< std::hex
<< data[i]
;
}
return ss.str();
}
template <typename T>
std::string Basic_Block<T>::ToByteString() const {
std::stringstream ss;
ss.write((const char*)(void*)Data(), BLOCK_SIZE);
return ss.str();
}
template <typename T>
std::string Basic_Block<T>::ToTextString() const {
std::string bytes = ToByteString();
// Trim extra nullterminators
bytes.resize(strlen(bytes.data()));
return bytes;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::MMul(const Basic_Block<T>& o) const {
Basic_Block<T> m;
// 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(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(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(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)));
return m;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::operator*(const Basic_Block<T>& other) const {
return this->MMul(other);
}
template <typename T>
void Basic_Block<T>::MMulInplace(const Basic_Block<T>& o) {
Basic_Block<T> m = *this;
// 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(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(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(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)));
return;
}
template <typename T>
Basic_Block<T>& Basic_Block<T>::operator*=(const Basic_Block<T>& other) {
MMulInplace(other);
return *this;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::Xor(const Basic_Block<T>& other) const {
Basic_Block<T> m;
for (std::size_t i = 0; i < data.size(); i++) {
m.Get(i) = this->Get(i) ^ other.Get(i);
}
return m;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::operator^(const Basic_Block<T>& other) const {
return Xor(other);
}
template <typename T>
void Basic_Block<T>::XorInplace(const Basic_Block<T>& other) {
for (std::size_t i = 0; i < data.size(); i++) {
this->Get(i) ^= other.Get(i);
}
return;
}
template <typename T>
Basic_Block<T>& Basic_Block<T>::operator^=(const Basic_Block<T>& other) {
XorInplace(other);
return *this;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::Add(const Basic_Block<T>& other) const {
Basic_Block<T> m;
for (std::size_t i = 0; i < data.size(); i++) {
m.Get(i) = this->Get(i) + other.Get(i);
}
return m;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::operator+(const Basic_Block<T>& other) const {
return Add(other);
}
template <typename T>
void Basic_Block<T>::AddInplace(const Basic_Block<T>& other) {
for (std::size_t i = 0; i < data.size(); i++) {
this->Get(i) += other.Get(i);
}
return;
}
template <typename T>
Basic_Block<T>& Basic_Block<T>::operator+=(const Basic_Block<T>& other) {
AddInplace(other);
return *this;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::Sub(const Basic_Block<T>& other) const {
Basic_Block<T> m;
for (std::size_t i = 0; i < data.size(); i++) {
m.Get(i) = this->Get(i) - other.Get(i);
}
return m;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::operator-(const Basic_Block<T>& other) const {
return Sub(other);
}
template <typename T>
void Basic_Block<T>::SubInplace(const Basic_Block<T>& other) {
for (std::size_t i = 0; i < data.size(); i++) {
this->Get(i) -= other.Get(i);
}
return;
}
template <typename T>
Basic_Block<T>& Basic_Block<T>::operator-=(const Basic_Block<T>& other) {
SubInplace(other);
return *this;
}
template <typename T>
void Basic_Block<T>::ShiftRowsUpInplace() {
Basic_Block<T> tmp = *this;
Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(1, 0));
Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(1, 1));
Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(1, 2));
Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(1, 3));
Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(2, 0));
Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(2, 1));
Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(2, 2));
Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(2, 3));
Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(3, 0));
Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(3, 1));
Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(3, 2));
Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(3, 3));
Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(0, 0));
Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(0, 1));
Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(0, 2));
Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(0, 3));
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftRowsUp() const {
Basic_Block<T> b;
b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(1, 0));
b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(1, 1));
b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(1, 2));
b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(1, 3));
b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(2, 0));
b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(2, 1));
b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(2, 2));
b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(2, 3));
b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(3, 0));
b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(3, 1));
b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(3, 2));
b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(3, 3));
b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(0, 0));
b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(0, 1));
b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(0, 2));
b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(0, 3));
return b;
}
template <typename T>
void Basic_Block<T>::ShiftRowsDownInplace() {
Basic_Block<T> tmp = *this;
Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(3, 0));
Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(3, 1));
Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(3, 2));
Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(3, 3));
Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(0, 0));
Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(0, 1));
Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(0, 2));
Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(0, 3));
Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(1, 0));
Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(1, 1));
Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(1, 2));
Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(1, 3));
Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(2, 0));
Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(2, 1));
Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(2, 2));
Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(2, 3));
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftRowsDown() const {
Basic_Block<T> b;
b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(3, 0));
b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(3, 1));
b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(3, 2));
b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(3, 3));
b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(0, 0));
b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(0, 1));
b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(0, 2));
b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(0, 3));
b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(1, 0));
b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(1, 1));
b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(1, 2));
b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(1, 3));
b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(2, 0));
b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(2, 1));
b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(2, 2));
b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(2, 3));
return b;
}
template <typename T>
void Basic_Block<T>::ShiftColumnsLeftInplace() {
Basic_Block<T> tmp = *this;
Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(0, 1));
Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(1, 1));
Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(2, 1));
Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(3, 1));
Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(0, 2));
Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(1, 2));
Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(2, 2));
Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(3, 2));
Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(0, 3));
Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(1, 3));
Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(2, 3));
Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(3, 3));
Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(0, 0));
Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(1, 0));
Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(2, 0));
Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(3, 0));
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftColumnsLeft() const {
Basic_Block<T> b;
b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(0, 1));
b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(1, 1));
b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(2, 1));
b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(3, 1));
b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(0, 2));
b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(1, 2));
b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(2, 2));
b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(3, 2));
b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(0, 3));
b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(1, 3));
b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(2, 3));
b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(3, 3));
b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(0, 0));
b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(1, 0));
b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(2, 0));
b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(3, 0));
return b;
}
template <typename T>
void Basic_Block<T>::ShiftColumnsRightInplace() {
Basic_Block<T> tmp = *this;
Get(MAT_INDEX(0, 1)) = tmp.Get(MAT_INDEX(0, 0));
Get(MAT_INDEX(1, 1)) = tmp.Get(MAT_INDEX(1, 0));
Get(MAT_INDEX(2, 1)) = tmp.Get(MAT_INDEX(2, 0));
Get(MAT_INDEX(3, 1)) = tmp.Get(MAT_INDEX(3, 0));
Get(MAT_INDEX(0, 2)) = tmp.Get(MAT_INDEX(0, 1));
Get(MAT_INDEX(1, 2)) = tmp.Get(MAT_INDEX(1, 1));
Get(MAT_INDEX(2, 2)) = tmp.Get(MAT_INDEX(2, 1));
Get(MAT_INDEX(3, 2)) = tmp.Get(MAT_INDEX(3, 1));
Get(MAT_INDEX(0, 3)) = tmp.Get(MAT_INDEX(0, 2));
Get(MAT_INDEX(1, 3)) = tmp.Get(MAT_INDEX(1, 2));
Get(MAT_INDEX(2, 3)) = tmp.Get(MAT_INDEX(2, 2));
Get(MAT_INDEX(3, 3)) = tmp.Get(MAT_INDEX(3, 2));
Get(MAT_INDEX(0, 0)) = tmp.Get(MAT_INDEX(0, 3));
Get(MAT_INDEX(1, 0)) = tmp.Get(MAT_INDEX(1, 3));
Get(MAT_INDEX(2, 0)) = tmp.Get(MAT_INDEX(2, 3));
Get(MAT_INDEX(3, 0)) = tmp.Get(MAT_INDEX(3, 3));
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftColumnsRight() const {
Basic_Block<T> b;
b.Get(MAT_INDEX(0, 1)) = Get(MAT_INDEX(0, 0));
b.Get(MAT_INDEX(1, 1)) = Get(MAT_INDEX(1, 0));
b.Get(MAT_INDEX(2, 1)) = Get(MAT_INDEX(2, 0));
b.Get(MAT_INDEX(3, 1)) = Get(MAT_INDEX(3, 0));
b.Get(MAT_INDEX(0, 2)) = Get(MAT_INDEX(0, 1));
b.Get(MAT_INDEX(1, 2)) = Get(MAT_INDEX(1, 1));
b.Get(MAT_INDEX(2, 2)) = Get(MAT_INDEX(2, 1));
b.Get(MAT_INDEX(3, 2)) = Get(MAT_INDEX(3, 1));
b.Get(MAT_INDEX(0, 3)) = Get(MAT_INDEX(0, 2));
b.Get(MAT_INDEX(1, 3)) = Get(MAT_INDEX(1, 2));
b.Get(MAT_INDEX(2, 3)) = Get(MAT_INDEX(2, 2));
b.Get(MAT_INDEX(3, 3)) = Get(MAT_INDEX(3, 2));
b.Get(MAT_INDEX(0, 0)) = Get(MAT_INDEX(0, 3));
b.Get(MAT_INDEX(1, 0)) = Get(MAT_INDEX(1, 3));
b.Get(MAT_INDEX(2, 0)) = Get(MAT_INDEX(2, 3));
b.Get(MAT_INDEX(3, 0)) = Get(MAT_INDEX(3, 3));
return b;
}
template <typename T>
void Basic_Block<T>::ShiftCellsLeftInplace() {
Basic_Block<T> tmp = *this;
Get(15) = tmp.Get(0);
for (std::size_t i = 0; i < 15; i++) {
Get(i) = tmp.Get(i+1);
}
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftCellsLeft() const {
Basic_Block<T> b;
b.Get(15) = Get(0);
for (std::size_t i = 0; i < 15; i++) {
b.Get(i) = Get(i+1);
}
return b;
}
template <typename T>
void Basic_Block<T>::ShiftCellsRightInplace() {
Basic_Block<T> tmp = *this;
Get(0) = tmp.Get(15);
for (std::size_t i = 1; i < 16; i++) {
Get(i) = tmp.Get(i-1);
}
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftCellsRight() const {
Basic_Block<T> b;
b.Get(0) = Get(15);
for (std::size_t i = 1; i < 16; i++) {
b.Get(i) = Get(i-1);
}
return b;
}
template <typename T>
Basic_Block<T>& Basic_Block<T>::operator=(const Basic_Block<T>& other) {
data = other.data;
return *this;
}
template <typename T>
bool Basic_Block<T>::GetBit(const std::size_t index) const {
// Fetch index of integer the bit is located in
const std::size_t intIndex = index / CHUNK_SIZE_BITS;
// Fetch bit index relative to that int
const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS);
// Pre-calculate the bitmask to use
const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1);
return data[intIndex] & bitmask;
}
template <typename T>
void Basic_Block<T>::SetBit(const std::size_t index, const bool state) {
// Fetch index of integer the bit is located in
const std::size_t intIndex = index / CHUNK_SIZE_BITS;
// Fetch bit index relative to that int
const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS);
// Pre-calculate the bitmask to use
const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1);
// Set the bit
if (state) {
data[intIndex] |= bitmask;
}
// Clear the bit
else {
data[intIndex] &= ~bitmask;
}
return;
}
template <typename T>
void Basic_Block<T>::FlipBit(const std::size_t index) {
// Fetch index of integer the bit is located in
const std::size_t intIndex = index / CHUNK_SIZE_BITS;
// Fetch bit index relative to that int
const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS);
// Pre-calculate the bitmask to use
const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1);
data[intIndex] ^= bitmask;
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftBitsLeft() const {
Basic_Block<T> b;
// First, copy this block over
b = *this;
// Then, shift all integers individually
for (std::size_t i = 0; i < data.size(); i++) {
b.data[i] <<= 1;
}
// Current state: the LSB is zero everywhere. We have to carry
// it over manually from the previous state.
// Carry over the MSB of data[i] to LSB of data[i-1]
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
constexpr std::size_t bitmaskLsb = 1;
for (int i = 0; i < data.size(); i++) {
const bool msb = data[i] & bitmaskMsb;
// Set the lsb
if (msb) {
b.data[Mod(i-1, data.size())] |= bitmaskLsb;
}
// Clear the lsb
else {
b.data[Mod(i-1, data.size())] &= ~bitmaskLsb;
}
}
return b;
}
template <typename T>
void Basic_Block<T>::ShiftBitsLeftInplace() {
Basic_Block<T> tmp = *this;
// Then, shift all integers individually
for (std::size_t i = 0; i < data.size(); i++) {
data[i] <<= 1;
}
// Current state: the LSB is zero everywhere. We have to carry
// it over manually from the previous state.
// Carry over the MSB of data[i] to LSB of data[i-1]
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
constexpr std::size_t bitmaskLsb = 1;
for (int i = 0; i < data.size(); i++) {
const bool msb = tmp.data[i] & bitmaskMsb;
// Set the lsb
if (msb) {
data[Mod(i-1, data.size())] |= bitmaskLsb;
}
// Clear the lsb
else {
data[Mod(i-1, data.size())] &= ~bitmaskLsb;
}
}
return;
}
template <typename T>
Basic_Block<T> Basic_Block<T>::ShiftBitsRight() const {
Basic_Block<T> b;
// First, copy this block over
b = *this;
// Then, shift all integers individually
for (std::size_t i = 0; i < data.size(); i++) {
b.data[i] >>= 1;
}
// Current state: the LSB is zero everywhere. We have to carry
// it over manually from the previous state.
// Carry over the LSB of data[i] to MSB of data[i+1]
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
constexpr std::size_t bitmaskLsb = 1;
for (int i = 0; i < data.size(); i++) {
const bool lsb = data[i] & bitmaskLsb;
// Set the msb
if (lsb) {
b.data[Mod(i+1, data.size())] |= bitmaskMsb;
}
// Clear the msb
else {
b.data[Mod(i+1, data.size())] &= ~bitmaskMsb;
}
}
return b;
}
template <typename T>
void Basic_Block<T>::ShiftBitsRightInplace() {
Basic_Block<T> tmp = *this;
// Then, shift all integers individually
for (std::size_t i = 0; i < data.size(); i++) {
data[i] >>= 1;
}
// Current state: the LSB is zero everywhere. We have to carry
// it over manually from the previous state.
// Carry over the LSB of data[i] to MSB of data[i+1]
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
constexpr std::size_t bitmaskLsb = 1;
for (int i = 0; i < data.size(); i++) {
const bool lsb = tmp.data[i] & bitmaskLsb;
// Set the msb
if (lsb) {
data[Mod(i+1, data.size())] |= bitmaskMsb;
}
// Clear the msb
else {
data[Mod(i+1, data.size())] &= ~bitmaskMsb;
}
}
return;
}
template <typename T>
T& Basic_Block<T>::Get(const std::uint8_t row, const std::uint8_t column){
return data[MAT_INDEX(row, column)];
}
template <typename T>
const T& Basic_Block<T>::Get(const std::uint8_t row, const std::uint8_t column) const {
return data[MAT_INDEX(row, column)];
}
template <typename T>
T& Basic_Block<T>::Get(const std::uint8_t index) {
return data[index];
}
template <typename T>
const T& Basic_Block<T>::Get(const std::uint8_t index) const {
return data[index];
}
template <typename T>
T& Basic_Block<T>::operator[](const std::uint8_t index) {
return data[index];
}
template <typename T>
const T& Basic_Block<T>::operator[](const std::uint8_t index) const {
return data[index];
}
template <typename T>
T* Basic_Block<T>::Data() noexcept {
return data.data();
}
template <typename T>
const T* Basic_Block<T>::Data() const noexcept {
return data.data();
}
template <typename T>
bool Basic_Block<T>::operator==(const Basic_Block<T>& other) const {
return data == other.data;
}
template <typename T>
bool Basic_Block<T>::operator!=(const Basic_Block<T>& other) const {
return data != other.data;
}
#if defined _WIN32 || defined _WIN64
#pragma optimize("", off )
#elif defined __GNUG__
#pragma GCC push_options
#pragma GCC optimize ("O0")
#endif
template <typename T>
Basic_Block<T>::~Basic_Block() {
Reset();
}
template <typename T>
void Basic_Block<T>::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
// Instantiate templates
template class Basic_Block<std::uint32_t>;
template class Basic_Block<std::uint16_t>;
}

278
GCryptLib/src/Feistel.cpp Normal file
View File

@ -0,0 +1,278 @@
#include <unordered_map>
#include "GCrypt/Feistel.h"
#include "GCrypt/Util.h"
#include "GCrypt/Config.h"
#include "GCrypt/SBoxLookup.h"
namespace Leonetienne::GCrypt {
Feistel::Feistel() {
}
Feistel::Feistel(const Key& key) {
SetKey(key);
}
Feistel::~Feistel() {
ZeroKeyMemory();
}
void Feistel::SetKey(const Key& key) {
GenerateRoundKeys(key);
isInitialized = true;
}
Block Feistel::Encipher(const Block& data) {
return Run(data, false);
}
Block Feistel::Decipher(const Block& data) {
return Run(data, true);
}
Block Feistel::Run(const Block& data, bool modeEncrypt) {
if (!isInitialized) {
throw std::runtime_error("Attempted to digest data on uninitialized GCipher!");
}
const auto splitData = FeistelSplit(data);
Halfblock l = splitData.first;
Halfblock r = splitData.second;
Halfblock tmp;
for (std::size_t i = 0; i < N_ROUNDS; i++) {
// Encryption
if (modeEncrypt) {
const std::size_t keyIndex = i;
// Do a feistel round
tmp = r;
r = l ^ F(r, roundKeys[keyIndex]);
l = tmp;
// Jumble it up a bit more
l.ShiftRowsUpInplace();
l.ShiftCellsRightInplace();
l.ShiftBitsLeftInplace();
l.ShiftColumnsLeftInplace();
// Seal all these operations with a key
l += ReductionFunction(roundKeys[keyIndex]);
}
// Decryption
else {
// Decryption needs keys in reverse order
const std::size_t keyIndex = N_ROUNDS - i - 1;
// Unjumble the jumble
r -= ReductionFunction(roundKeys[keyIndex]);
r.ShiftColumnsRightInplace();
r.ShiftBitsRightInplace();
r.ShiftCellsLeftInplace();
r.ShiftRowsDownInplace();
// Do a feistel round
tmp = r;
r = l ^ F(r, roundKeys[keyIndex]);
l = tmp;
}
}
// Block has finished de*ciphering.
// Let's generate a new set of round keys.
GenerateRoundKeys(roundKeys.back());
return FeistelCombine(r, l);
}
Halfblock Feistel::F(Halfblock m, const Key& key) {
// Made-up F function:
// Expand to full bitwidth
Block m_expanded = ExpansionFunction(m);
// Mix up the block a bit
m_expanded.ShiftCellsRightInplace();
m_expanded.ShiftRowsUpInplace();
// Matrix-mult with key (this is irreversible)
m_expanded *= key;
// Now do a bitshift
m_expanded.ShiftBitsLeftInplace();
// Apply the sbox
SBox(m_expanded);
// Reduce back to a halfblock
Halfblock hb = ReductionFunction(m_expanded);
// To jumble it up a last time,
// matrix-multiply it with the input halfblock
hb *= m;
return hb;
}
std::pair<Halfblock, Halfblock> Feistel::FeistelSplit(const Block& block) {
Halfblock l;
Halfblock r;
memcpy(l.Data(), block.Data(), Halfblock::BLOCK_SIZE);
memcpy(r.Data(), block.Data() + 8, Halfblock::BLOCK_SIZE);
// +8, because 8 is HALF the number of elements in the array. We only want to copy HALF a full-sized block.
return std::make_pair(l, r);
}
Block Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) {
Block b;
memcpy(b.Data(), l.Data(), Halfblock::BLOCK_SIZE);
memcpy(b.Data() + 8, r.Data(), Halfblock::BLOCK_SIZE);
// +8, because 8 is HALF the number of elements in the array. We only want to copy HALF a full-sized block.
return b;
}
Block Feistel::ExpansionFunction(const Halfblock& hb) {
Block b;
// Copy the bits over
for (std::size_t i = 0; i < 16; i++) {
b[i] = hb[i];
}
// Multiply the block a few tims with a bitshifted version
// This is irriversible, too
for (std::size_t i = 0; i < 3; i++) {
b *= b.ShiftBitsRight();
}
return b;
}
Halfblock Feistel::ReductionFunction(const Block& block) {
// Just apply a modulo operation, remapping a 32bit integer
// onto 16bit space (default configuration).
// Without saying, modulo is irreversible.
Halfblock hb;
for (std::size_t i = 0; i < 16; i++) {
hb[i] = block[i] % (1 << (Halfblock::CHUNK_SIZE_BITS - 1));
}
return hb;
}
void Feistel::SBox(Block& block) {
std::uint8_t* curByte = (std::uint8_t*)(void*)block.Data();
// Iterate over all bytes in the block
for (std::size_t i = 0; i < Block::BLOCK_SIZE; i++) {
curByte++;
// Subsitute byte
*curByte = sboxLookup[*curByte];
}
return;
}
/*
std::string Feistel::SBox(const std::string& in) {
static std::unordered_map<std::string, std::string> subMap;
static bool mapInitialized = false;
if (!mapInitialized) {
subMap["0000"] = "1100";
subMap["0001"] = "1000";
subMap["0010"] = "0001";
subMap["0011"] = "0111";
subMap["0100"] = "1011";
subMap["0101"] = "0011";
subMap["0110"] = "1101";
subMap["0111"] = "1111";
subMap["1000"] = "0000";
subMap["1001"] = "1010";
subMap["1010"] = "0100";
subMap["1011"] = "1001";
subMap["1100"] = "0010";
subMap["1101"] = "1110";
subMap["1110"] = "0101";
subMap["1111"] = "0110";
mapInitialized = true;
}
return subMap[in];
}
*/
void Feistel::GenerateRoundKeys(const Key& seedKey) {
// Clear initial key memory
ZeroKeyMemory();
roundKeys = Keyset();
// Derive all round keys with simple matrix operations
roundKeys[0] = seedKey;
for (std::size_t i = 1; i < roundKeys.size(); i++) {
// Initialize new round key with last round key
const Key& lastKey = roundKeys[i - 1];
roundKeys[i] = lastKey;
// Stir it good
roundKeys[i].ShiftRowsUpInplace();
// Bitshift and matrix-mult 3 times
// (each time jumbles it up pretty good)
// This is irreversible
roundKeys[i].ShiftBitsRightInplace();
roundKeys[i] *= lastKey;
roundKeys[i].ShiftBitsRightInplace();
roundKeys[i] *= lastKey;
roundKeys[i].ShiftBitsRightInplace();
roundKeys[i] *= lastKey;
// Lastly, do apply some cell shifting, and other mutations
roundKeys[i].ShiftCellsRightInplace();
roundKeys[i] += lastKey;
roundKeys[i].ShiftColumnsRightInplace();
roundKeys[i] ^= lastKey;
}
return;
}
void Feistel::operator=(const Feistel& other) {
roundKeys = other.roundKeys;
isInitialized = other.isInitialized;
return;
}
// These pragmas only work for MSVC and g++, as far as i know. Beware!!!
#if defined _WIN32 || defined _WIN64
#pragma optimize("", off )
#elif defined __GNUG__
#pragma GCC push_options
#pragma GCC optimize ("O0")
#endif
void Feistel::ZeroKeyMemory() {
for (Key& key : roundKeys) {
key.Reset();
}
return;
}
#if defined _WIN32 || defined _WIN64
#pragma optimize("", on )
#elif defined __GNUG__
#pragma GCC pop_options
#endif
}

91
GCryptLib/src/GCipher.cpp Normal file
View File

@ -0,0 +1,91 @@
#include <iostream>
#include <vector>
#include <stdexcept>
#include "GCrypt/GCipher.h"
#include "GCrypt/Util.h"
#include "GCrypt/InitializationVector.h"
namespace Leonetienne::GCrypt {
GCipher::GCipher() {
}
GCipher::GCipher(const Key& key, const DIRECTION direction) :
direction { direction },
lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key
feistel(key)
{
isInitialized = true;
return;
}
void GCipher::Initialize(const Key& key, const DIRECTION direction) {
feistel = Feistel(key);
lastBlock = InitializationVector(key);
this->direction = direction;
isInitialized = true;
return;
}
Block GCipher::Digest(const Block& input) {
if (!isInitialized) {
throw std::runtime_error("Attempted to digest data on uninitialized GCipher!");
}
switch (direction) {
case DIRECTION::ENCIPHER: {
// Rename our input to cleartext
const Block& cleartext = input;
// First, xor our cleartext with the last block, and then encipher it
Block ciphertext = feistel.Encipher(cleartext ^ lastBlock);
// Now set our lastBlock to the ciphertext of this block
lastBlock = ciphertext;
// Now return the ciphertext
return ciphertext;
}
case DIRECTION::DECIPHER: {
// Rename our input into ciphertext
const Block& ciphertext = input;
// First, decipher our ciphertext, and then xor it with our last block
Block cleartext = feistel.Decipher(ciphertext) ^ lastBlock;
// Now set our lastBLock to the ciphertext of this block
lastBlock = ciphertext;
// Now return the cleartext
return cleartext;
}
}
throw std::runtime_error("Unreachable branch reached.");
}
void GCipher::SetKey(const Key& key) {
if (!isInitialized) {
throw std::runtime_error("Attempted to set key on uninitialized GCipher!");
}
feistel.SetKey(key);
return;
}
void GCipher::operator=(const GCipher& other) {
direction = other.direction;
feistel = other.feistel;
lastBlock = other.lastBlock;
isInitialized = other.isInitialized;
return;
}
}

97
GCryptLib/src/GHash.cpp Normal file
View File

@ -0,0 +1,97 @@
#include "GCrypt/GHash.h"
#include "GCrypt/Util.h"
#include "GCrypt/InitializationVector.h"
#include <vector>
namespace Leonetienne::GCrypt {
GHash::GHash() {
// Initialize our cipher with a static, but randomly distributed key.
Block ivSeed;
ivSeed.FromByteString("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN");
block = InitializationVector(ivSeed);
Key key;
key.FromByteString("nsoCZfvdqpRkeVTt9wzvPR3TT26peOW9E2kTHh3pdPCq2M7BpskvUljJHSrobUTI");
cipher = GCipher(
// The key really does not matter, as it gets changed
// each time before digesting anything.
key,
GCipher::DIRECTION::ENCIPHER
);
return;
}
void GHash::Digest(const Block& data) {
// Set the cipher key to the current data to be hashed
cipher.SetKey(data);
// Encipher the current block, and matrix-mult it with the current hashsum
block ^= cipher.Digest(data);
return;
}
const Block& GHash::GetHashsum() const {
return block;
}
Block GHash::CalculateHashsum(const std::vector<Block>& data, std::size_t n_bytes) {
// If we have no supplied n_bytes, let's just assume sizeof(data).
if (n_bytes == std::string::npos) {
n_bytes = data.size() * Block::BLOCK_SIZE;
}
// Create hasher instance
GHash hasher;
// Digest all blocks
for (const Block& block : data) {
hasher.Digest(block);
}
// Add an additional block, containing the length of the input
// Here it is actually good to use a binary string ("10011"),
// because std::size_t is not fixed to 32-bits. It may aswell
// be 64 bits, depending on the platform.
// Then it would be BAD to just cram it into a 32-bit uint32.
// This way, in case of 64-bits, it would just occupy 2 uint32's.
// Also, this operation gets done ONCE per n blocks. This won't
// hurt performance.
// I know that we are first converting n_bytes to str(n_bytes),
// and then converting this to a binstring, making it unnecessarily large,
// but who cares. It has a whole 512 bit block to itself.
// The max size (2^64) would occupy 155 bits at max. (log10(2^64)*8 = 155)
std::stringstream ss;
ss << n_bytes;
Block lengthBlock;
lengthBlock.FromTextString(ss.str());
// Digest the length block
hasher.Digest(lengthBlock);
// Return the total hashsum
return hasher.GetHashsum();
}
Block GHash::HashString(const std::string& str) {
const std::vector<Block> blocks = StringToBitblocks(str);
const std::size_t n_bytes = str.length();
return CalculateHashsum(blocks, n_bytes);
}
void GHash::operator=(const GHash& other) {
cipher = other.cipher;
return;
}
}

116
GCryptLib/src/GPrng.cpp Normal file
View File

@ -0,0 +1,116 @@
#include "GCrypt/GPrng.h"
#include <cassert>
namespace Leonetienne::GCrypt {
GPrng::GPrng(const Block& seed) {
this->seed = seed;
hasher.Digest(seed);
}
GPrng::GPrng() {
}
void GPrng::Seed(const Block& seed) {
hasher = GHash();
this->seed = seed;
hasher.Digest(seed);
return;
}
bool GPrng::GetBit() {
// If we have no more bits to go, create new ones
if (nextBit >= Block::BLOCK_SIZE_BITS) {
AdvanceBlock();
}
// Return the next bit.
return hasher.GetHashsum().GetBit(nextBit++);
}
void GPrng::AdvanceBlock() {
// To prevent an attacker from being able
// to predict block n, by knowing block n-1, and block n-2,
// we will advance the hash function by block n-1 XOR seed.
// This way it is impossible for an attacker to know the
// state of the hash function, unless the seed is known.
// Advance the block (Add the current hashsum XOR seed to the hasher)
hasher.Digest(Block(hasher.GetHashsum() ^ seed));
// Reset the pointer
nextBit = 0;
return;
}
Block GPrng::GetBlock() {
// Tactic on efficiently generating a new block:
// 1) Fetch complete current hashsum (it might have been partially given out already)
// 2) Bitshift it, and matrix-mult it with the seed (that is irreversible)
// That should be a one-way function, and create a new unique block.
// Performance improvement over the previous method:
// (generating 100.000 blocks):
// 12 seconds -> 0.12 seconds
// Fetch our current block
Block hashsum = hasher.GetHashsum();
// Derive/'hash' it to hashsum'
hashsum *= seed;
hashsum.ShiftBitsLeftInplace();
hashsum *= seed;
// Advance the block, so that the following block will be a new block
AdvanceBlock();
// Return our hashsum
return hashsum;
}
std::uint32_t GPrng::operator()() {
// Tactic:
// A block intrinsically consists of 16 32-bit uints.
// We'll just skip all the bits until the next whole integer,
// fetch this complete int, and then advance our pointer
// by 32 bits.
// Performance improvement over the previous method:
// (generating 1.000.000 integers):
// 5.26 seconds -> 3.75 seconds
// Advance our pointer to the next whole uint32
// Do we even have >= 32 bits left in our block?
if (nextBit > Block::BLOCK_SIZE_BITS - Block::CHUNK_SIZE_BITS) {
// No: Create a new block
AdvanceBlock();
}
// We don't have to do this, if our pointer is already at
// the beginning of a whole uint32
if (nextBit % Block::CHUNK_SIZE_BITS != 0) {
nextBit = ((nextBit / Block::CHUNK_SIZE_BITS) + 1) * Block::CHUNK_SIZE_BITS;
}
// Fetch our integer from the block
const std::uint32_t randint =
hasher.GetHashsum().Get(nextBit / Block::CHUNK_SIZE_BITS);
// Advance our pointer
nextBit += Block::CHUNK_SIZE_BITS;
// New state of the pointer:
// It ow may be more now than the size of a block, but that
// gets checked at the begin of a function.
// Not at the end, like here.
// Return our integer
return randint;
}
}

158
GCryptLib/src/GWrapper.cpp Normal file
View File

@ -0,0 +1,158 @@
#include "GCrypt/GWrapper.h"
#include "GCrypt/GCipher.h"
#include "GCrypt/Util.h"
#include <vector>
namespace Leonetienne::GCrypt {
std::string GWrapper::EncryptString(
const std::string& cleartext,
const Key& key)
{
// Recode the ascii-string to bits
const std::vector<Block> cleartext_blocks = StringToBitblocks(cleartext);
// Create cipher instance
GCipher cipher(key, GCipher::DIRECTION::ENCIPHER);
// Encrypt all blocks
std::vector<Block> ciphertext_blocks;
for (const Block& clearBlock : cleartext_blocks) {
ciphertext_blocks.emplace_back(cipher.Digest(clearBlock));
}
// Recode the ciphertext blocks to a hex-string
std::stringstream ss;
for (const Block& block : ciphertext_blocks) {
ss << block.ToHexString();
}
// Return it
return ss.str();
}
std::string GWrapper::DecryptString(
const std::string& ciphertext,
const Key& key)
{
// Make sure our ciphertext is a multiple of block size
if (ciphertext.length() % Block::BLOCK_SIZE*2 != 0) { // Two chars per byte
throw std::runtime_error("Leonetienne::GCrypt::GWrapper::DecryptString() received ciphertext of length not a multiple of block size.");
}
// Recode the hex-string to blocks
std::vector<Block> ciphertext_blocks;
ciphertext_blocks.reserve(ciphertext.length() / (Block::BLOCK_SIZE*2));
for (std::size_t i = 0; i < ciphertext.length(); i += Block::BLOCK_SIZE*2) {
Block block;
block.FromHexString(ciphertext.substr(i, Block::BLOCK_SIZE*2));
ciphertext_blocks.emplace_back(block);
}
// Create cipher instance
GCipher cipher(key, GCipher::DIRECTION::DECIPHER);
// Decrypt all blocks
std::vector<Block> cleartext_blocks;
for (const Block& cipherBlock : ciphertext_blocks) {
cleartext_blocks.emplace_back(cipher.Digest(cipherBlock));
}
// Recode the cleartext blocks to bytes
std::stringstream ss;
for (const Block& block : cleartext_blocks) {
ss << block.ToTextString();
}
// Return it
return ss.str();
}
bool GWrapper::EncryptFile(
const std::string& filename_in,
const std::string& filename_out,
const Key& key,
bool printProgressReport)
{
try {
// Read the file to blocks
const std::vector<Block> cleartext_blocks = ReadFileToBlocks(filename_in);
// Encrypt our cleartext blocks
std::vector<Block> ciphertext_blocks;
ciphertext_blocks.reserve(cleartext_blocks.size());
// Create cipher instance
GCipher cipher(key, GCipher::DIRECTION::ENCIPHER);
// Encrypt all blocks
for (const Block& clearBlock : cleartext_blocks) {
ciphertext_blocks.emplace_back(cipher.Digest(clearBlock));
}
// Write our ciphertext blocks to file
WriteBlocksToFile(filename_out, ciphertext_blocks);
return true;
}
catch (std::runtime_error&) {
return false;
}
}
bool GWrapper::DecryptFile(
const std::string& filename_in,
const std::string& filename_out,
const Key& key,
bool printProgressReport)
{
try {
// Read the file to blocks
const std::vector<Block> ciphertext_blocks = ReadFileToBlocks(filename_in);
// Decrypt our cleartext blocks
std::vector<Block> cleartext_blocks;
cleartext_blocks.reserve(ciphertext_blocks.size());
// Create cipher instance
GCipher cipher(key, GCipher::DIRECTION::DECIPHER);
// Decrypt all blocks
for (const Block& cipherBlock : ciphertext_blocks) {
cleartext_blocks.emplace_back(cipher.Digest(cipherBlock));
}
// Write our cleartext blocks to file
WriteBlocksToFile(filename_out, cleartext_blocks);
return true;
}
catch (std::runtime_error&) {
return false;
}
}
std::vector<Block> GWrapper::CipherBlocks(
const std::vector<Block>& data,
const Key& key,
const GCipher::DIRECTION direction)
{
// Create cipher instance
GCipher cipher(key, direction);
std::vector<Block> digested;
digested.reserve(data.size());
// Digest all our blocks
for (const Block& block : data) {
Block digestedBlock = cipher.Digest(block);
digested.emplace_back(digestedBlock);
}
// Return it
return digested;
}
}

View File

@ -0,0 +1,17 @@
#include "GCrypt/InitializationVector.h"
#include "GCrypt/Feistel.h"
namespace Leonetienne::GCrypt {
InitializationVector::InitializationVector(const Block& seed) {
// We'll generate our initialization vector by encrypting our seed with itself as a key
// iv = E(M=seed, K=seed)
iv = Feistel(seed).Encipher(seed);
}
InitializationVector::operator Block() const {
return iv;
}
}

75
GCryptLib/src/Key.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "GCrypt/Key.h"
#include "GCrypt/GHash.h"
#include "GCrypt/Util.h"
#include <random>
#include <cassert>
#include <sstream>
#include <fstream>
namespace Leonetienne::GCrypt {
Key Key::FromPassword(const std::string& password) {
return GHash::HashString(password);
}
Key Key::Random() {
// Create our truly-random rng
std::random_device rng;
constexpr std::size_t bitsPerCall = sizeof(std::random_device::result_type) * 8;
// Create a new key, and assign 16 random values
Key key;
for (std::size_t i = 0; i < 16; i++) {
key[i] = rng();
}
// Return it
return key;
}
Key Key::LoadFromFile(const std::string& path) {
// Read this many chars
const std::size_t maxChars = Key::BLOCK_SIZE;
// Open ifilestream for keyfile
std::ifstream ifs(path, std::ios::in | std::ios::binary);
// Is the file open now? Or were there any issues...
if (!ifs.good()) {
throw std::runtime_error(std::string("Unable to open ifilestream for keyfile \"") + path + "\"! Aborting...");
}
// Create a new key, and zero it
Key key;
key.Reset();
// Read into it
ifs.read((char*)(void*)key.Data(), Key::BLOCK_SIZE);
// Return it
return key;
}
void Key::WriteToFile(const std::string& path) const {
// Create an ofilestream
std::ofstream ofs(path, std::ios::out | std::ios::binary);
// Write the key
ofs.write((char*)(void*)Data(), Key::BLOCK_SIZE);
// Close the file handle
ofs.close();
return;
}
Key::Key() : Block() {
}
Key::Key(const Block& b) : Block(b) {
}
Key::Key(const Key& k) : Block(k) {
}
}

142
GCryptLib/src/Util.cpp Normal file
View File

@ -0,0 +1,142 @@
#include "GCrypt/Util.h"
#include "GCrypt/GHash.h"
#include <vector>
namespace Leonetienne::GCrypt {
std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft) {
// Fast-reject: Already above padded length
if (str.length() >= len) {
return str;
}
std::stringstream ss;
// Pad left:
if (padLeft) {
for (std::size_t i = 0; i < len - str.size(); i++) {
ss << pad;
}
ss << str;
}
// Pad right:
else {
ss << str;
for (std::size_t i = 0; i < len - str.size(); i++) {
ss << pad;
}
}
return ss.str();
}
std::string BitblocksToBytes(const std::vector<Block>& blocks) {
std::stringstream ss;
for (const Block& block : blocks) {
ss << block.ToByteString();
}
return ss.str();
}
std::string BitblocksToString(const std::vector<Block>& blocks) {
// Decode to bytes
std::string text = BitblocksToBytes(blocks);
// Dümp excess nullbytes
text.resize(strlen(text.data()));
return text;
}
std::vector<Block> ReadFileToBlocks(const std::string& filepath, std::size_t& bytes_read) {
// Read file
bytes_read = 0;
// "ate" specifies that the read-pointer is already at the end of the file
// this allows to estimate the file size
std::ifstream ifs(filepath, std::ios::binary | std::ios::ate);
if (!ifs.good()) {
throw std::runtime_error("Unable to open ifilestream!");
}
// Create our vector of blocks, and resorve a good guess
// of memory
std::vector<Block> blocks;
blocks.reserve((ifs.tellg() / Block::BLOCK_SIZE) + 1);
// Move read head to the file beginning
ifs.seekg(std::ios_base::beg);
// Whilst not reached eof, read into blocks
while (!ifs.eof()) {
// Create a new block, and zero it
Block block;
block.Reset();
// Read data into the block
ifs.read((char*)(void*)block.Data(), Block::BLOCK_SIZE);
const std::size_t n_bytes_read_block = ifs.gcount();
bytes_read += n_bytes_read_block;
if (n_bytes_read_block > 0) {
// Append the block to our vector
blocks.emplace_back(block);
}
}
// Close the filehandle
ifs.close();
return blocks;
}
std::vector<Block> ReadFileToBlocks(const std::string& filepath) {
std::size_t bytes_read_dummy; // Create a dumme for the parameter
return ReadFileToBlocks(filepath, bytes_read_dummy);
}
void WriteBlocksToFile(
const std::string& filepath,
const std::vector<Block>& blocks
){
// Create outfile file handle
std::ofstream ofs(filepath, std::ios::binary);
if (!ofs.good()) {
throw std::runtime_error("Unable to open ofilestream!");
}
// Write all the blocks
for (const Block& block : blocks) {
ofs.write((char*)(void*)block.Data(), Block::BLOCK_SIZE);
}
// Close the filehandle
ofs.close();
return;
}
std::vector<Block> StringToBitblocks(const std::string& str) {
// Create our block vector, and reserve exactly
// how many blocks are required to store this string
const std::size_t num_blocks = (str.length() / Block::BLOCK_SIZE) + 1;
std::vector<Block> blocks;
blocks.reserve(num_blocks);
for (std::size_t i = 0; i < str.length(); i += Block::BLOCK_SIZE) {
Block block;
block.FromTextString(str.substr(i, Block::BLOCK_SIZE));
blocks.emplace_back(block);
}
return blocks;
}
}

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

@ -0,0 +1,902 @@
#include <GCrypt/Block.h>
#include <GCrypt/Key.h>
#include "Catch2.h"
#include <cstdlib>
#include <time.h>
#include <sstream>
#include <iostream>
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, binary strings works
TEST_CASE(__FILE__"/BinaryStringConversion", "[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.ToBinaryString() == ss.str());
}
// Tests that converting to, and from, hexstrings works
TEST_CASE(__FILE__"/HexStringConversion", "[Block]") {
// Setup
srand(time(0));
std::stringstream ss;
const std::string charset = "0123456789abcdef";
for (std::size_t i = 0; i < 128; i++) {
ss << charset[rand() % charset.length()];
}
// Exercise
Block block;
block.FromHexString(ss.str());
// Verify
REQUIRE(block.ToHexString() == ss.str());
}
// Tests that converting to, and from, bytestrings works
TEST_CASE(__FILE__"/ByteStringConversion", "[Block]") {
// Setup
srand(time(0));
std::stringstream ss;
for (std::size_t i = 0; i < 64; i++) {
ss << (char)(rand() % 256);
}
// Exercise
Block block;
block.FromByteString(ss.str());
// Verify
REQUIRE(block.ToByteString() == ss.str());
}
// Tests that converting to, and from, textstrings works
TEST_CASE(__FILE__"/TextStringConversion", "[Block]") {
// Setup
const std::string textstr = "Hello, World :3";
// Exercise
Block block;
block.FromTextString(textstr);
// Verify
REQUIRE(block.ToTextString() == textstr);
}
// 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+ (add) works
TEST_CASE(__FILE__"/add", "[Block]") {
// Setup
Block block;
for (std::size_t i = 0; i < 16; i++) {
block.Get(i) = i * 1024;
}
Block addRH;
for (std::size_t i = 0; i < 16; i++) {
addRH.Get(i) = i * 5099;
}
// Exercise
Block result = block + addRH;
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- (subtract) works
TEST_CASE(__FILE__"/subtract", "[Block]") {
// Setup
Block block;
for (std::size_t i = 0; i < 16; i++) {
block.Get(i) = i * 1024;
}
Block subRH;
for (std::size_t i = 0; i < 16; i++) {
subRH.Get(i) = i * 5099;
}
// Exercise
Block result = block - subRH;
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 subtraction undoes addition, and vica versa
TEST_CASE(__FILE__"/subtraction-undoes-addition", "[Block]") {
// Setup
const Block a = Key::Random();
const Block b = Key::Random();
// Exercise
const Block a_plus_b = a + b;
const Block a_plus_b_minus_b = a_plus_b - b;
// Verify
REQUIRE(a == a_plus_b_minus_b);
}
// 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);
}
}
// Tests that shift rows up works
TEST_CASE(__FILE__"/shift-rows-up", "[Block]") {
// Setup
Block a;
a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13;
a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23;
a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33;
a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43;
Block e; /* expected */
e.Get(0,0) = 20; e.Get(0,1) = 21; e.Get(0,2) = 22; e.Get(0,3) = 23;
e.Get(1,0) = 30; e.Get(1,1) = 31; e.Get(1,2) = 32; e.Get(1,3) = 33;
e.Get(2,0) = 40; e.Get(2,1) = 41; e.Get(2,2) = 42; e.Get(2,3) = 43;
e.Get(3,0) = 10; e.Get(3,1) = 11; e.Get(3,2) = 12; e.Get(3,3) = 13;
// Exercise
a.ShiftRowsUpInplace();
// Verify
REQUIRE(a == e);
}
// 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();
const Block initial_a = a;
// Exercise and verify
a.ShiftRowsUpInplace();
REQUIRE(a == initial_a.ShiftRowsUp());
}
// Tests that shift rows down works
TEST_CASE(__FILE__"/shift-rows-down", "[Block]") {
// Setup
Block a;
a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13;
a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23;
a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33;
a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43;
Block e; /* expected */
e.Get(0,0) = 40; e.Get(0,1) = 41; e.Get(0,2) = 42; e.Get(0,3) = 43;
e.Get(1,0) = 10; e.Get(1,1) = 11; e.Get(1,2) = 12; e.Get(1,3) = 13;
e.Get(2,0) = 20; e.Get(2,1) = 21; e.Get(2,2) = 22; e.Get(2,3) = 23;
e.Get(3,0) = 30; e.Get(3,1) = 31; e.Get(3,2) = 32; e.Get(3,3) = 33;
// Exercise
a.ShiftRowsDownInplace();
// Verify
REQUIRE(a == e);
}
// 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();
const Block initial_a = a;
// Exercise and verify
a.ShiftRowsDownInplace();
REQUIRE(a == initial_a.ShiftRowsDown());
}
// Tests that shift columns left works
TEST_CASE(__FILE__"/shift-columns-left", "[Block]") {
// Setup
Block a;
a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13;
a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23;
a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33;
a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43;
Block e; /* expected */
e.Get(0,0) = 11; e.Get(0,1) = 12; e.Get(0,2) = 13; e.Get(0,3) = 10;
e.Get(1,0) = 21; e.Get(1,1) = 22; e.Get(1,2) = 23; e.Get(1,3) = 20;
e.Get(2,0) = 31; e.Get(2,1) = 32; e.Get(2,2) = 33; e.Get(2,3) = 30;
e.Get(3,0) = 41; e.Get(3,1) = 42; e.Get(3,2) = 43; e.Get(3,3) = 40;
// Exercise
a.ShiftColumnsLeftInplace();
// Verify
REQUIRE(a == e);
}
// 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();
const Block initial_a = a;
// Exercise and verify
a.ShiftColumnsLeftInplace();
REQUIRE(a == initial_a.ShiftColumnsLeft());
}
// Tests that shift columns right works
TEST_CASE(__FILE__"/shift-columns-right", "[Block]") {
// Setup
Block a;
a.Get(0,0) = 10; a.Get(0,1) = 11; a.Get(0,2) = 12; a.Get(0,3) = 13;
a.Get(1,0) = 20; a.Get(1,1) = 21; a.Get(1,2) = 22; a.Get(1,3) = 23;
a.Get(2,0) = 30; a.Get(2,1) = 31; a.Get(2,2) = 32; a.Get(2,3) = 33;
a.Get(3,0) = 40; a.Get(3,1) = 41; a.Get(3,2) = 42; a.Get(3,3) = 43;
Block e; /* expected */
e.Get(0,0) = 13; e.Get(0,1) = 10; e.Get(0,2) = 11; e.Get(0,3) = 12;
e.Get(1,0) = 23; e.Get(1,1) = 20; e.Get(1,2) = 21; e.Get(1,3) = 22;
e.Get(2,0) = 33; e.Get(2,1) = 30; e.Get(2,2) = 31; e.Get(2,3) = 32;
e.Get(3,0) = 43; e.Get(3,1) = 40; e.Get(3,2) = 41; e.Get(3,3) = 42;
// Exercise
a.ShiftColumnsRightInplace();
// Verify
REQUIRE(a == e);
}
// 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();
const Block initial_a = a;
// Exercise and verify
a.ShiftColumnsRightInplace();
REQUIRE(a == initial_a.ShiftColumnsRight());
}
// Tests that shift cells left works
TEST_CASE(__FILE__"/shift-cells-left", "[Block]") {
// Setup
Block a;
for (std::size_t i = 0; i < 16; i++) {
a.Get(i) = i;
}
Block expected;
for (std::size_t i = 0; i < 15; i++) {
expected.Get(i) = i+1;
}
expected.Get(15) = 0;
// Exercise
a.ShiftCellsLeftInplace();
// Verify
REQUIRE(a == expected);
}
// 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();
const Block initial_a = a;
// Exercise and verify
a.ShiftCellsLeftInplace();
REQUIRE(a == initial_a.ShiftCellsLeft());
}
// Tests that shift cells right works
TEST_CASE(__FILE__"/shift-cells-right", "[Block]") {
// Setup
Block a;
for (std::size_t i = 0; i < 16; i++) {
a.Get(i) = i;
}
Block expected;
for (std::size_t i = 1; i < 16; i++) {
expected.Get(i) = i-1;
}
expected.Get(0) = 15;
// Exercise
a.ShiftCellsRightInplace();
// Verify
REQUIRE(a == expected);
}
// 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();
const Block initial_a = a;
// Exercise and verify
a.ShiftCellsRightInplace();
REQUIRE(a == initial_a.ShiftCellsRight());
}
// Tests that shifting down undoes shifting up, and vica versa
TEST_CASE(__FILE__"/shift-down-undoes-shift-up", "[Block]") {
// Setup
Block a = Key::Random();
const Block initial_a = a;
// Exercise
a.ShiftRowsUpInplace();
a.ShiftRowsDownInplace();
// Verify
REQUIRE(a == initial_a);
}
// Tests that shifting left undoes shifting right, and vica versa
TEST_CASE(__FILE__"/shift-left-undoes-shift-right", "[Block]") {
// Setup
Block a = Key::Random();
const Block initial_a = a;
// Exercise
a.ShiftColumnsRightInplace();
a.ShiftColumnsLeftInplace();
// Verify
REQUIRE(a == initial_a);
}
// 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();
const Block initial_a = a;
// Exercise
a.ShiftCellsRightInplace();
a.ShiftCellsLeftInplace();
// Verify
REQUIRE(a == initial_a);
}
// 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 key = Key::FromPassword("Papaya");
const Block initial_a = a;
// Exercise (mix-up)
for (std::size_t i = 0; i < 64; i++) {
a.ShiftRowsUpInplace();
a.ShiftColumnsLeftInplace();
a += key;
a.ShiftCellsRightInplace();
}
// Exercise (un-mix)
for (std::size_t i = 0; i < 64; i++) {
a.ShiftCellsLeftInplace();
a -= key;
a.ShiftColumnsRightInplace();
a.ShiftRowsDownInplace();
}
// Verify
REQUIRE(a == initial_a);
}
// 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();
// Exercise
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << a.GetBit(i);
}
// Verify
REQUIRE(ss.str() == a.ToBinaryString());
}
}
// 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());
}
}
// Tests that the set-bit to-false method works
TEST_CASE(__FILE__"/set-bit-to-false", "[Block]") {
// Setup
Block a = Key::Random();
// Exercise
a.SetBit(5, 0);
a.SetBit(15, 0);
a.SetBit(105, 0);
a.SetBit(205, 0);
// Verify
REQUIRE(a.GetBit(5) == false);
REQUIRE(a.GetBit(15) == false);
REQUIRE(a.GetBit(105) == false);
REQUIRE(a.GetBit(205) == false);
}
// Tests that the set-bit to-true method works
TEST_CASE(__FILE__"/set-bit-to-true", "[Block]") {
// Setup
Block a = Key::Random();
// Exercise
a.SetBit(5, 1);
a.SetBit(15, 1);
a.SetBit(105, 1);
a.SetBit(205, 1);
// Verify
REQUIRE(a.GetBit(5) == true);
REQUIRE(a.GetBit(15) == true);
REQUIRE(a.GetBit(105) == true);
REQUIRE(a.GetBit(205) == true);
}
// Tests that the flip-bit method works
TEST_CASE(__FILE__"/flip-bit", "[Block]") {
// Setup
Block a = Key::Random();
std::string compare = a.ToBinaryString();
compare[5] = compare[5] == '1' ? '0' : '1';
compare[15] = compare[15] == '1' ? '0' : '1';
compare[105] = compare[105] == '1' ? '0' : '1';
compare[205] = compare[205] == '1' ? '0' : '1';
// Exercise
a.FlipBit(5);
a.FlipBit(15);
a.FlipBit(105);
a.FlipBit(205);
// Verify
REQUIRE(a.ToBinaryString() == compare);
}
// Tests that bitshifts (to the left) work
TEST_CASE(__FILE__"/bitshift-left", "[Block]") {
// Setup
srand(time(0));
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << (rand()%2 == 0 ? '1' : '0');
}
const std::string originalBits = ss.str();
ss.str("");
// Shift string manually
std::string shiftedBits = originalBits;
shiftedBits.erase(0, 1);
ss << shiftedBits << originalBits[0];
shiftedBits = ss.str();
// Create block of original bits
Block block(originalBits);
// Exercise
block = block.ShiftBitsLeft();
// Verify
REQUIRE(block.ToBinaryString().length() == shiftedBits.length());
REQUIRE(block.ToBinaryString() == shiftedBits);
}
// Tests that inplace-bitshifts to the left do the exact same as copy bitshifts
TEST_CASE(__FILE__"/bitshift-left-inplace", "[Block]") {
// Setup
srand(time(0));
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << (rand()%2 == 0 ? '1' : '0');
}
Block a(ss.str());
// Exercise
Block b = a.ShiftBitsLeft();
a.ShiftBitsLeftInplace();
// Verify
REQUIRE(a == b);
}
// Tests that bitshifts (to the right) work
TEST_CASE(__FILE__"/bitshift-right", "[Block]") {
// Setup
srand(time(0));
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << (rand()%2 == 0 ? '1' : '0');
}
const std::string originalBits = ss.str();
ss.str("");
// Shift string manually
std::string shiftedBits = originalBits;
shiftedBits.erase(shiftedBits.length() - 1);
ss << originalBits[originalBits.length()-1] << shiftedBits;
shiftedBits = ss.str();
// Create block of original bits
Block block(originalBits);
// Exercise
block = block.ShiftBitsRight();
// Verify
REQUIRE(block.ToBinaryString().length() == shiftedBits.length());
REQUIRE(block.ToBinaryString() == shiftedBits);
}
// Tests that inplace-bitshifts to the right do the exact same as copy bitshifts
TEST_CASE(__FILE__"/bitshift-right-inplace", "[Block]") {
// Setup
srand(time(0));
std::stringstream ss;
for (std::size_t i = 0; i < 512; i++) {
ss << (rand()%2 == 0 ? '1' : '0');
}
Block a(ss.str());
// Exercise
Block b = a.ShiftBitsRight();
a.ShiftBitsRightInplace();
// Verify
REQUIRE(a == b);
}
// Tests that bitshifting undoes itself
TEST_CASE(__FILE__"/bitshifting-undoes-itself", "[Block]") {
// Setup
Block a = Key::Random();
const Block initial_a = a;
// Exercise (mix-up)
for (std::size_t i = 0; i < 100; i++) {
a.ShiftBitsLeftInplace();
}
// Exercise (un-mix)
for (std::size_t i = 0; i < 100; i++) {
a.ShiftBitsRightInplace();
}
// Verify
REQUIRE(a == initial_a);
}

17965
GCryptLib/test/Catch2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
#include <GCrypt/GWrapper.h>
#include <GCrypt/Util.h>
#include "Catch2.h"
using namespace Leonetienne::GCrypt;
// THESE TESTS ASSUME BLOCK_SIZE == 512
// Tests that encrypting a message of exactly BLOCK_SIZE yields the exact message back
TEST_CASE(__FILE__"/SingleBlock", "[Encryption/Decryption consistency]") {
// Instanciate our cipher and supply a key
const Key key = Key::FromPassword("1234");
// Recode the ascii-string to bits
const std::string cleartext_bits =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100010000001011100010010001101111100100101100010001"
"0000011110010110111010110110111110011110011010001100100111110101";
std::vector<Block> cleartext_blocks({Block(cleartext_bits)});
// Encrypt our cleartext bits
const std::vector<Block> ciphertext_blocks = GWrapper::CipherBlocks(cleartext_blocks, key, GCipher::DIRECTION::ENCIPHER);
// Decipher it again
const std::vector<Block> decrypted_blocks = GWrapper::CipherBlocks(ciphertext_blocks, key, GCipher::DIRECTION::DECIPHER);
// Assert that the decrypted text equals the plaintext
REQUIRE(
cleartext_blocks ==
decrypted_blocks
);
}
// Tests that a decrypted ciphertext equals its plaintext version, using a cleartext that requires A LOT of blocks
TEST_CASE(__FILE__"MultiBlock_NoPadding/", "[Encryption/Decryption consistency]") {
// Instanciate our cipher and supply a key
const Key key = Key::FromPassword("1234");
std::stringstream ss;
const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Read 10 blocks worth of characters
srand(time(0));
for (std::size_t i = 0; i < 512*10; i++) {
ss << charset[rand() % charset.length()];
}
const std::string cleartext_str = ss.str();
std::vector<Block> cleartext_blocks = StringToBitblocks(cleartext_str);
// Encrypt our cleartext bits
std::vector<Block> ciphertext_blocks;
ciphertext_blocks.reserve(cleartext_blocks.size());
{
GCipher cipher(key, GCipher::DIRECTION::ENCIPHER);
for (const Block& clearBlock : cleartext_blocks) {
ciphertext_blocks.emplace_back(cipher.Digest(clearBlock));
}
}
// Decipher it again
std::vector<Block> deciphered_blocks;
deciphered_blocks.reserve(ciphertext_blocks.size());
{
GCipher cipher(key, GCipher::DIRECTION::DECIPHER);
for (const Block& ciphBlock : ciphertext_blocks) {
deciphered_blocks.emplace_back(cipher.Digest(ciphBlock));
}
}
// Assert that the decrypted text equals the plaintext
REQUIRE(
cleartext_blocks ==
deciphered_blocks
);
}

View File

@ -0,0 +1,86 @@
#include <GCrypt/GWrapper.h>
#include <GCrypt/Util.h>
#include "Catch2.h"
using namespace Leonetienne::GCrypt;
// Tests that encrypting and decrypting short strings using the wrapper works.
// This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated.
TEST_CASE(__FILE__"/Encrypting and decrypting strings works, Single block", "[Wrapper]") {
// Setup
const std::string plaintext = "Hello, World!";
const Key key = Key::FromPassword("Der Affe will Zucker");
std::string ciphertext;
std::string decrypted;
// Encryption
ciphertext = GWrapper::EncryptString(plaintext, key);
// Decryption
decrypted = GWrapper::DecryptString(ciphertext, key);
// Assertion
REQUIRE(plaintext == decrypted);
}
// Tests that encrypting and decrypting very long strings using the wrapper works.
// This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated.
TEST_CASE(__FILE__"/Encrypting and decrypting strings works, Many blocks block", "[Wrapper]") {
// Setup
// Read an not-multiple-of-blocksize amount of random chars, that's very large (about 200kb long string)
srand(time(0));
std::stringstream ss;
const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (std::size_t i = 0; i < 198273; i++) {
ss << charset[rand() % charset.length()];
}
const std::string plaintext = ss.str();
const Key key = Key::FromPassword("Der Affe will Zucker");
std::string ciphertext;
std::string decrypted;
// Encryption
ciphertext = GWrapper::EncryptString(plaintext, key);
// Decryption
decrypted = GWrapper::DecryptString(ciphertext, key);
// Assertion
REQUIRE(plaintext == decrypted);
}
// Tests that encrypting and decrypting files using the wrapper works.
// This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated.
TEST_CASE(__FILE__"/Encrypting and decrypting files works", "[Wrapper]") {
// Setup
const std::string testfile_dir = "testAssets/";
const std::string filename_plain = testfile_dir + "testfile.png";
const std::string filename_encrypted = testfile_dir + "testfile.png.crypt";
const std::string filename_decrypted = testfile_dir + "testfile.png.clear.png";
const Key key = Key::FromPassword("Der Affe will Zucker");
// Encryption
GWrapper::EncryptFile(filename_plain, filename_encrypted, key);
// Decryption
GWrapper::DecryptFile(filename_encrypted, filename_decrypted, key);
// Read in both the base, and the decrypted file
const std::vector<Block> plainfile = ReadFileToBlocks(filename_plain);
const std::vector<Block> decryptfile = ReadFileToBlocks(filename_decrypted);
// Assertion (If this fails, maybe check if the image is even readable by an image viewer)
REQUIRE(plainfile.size() == decryptfile.size());
REQUIRE(plainfile == decryptfile);
}

View File

@ -0,0 +1,94 @@
#include <GCrypt/Util.h>
#include <GCrypt/Block.h>
#include <GCrypt/Config.h>
#include <unordered_map>
#include <sstream>
#include <iostream>
#include "Catch2.h"
using namespace Leonetienne::GCrypt;
// We can generate passwords by just translating a decimal number to base "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// So this is just a helper function to generate random passwords
inline std::string Base10_2_X(const unsigned long long int i, const std::string set, unsigned int padding) {
if (set.length() == 0)
return ""; // Return empty string, if set is empty. Play stupid games, win stupid prizes.
std::stringstream ss;
if (i != 0) {
{
unsigned long long int buf = i;
while (buf != 0) {
const unsigned long long int mod = buf % set.length();
buf /= set.length();
ss << set[(std::size_t)mod];
}
}
{
const std::string buf = ss.str();
ss.str("");
for (long long int i = buf.length() - 1; i >= 0; i--) {
ss << buf[(std::size_t)i];
}
}
}
else {
ss << set[0]; // If i is 0, just pass a null-value. The algorithm would hang otherwise.
}
// Add as much null-values to the left as requested.
if (ss.str().length() < padding) {
const std::size_t cachedLen = ss.str().length();
const std::string cachedStr = ss.str();
ss.str("");
for (std::size_t i = 0; i < padding - cachedLen; i++) {
ss << set[0];
}
ss << cachedStr;
}
return ss.str();
}
// Run a few thousand random passwords through the keygen and see if we'll find a collision.
// This test passing does NOT mean that it's resistant! Maybe good, maybe shit! But if it fails, it's definitely shit.
// Already validated range: Password 0 - 1.000.000
TEST_CASE(__FILE__"/Password to key transformation collision resistance", "[Key extrapolation]") {
// To test resistence set this to a high number around a million.
// 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, std::string> keys; // <key, password>
// Try NUM_RUN_TESTS passwords
const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (std::size_t i = 0; i < NUM_RUN_TESTS; i++) {
// Get password
const std::string password = Base10_2_X(i, charset, 0);
// Generate key
const std::string newKeyBits = Key::FromPassword(password).ToBinaryString();
// Check if this block is already in our map
if (keys.find(newKeyBits) != keys.cend()) {
std::cout << "Collision found between password \""
<< password
<< "\" and \""
<< keys[newKeyBits]
<< "\". The key is \""
<< newKeyBits
<< "\".";
FAIL();
}
// All good? Insert it into our map
keys[newKeyBits] = password;
}
return;
}

2
GCryptLib/test/main.cpp Normal file
View File

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "Catch2.h"

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -0,0 +1,51 @@
#!zsh
echo "Make sure to have run all visualization executables in ../build/ (cmake -B build)!"
echo "These generate the base images!"
# Copy all images over, but as pngs, and a bit larger
find ../build/ -maxdepth 1 -type f -name '*.bmp' |\
xargs -I {}\
convert "{}"\
-filter box\
-resize 256x\
"{}.png"
mv ../build/*.png .
# Create a few gifs
# Singleblock diffusion
convert -delay 10 -loop 0 -dispose previous \
"visualize-singleblock-diffusion-input.bmp.png"\
"visualize-singleblock-diffusion-input-flip.bmp.png"\
"visualize-singleblock-diffusion-input.gif"
convert -delay 10 -loop 0 -dispose previous \
"visualize-singleblock-diffusion-output.bmp.png"\
"visualize-singleblock-diffusion-output-flip.bmp.png"\
"visualize-singleblock-diffusion-output.gif"
# Multiblock diffusion
convert -delay 10 -loop 0 -dispose previous \
"visualize-multiblock-diffusion-input.bmp.png"\
"visualize-multiblock-diffusion-input-flip.bmp.png"\
"visualize-multiblock-diffusion-input.gif"
convert -delay 10 -loop 0 -dispose previous \
"visualize-multiblock-diffusion-output.bmp.png"\
"visualize-multiblock-diffusion-output-flip.bmp.png"\
"visualize-multiblock-diffusion-output.gif"
# Extreme input diffusion
convert -delay 10 -loop 0 -dispose previous \
"visualize-extreme-input-diffusion-input.bmp.png"\
"visualize-extreme-input-diffusion-input-flip.bmp.png"\
"visualize-extreme-input-diffusion-input.gif"
convert -delay 10 -loop 0 -dispose previous \
"visualize-extreme-input-diffusion-output.bmp.png"\
"visualize-extreme-input-diffusion-output-flip.bmp.png"\
"visualize-extreme-input-diffusion-output.gif"

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 908 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Some files were not shown because too many files have changed in this diff Show More