diff --git a/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/Makefile b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/Makefile new file mode 100644 index 00000000..4258475b --- /dev/null +++ b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/Makefile @@ -0,0 +1,31 @@ +# +# This is an example Makefile for a caesar cipher program. This +# program uses both the caesar cipher module and a crypto analysis module. +# Typing 'make' or 'make main' will create the executable file. +# + +# define some Makefile variables for the compiler and compiler flags +# to use Makefile variables later in the Makefile: $() +# +# -g adds debugging information to the executable file +# -Wall turns on most, but not all, compiler warnings +# -std=c++11 turns on c++11 options +# +# for C++ define CC = g++ +CC=g++ +CFLAGS=-O3 -std=c++11 -Wall + +all: main + +main: cryptoAnalysis.o caesarCipher.o + $(CC) $(CFLAGS) caesarCipher.o cryptoAnalysis.o main.cpp -o main + +cryptoAnalysis.o: cryptoAnalysis.h cryptoAnalysis.cpp \ + caesarCipher.h caesarCipher.cpp + $(CC) $(CFLAGS) -c cryptoAnalysis.cpp caesarCipher.cpp + +caesarCipher.o: caesarCipher.h caesarCipher.cpp + $(CC) $(CFLAGS) -c caesarCipher.cpp + +clean: + rm *.o main diff --git a/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/caesarCipher.cpp b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/caesarCipher.cpp new file mode 100644 index 00000000..78676e64 --- /dev/null +++ b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/caesarCipher.cpp @@ -0,0 +1,58 @@ +#include +#include +#include + +#include "caesarCipher.h" + +// Caesar Cipher, (ROT13 encription, which uses an offset of 13) +// +// Simple and most widely known encryption of the encryption techniques. +// Caesar cipher is a substitution cipher where each letter in plain text +// is 'shifted' a certain number of letters in the alphabet. +// This cipher offers no communication security and can easily be broken +// by pen and paper +// +// Encryption: E(x) = (x + n) mod 26 +// Decryption: D(x) = (x - n) mod 26 +// + +int mod(int a, int b) { + int r = a % b; + return r < 0 ? r + b : r; +} + +std::string updateCipher(std::string cipher, + const std::function func) { + char character; + for (unsigned int i = 0; i < cipher.length(); i++) { + character = std::toupper(cipher[i]); + cipher[i] = std::isalpha(character) ? func(character) : character; + } + return cipher; +} + +std::string encrypt(const std::string cipher, const int& shiftAmount) { + return updateCipher(cipher, [&shiftAmount](char letter) { + return mod(((int)letter - 65) + shiftAmount, 26) + 65; + }); +} + +std::string decrypt(const std::string cipher, const int& shiftAmount) { + return updateCipher(cipher, [&shiftAmount](char letter) { + return mod(((int)letter - 65) - shiftAmount, 26) + 65; + }); +} + +void testEncryption(const std::string cipher, const int& shiftAmount){ + std::cout << "Encrypting: \n\t\"" << cipher << "\" shifted: " + << shiftAmount << std::endl; + std::string encryptedCipher = encrypt(cipher, shiftAmount); + std::cout << "\t\"" << encryptedCipher << "\"" << std::endl; +} + +void testDecryption(const std::string cipher, const int& shiftAmount){ + std::cout << "Decrypting: \n\t\"" << cipher << "\" shifted: " + << shiftAmount << std::endl; + std::string decryptedCipher = decrypt(cipher, shiftAmount); + std::cout << "\t\"" << decryptedCipher << "\"" << std::endl; +} diff --git a/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/caesarCipher.h b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/caesarCipher.h new file mode 100644 index 00000000..1026f4b2 --- /dev/null +++ b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/caesarCipher.h @@ -0,0 +1,18 @@ +#ifndef CAESAR_CIPHER_H +#define CAESAR_CIPHER_H + +#include +#include + +std::string updateCipher(std::string, const std::function); + +std::string encrypt(const std::string, const int&); + +std::string decrypt(const std::string, const int&); + +void testEncryption(const std::string, const int&); + +void testDecryption(const std::string, const int&); + +#endif /* CAESAR_CIPHER_H */ + diff --git a/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/cryptoAnalysis.cpp b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/cryptoAnalysis.cpp new file mode 100644 index 00000000..2937887a --- /dev/null +++ b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/cryptoAnalysis.cpp @@ -0,0 +1,115 @@ +#include +#include +#include + +#include "cryptoAnalysis.h" +#include "caesarCipher.h" + +// Crytoanalysis Breaking the code +// Caesar cipher is a perfect example of how insecure it is. +// This cipher can be broken simply through cryptanalysis. +// Cryptanalysis is the art of breaking codes and ciphers. +// In the English language, there is a very distinct distribution +// that helps crack the code. +// For instance, 'e' is the most common letter and it appears almost +// 13% of the time. 'z' is the least common letter and appears 1% of the time. + +chiSquaredResult_t calculateBestResult(const results_t& results) { + auto bestResult = results[0]; + for (auto it = results.begin(); it != results.end(); it++) { + if (std::get<2>(bestResult) > std::get<2>(*it)) { + bestResult = *it; + } + } + return bestResult; +} + +void printResults(const results_t& results) { + // determine correct answer based on chi squared results + auto bestResult = calculateBestResult(results); + + std::cout << std::setw(10) << "Offset" << std::setw(20) + << "Encrypted string" << std::setw(27) << "chi squared" << std::endl; + for (auto it = results.begin(); it != results.end(); it++) { + std::cout << std::setw(10) << std::get<0>(*it) << std::setw(30) + << std::get<1>(*it).substr(0,26) << "..." << std::setw(14) + << std::get<2>(*it) << std::endl; + } + + std::cout << std::endl + << "Chi Squared analysis determined that the decrypted text should be \"" + << std::get<1>(bestResult) << "\" which had a score of: " + << std::get<2>(bestResult) << " and an offset of: " + << std::get<0>(bestResult) << std::endl; +} + +void clearFrequencyList(std::vector& observedFrequencyList) { + if (observedFrequencyList.size() > 0) { + observedFrequencyList.clear(); + } + + // initialize frequencyList + for (int i = 0; i < 26; i++) { + observedFrequencyList.push_back(0); + } +} + +void buildFrequencyList( + std::vector& observedFrequencyList, + const std::string& cipher) { + // Count the frequencies of characters into an array + // Ignore all non-alphabetic characters + for (unsigned int i = 0; i < cipher.size(); i++) { + if (std::isalpha(cipher[i])) { + observedFrequencyList[cipher[i] - 65]++; + } + } +} + +void initializeFrequencyList(std::vector& observedFrequencyList, + const std::string& encryptedCipher) { + clearFrequencyList(observedFrequencyList); + buildFrequencyList(observedFrequencyList, encryptedCipher); +} + +float calculateChiSquaredFromCipher( + const std::string& encryptedCipher, + const std::vector& observedFrequencyList) { + + // Chi squared is determined by the summation of + // (observed - expected)^2/expected over the frequencies of each character. + float letterFrequency, + observedFrequency, + expectedFrequency, + chiSquaredSum = 0; + int totalCount = encryptedCipher.size(); + for (int i = 0; i < 26; i++) { + observedFrequency = observedFrequencyList[i]; + letterFrequency = englishFrequencyList[i]; + expectedFrequency = (totalCount * letterFrequency); + chiSquaredSum += + pow(observedFrequency - expectedFrequency, 2) / expectedFrequency; + } + return chiSquaredSum; +} + +void performChiSquaredAnalysis(const std::string& cipher) { + float chiSquaredSum; + std::vector observedFrequencyList; + results_t chiSquaredResults; + + // 1. Iterate through each possible offset in the english language + // 2. Determine the frequencies of each letter in the cipher + // 3. Calculate Chi Squared on the frequencies on a given offset + // 4. Save results for report + for (int i = 0; i < 26; i++) { + std::string encryptedCipher = encrypt(cipher, i); + initializeFrequencyList(observedFrequencyList, encryptedCipher); + chiSquaredSum = calculateChiSquaredFromCipher( + encryptedCipher, observedFrequencyList); + chiSquaredResults.push_back( + std::make_tuple(i, encryptedCipher, chiSquaredSum)); + } + printResults(chiSquaredResults); +} + diff --git a/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/cryptoAnalysis.h b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/cryptoAnalysis.h new file mode 100644 index 00000000..70e30361 --- /dev/null +++ b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/cryptoAnalysis.h @@ -0,0 +1,55 @@ +#ifndef CRYPTO_ANALYSIS_H +#define CRYPTO_ANALYSIS_H + +#include +#include +#include + +typedef std::tuple chiSquaredResult_t; +typedef std::vector results_t; + +const std::vector englishFrequencyList { + .0855, /* A */ + .0160, /* B */ + .0316, /* C */ + .0387, /* D */ + .1210, /* E */ + .0218, /* F */ + .0209, /* G */ + .0496, /* H */ + .0733, /* I */ + .0022, /* J */ + .0081, /* K */ + .0421, /* L */ + .0253, /* M */ + .0717, /* N */ + .0747, /* O */ + .0207, /* P */ + .0010, /* Q */ + .0633, /* R */ + .0673, /* S */ + .0894, /* T */ + .0268, /* U */ + .0106, /* V */ + .0183, /* W */ + .0019, /* X */ + .0172, /* Y */ + .0011, /* Z */ +}; + +chiSquaredResult_t calculateBestResult(const results_t&); + +void printResults(const results_t&); + +void clearFrequencyList(std::vector&); + +void buildFrequencyList(std::vector&, const std::string&); + +void initializeFrequencyList(std::vector&, const std::string&); + +float calculateChiSquaredFromCipher(const std::string&, + const std::vector&); + +void performChiSquaredAnalysis(const std::string&); + +#endif /* CRYPTO_ANALYSIS_H */ diff --git a/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/main.cpp b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/main.cpp new file mode 100644 index 00000000..b945e15a --- /dev/null +++ b/src/algorithm_practice/Cryptography_Algorithms/encryption/caesarCipher/main.cpp @@ -0,0 +1,49 @@ +#include +#include +#include "caesarCipher.h" +#include "cryptoAnalysis.h" + +int main(int argc, char *argv[]) +{ + // general encryption and decryption tests + std::cout << "-------------" << std::endl; + std::cout << "Caesar Cipher" << std::endl; + std::cout << "-------------" << std::endl; + std::string example = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + testEncryption(example, 3); //DEFGHIJKLMNOPQRSTUVWXYZABC + + std::string example2 = "ATTACKATDAWN"; + testEncryption(example2, 5); // FYYFHPFYIFBS + + std::string example3 = "DEFGHIJKLMNOPQRSTUVWXYZABC"; + testDecryption(example3, 3); // ABCDEFGHIJKLMNOPQRSTUVWXYZ + + std::string example4 = "FYYFHPFYIFBS"; + testDecryption(example4, 5); // ATTACKATDAWN + + std::string exampleEdgeCase1 = "Test With Spaces and Capitals"; + testEncryption(exampleEdgeCase1, 23); // QBPQTFQEPMXZBPXKAZXMFQXIP + testDecryption(exampleEdgeCase1, 23); + + std::string exampleEdgeCase2 = "T3$T w1th Numb3rS & $ymB0ls"; + testEncryption(exampleEdgeCase2, 123); + testDecryption(exampleEdgeCase2, 123); + + // solve using chi-squared + std::cout + << "------------------------------------------" << std::endl + << "Solve via chi-squared statistical analysis" << std::endl + << "------------------------------------------" << std::endl; + + std::vector testCiphers { + "FYYFHPFYIFBS", "QBPQ TFQE PMXZBP XKA ZXMFQXIP!", + "AOLJHLZHYJPWOLYPZVULVMAOLLHYSPLZARUVDUHUKZPTWSLZAJPWOLYZPAPZHAFWLVMZBIZA" + "PABAPVUJPWOLYPUDOPJOLHJOSLAALYPUAOLWSHPUALEAPZZOPMALKHJLYAHPUUBTILYVMWSH" + "JLZKVDUAOLHSWOHILA" + }; + + for (auto it = testCiphers.begin(); it != testCiphers.end(); it++){ + performChiSquaredAnalysis(*it); + } + +}