diff --git a/ExampleApp/ExampleApp.vcxproj b/ExampleApp/ExampleApp.vcxproj
new file mode 100644
index 0000000..fc73e05
--- /dev/null
+++ b/ExampleApp/ExampleApp.vcxproj
@@ -0,0 +1,156 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {b9a390ac-f382-42e6-92dd-3321293e7c27}
+ ExampleApp
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)
+
+
+ false
+ $(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)
+
+
+ true
+ $(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)
+
+
+ false
+ $(SolutionDir)/GhettoCrypt;$(VC_IncludePath);$(WindowsSDK_IncludePath)
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+ {2b2cf665-f5e6-44db-961f-fc81c88a356d}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ExampleApp/ExampleApp.vcxproj.filters b/ExampleApp/ExampleApp.vcxproj.filters
new file mode 100644
index 0000000..46d313e
--- /dev/null
+++ b/ExampleApp/ExampleApp.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Quelldateien
+
+
+
\ No newline at end of file
diff --git a/ExampleApp/main.cpp b/ExampleApp/main.cpp
new file mode 100644
index 0000000..43ce13f
--- /dev/null
+++ b/ExampleApp/main.cpp
@@ -0,0 +1,45 @@
+#pragma once
+#include
+#include
+
+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;
+}
diff --git a/GhettoCrypt.sln b/GhettoCrypt.sln
new file mode 100644
index 0000000..844e746
--- /dev/null
+++ b/GhettoCrypt.sln
@@ -0,0 +1,41 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30907.101
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GhettoCrypt", "GhettoCrypt\GhettoCrypt.vcxproj", "{2B2CF665-F5E6-44DB-961F-FC81C88A356D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExampleApp", "ExampleApp\ExampleApp.vcxproj", "{B9A390AC-F382-42E6-92DD-3321293E7C27}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Debug|x64.ActiveCfg = Debug|x64
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Debug|x64.Build.0 = Debug|x64
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Debug|x86.ActiveCfg = Debug|Win32
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Debug|x86.Build.0 = Debug|Win32
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Release|x64.ActiveCfg = Release|x64
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Release|x64.Build.0 = Release|x64
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Release|x86.ActiveCfg = Release|Win32
+ {2B2CF665-F5E6-44DB-961F-FC81C88A356D}.Release|x86.Build.0 = Release|Win32
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Debug|x64.ActiveCfg = Debug|x64
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Debug|x64.Build.0 = Debug|x64
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Debug|x86.ActiveCfg = Debug|Win32
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Debug|x86.Build.0 = Debug|Win32
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Release|x64.ActiveCfg = Release|x64
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Release|x64.Build.0 = Release|x64
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Release|x86.ActiveCfg = Release|Win32
+ {B9A390AC-F382-42E6-92DD-3321293E7C27}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {418C3728-070A-4171-8A02-17FEE780E015}
+ EndGlobalSection
+EndGlobal
diff --git a/Block.h b/GhettoCrypt/Block.h
similarity index 100%
rename from Block.h
rename to GhettoCrypt/Block.h
diff --git a/Cipher.cpp b/GhettoCrypt/Cipher.cpp
similarity index 100%
rename from Cipher.cpp
rename to GhettoCrypt/Cipher.cpp
diff --git a/Cipher.h b/GhettoCrypt/Cipher.h
similarity index 100%
rename from Cipher.h
rename to GhettoCrypt/Cipher.h
diff --git a/Config.h b/GhettoCrypt/Config.h
similarity index 100%
rename from Config.h
rename to GhettoCrypt/Config.h
diff --git a/Feistel.cpp b/GhettoCrypt/Feistel.cpp
similarity index 100%
rename from Feistel.cpp
rename to GhettoCrypt/Feistel.cpp
diff --git a/Feistel.h b/GhettoCrypt/Feistel.h
similarity index 100%
rename from Feistel.h
rename to GhettoCrypt/Feistel.h
diff --git a/Flexblock.h b/GhettoCrypt/Flexblock.h
similarity index 100%
rename from Flexblock.h
rename to GhettoCrypt/Flexblock.h
diff --git a/GhettoCipherWrapper.cpp b/GhettoCrypt/GhettoCipherWrapper.cpp
similarity index 100%
rename from GhettoCipherWrapper.cpp
rename to GhettoCrypt/GhettoCipherWrapper.cpp
diff --git a/GhettoCipherWrapper.h b/GhettoCrypt/GhettoCipherWrapper.h
similarity index 100%
rename from GhettoCipherWrapper.h
rename to GhettoCrypt/GhettoCipherWrapper.h
diff --git a/Feistel.vcxproj b/GhettoCrypt/GhettoCrypt.vcxproj
similarity index 97%
rename from Feistel.vcxproj
rename to GhettoCrypt/GhettoCrypt.vcxproj
index 86ded4e..38c0190 100644
--- a/Feistel.vcxproj
+++ b/GhettoCrypt/GhettoCrypt.vcxproj
@@ -22,7 +22,7 @@
16.0
Win32Proj
{2b2cf665-f5e6-44db-961f-fc81c88a356d}
- Feistel
+ GhettoCrypt
10.0
GhettoCrypt
diff --git a/Feistel.vcxproj.filters b/GhettoCrypt/GhettoCrypt.vcxproj.filters
similarity index 100%
rename from Feistel.vcxproj.filters
rename to GhettoCrypt/GhettoCrypt.vcxproj.filters
diff --git a/Halfblock.h b/GhettoCrypt/Halfblock.h
similarity index 100%
rename from Halfblock.h
rename to GhettoCrypt/Halfblock.h
diff --git a/Keyset.h b/GhettoCrypt/Keyset.h
similarity index 100%
rename from Keyset.h
rename to GhettoCrypt/Keyset.h
diff --git a/Util.h b/GhettoCrypt/Util.h
similarity index 100%
rename from Util.h
rename to GhettoCrypt/Util.h
diff --git a/Version.h b/GhettoCrypt/Version.h
similarity index 100%
rename from Version.h
rename to GhettoCrypt/Version.h
diff --git a/INCLUDE/GhettoCipher.cpp b/INCLUDE/GhettoCipher.cpp
new file mode 100644
index 0000000..a4a6200
--- /dev/null
+++ b/INCLUDE/GhettoCipher.cpp
@@ -0,0 +1,425 @@
+#include "GhettoCipher.h"
+
+/*** ./../Feistel/Cipher.cpp ***/
+
+#include
+
+GhettoCipher::Cipher::Cipher(const Block& key)
+ :
+ key { key }
+{
+
+ return;
+}
+
+GhettoCipher::Cipher::Cipher(const std::string& password)
+{
+ key = PasswordToKey(password);
+
+ return;
+}
+
+GhettoCipher::Cipher::~Cipher()
+{
+ // Clear key memory
+ ZeroKeyMemory();
+
+ return;
+}
+
+void GhettoCipher::Cipher::SetKey(const Block& key)
+{
+ ZeroKeyMemory();
+
+ this->key = key;
+ return;
+}
+
+void GhettoCipher::Cipher::SetPassword(const std::string& password)
+{
+ ZeroKeyMemory();
+
+ key = PasswordToKey(password);
+ return;
+}
+
+GhettoCipher::Flexblock GhettoCipher::Cipher::Encipher(const Flexblock& data, bool printProgress) const
+{
+ // Split cleartext into blocks
+ std::vector blocks;
+
+ for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE)
+ blocks.push_back(Block(
+ PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false))
+ );
+
+ // Encrypt individual blocks using cipher block chaining
+ Feistel feistel(key);
+
+ for (std::size_t i = 0; i < blocks.size(); i++)
+ {
+ // Print reports if desired. If we have > 1000 blocks, print one report every 100 blocks. Otherwise for every 10th block.
+ if ((i % ((blocks.size() > 1000)? 100 : 10) == 0) && (printProgress))
+ std::cout << "Encrypting... (Block " << i << " / " << blocks.size() << " - " << ((float)i*100 / blocks.size()) << "%)" << std::endl;
+
+ const Block& lastBlock = (i>0) ? blocks[i-1] : emptyBlock;
+ blocks[i] = feistel.Encipher(blocks[i] ^ lastBlock);
+ }
+
+ // Concatenate ciphertext blocks back into a flexblock
+ std::stringstream ss;
+ for (Block& b : blocks)
+ ss << b;
+
+ // Return it
+ return ss.str();
+}
+
+GhettoCipher::Flexblock GhettoCipher::Cipher::Decipher(const Flexblock& data, bool printProgress) const
+{
+ // Split ciphertext into blocks
+ std::vector blocks;
+
+ for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE)
+ blocks.push_back(Block(
+ PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false))
+ );
+
+ // Decrypt individual blocks
+ Feistel feistel(key);
+
+ // We can't do this in-loop for decryption, because we are decrypting the blocks in-place.
+ Block lastBlock = emptyBlock;
+
+ for (std::size_t i = 0; i < blocks.size(); i++)
+ {
+ // Print reports if desired. If we have > 1000 blocks, print one report every 100 blocks. Otherwise for every 10th block.
+ if ((i % ((blocks.size() > 1000) ? 100 : 10) == 0) && (printProgress))
+ std::cout << "Decrypting... (Block " << i << " / " << blocks.size() << " - " << ((float)i*100/ blocks.size()) << "%)" << std::endl;
+
+ Block tmpCopy = blocks[i];
+
+ blocks[i] = feistel.Decipher(blocks[i]) ^ lastBlock;
+
+ lastBlock = std::move(tmpCopy);
+ }
+
+ // Concatenate ciphertext blocks back into a flexblock
+ std::stringstream ss;
+ for (Block& b : blocks)
+ ss << b;
+
+ // Return it
+ return ss.str();
+}
+
+#if defined _WIN32 || defined _WIN64
+#pragma optimize("", off )
+#endif
+void GhettoCipher::Cipher::ZeroKeyMemory()
+{
+ key.reset();
+ return;
+}
+#if defined _WIN32 || defined _WIN64
+#pragma optimize("", on )
+#endif
+
+const GhettoCipher::Block GhettoCipher::Cipher::emptyBlock;
+
+
+/*** ./../Feistel/Feistel.cpp ***/
+
+
+GhettoCipher::Feistel::Feistel(const Block& key)
+{
+ SetKey(key);
+ return;
+}
+
+GhettoCipher::Feistel::~Feistel()
+{
+ ZeroKeyMemory();
+
+ return;
+}
+
+void GhettoCipher::Feistel::SetKey(const Block& key)
+{
+ GenerateRoundKeys(key);
+ return;
+}
+
+GhettoCipher::Block GhettoCipher::Feistel::Encipher(const Block& data) const
+{
+ return Run(data, false);
+}
+
+GhettoCipher::Block GhettoCipher::Feistel::Decipher(const Block& data) const
+{
+ return Run(data, true);
+}
+
+GhettoCipher::Block GhettoCipher::Feistel::Run(const Block& data, bool reverseKeys) const
+{
+ const auto splitData = FeistelSplit(data);
+ GhettoCipher::Halfblock l = splitData.first;
+ GhettoCipher::Halfblock r = splitData.second;
+
+ Halfblock tmp;
+
+ for (std::size_t i = 0; i < N_ROUNDS; i++)
+ {
+ // Calculate key index
+ std::size_t keyIndex;
+ if (reverseKeys)
+ keyIndex = N_ROUNDS - i - 1;
+ else
+ keyIndex = i;
+
+ // Do a feistel round
+ tmp = r;
+ r = l ^ F(r, roundKeys[keyIndex]);
+ l = tmp;
+ }
+
+ return FeistelCombine(r, l);
+}
+
+GhettoCipher::Halfblock GhettoCipher::Feistel::F(Halfblock m, const Block& key)
+{
+ // Made-up F function
+
+ // Expand to full bitwidth
+ Block m_expanded = ExpansionFunction(m);
+
+ // Shift to left by 1
+ m_expanded = Shiftl(m_expanded, 1);
+
+ // Xor with key
+ m_expanded ^= key;
+
+ // Non-linearly apply subsitution boxes
+ std::stringstream ss;
+ const std::string m_str = m_expanded.to_string();
+
+ for (std::size_t i = 0; i < m_str.size(); i += 4)
+ {
+ ss << SBox(m_str.substr(i, 4));
+ }
+
+ m_expanded = Block(ss.str());
+
+ // Return the compressed version
+ return CompressionFunction(m_expanded);
+}
+
+std::pair GhettoCipher::Feistel::FeistelSplit(const Block& block)
+{
+ const std::string bits = block.to_string();
+
+ Halfblock l(bits.substr(0, bits.size() / 2));
+ Halfblock r(bits.substr(bits.size() / 2));
+
+ return std::make_pair(l, r);
+}
+
+GhettoCipher::Block GhettoCipher::Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r)
+{
+ return Block(l.to_string() + r.to_string());
+}
+
+GhettoCipher::Block GhettoCipher::Feistel::ExpansionFunction(const Halfblock& block)
+{
+ std::stringstream ss;
+ const std::string bits = block.to_string();
+
+ // We have to double the bits!
+ for (std::size_t i = 0; i < bits.size(); i += 2)
+ {
+ const std::string sub = bits.substr(i, 2);
+
+ if (sub == "00") ss << "1101";
+ else if (sub == "01") ss << "1000";
+ else if (sub == "10") ss << "0010";
+ else if (sub == "11") ss << "0111";
+
+ }
+
+ return Block(ss.str());
+}
+
+GhettoCipher::Halfblock GhettoCipher::Feistel::CompressionFunction(const Block& block)
+{
+ std::stringstream ss;
+ const std::string bits = block.to_string();
+
+ // We have to double the bits!
+ for (std::size_t i = 0; i < bits.size(); i += 4)
+ {
+ const std::string sub = bits.substr(i, 4);
+
+ if (sub == "0000") ss << "10";
+ else if (sub == "0001") ss << "01";
+ else if (sub == "0010") ss << "10";
+ else if (sub == "0011") ss << "10";
+ else if (sub == "0100") ss << "11";
+ else if (sub == "0101") ss << "01";
+ else if (sub == "0110") ss << "00";
+ else if (sub == "0111") ss << "11";
+ else if (sub == "1000") ss << "01";
+ else if (sub == "1001") ss << "00";
+ else if (sub == "1010") ss << "11";
+ else if (sub == "1011") ss << "00";
+ else if (sub == "1100") ss << "11";
+ else if (sub == "1101") ss << "10";
+ else if (sub == "1110") ss << "00";
+ else if (sub == "1111") ss << "01";
+ }
+
+ return Halfblock(ss.str());
+}
+
+std::string GhettoCipher::Feistel::SBox(const std::string& in)
+{
+ if (in == "0000") return "1100";
+ else if (in == "0001") return "1000";
+ else if (in == "0010") return "0001";
+ else if (in == "0011") return "0111";
+ else if (in == "0100") return "1011";
+ else if (in == "0101") return "0011";
+ else if (in == "0110") return "1101";
+ else if (in == "0111") return "1111";
+ else if (in == "1000") return "0000";
+ else if (in == "1001") return "1010";
+ else if (in == "1010") return "0100";
+ else if (in == "1011") return "1001";
+ else if (in == "1100") return "0010";
+ else if (in == "1101") return "1110";
+ else if (in == "1110") return "0101";
+ else /*if (in == "1111")*/ return "0110";
+}
+
+void GhettoCipher::Feistel::GenerateRoundKeys(const Block& seedKey)
+{
+ // Generate round keys via output feedback modus (OFM) method
+
+ // Clear initial key memory
+ ZeroKeyMemory();
+ roundKeys = Keyset();
+
+ // Generate new keys from the seed key
+ roundKeys[0] = seedKey;
+ roundKeys[1] = (Shiftl(seedKey, 32) ^ roundKeys[0]);
+
+ for (std::size_t i = 2; i < roundKeys.size(); i++)
+ {
+ roundKeys[i] = Shiftl(roundKeys[i - 1], i + 32) ^ roundKeys[i - 2];
+ }
+
+ return;
+}
+
+// These pragmas only work for MSVC, as far as i know. Beware!!!
+#if defined _WIN32 || defined _WIN64
+#pragma optimize("", off )
+#endif
+void GhettoCipher::Feistel::ZeroKeyMemory()
+{
+ for (Block& key : roundKeys)
+ key.reset();
+
+ return;
+}
+#if defined _WIN32 || defined _WIN64
+#pragma optimize("", on )
+#endif
+
+
+/*** ./../Feistel/GhettoCipherWrapper.cpp ***/
+
+
+std::string GhettoCipher::GhettoCryptWrapper::EncryptString(const std::string& cleartext, const std::string& password)
+{
+ // Instanciate our cipher and supply a key
+ Cipher cipher(password);
+
+ // Recode the ascii-string to bits
+ const Flexblock cleartext_bits = StringToBits(cleartext);
+
+ // Encrypt our cleartext bits
+ const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits);
+
+ // Recode the ciphertext bits to a hex-string
+ const std::string ciphertext = BitsToHexstring(ciphertext_bits);
+
+ // Return it
+ return ciphertext;
+}
+
+std::string GhettoCipher::GhettoCryptWrapper::DecryptString(const std::string& ciphertext, const std::string& password)
+{
+ // Instanciate our cipher and supply a key
+ Cipher cipher(password);
+
+ // Recode the hex-string to bits
+ const Flexblock ciphertext_bits = HexstringToBits(ciphertext);
+
+ // Decrypt the ciphertext bits
+ const std::string cleartext_bits = cipher.Decipher(ciphertext_bits);
+
+ // Recode the cleartext bits to an ascii-string
+ const std::string cleartext = BitsToString(cleartext_bits);
+
+ // Return it
+ return cleartext;
+}
+
+bool GhettoCipher::GhettoCryptWrapper::EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password)
+{
+ try
+ {
+ // Read the file to bits
+ const Flexblock cleartext_bits = ReadFileToBits(filename_in);
+
+ // Instanciate our cipher and supply a key
+ Cipher cipher(password);
+
+ // Encrypt our cleartext bits
+ const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits);
+
+ // Write our ciphertext bits to file
+ WriteBitsToFile(filename_out, ciphertext_bits);
+
+ return true;
+ }
+ catch (std::runtime_error&)
+ {
+ return false;
+ }
+}
+
+bool GhettoCipher::GhettoCryptWrapper::DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password)
+{
+ try
+ {
+ // Read the file to bits
+ const Flexblock ciphertext_bits = ReadFileToBits(filename_in);
+
+ // Instanciate our cipher and supply a key
+ Cipher cipher(password);
+
+ // Decrypt the ciphertext bits
+ const Flexblock cleartext_bits = cipher.Decipher(ciphertext_bits);
+
+ // Write our cleartext bits to file
+ WriteBitsToFile(filename_out, cleartext_bits);
+
+ return true;
+ }
+ catch (std::runtime_error&)
+ {
+ return false;
+ }
+}
+
diff --git a/INCLUDE/GhettoCipher.h b/INCLUDE/GhettoCipher.h
new file mode 100644
index 0000000..73c5e7f
--- /dev/null
+++ b/INCLUDE/GhettoCipher.h
@@ -0,0 +1,447 @@
+#pragma once
+
+/*** ./../Feistel/GhettoCipherWrapper.h ***/
+
+#pragma once
+#include
+
+namespace GhettoCipher
+{
+ /** This class is a wrapper to make working with the GhettoCipher super easy with a python-like syntax
+ */
+ class GhettoCryptWrapper
+ {
+ public:
+ //! Will encrypt a string and return it hexadecimally encoded.
+ static std::string EncryptString(const std::string& cleartext, const std::string& password);
+
+ //! Will decrypt a hexadecimally encoded string.
+ static std::string DecryptString(const std::string& ciphertext, const std::string& password);
+
+ //! 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 std::string& password);
+
+ //! 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 std::string& password);
+
+ private:
+ // No instanciation! >:(
+ GhettoCryptWrapper();
+ };
+}
+
+/*** ./../Feistel/Flexblock.h ***/
+
+#pragma once
+#include
+
+namespace GhettoCipher
+{
+ //! A "bitset" of variable length
+ typedef std::string Flexblock;
+}
+
+/*** ./../Feistel/Config.h ***/
+
+#pragma once
+
+namespace GhettoCipher
+{
+ constexpr int BLOCK_SIZE = 128;
+ constexpr int N_ROUNDS = 64;
+}
+
+/*** ./../Feistel/Halfblock.h ***/
+
+#pragma once
+#include
+
+namespace GhettoCipher
+{
+ constexpr int HALFBLOCK_SIZE = (BLOCK_SIZE / 2);
+ typedef std::bitset Halfblock;
+}
+
+/*** ./../Feistel/Block.h ***/
+
+#pragma once
+#include
+
+namespace GhettoCipher
+{
+ typedef std::bitset Block;
+}
+
+/*** ./../Feistel/Util.h ***/
+
+#pragma once
+#include
+#include
+#include
+
+namespace GhettoCipher
+{
+ //! Mod-operator that works with negative values
+ inline int Mod(int numerator, int denominator)
+ {
+ return (denominator + (numerator % denominator)) % denominator;
+ }
+
+ //! Will perform a wrapping left-bitshift on a bitset
+ template
+ inline std::bitset Shiftl(const std::bitset& bits, std::size_t amount)
+ {
+ std::stringstream ss;
+ const std::string bitss = bits.to_string();
+
+ for (std::size_t i = 0; i < bitss.size(); i++)
+ ss << bitss[Mod((i + amount), bitss.size())];
+
+ return std::bitset(ss.str());
+ }
+
+ //! Will perform a wrapping right-bitshift on a bitset
+ template
+ inline std::bitset Shiftr(const std::bitset& bits, std::size_t amount)
+ {
+ std::stringstream ss;
+ const std::string bitss = bits.to_string();
+
+ for (std::size_t i = 0; i < bitss.size(); i++)
+ ss << bitss[Mod((i - amount), bitss.size())];
+
+ return std::bitset(ss.str());
+ }
+
+ inline std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true)
+ {
+ // 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();
+ }
+
+ //! Will convert a string to a fixed data block
+ inline Block StringToBitblock(const std::string& s)
+ {
+ std::stringstream ss;
+
+ for (std::size_t i = 0; i < s.size(); i++)
+ ss << std::bitset<8>(s[i]);
+
+ // Pad rest with zeores
+ return Block(PadStringToLength(ss.str(), 128, '0', false));
+ }
+
+ //! Will convert a string to a flexible data block
+ inline Flexblock StringToBits(const std::string& s)
+ {
+ std::stringstream ss;
+
+ for (std::size_t i = 0; i < s.size(); i++)
+ ss << std::bitset<8>(s[i]);
+
+ return Flexblock(ss.str());
+ }
+
+ //! Will convert a fixed data block to a string
+ inline std::string BitblockToString(const Block& bits)
+ {
+ std::stringstream ss;
+
+ const std::string bitstring = bits.to_string();
+
+ for (std::size_t i = 0; i < BLOCK_SIZE; i += 8)
+ {
+ ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong();
+ }
+
+ return ss.str();
+ }
+
+ //! Will convert a flexible data block to a string
+ inline std::string BitsToString(const Flexblock& bits)
+ {
+ std::stringstream ss;
+
+ const std::string bitstring = bits;
+
+ for (std::size_t i = 0; i < bits.size(); i += 8)
+ {
+ ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong();
+ }
+
+ return ss.str();
+ }
+
+ //! Turns a fixed data block into a hex-string
+ inline std::string BitblockToHexstring(const Block& b)
+ {
+ std::stringstream ss;
+ const std::string charset = "0123456789abcdef";
+ const std::string bstr = b.to_string();
+
+ for (std::size_t i = 0; i < bstr.size(); i += 4)
+ ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()];
+
+ return ss.str();
+ }
+
+ //! Turns a flexible data block into a hex-string
+ inline std::string BitsToHexstring(const Flexblock& b)
+ {
+ std::stringstream ss;
+ const std::string charset = "0123456789abcdef";
+ const std::string bstr = b;
+
+ for (std::size_t i = 0; i < bstr.size(); i += 4)
+ ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()];
+
+ return ss.str();
+ }
+
+
+ //! Turns a hex string into a fixed data block
+ inline Block HexstringToBitblock(const std::string& hexstring)
+ {
+ std::stringstream ss;
+
+ for (std::size_t i = 0; i < hexstring.size(); i++)
+ {
+ const char c = hexstring[i];
+
+ // Get value
+ std::size_t value;
+ if ((c >= '0') && (c <= '9'))
+ // Is it a number?
+ value = (c - '0') + 0;
+ else if ((c >= 'a') && (c <= 'f'))
+ // Else, it is a lowercase letter
+ value = (c - 'a') + 10;
+ else
+ throw std::logic_error("non-hex string detected in HexstringToBits()");
+
+ // Append to our bits
+ ss << std::bitset<4>(value);
+ }
+
+ return Block(ss.str());
+ }
+
+ //! Turns a hex string into a flexible data block
+ inline Flexblock HexstringToBits(const std::string& hexstring)
+ {
+ std::stringstream ss;
+
+ for (std::size_t i = 0; i < hexstring.size(); i++)
+ {
+ const char c = hexstring[i];
+
+ // Get value
+ std::size_t value;
+ if ((c >= '0') && (c <= '9'))
+ // Is it a number?
+ value = (c - '0') + 0;
+ else if ((c >= 'a') && (c <= 'f'))
+ // Else, it is a lowercase letter
+ value = (c - 'a') + 10;
+ else
+ throw std::logic_error("non-hex string detected in HexstringToBits()");
+
+ // Append to our bits
+ ss << std::bitset<4>(value);
+ }
+
+ return ss.str();
+ }
+
+ //! Creates a key of size key-size from a password of arbitrary length.
+ inline Block PasswordToKey(const std::string& in)
+ {
+ Block b;
+
+ // Segment the password in segments of key-size, and xor them together.
+ for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE / 8)
+ b ^= StringToBitblock(in.substr(i, BLOCK_SIZE / 8));
+
+ return b;
+ }
+
+ //! Will read a file into a flexblock
+ inline Flexblock ReadFileToBits(const std::string& filepath)
+ {
+ // Read file
+ std::ifstream ifs(filepath, std::ios::binary);
+
+ if (!ifs.good())
+ throw std::runtime_error("Unable to open ifilestream!");
+
+ std::stringstream ss;
+ std::copy(
+ std::istreambuf_iterator(ifs),
+ std::istreambuf_iterator(),
+ std::ostreambuf_iterator(ss)
+ );
+
+ ifs.close();
+
+ const std::string bytes = ss.str();
+
+ // Convert bytes to bits
+ return StringToBits(bytes);
+ }
+
+ //! Will save bits to a binary file
+ inline void WriteBitsToFile(const std::string& filepath, const Flexblock& bits)
+ {
+ // Convert bits to bytes
+ const std::string bytes = BitsToString(bits);
+
+ // Write bits to file
+ std::ofstream ofs(filepath, std::ios::binary);
+
+ if (!ofs.good())
+ throw std::runtime_error("Unable to open ofilestream!");
+
+ ofs.write(bytes.data(), bytes.length());
+ ofs.close();
+
+ return;
+ }
+}
+
+/*** ./../Feistel/Keyset.h ***/
+
+#pragma once
+#include
+
+namespace GhettoCipher
+{
+ typedef std::array Keyset;
+}
+
+/*** ./../Feistel/Feistel.h ***/
+
+#pragma once
+
+namespace GhettoCipher
+{
+ /** Class to perform a feistel block chipher
+ */
+ class Feistel
+ {
+ public:
+ explicit Feistel(const Block& 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 Block& key);
+
+ //! Will encipher a data block via the set seed-key
+ Block Encipher(const Block& data) const;
+
+ //! Will decipher a data block via the set seed-key
+ Block Decipher(const Block& data) const;
+
+ private:
+ //! Will run the feistel rounds, with either regular key order or reversed key order
+ Block Run(const Block& data, bool reverseKeys) const;
+
+ //! Arbitrary cipher function
+ static Halfblock F(Halfblock m, const Block& key);
+
+ //! Split a data block into two half blocks (into L and R)
+ static std::pair 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 compress a fullblock to a halfblock
+ static Halfblock CompressionFunction(const Block& block);
+
+ //! Substitutes four bits by static random others
+ static std::string SBox(const std::string& in);
+
+ //! Will generate a the round keys
+ void GenerateRoundKeys(const Block& seedKey);
+
+ //! Will zero the memory used by the keyset
+ void ZeroKeyMemory();
+
+ Keyset roundKeys;
+ };
+}
+
+/*** ./../Feistel/Cipher.h ***/
+
+#pragma once
+
+namespace GhettoCipher
+{
+ /** Class to apply a block cipher to messages of arbitrary length in a distributed manner
+ */
+ class Cipher
+ {
+ public:
+ explicit Cipher(const Block& key);
+ explicit Cipher(const std::string& password);
+
+ Cipher(const Cipher& other) = delete;
+ Cipher(Cipher&& other) noexcept = delete;
+
+ ~Cipher();
+
+ //! Will set the key
+ void SetKey(const Block& key);
+
+ //! Will set the key from a password
+ void SetPassword(const std::string& password);
+
+ //! Will encipher a flexblock of data
+ Flexblock Encipher(const Flexblock& data, bool printProgress = false) const;
+
+ //! Will decipher a flexblock of data
+ Flexblock Decipher(const Flexblock& data, bool printProgress = false) const;
+
+ private:
+ Block key;
+
+ //! Will zero the memory used by the key
+ void ZeroKeyMemory();
+
+ // Initial value for cipher block chaining
+ static const Block emptyBlock;
+ };
+}
diff --git a/INCLUDE/deggl b/INCLUDE/deggl
new file mode 100644
index 0000000..a91a3b3
Binary files /dev/null and b/INCLUDE/deggl differ
diff --git a/INCLUDE/generate.sh b/INCLUDE/generate.sh
new file mode 100644
index 0000000..8ec48fc
--- /dev/null
+++ b/INCLUDE/generate.sh
@@ -0,0 +1,7 @@
+# Compile single-header
+deggl -i ../Feistel/*.cpp --out GhettoCipher --loc
+
+# Verify that this builds cleanly via g++
+echo "Verifying build..."
+g++ GhettoCipher.cpp -c -S -o - -Wall > /dev/null
+echo "If you saw no compiler errors, everything's good!"