Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

algo(cpp-caesarCipher): #30

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <iostream>
#include <string>
#include <functional>

#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<char(char)> 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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef CAESAR_CIPHER_H
#define CAESAR_CIPHER_H

#include <string>
#include <functional>

std::string updateCipher(std::string, const std::function<char(char)>);

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 */

Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include <iostream>
#include <iomanip>
#include <math.h>

#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<int>& observedFrequencyList) {
if (observedFrequencyList.size() > 0) {
observedFrequencyList.clear();
}

// initialize frequencyList
for (int i = 0; i < 26; i++) {
observedFrequencyList.push_back(0);
}
}

void buildFrequencyList(
std::vector<int>& 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<int>& observedFrequencyList,
const std::string& encryptedCipher) {
clearFrequencyList(observedFrequencyList);
buildFrequencyList(observedFrequencyList, encryptedCipher);
}

float calculateChiSquaredFromCipher(
const std::string& encryptedCipher,
const std::vector<int>& 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<int> 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);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef CRYPTO_ANALYSIS_H
#define CRYPTO_ANALYSIS_H

#include <string>
#include <vector>
#include <tuple>

typedef std::tuple<int, std::string, float> chiSquaredResult_t;
typedef std::vector<chiSquaredResult_t> results_t;

const std::vector<float> 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<int>&);

void buildFrequencyList(std::vector<int>&, const std::string&);

void initializeFrequencyList(std::vector<int>&, const std::string&);

float calculateChiSquaredFromCipher(const std::string&,
const std::vector<int>&);

void performChiSquaredAnalysis(const std::string&);

#endif /* CRYPTO_ANALYSIS_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <string>
#include <iostream>
#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<std::string> testCiphers {
"FYYFHPFYIFBS", "QBPQ TFQE PMXZBP XKA ZXMFQXIP!",
"AOLJHLZHYJPWOLYPZVULVMAOLLHYSPLZARUVDUHUKZPTWSLZAJPWOLYZPAPZHAFWLVMZBIZA"
"PABAPVUJPWOLYPUDOPJOLHJOSLAALYPUAOLWSHPUALEAPZZOPMALKHJLYAHPUUBTILYVMWSH"
"JLZKVDUAOLHSWOHILA"
};

for (auto it = testCiphers.begin(); it != testCiphers.end(); it++){
performChiSquaredAnalysis(*it);
}

}