Skip to content

Instantly share code, notes, and snippets.

@Animesh-Ghosh
Created April 13, 2020 14:19
Show Gist options
  • Select an option

  • Save Animesh-Ghosh/d143ddc16d23d6ffd2661844915d4082 to your computer and use it in GitHub Desktop.

Select an option

Save Animesh-Ghosh/d143ddc16d23d6ffd2661844915d4082 to your computer and use it in GitHub Desktop.
Some ciphers.
/*
To build
g++ crypt.cpp -o crypt.exe -std=c++11 -Wall -Wextra -O2
*/
#include <iostream>
#include <algorithm>
#include <array>
#include <vector>
#include <set>
#include <map>
#include <chrono>
#include <random>
// abstract base class with pure virtual methods to be overloaded
// for each type of cipher that inherits from this class
class Crypt {
protected:
std::string message; // message string which will be mutated
public:
Crypt() : message("") {
std::cout << "Constructing Crypt with no message.\n";
}
Crypt(const std::string &message) : message(message) {
std::cout << "Constructing Crypt with message: " << message << '\n';
}
~Crypt() {
std::cout << "Destroying Crypt...\n";
}
virtual void setMessage(const std::string &message) {
this->message = message;
}
// pure virtual method declarations
virtual std::string Encrypt() = 0;
virtual std::string Decrypt() = 0;
};
// Ceasar cipher which moves characters by 3 values
class CeasarCipher : public Crypt {
protected:
static const std::array<char, 26> alphabets;
// helper method to get index of a character (all lower case)
// protected so as to be used by derived class as well
unsigned int getIdx(const char &c) {
for (unsigned int i = 0; i < alphabets.size(); ++i) {
if (alphabets[i] == c) {
return i;
}
}
return 0;
}
public:
CeasarCipher() : Crypt() {}
CeasarCipher(const std::string &message)
: Crypt(message) {}
~CeasarCipher() {
std::cout << "Destroying CeasarCipher...\n";
}
std::string Encrypt() {
if (message == "") {
return "No message to encrypt!";
}
std::for_each(message.begin(), message.end(), [&](char &c) {
c = alphabets[(getIdx(c) + 3) % alphabets.size()];
});
return message;
}
std::string Decrypt() {
if (message == "") {
return "No message to decrypt!";
}
std::for_each(message.begin(), message.end(), [&](char &c) {
int idx = getIdx(c) - 3;
c = alphabets[idx < 0 ? alphabets.size() + idx : idx];
});
return message;
}
};
const std::array<char, 26> CeasarCipher::alphabets = {
'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'
};
// extended Ceasar cipher which moves characters any given amount of value
class CeasarCipherExt : public CeasarCipher {
protected:
const unsigned int key;
public:
CeasarCipherExt() : CeasarCipher(), key(1u) {
std::cout << "Constructing CeasarCipherExt with key: " << key << '\n';
}
CeasarCipherExt(const std::string &message, unsigned int key)
: CeasarCipher(message), key(key) {
std::cout << "Constructing CeasarCipherExt with key: " << key << '\n';
}
~CeasarCipherExt() {
std::cout << "Destroying CeasarCipherExt...\n";
}
std::string Encrypt() {
if (message == "") {
return "No message to encrypt!";
}
std::for_each(message.begin(), message.end(), [&](char &c) {
c = alphabets[(getIdx(c) + key) % alphabets.size()];
});
return message;
}
std::string Decrypt() {
if (message == "") {
return "No message to decrypt!";
}
std::for_each(message.begin(), message.end(), [&](char &c) {
int idx = getIdx(c) - key;
c = alphabets[idx < 0 ? alphabets.size() + idx : idx];
});
return message;
}
};
template<typename T>
std::ostream& operator<<(std::ostream &os, const std::vector<T> &v) {
for (const T &x : v) {
os << x << ' ';
}
return os;
}
// Rail fence cipher
class RailFence : public Crypt {
private:
std::vector<char> upperFence, lowerFence;
void constructFences() {
for (unsigned int i = 0; i < message.size(); ++i) {
if (i % 2 == 0) {
upperFence.push_back(message[i]);
}
else {
lowerFence.push_back(message[i]);
}
}
}
public:
RailFence() : Crypt() {}
RailFence(const std::string &message) : Crypt(message) {
constructFences();
}
~RailFence() {
std::cout << "Destroying RailFence...\n";
}
void setMessage(const std::string &message) {
this->message = message;
constructFences();
}
std::string Encrypt() {
if (message == "") {
return "No message to encrypt!";
}
std::string newMessage;
for (const char &c : upperFence) {
newMessage.push_back(c);
}
for (const char &c : lowerFence) {
newMessage.push_back(c);
}
message = newMessage;
return message;
}
std::string Decrypt() {
if (message == "") {
return "No message to decrypt!";
}
std::string newMessage;
for (const char &c : upperFence) {
newMessage.push_back(c);
newMessage.push_back(0); // appending empty character
}
for (unsigned int i = 0, k = 0; i < newMessage.size(); ++i) {
if (newMessage[i] == 0) {
newMessage[i] = lowerFence[k++];
}
}
message = newMessage;
return message;
}
};
template<typename T>
std::ostream& operator<<(std::ostream &os, const std::set<T> &s) {
std::for_each(s.begin(), s.end(), [&](const T &x) {
os << x << ' ';
});
return os;
}
template<typename key, typename value>
std::ostream& operator<<(std::ostream &os, const std::map<key, value> &map) {
for (auto it = map.begin(); it != map.end(); ++it) {
os << it->first << " -> " << it->second << '\n';
}
return os;
}
class MonoAlpha : public Crypt {
private:
static const std::set<char> alphabets;
std::map<char, char> charMap, reverseCharMap;
void constructMaps() {
using clock = std::chrono::system_clock;
unsigned seed = clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::set<char> assignedChars;
std::for_each(alphabets.begin(), alphabets.end(), [&](const char &c) {
const std::set<char> currentChar = { c };
std::vector<char> difference(alphabets.size());
auto it = std::set_difference(
alphabets.begin(), alphabets.end(),
currentChar.begin(), currentChar.end(),
difference.begin()
);
difference.resize(it - difference.begin());
std::uniform_int_distribution<int> distribution(0, difference.size() - 1);
char replacement = difference[distribution(generator)];
if (charMap.size() > 0) {
while (assignedChars.count(replacement) != 0) {
replacement = difference[distribution(generator)];
}
}
charMap[c] = replacement;
reverseCharMap[replacement] = c;
assignedChars.insert(replacement);
});
}
public:
MonoAlpha() : Crypt() {}
MonoAlpha(const std::string &message) : Crypt(message) {
constructMaps();
}
~MonoAlpha() {
std::cout << "Destroying MonoAlpha...\n";
}
void setMessage(const std::string &message) {
this->message = message;
constructMaps();
}
std::string Encrypt() {
if (message == "") {
return "No message to encrypt!";
}
for (char &c : message) {
c = charMap.find(c)->second;
}
return message;
}
std::string Decrypt() {
if (message == "") {
return "No message to decrypt!";
}
for (char& c : message) {
c = reverseCharMap.find(c)->second;
}
return message;
}
};
const std::set<char> MonoAlpha::alphabets = {
'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'
};
int main() {
const std::string message = R"(a very long test message...
so long that infact it can't be deciphered!)";
// CeasarCipher ceasar_cipher(message);
// std::cout << ceasar_cipher.Encrypt() << '\n'; // newline, special characters (ASCII) not preserved
// std::cout << ceasar_cipher.Decrypt() << '\n';
// CeasarCipherExt ceasar_cipher_ext(message, 5);
// std::cout << ceasar_cipher_ext.Encrypt() << '\n'; // newline, special characters (ASCII) not preserved
// std::cout << ceasar_cipher_ext.Decrypt() << '\n';
RailFence rail_fence_cipher(message);
std::cout << rail_fence_cipher.Encrypt() << '\n';
std::cout << rail_fence_cipher.Decrypt() << '\n';
// MonoAlpha mono_alpha_cipher;
// mono_alpha_cipher.setMessage(message);
// std::cout << mono_alpha_cipher.Encrypt() << '\n'; // newline, special characters (ASCII) not preserved
// std::cout << mono_alpha_cipher.Decrypt() << '\n';
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment