chore: import upstream snapshot with attribution
Awesome CI Workflow / Code Formatter (push) Has been cancelled
Awesome CI Workflow / Compile checks (macOS-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (windows-latest) (push) Has been cancelled
Awesome CI Workflow / Code Formatter (push) Has been cancelled
Awesome CI Workflow / Compile checks (macOS-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (windows-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/ciphers")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [A1Z26
|
||||
* cipher](https://www.dcode.fr/letter-number-cipher)
|
||||
* @details The A1Z26 cipher is a simple substiution cipher where each letter is
|
||||
* replaced by the number of the order they're in. For example, A corresponds to
|
||||
* 1, B = 2, C = 3, etc.
|
||||
*
|
||||
* @author [Focusucof](https://github.com/Focusucof)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::transform and std::replace
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for uint8_t
|
||||
#include <iostream> /// for IO operations
|
||||
#include <map> /// for std::map
|
||||
#include <sstream> /// for std::stringstream
|
||||
#include <string> /// for std::string
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace ciphers
|
||||
* @brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/**
|
||||
* @namespace a1z26
|
||||
* @brief Functions for [A1Z26](https://www.dcode.fr/letter-number-cipher)
|
||||
* encryption and decryption implementation
|
||||
*/
|
||||
namespace a1z26 {
|
||||
|
||||
std::map<uint8_t, char> a1z26_decrypt_map = {
|
||||
{1, 'a'}, {2, 'b'}, {3, 'c'}, {4, 'd'}, {5, 'e'}, {6, 'f'}, {7, 'g'},
|
||||
{8, 'h'}, {9, 'i'}, {10, 'j'}, {11, 'k'}, {12, 'l'}, {13, 'm'}, {14, 'n'},
|
||||
{15, 'o'}, {16, 'p'}, {17, 'q'}, {18, 'r'}, {19, 's'}, {20, 't'}, {21, 'u'},
|
||||
{22, 'v'}, {23, 'w'}, {24, 'x'}, {25, 'y'}, {26, 'z'},
|
||||
};
|
||||
|
||||
std::map<char, uint8_t> a1z26_encrypt_map = {
|
||||
{'a', 1}, {'b', 2}, {'c', 3}, {'d', 4}, {'e', 5}, {'f', 6}, {'g', 7},
|
||||
{'h', 8}, {'i', 9}, {'j', 10}, {'k', 11}, {'l', 12}, {'m', 13}, {'n', 14},
|
||||
{'o', 15}, {'p', 16}, {'q', 17}, {'r', 18}, {'s', 19}, {'t', 20}, {'u', 21},
|
||||
{'v', 22}, {'w', 23}, {'x', 24}, {'y', 25}, {'z', 26}};
|
||||
|
||||
/**
|
||||
* @brief a1z26 encryption implementation
|
||||
* @param text is the plaintext input
|
||||
* @returns encoded string with dashes to seperate letters
|
||||
*/
|
||||
std::string encrypt(std::string text) {
|
||||
std::string result;
|
||||
std::transform(text.begin(), text.end(), text.begin(),
|
||||
::tolower); // convert string to lowercase
|
||||
std::replace(text.begin(), text.end(), ':', ' ');
|
||||
for (char letter : text) {
|
||||
if (letter != ' ') {
|
||||
result += std::to_string(
|
||||
a1z26_encrypt_map[letter]); // convert int to string and append
|
||||
// to result
|
||||
result += "-"; // space out each set of numbers with spaces
|
||||
} else {
|
||||
result.pop_back();
|
||||
result += ' ';
|
||||
}
|
||||
}
|
||||
result.pop_back(); // remove leading dash
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief a1z26 decryption implementation
|
||||
* @param text is the encrypted text input
|
||||
* @param bReturnUppercase is if the decoded string should be in uppercase or
|
||||
* not
|
||||
* @returns the decrypted string in all uppercase or all lowercase
|
||||
*/
|
||||
std::string decrypt(const std::string& text, bool bReturnUppercase = false) {
|
||||
std::string result;
|
||||
|
||||
// split words seperated by spaces into a vector array
|
||||
std::vector<std::string> word_array;
|
||||
std::stringstream sstream(text);
|
||||
std::string word;
|
||||
while (sstream >> word) {
|
||||
word_array.push_back(word);
|
||||
}
|
||||
|
||||
for (auto& i : word_array) {
|
||||
std::replace(i.begin(), i.end(), '-', ' ');
|
||||
std::vector<std::string> text_array;
|
||||
|
||||
std::stringstream ss(i);
|
||||
std::string res_text;
|
||||
while (ss >> res_text) {
|
||||
text_array.push_back(res_text);
|
||||
}
|
||||
|
||||
for (auto& i : text_array) {
|
||||
result += a1z26_decrypt_map[stoi(i)];
|
||||
}
|
||||
|
||||
result += ' ';
|
||||
}
|
||||
result.pop_back(); // remove any leading whitespace
|
||||
|
||||
if (bReturnUppercase) {
|
||||
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace a1z26
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::string input = "Hello World";
|
||||
std::string expected = "8-5-12-12-15 23-15-18-12-4";
|
||||
std::string output = ciphers::a1z26::encrypt(input);
|
||||
|
||||
std::cout << "Input: " << input << std::endl;
|
||||
std::cout << "Expected: " << expected << std::endl;
|
||||
std::cout << "Output: " << output << std::endl;
|
||||
assert(output == expected);
|
||||
std::cout << "TEST PASSED";
|
||||
|
||||
// 2nd test
|
||||
input = "12-15-23-5-18-3-1-19-5";
|
||||
expected = "lowercase";
|
||||
output = ciphers::a1z26::decrypt(input);
|
||||
|
||||
std::cout << "Input: " << input << std::endl;
|
||||
std::cout << "Expected: " << expected << std::endl;
|
||||
std::cout << "Output: " << output << std::endl;
|
||||
assert(output == expected);
|
||||
std::cout << "TEST PASSED";
|
||||
|
||||
// 3rd test
|
||||
input = "21-16-16-5-18-3-1-19-5";
|
||||
expected = "UPPERCASE";
|
||||
output = ciphers::a1z26::decrypt(input, true);
|
||||
|
||||
std::cout << "Input: " << input << std::endl;
|
||||
std::cout << "Expected: " << expected << std::endl;
|
||||
std::cout << "Output: " << output << std::endl;
|
||||
assert(output == expected);
|
||||
std::cout << "TEST PASSED";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation
|
||||
* @details The Atbash cipher is a subsitution cipher where the letters of the
|
||||
* alphabet are in reverse. For example, A is replaced with Z, B is replaced
|
||||
* with Y, etc.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The algorithm takes a string, and looks up the corresponding reversed letter
|
||||
* for each letter in the word and replaces it. Spaces are ignored and case is
|
||||
* preserved.
|
||||
*
|
||||
* @author [Focusucof](https://github.com/Focusucof)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <map> /// for std::map
|
||||
#include <string> /// for std::string
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace atbash
|
||||
* \brief Functions for the [Atbash
|
||||
* Cipher](https://en.wikipedia.org/wiki/Atbash) implementation
|
||||
*/
|
||||
namespace atbash {
|
||||
std::map<char, char> atbash_cipher_map = {
|
||||
{'a', 'z'}, {'b', 'y'}, {'c', 'x'}, {'d', 'w'}, {'e', 'v'}, {'f', 'u'},
|
||||
{'g', 't'}, {'h', 's'}, {'i', 'r'}, {'j', 'q'}, {'k', 'p'}, {'l', 'o'},
|
||||
{'m', 'n'}, {'n', 'm'}, {'o', 'l'}, {'p', 'k'}, {'q', 'j'}, {'r', 'i'},
|
||||
{'s', 'h'}, {'t', 'g'}, {'u', 'f'}, {'v', 'e'}, {'w', 'd'}, {'x', 'c'},
|
||||
{'y', 'b'}, {'z', 'a'}, {'A', 'Z'}, {'B', 'Y'}, {'C', 'X'}, {'D', 'W'},
|
||||
{'E', 'V'}, {'F', 'U'}, {'G', 'T'}, {'H', 'S'}, {'I', 'R'}, {'J', 'Q'},
|
||||
{'K', 'P'}, {'L', 'O'}, {'M', 'N'}, {'N', 'M'}, {'O', 'L'}, {'P', 'K'},
|
||||
{'Q', 'J'}, {'R', 'I'}, {'S', 'H'}, {'T', 'G'}, {'U', 'F'}, {'V', 'E'},
|
||||
{'W', 'D'}, {'X', 'C'}, {'Y', 'B'}, {'Z', 'A'}, {' ', ' '}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief atbash cipher encryption and decryption
|
||||
* @param text Plaintext to be encrypted
|
||||
* @returns encoded or decoded string
|
||||
*/
|
||||
std::string atbash_cipher(const std::string& text) {
|
||||
std::string result;
|
||||
for (char letter : text) {
|
||||
result += atbash_cipher_map[letter];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace atbash
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::string text = "Hello World";
|
||||
std::string expected = "Svool Dliow";
|
||||
std::string encrypted_text = ciphers::atbash::atbash_cipher(text);
|
||||
std::string decrypted_text = ciphers::atbash::atbash_cipher(encrypted_text);
|
||||
assert(expected == encrypted_text);
|
||||
assert(text == decrypted_text);
|
||||
std::cout << "Original text: " << text << std::endl;
|
||||
std::cout << ", Expected text: " << expected << std::endl;
|
||||
std::cout << ", Encrypted text: " << encrypted_text << std::endl;
|
||||
std::cout << ", Decrypted text: " << decrypted_text << std::endl;
|
||||
std::cout << "\nAll tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* @brief [Base64 Encoding and
|
||||
* Decoding](https://en.wikipedia.org/wiki/Base64)
|
||||
* @details In programming, [Base64](https://en.wikipedia.org/wiki/Base64) is a
|
||||
* group of binary-to-text encoding schemes that represent binary data (more
|
||||
* specifically, a sequence of 8-bit bytes) in an ASCII string format by
|
||||
* translating the data into a radix-64 representation. The term Base64
|
||||
* originates from a specific MIME content transfer encoding. Each non-final
|
||||
* Base64 digit represents exactly 6 bits of data. Three 8-bit bytes (i.e., a
|
||||
* total of 24 bits) can therefore be represented by four 6-bit Base64
|
||||
* digits.
|
||||
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
|
||||
*/
|
||||
#include <cassert> /// for `assert` operations
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace ciphers
|
||||
* @brief Cipher algorithms
|
||||
*/
|
||||
namespace ciphers {
|
||||
/**
|
||||
* @namespace base64_encoding
|
||||
* @brief Functions for [Base64 Encoding and
|
||||
* Decoding](https://en.wikipedia.org/wiki/Base64) implementation.
|
||||
*/
|
||||
namespace base64_encoding {
|
||||
// chars denoting the format for encoding and decoding array.
|
||||
// This array is already decided by
|
||||
// [RFC4648](https://tools.ietf.org/html/rfc4648#section-4) standard
|
||||
const std::string chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
/**
|
||||
* @brief Base64 Encoder
|
||||
* @details Converts the given string to Base64 equivalent.
|
||||
* @param input Input as a string
|
||||
* @returns Base64 encoded string
|
||||
*/
|
||||
std::string base64_encode(const std::string &input) {
|
||||
std::string base64_string; /// Output of this function: base64 string
|
||||
// base64 deals with 6-bit chars encoded as per chars, so
|
||||
// we will always filter 6-bits from input.
|
||||
for (uint32_t i = 0; i < input.size(); i += 3) {
|
||||
char first_byte = input[i]; /// First byte of the iteration
|
||||
// Take first six bits of first character.
|
||||
// Encode the first six bits with character defined in string `chars`
|
||||
base64_string.push_back(chars[first_byte >> 2]);
|
||||
|
||||
if (i + 1 < input.size()) {
|
||||
char second_byte = input[i + 1]; /// Second byte of the iteration
|
||||
// Take remaining two bits of first character, and four first bits
|
||||
// from second character Combine two numbers as 6-bit digits and
|
||||
// encode by array chars (first two bits of first byte and next four
|
||||
// of second byte)
|
||||
base64_string.push_back(
|
||||
chars[(((first_byte & 3) << 4) | ((second_byte & 0xF0) >> 4))]);
|
||||
|
||||
if (i + 2 < input.size()) {
|
||||
char third_byte = input[i + 2]; /// Third byte of the iteration
|
||||
// Take remaining four bits of second character, and first two
|
||||
// bits from third character Combine two numbers as 6-bit digits
|
||||
// and encode by array chars (remaining four bits of second byte
|
||||
// and first two of third byte)
|
||||
base64_string.push_back(chars[((third_byte & 0xC0) >> 6) |
|
||||
((second_byte & 0x0F) << 2)]);
|
||||
// Encode remaining 6-bit of third byte by array chars
|
||||
base64_string.push_back(chars[(third_byte & 0x3F)]);
|
||||
} else {
|
||||
// Take remaining four bits of second character as 6-bit number
|
||||
base64_string.push_back(chars[((second_byte & 0x0F) << 2)]);
|
||||
base64_string.push_back('='); // padding characters
|
||||
}
|
||||
} else {
|
||||
// Take remaining two bits of first character as 6-bit number
|
||||
base64_string.push_back(chars[((first_byte & 3) << 4)]);
|
||||
base64_string.push_back('='); // padding characters
|
||||
base64_string.push_back('='); // padding characters
|
||||
}
|
||||
}
|
||||
return base64_string;
|
||||
}
|
||||
/**
|
||||
* @brief Utility function for finding index
|
||||
* @details Utility function for finding the position of a character in array
|
||||
* `chars`
|
||||
* @param c character to search in array `chars`
|
||||
* @returns integer denoting position of character in array `chars`
|
||||
*/
|
||||
uint8_t find_idx(const char c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return c - 'A';
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
return c - 'a' + 26;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
return c - '0' + 52;
|
||||
} else if (c == '+') {
|
||||
return 62;
|
||||
} else if (c == '/') {
|
||||
return 63;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* @brief Base64 Decoder
|
||||
* @details Decodes the Base64 string
|
||||
* @param base64_str Input as a Base64 string
|
||||
* @returns Base64 decoded string
|
||||
*/
|
||||
std::string base64_decode(const std::string &base64_str) {
|
||||
std::string
|
||||
base64_decoded; /// Output of this function: base64 decoded string
|
||||
for (uint32_t i = 0; i < base64_str.size(); i += 4) {
|
||||
/// First 6-bit representation of Base64
|
||||
char first_byte = base64_str[i];
|
||||
/// Second 6-bit representation of Base64
|
||||
char second_byte = base64_str[i + 1];
|
||||
// Actual str characters are of 8 bits (or 1 byte):
|
||||
// :: 8 bits are decode by taking 6 bits from 1st byte of base64 string
|
||||
// and first 2 bits from 2nd byte of base64 string.
|
||||
char first_actual_byte = static_cast<char>(
|
||||
(find_idx(first_byte) << 2) | ((find_idx(second_byte)) >> 4));
|
||||
base64_decoded.push_back(first_actual_byte);
|
||||
if (i + 2 < base64_str.size() && base64_str[i + 2] != '=') {
|
||||
/// Third 6-bit representation of Base64
|
||||
char third_byte = base64_str[i + 2];
|
||||
// :: Next 8 bits are decode by taking remaining 4 bits from 2nd
|
||||
// byte of base64 string and first 4 bits from 3rd byte of base64
|
||||
// string.
|
||||
char second_actual_byte =
|
||||
static_cast<char>(((find_idx(second_byte) & 0x0F) << 4) |
|
||||
(find_idx(third_byte) >> 2));
|
||||
base64_decoded.push_back(second_actual_byte);
|
||||
|
||||
if (i + 3 < base64_str.size() && base64_str[i + 3] != '=') {
|
||||
/// Fourth 6-bit representation of Base64 string
|
||||
char fourth_byte = base64_str[i + 3];
|
||||
// :: Taking remaining 2 bits from 3rd byte of base64 string
|
||||
// and all 6 bits from 4th byte of base64 string.
|
||||
char third_actual_byte =
|
||||
static_cast<char>(((find_idx(third_byte) & 0x03) << 6) |
|
||||
find_idx(fourth_byte));
|
||||
base64_decoded.push_back(third_actual_byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
return base64_decoded;
|
||||
}
|
||||
} // namespace base64_encoding
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self test-implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st Test
|
||||
std::string str =
|
||||
"To err is human, but to really foul things up you need a computer.";
|
||||
std::string base64_str = ciphers::base64_encoding::base64_encode(str);
|
||||
std::string verify =
|
||||
"VG8gZXJyIGlzIGh1bWFuLCBidXQgdG8gcmVhbGx5IGZvdWwgdGhpbmdzIHVwIHlvdSBuZW"
|
||||
"VkIGEgY29tcHV0ZXIu";
|
||||
// verify encoding
|
||||
assert(base64_str == verify);
|
||||
std::string original_str =
|
||||
ciphers::base64_encoding::base64_decode(base64_str);
|
||||
// verify decoding
|
||||
assert(original_str == str);
|
||||
|
||||
// 2nd Test from [Wikipedia](https://en.wikipedia.org/wiki/Base64)
|
||||
str =
|
||||
"Man is distinguished, not only by his reason, but by this singular "
|
||||
"passion from other animals, which is a lust of the mind, that by a "
|
||||
"perseverance of delight in the continued and indefatigable generation "
|
||||
"of knowledge, exceeds the short vehemence of any carnal pleasure.";
|
||||
|
||||
base64_str = ciphers::base64_encoding::base64_encode(str);
|
||||
verify =
|
||||
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieS"
|
||||
"B0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBh"
|
||||
"IGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodC"
|
||||
"BpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25v"
|
||||
"d2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbG"
|
||||
"Vhc3VyZS4=";
|
||||
// verify encoding
|
||||
assert(base64_str == verify);
|
||||
original_str = ciphers::base64_encoding::base64_decode(base64_str);
|
||||
// verify decoding
|
||||
assert(original_str == str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file caesar_cipher.cpp
|
||||
* @brief Implementation of [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) algorithm.
|
||||
*
|
||||
* @details
|
||||
* In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher,
|
||||
* Caesar's code or Caesar shift, is one of the simplest and most widely known encryption
|
||||
* techniques. It is a type of substitution cipher in which each letter in the plaintext
|
||||
* is replaced by a letter some fixed number of positions down the alphabet. For example,
|
||||
* with a left shift of 3, D would be replaced by A, E would become B, and so on.
|
||||
* The method is named after Julius Caesar, who used it in his private correspondence.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The encryption can also be represented using modular arithmetic by first transforming
|
||||
* the letters into numbers, according to the scheme, A → 0, B → 1, ..., Z → 25.
|
||||
* Encryption of a letter x by a shift n can be described mathematically as,
|
||||
* \f[ E(x) = (x + n)\;\mbox{mod}\; 26\f]
|
||||
* while decryption can be described as,
|
||||
* \f[ D(x) = (x - n) \;\mbox{mod}\; 26\f]
|
||||
*
|
||||
* \note This program implements caesar cipher for only uppercase English alphabet characters (i.e. A-Z).
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace caesar
|
||||
* \brief Functions for [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) algorithm.
|
||||
*/
|
||||
namespace caesar {
|
||||
namespace {
|
||||
/**
|
||||
* This function finds character for given value (i.e.A-Z)
|
||||
* @param x value for which we want character
|
||||
* @returns corresponding character for perticular value
|
||||
*/
|
||||
inline char get_char(const int x) {
|
||||
// By adding 65 we are scaling 0-25 to 65-90.
|
||||
// Which are in fact ASCII values of A-Z.
|
||||
return char(x + 65);
|
||||
}
|
||||
/**
|
||||
* This function finds value for given character (i.e.0-25)
|
||||
* @param c character for which we want value
|
||||
* @returns returns corresponding value for perticular character
|
||||
*/
|
||||
inline int get_value(const char c) {
|
||||
// A-Z have ASCII values in range 65-90.
|
||||
// Hence subtracting 65 will scale them to 0-25.
|
||||
return int(c - 65);
|
||||
}
|
||||
} // Unnamed namespace
|
||||
/**
|
||||
* Encrypt given text using caesar cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param shift number of shifts to be applied
|
||||
* @returns new encrypted text
|
||||
*/
|
||||
std::string encrypt (const std::string &text, const int &shift) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
for (char c : text) { // Going through each character
|
||||
int place_value = get_value(c); // Getting value of character (i.e. 0-25)
|
||||
place_value = (place_value + shift) % 26; // Applying encryption formula
|
||||
char new_char = get_char(place_value); // Getting new character from new value (i.e. A-Z)
|
||||
encrypted_text += new_char; // Appending encrypted character
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given text using caesar cipher.
|
||||
* @param text text to be decrypted
|
||||
* @param shift number of shifts to be applied
|
||||
* @returns new decrypted text
|
||||
*/
|
||||
std::string decrypt (const std::string &text, const int &shift) {
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
for (char c : text) { // Going through each character
|
||||
int place_value = get_value(c); // Getting value of character (i.e. 0-25)
|
||||
place_value = (place_value - shift) % 26;// Applying decryption formula
|
||||
if(place_value < 0) { // Handling case where remainder is negative
|
||||
place_value = place_value + 26;
|
||||
}
|
||||
char new_char = get_char(place_value); // Getting original character from decrypted value (i.e. A-Z)
|
||||
decrypted_text += new_char; // Appending decrypted character
|
||||
}
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace caesar
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::string text1 = "ALANTURING";
|
||||
std::string encrypted1 = ciphers::caesar::encrypt(text1, 17);
|
||||
std::string decrypted1 = ciphers::caesar::decrypt(encrypted1, 17);
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1;
|
||||
std::cout << " , Encrypted text (with shift = 21) : " << encrypted1;
|
||||
std::cout << " , Decrypted text : "<< decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "HELLOWORLD";
|
||||
std::string encrypted2 = ciphers::caesar::encrypt(text2, 1729);
|
||||
std::string decrypted2 = ciphers::caesar::decrypt(encrypted2, 1729);
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2;
|
||||
std::cout << " , Encrypted text (with shift = 1729) : " << encrypted2;
|
||||
std::cout << " , Decrypted text : "<< decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Elliptic Curve Diffie Hellman Key
|
||||
* Exchange](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange).
|
||||
*
|
||||
* @details
|
||||
* The ECDH (Elliptic Curve Diffie–Hellman Key Exchange) is anonymous key
|
||||
* agreement scheme, which allows two parties, each having an elliptic-curve
|
||||
* public–private key pair, to establish a shared secret over an insecure
|
||||
* channel.
|
||||
* ECDH is very similar to the classical DHKE (Diffie–Hellman Key Exchange)
|
||||
* algorithm, but it uses ECC point multiplication instead of modular
|
||||
* exponentiations. ECDH is based on the following property of EC points:
|
||||
* (a * G) * b = (b * G) * a
|
||||
* If we have two secret numbers a and b (two private keys, belonging to Alice
|
||||
* and Bob) and an ECC elliptic curve with generator point G, we can exchange
|
||||
* over an insecure channel the values (a * G) and (b * G) (the public keys of
|
||||
* Alice and Bob) and then we can derive a shared secret:
|
||||
* secret = (a * G) * b = (b * G) * a.
|
||||
* Pretty simple. The above equation takes the following form:
|
||||
* alicePubKey * bobPrivKey = bobPubKey * alicePrivKey = secret
|
||||
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
#include "uint256_t.hpp" /// for 256-bit integer
|
||||
|
||||
/**
|
||||
* @namespace ciphers
|
||||
* @brief Cipher algorithms
|
||||
*/
|
||||
namespace ciphers {
|
||||
/**
|
||||
* @brief namespace elliptic_curve_key_exchange
|
||||
* @details Demonstration of [Elliptic Curve
|
||||
* Diffie-Hellman](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange)
|
||||
* key exchange.
|
||||
*/
|
||||
namespace elliptic_curve_key_exchange {
|
||||
|
||||
/**
|
||||
* @brief Definition of struct Point
|
||||
* @details Definition of Point in the curve.
|
||||
*/
|
||||
typedef struct Point {
|
||||
uint256_t x, y; /// x and y co-ordinates
|
||||
|
||||
/**
|
||||
* @brief operator == for Point
|
||||
* @details check whether co-ordinates are equal to the given point
|
||||
* @param p given point to be checked with this
|
||||
* @returns true if x and y are both equal with Point p, else false
|
||||
*/
|
||||
inline bool operator==(const Point &p) { return x == p.x && y == p.y; }
|
||||
|
||||
/**
|
||||
* @brief ostream operator for printing Point
|
||||
* @param op ostream operator
|
||||
* @param p Point to be printed on console
|
||||
* @returns op, the ostream object
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &op, const Point &p) {
|
||||
op << p.x << " " << p.y;
|
||||
return op;
|
||||
}
|
||||
} Point;
|
||||
|
||||
/**
|
||||
* @brief This function calculates number raised to exponent power under modulo
|
||||
* mod using [Modular
|
||||
* Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_exponentiation.cpp).
|
||||
* @param number integer base
|
||||
* @param power unsigned integer exponent
|
||||
* @param mod integer modulo
|
||||
* @return number raised to power modulo mod
|
||||
*/
|
||||
uint256_t exp(uint256_t number, uint256_t power, const uint256_t &mod) {
|
||||
if (!power) {
|
||||
return uint256_t(1);
|
||||
}
|
||||
uint256_t ans(1);
|
||||
number = number % mod;
|
||||
while (power) {
|
||||
if ((power & 1)) {
|
||||
ans = (ans * number) % mod;
|
||||
}
|
||||
power >>= 1;
|
||||
if (power) {
|
||||
number = (number * number) % mod;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Addition of points
|
||||
* @details Add given point to generate third point. More description can be
|
||||
* found
|
||||
* [here](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_addition),
|
||||
* and
|
||||
* [here](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_doubling)
|
||||
* @param a First point
|
||||
* @param b Second point
|
||||
* @param curve_a_coeff Coefficient `a` of the given curve (y^2 = x^3 + ax + b)
|
||||
* % mod
|
||||
* @param mod Given field
|
||||
* @return the resultant point
|
||||
*/
|
||||
Point addition(Point a, Point b, const uint256_t &curve_a_coeff,
|
||||
uint256_t mod) {
|
||||
uint256_t lambda(0); /// Slope
|
||||
uint256_t zero(0); /// value zero
|
||||
lambda = zero = 0;
|
||||
uint256_t inf = ~zero;
|
||||
if (a.x != b.x || a.y != b.y) {
|
||||
// Slope being infinite.
|
||||
if (b.x == a.x) {
|
||||
return {inf, inf};
|
||||
}
|
||||
uint256_t num = (b.y - a.y + mod), den = (b.x - a.x + mod);
|
||||
lambda = (num * (exp(den, mod - 2, mod))) % mod;
|
||||
} else {
|
||||
/**
|
||||
* slope when the line is tangent to curve. This operation is performed
|
||||
* while doubling. Taking derivative of `y^2 = x^3 + ax + b`
|
||||
* => `2y dy = (3 * x^2 + a)dx`
|
||||
* => `(dy/dx) = (3x^2 + a)/(2y)`
|
||||
*/
|
||||
/**
|
||||
* if y co-ordinate is zero, the slope is infinite, return inf.
|
||||
* else calculate the slope (here % mod and store in lambda)
|
||||
*/
|
||||
if (!a.y) {
|
||||
return {inf, inf};
|
||||
}
|
||||
uint256_t axsq = ((a.x * a.x)) % mod;
|
||||
// Mulitply by 3 adjustment
|
||||
axsq += (axsq << 1);
|
||||
axsq %= mod;
|
||||
// Mulitply by 2 adjustment
|
||||
uint256_t a_2 = (a.y << 1);
|
||||
lambda =
|
||||
(((axsq + curve_a_coeff) % mod) * exp(a_2, mod - 2, mod)) % mod;
|
||||
}
|
||||
Point c;
|
||||
// new point: x = ((lambda^2) - x1 - x2)
|
||||
// y = (lambda * (x1 - x)) - y1
|
||||
c.x = ((lambda * lambda) % mod + (mod << 1) - a.x - b.x) % mod;
|
||||
c.y = (((lambda * (a.x + mod - c.x)) % mod) + mod - a.y) % mod;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief multiply Point and integer
|
||||
* @details Multiply Point by a scalar factor (here it is a private key p). The
|
||||
* multiplication is called as [double and add
|
||||
* method](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add)
|
||||
* @param a Point to multiply
|
||||
* @param curve_a_coeff Coefficient of given curve (y^2 = x^3 + ax + b) % mod
|
||||
* @param p The scalar value
|
||||
* @param mod Given field
|
||||
* @returns the resultant point
|
||||
*/
|
||||
Point multiply(const Point &a, const uint256_t &curve_a_coeff, uint256_t p,
|
||||
const uint256_t &mod) {
|
||||
Point N = a;
|
||||
N.x %= mod;
|
||||
N.y %= mod;
|
||||
uint256_t inf{};
|
||||
inf = ~uint256_t(0);
|
||||
Point Q = {inf, inf};
|
||||
while (p) {
|
||||
if ((p & 1)) {
|
||||
if (Q.x == inf && Q.y == inf) {
|
||||
Q.x = N.x;
|
||||
Q.y = N.y;
|
||||
} else {
|
||||
Q = addition(Q, N, curve_a_coeff, mod);
|
||||
}
|
||||
}
|
||||
p >>= 1;
|
||||
if (p) {
|
||||
N = addition(N, N, curve_a_coeff, mod);
|
||||
}
|
||||
}
|
||||
return Q;
|
||||
}
|
||||
} // namespace elliptic_curve_key_exchange
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* uint128_t header
|
||||
* @returns void
|
||||
*/
|
||||
static void uint128_t_tests() {
|
||||
// 1st test: Operations test
|
||||
uint128_t a("122"), b("2312");
|
||||
assert(a + b == 2434);
|
||||
assert(b - a == 2190);
|
||||
assert(a * b == 282064);
|
||||
assert(b / a == 18);
|
||||
assert(b % a == 116);
|
||||
assert((a & b) == 8);
|
||||
assert((a | b) == 2426);
|
||||
assert((a ^ b) == 2418);
|
||||
assert((a << 64) == uint128_t("2250502776992565297152"));
|
||||
assert((b >> 7) == 18);
|
||||
|
||||
// 2nd test: Operations test
|
||||
a = uint128_t("12321421424232142122");
|
||||
b = uint128_t("23123212");
|
||||
assert(a + b == uint128_t("12321421424255265334"));
|
||||
assert(a - b == uint128_t("12321421424209018910"));
|
||||
assert(a * b == uint128_t("284910839733861759501135864"));
|
||||
assert(a / b == 532859423865LL);
|
||||
assert(a % b == 3887742);
|
||||
assert((a & b) == 18912520);
|
||||
assert((a | b) == uint128_t("12321421424236352814"));
|
||||
assert((a ^ b) == uint128_t("12321421424217440294"));
|
||||
assert((a << 64) == uint128_t("227290107637132170748078080907806769152"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* uint256_t header
|
||||
* @returns void
|
||||
*/
|
||||
static void uint256_t_tests() {
|
||||
// 1st test: Operations test
|
||||
uint256_t a("122"), b("2312");
|
||||
assert(a + b == 2434);
|
||||
assert(b - a == 2190);
|
||||
assert(a * b == 282064);
|
||||
assert(b / a == 18);
|
||||
assert(b % a == 116);
|
||||
assert((a & b) == 8);
|
||||
assert((a | b) == 2426);
|
||||
assert((a ^ b) == 2418);
|
||||
assert((a << 64) == uint256_t("2250502776992565297152"));
|
||||
assert((b >> 7) == 18);
|
||||
|
||||
// 2nd test: Operations test
|
||||
a = uint256_t("12321423124513251424232142122");
|
||||
b = uint256_t("23124312431243243215354315132413213212");
|
||||
assert(a + b == uint256_t("23124312443564666339867566556645355334"));
|
||||
// Since a < b, the value is greater
|
||||
assert(a - b == uint256_t("115792089237316195423570985008687907853246860353"
|
||||
"221642219366742944204948568846"));
|
||||
assert(a * b == uint256_t("284924437928789743312147393953938013677909398222"
|
||||
"169728183872115864"));
|
||||
assert(b / a == uint256_t("1876756621"));
|
||||
assert(b % a == uint256_t("2170491202688962563936723450"));
|
||||
assert((a & b) == uint256_t("3553901085693256462344"));
|
||||
assert((a | b) == uint256_t("23124312443564662785966480863388892990"));
|
||||
assert((a ^ b) == uint256_t("23124312443564659232065395170132430646"));
|
||||
assert((a << 128) == uint256_t("4192763024643754272961909047609369343091683"
|
||||
"376561852756163540549632"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* provided algorithm above
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// demonstration of key exchange using curve secp112r1
|
||||
|
||||
// Equation of the form y^2 = (x^3 + ax + b) % P (here p is mod)
|
||||
uint256_t a("4451685225093714772084598273548424"),
|
||||
b("2061118396808653202902996166388514"),
|
||||
mod("4451685225093714772084598273548427");
|
||||
|
||||
// Generator value: is pre-defined for the given curve
|
||||
ciphers::elliptic_curve_key_exchange::Point ptr = {
|
||||
uint256_t("188281465057972534892223778713752"),
|
||||
uint256_t("3419875491033170827167861896082688")};
|
||||
|
||||
// Shared key generation.
|
||||
// For alice
|
||||
std::cout << "For alice:\n";
|
||||
// Alice's private key (can be generated randomly)
|
||||
uint256_t alice_private_key("164330438812053169644452143505618");
|
||||
ciphers::elliptic_curve_key_exchange::Point alice_public_key =
|
||||
multiply(ptr, a, alice_private_key, mod);
|
||||
std::cout << "\tPrivate key: " << alice_private_key << "\n";
|
||||
std::cout << "\tPublic Key: " << alice_public_key << std::endl;
|
||||
|
||||
// For Bob
|
||||
std::cout << "For Bob:\n";
|
||||
// Bob's private key (can be generated randomly)
|
||||
uint256_t bob_private_key("1959473333748537081510525763478373");
|
||||
ciphers::elliptic_curve_key_exchange::Point bob_public_key =
|
||||
multiply(ptr, a, bob_private_key, mod);
|
||||
std::cout << "\tPrivate key: " << bob_private_key << "\n";
|
||||
std::cout << "\tPublic Key: " << bob_public_key << std::endl;
|
||||
|
||||
// After public key exchange, create a shared key for communication.
|
||||
// create shared key:
|
||||
ciphers::elliptic_curve_key_exchange::Point alice_shared_key = multiply(
|
||||
bob_public_key, a,
|
||||
alice_private_key, mod),
|
||||
bob_shared_key = multiply(
|
||||
alice_public_key, a,
|
||||
bob_private_key, mod);
|
||||
|
||||
std::cout << "Shared keys:\n";
|
||||
std::cout << alice_shared_key << std::endl;
|
||||
std::cout << bob_shared_key << std::endl;
|
||||
|
||||
// Check whether shared keys are equal
|
||||
assert(alice_shared_key == bob_shared_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
uint128_t_tests(); // running predefined 128-bit unsigned integer tests
|
||||
uint256_t_tests(); // running predefined 256-bit unsigned integer tests
|
||||
test(); // running self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/**
|
||||
* @file hill_cipher.cpp
|
||||
* @brief Implementation of [Hill
|
||||
* cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm.
|
||||
*
|
||||
* Program to generate the encryption-decryption key and perform encryption and
|
||||
* decryption of ASCII text using the famous block cipher algorithm. This is a
|
||||
* powerful encryption algorithm that is relatively easy to implement with a
|
||||
* given key. The strength of the algorithm depends on the size of the block
|
||||
* encryption matrix key; the bigger the matrix, the stronger the encryption and
|
||||
* more difficult to break it. However, the important requirement for the matrix
|
||||
* is that:
|
||||
* 1. matrix should be invertible - all inversion conditions should be satisfied
|
||||
* and
|
||||
* 2. its determinant must not have any common factors with the length of
|
||||
* character set
|
||||
* Due to this restriction, most implementations only implement with small 3x3
|
||||
* encryption keys and a small subset of ASCII alphabets.
|
||||
*
|
||||
* In the current implementation, I present to you an implementation for
|
||||
* generating larger encryption keys (I have attempted upto 10x10) and an ASCII
|
||||
* character set of 97 printable characters. Hence, a typical ASCII text file
|
||||
* could be easily encrypted with the module. The larger character set increases
|
||||
* the modulo of cipher and hence the matrix determinants can get very large
|
||||
* very quickly rendering them ill-defined.
|
||||
*
|
||||
* \note This program uses determinant computation using LU decomposition from
|
||||
* the file lu_decomposition.h
|
||||
* \note The matrix generation algorithm is very rudimentary and does not
|
||||
* guarantee an invertible modulus matrix. \todo Better matrix generation
|
||||
* algorithm.
|
||||
*
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "../numerical_methods/lu_decomposition.h"
|
||||
|
||||
/**
|
||||
* operator to print a matrix
|
||||
*/
|
||||
template <typename T>
|
||||
static std::ostream &operator<<(std::ostream &out, matrix<T> const &v) {
|
||||
const int width = 15;
|
||||
const char separator = ' ';
|
||||
|
||||
for (size_t row = 0; row < v.size(); row++) {
|
||||
for (size_t col = 0; col < v[row].size(); col++)
|
||||
out << std::left << std::setw(width) << std::setfill(separator)
|
||||
<< v[row][col];
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** dictionary of characters that can be encrypted and decrypted */
|
||||
static const char *STRKEY =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&"
|
||||
"*()_+`-=[]{}|;':\",./<>?\\\r\n \0";
|
||||
|
||||
/**
|
||||
* @brief Implementation of [Hill
|
||||
* Cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm
|
||||
*/
|
||||
class HillCipher {
|
||||
private:
|
||||
/**
|
||||
* @brief Function to generate a random integer in a given interval
|
||||
*
|
||||
* @param a lower limit of interval
|
||||
* @param b upper limit of interval
|
||||
* @tparam T type of output
|
||||
* @return random integer in the interval \f$[a,b)\f$
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
static const T2 rand_range(T1 a, T1 b) {
|
||||
// generate random number between 0 and 1
|
||||
long double r = static_cast<long double>(std::rand()) / RAND_MAX;
|
||||
|
||||
// scale and return random number as integer
|
||||
return static_cast<T2>(r * (b - a) + a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function overload to fill a matrix with random integers in a given
|
||||
* interval
|
||||
*
|
||||
* @param M pointer to matrix to be filled with random numbers
|
||||
* @param a lower limit of interval
|
||||
* @param b upper limit of interval
|
||||
* @tparam T1 type of input range
|
||||
* @tparam T2 type of matrix
|
||||
* @return determinant of generated random matrix
|
||||
*
|
||||
* @warning There will need to be a balance between the matrix size and the
|
||||
* range of random numbers. If the matrix is large, the range of random
|
||||
* numbers must be small to have a well defined keys. Or if the matrix is
|
||||
* smaller, the random numbers range can be larger. For an 8x8 matrix, range
|
||||
* should be no more than \f$[0,10]\f$
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
static double rand_range(matrix<T2> *M, T1 a, T1 b) {
|
||||
for (size_t i = 0; i < M->size(); i++) {
|
||||
for (size_t j = 0; j < M[0][0].size(); j++) {
|
||||
M[0][i][j] = rand_range<T1, T2>(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
return determinant_lu(*M);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute
|
||||
* [GCD](https://en.wikipedia.org/wiki/Greatest_common_divisor) of two
|
||||
* integers using Euler's algorithm
|
||||
*
|
||||
* @param a first number
|
||||
* @param b second number
|
||||
* @return GCD of \f$a\f$ and \f$b\f$
|
||||
*/
|
||||
template <typename T>
|
||||
static const T gcd(T a, T b) {
|
||||
if (b > a) // ensure always a < b
|
||||
std::swap(a, b);
|
||||
|
||||
while (b != 0) {
|
||||
T tmp = b;
|
||||
b = a % b;
|
||||
a = tmp;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function to perform vector multiplication with encryption
|
||||
* or decryption matrix
|
||||
*
|
||||
* @param vector vector to multiply
|
||||
* @param key encryption or decryption key matrix
|
||||
* @return corresponding encrypted or decrypted text
|
||||
*/
|
||||
static const std::valarray<uint8_t> mat_mul(
|
||||
const std::valarray<uint8_t> &vector, const matrix<int> &key) {
|
||||
std::valarray<uint8_t> out(vector); // make a copy
|
||||
|
||||
size_t L = std::strlen(STRKEY);
|
||||
|
||||
for (size_t i = 0; i < key.size(); i++) {
|
||||
int tmp = 0;
|
||||
for (size_t j = 0; j < vector.size(); j++) {
|
||||
tmp += key[i][j] * vector[j];
|
||||
}
|
||||
out[i] = static_cast<uint8_t>(tmp % L);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the character at a given index in the ::STRKEY
|
||||
*
|
||||
* @param idx index value
|
||||
* @return character at the index
|
||||
*/
|
||||
static inline char get_idx_char(const uint8_t idx) { return STRKEY[idx]; }
|
||||
|
||||
/**
|
||||
* @brief Get the index of a character in the ::STRKEY
|
||||
*
|
||||
* @param ch character to search
|
||||
* @return index of character
|
||||
*/
|
||||
static inline uint8_t get_char_idx(const char ch) {
|
||||
size_t L = std::strlen(STRKEY);
|
||||
|
||||
for (size_t idx = 0; idx <= L; idx++)
|
||||
if (STRKEY[idx] == ch)
|
||||
return idx;
|
||||
|
||||
std::cerr << __func__ << ":" << __LINE__ << ": (" << ch
|
||||
<< ") Should not reach here!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convenience function to perform block cipher operations. The
|
||||
* operations are identical for both encryption and decryption.
|
||||
*
|
||||
* @param text input text to encrypt or decrypt
|
||||
* @param key key for encryption or decryption
|
||||
* @return encrypted/decrypted output
|
||||
*/
|
||||
static const std::string codec(const std::string &text,
|
||||
const matrix<int> &key) {
|
||||
size_t text_len = text.length();
|
||||
size_t key_len = key.size();
|
||||
|
||||
// length of output string must be a multiple of key_len
|
||||
// create output string and initialize with '\0' character
|
||||
size_t L2 = text_len % key_len == 0
|
||||
? text_len
|
||||
: text_len + key_len - (text_len % key_len);
|
||||
std::string coded_text(L2, '\0');
|
||||
|
||||
// temporary array for batch processing
|
||||
int i;
|
||||
#ifdef _OPENMP
|
||||
#pragma parallel omp for private(i)
|
||||
#endif
|
||||
for (i = 0; i < L2 - key_len + 1; i += key_len) {
|
||||
std::valarray<uint8_t> batch_int(key_len);
|
||||
for (size_t j = 0; j < key_len; j++) {
|
||||
batch_int[j] = get_char_idx(text[i + j]);
|
||||
}
|
||||
|
||||
batch_int = mat_mul(batch_int, key);
|
||||
|
||||
for (size_t j = 0; j < key_len; j++) {
|
||||
coded_text[i + j] =
|
||||
STRKEY[batch_int[j]]; // get character at key
|
||||
}
|
||||
}
|
||||
|
||||
return coded_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matrix inverse using Row-transformations. Given matrix must
|
||||
* be a square and non-singular.
|
||||
* \returns inverse matrix
|
||||
**/
|
||||
template <typename T>
|
||||
static matrix<double> get_inverse(matrix<T> const &A) {
|
||||
// Assuming A is square matrix
|
||||
size_t N = A.size();
|
||||
|
||||
matrix<double> inverse(N, std::valarray<double>(N));
|
||||
for (size_t row = 0; row < N; row++) {
|
||||
for (size_t col = 0; col < N; col++) {
|
||||
// create identity matrix
|
||||
inverse[row][col] = (row == col) ? 1.f : 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (A.size() != A[0].size()) {
|
||||
std::cerr << "A must be a square matrix!" << std::endl;
|
||||
return inverse;
|
||||
}
|
||||
|
||||
// preallocate a temporary matrix identical to A
|
||||
matrix<double> temp(N, std::valarray<double>(N));
|
||||
for (size_t row = 0; row < N; row++) {
|
||||
for (size_t col = 0; col < N; col++)
|
||||
temp[row][col] = static_cast<double>(A[row][col]);
|
||||
}
|
||||
|
||||
// start transformations
|
||||
for (size_t row = 0; row < N; row++) {
|
||||
for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) {
|
||||
// this to ensure diagonal elements are not 0
|
||||
temp[row] = temp[row] + temp[row2];
|
||||
inverse[row] = inverse[row] + inverse[row2];
|
||||
}
|
||||
|
||||
for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) {
|
||||
// this to further ensure diagonal elements are not 0
|
||||
for (size_t row2 = 0; row2 < N; row2++) {
|
||||
temp[row2][row] = temp[row2][row] + temp[row2][col2];
|
||||
inverse[row2][row] =
|
||||
inverse[row2][row] + inverse[row2][col2];
|
||||
}
|
||||
}
|
||||
|
||||
if (temp[row][row] == 0) {
|
||||
// Probably a low-rank matrix and hence singular
|
||||
std::cerr << "Low-rank matrix, no inverse!" << std::endl;
|
||||
return inverse;
|
||||
}
|
||||
|
||||
// set diagonal to 1
|
||||
double divisor = temp[row][row];
|
||||
temp[row] = temp[row] / divisor;
|
||||
inverse[row] = inverse[row] / divisor;
|
||||
// Row transformations
|
||||
for (size_t row2 = 0; row2 < N; row2++) {
|
||||
if (row2 == row)
|
||||
continue;
|
||||
double factor = temp[row2][row];
|
||||
temp[row2] = temp[row2] - factor * temp[row];
|
||||
inverse[row2] = inverse[row2] - factor * inverse[row];
|
||||
}
|
||||
}
|
||||
|
||||
return inverse;
|
||||
}
|
||||
|
||||
static int modulo(int a, int b) {
|
||||
int ret = a % b;
|
||||
if (ret < 0)
|
||||
ret += b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Generate encryption matrix of a given size. Larger size matrices
|
||||
* are difficult to generate but provide more security. Important conditions
|
||||
* are:
|
||||
* 1. matrix should be invertible
|
||||
* 2. determinant must not have any common factors with the length of
|
||||
* character key
|
||||
* There is no head-fast way to generate hte matrix under the given
|
||||
* numerical restrictions of the machine but the conditions added achieve
|
||||
* the goals. Bigger the matrix, greater is the probability of the matrix
|
||||
* being ill-defined.
|
||||
*
|
||||
* @param size size of matrix (typically \f$\text{size}\le10\f$)
|
||||
* @param limit1 lower limit of range of random elements (default=0)
|
||||
* @param limit2 upper limit of range of random elements (default=10)
|
||||
* @return Encryption martix
|
||||
*/
|
||||
static matrix<int> generate_encryption_key(size_t size, int limit1 = 0,
|
||||
int limit2 = 10) {
|
||||
matrix<int> encrypt_key(size, std::valarray<int>(size));
|
||||
matrix<int> min_mat = encrypt_key;
|
||||
int mat_determinant = -1; // because matrix has only ints, the
|
||||
// determinant will also be an int
|
||||
int L = std::strlen(STRKEY);
|
||||
|
||||
double dd;
|
||||
do {
|
||||
// keeping the random number range smaller generates better
|
||||
// defined matrices with more ease of cracking
|
||||
dd = rand_range(&encrypt_key, limit1, limit2);
|
||||
mat_determinant = static_cast<int>(dd);
|
||||
|
||||
if (mat_determinant < 0)
|
||||
mat_determinant = (mat_determinant % L);
|
||||
} while (std::abs(dd) > 1e3 || // while ill-defined
|
||||
dd < 0.1 || // while singular or negative determinant
|
||||
!std::isfinite(dd) || // while determinant is not finite
|
||||
gcd(mat_determinant, L) != 1); // while no common factors
|
||||
// std::cout <<
|
||||
|
||||
return encrypt_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate decryption matrix from an encryption matrix key.
|
||||
*
|
||||
* @param encrypt_key encryption key for which to create a decrypt key
|
||||
* @return Decryption martix
|
||||
*/
|
||||
static matrix<int> generate_decryption_key(matrix<int> const &encrypt_key) {
|
||||
size_t size = encrypt_key.size();
|
||||
int L = std::strlen(STRKEY);
|
||||
|
||||
matrix<int> decrypt_key(size, std::valarray<int>(size));
|
||||
int det_encrypt = static_cast<int>(determinant_lu(encrypt_key));
|
||||
|
||||
int mat_determinant = det_encrypt < 0 ? det_encrypt % L : det_encrypt;
|
||||
|
||||
matrix<double> tmp_inverse = get_inverse(encrypt_key);
|
||||
|
||||
// find co-prime factor for inversion
|
||||
int det_inv = -1;
|
||||
for (int i = 0; i < L; i++) {
|
||||
if (modulo(mat_determinant * i, L) == 1) {
|
||||
det_inv = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (det_inv == -1) {
|
||||
std::cerr << "Could not find a co-prime for inversion\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mat_determinant = det_inv * det_encrypt;
|
||||
|
||||
// perform modular inverse of encryption matrix
|
||||
int i;
|
||||
#ifdef _OPENMP
|
||||
#pragma parallel omp for private(i)
|
||||
#endif
|
||||
for (i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
int temp = std::round(tmp_inverse[i][j] * mat_determinant);
|
||||
decrypt_key[i][j] = modulo(temp, L);
|
||||
}
|
||||
}
|
||||
return decrypt_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate encryption and decryption key pair
|
||||
*
|
||||
* @param size size of matrix key (typically \f$\text{size}\le10\f$)
|
||||
* @param limit1 lower limit of range of random elements (default=0)
|
||||
* @param limit2 upper limit of range of random elements (default=10)
|
||||
* @return std::pair<matrix<int>, matrix<int>> encryption and decryption
|
||||
* keys as a pair
|
||||
*
|
||||
* @see ::generate_encryption_key
|
||||
*/
|
||||
static std::pair<matrix<int>, matrix<int>> generate_keys(size_t size,
|
||||
int limit1 = 0,
|
||||
int limit2 = 10) {
|
||||
matrix<int> encrypt_key = generate_encryption_key(size);
|
||||
matrix<int> decrypt_key = generate_decryption_key(encrypt_key);
|
||||
double det2 = determinant_lu(decrypt_key);
|
||||
while (std::abs(det2) < 0.1 || std::abs(det2) > 1e3) {
|
||||
encrypt_key = generate_encryption_key(size, limit1, limit2);
|
||||
decrypt_key = generate_decryption_key(encrypt_key);
|
||||
det2 = determinant_lu(decrypt_key);
|
||||
}
|
||||
return std::make_pair(encrypt_key, decrypt_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypt a given text using a given key
|
||||
*
|
||||
* @param text string to encrypt
|
||||
* @param encrypt_key key for encryption
|
||||
* @return encrypted text
|
||||
*/
|
||||
static const std::string encrypt_text(const std::string &text,
|
||||
const matrix<int> &encrypt_key) {
|
||||
return codec(text, encrypt_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrypt a given text using a given key
|
||||
*
|
||||
* @param text string to decrypt
|
||||
* @param decrypt_key key for decryption
|
||||
* @return decrypted text
|
||||
*/
|
||||
static const std::string decrypt_text(const std::string &text,
|
||||
const matrix<int> &decrypt_key) {
|
||||
return codec(text, decrypt_key);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self test 1 - using 3x3 randomly generated key
|
||||
*
|
||||
* @param text string to encrypt and decrypt
|
||||
*/
|
||||
void test1(const std::string &text) {
|
||||
// std::string text = "Hello world!";
|
||||
std::cout << "======Test 1 (3x3 key) ======\nOriginal text:\n\t" << text
|
||||
<< std::endl;
|
||||
|
||||
std::pair<matrix<int>, matrix<int>> p =
|
||||
ciphers::HillCipher::generate_keys(3, 0, 100);
|
||||
matrix<int> ekey = p.first;
|
||||
matrix<int> dkey = p.second;
|
||||
|
||||
// matrix<int> ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}};
|
||||
// std::cout << "Encryption key: \n" << ekey;
|
||||
std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
|
||||
std::cout << "Encrypted text:\n\t" << gibberish << std::endl;
|
||||
|
||||
// matrix<int> dkey = ciphers::HillCipher::generate_decryption_key(ekey);
|
||||
// std::cout << "Decryption key: \n" << dkey;
|
||||
std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
|
||||
std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;
|
||||
|
||||
std::ofstream out_file("hill_cipher_test1.txt");
|
||||
out_file << "Block size: " << ekey.size() << "\n";
|
||||
out_file << "Encryption Key:\n" << ekey;
|
||||
out_file << "\nDecryption Key:\n" << dkey;
|
||||
out_file.close();
|
||||
|
||||
assert(txt_back == text);
|
||||
std::cout << "Passed :)\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self test 2 - using 8x8 randomly generated key
|
||||
*
|
||||
* @param text string to encrypt and decrypt
|
||||
*/
|
||||
void test2(const std::string &text) {
|
||||
// std::string text = "Hello world!";
|
||||
std::cout << "======Test 2 (8x8 key) ======\nOriginal text:\n\t" << text
|
||||
<< std::endl;
|
||||
|
||||
std::pair<matrix<int>, matrix<int>> p =
|
||||
ciphers::HillCipher::generate_keys(8, 0, 3);
|
||||
matrix<int> ekey = p.first;
|
||||
matrix<int> dkey = p.second;
|
||||
|
||||
std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
|
||||
std::cout << "Encrypted text:\n\t" << gibberish << std::endl;
|
||||
|
||||
std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
|
||||
std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;
|
||||
|
||||
std::ofstream out_file("hill_cipher_test2.txt");
|
||||
out_file << "Block size: " << ekey.size() << "\n";
|
||||
out_file << "Encryption Key:\n" << ekey;
|
||||
out_file << "\nDecryption Key:\n" << dkey;
|
||||
out_file.close();
|
||||
|
||||
assert(txt_back.compare(0, text.size(), text) == 0);
|
||||
std::cout << "Passed :)\n";
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
std::srand(std::time(nullptr));
|
||||
std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t"
|
||||
<< ciphers::STRKEY << "\n";
|
||||
|
||||
std::string text = "This is a simple text with numb3r5 and exclamat!0n.";
|
||||
|
||||
test1(text);
|
||||
test2(text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* @file
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*
|
||||
* @brief Implementation of [Morse Code]
|
||||
* (https://en.wikipedia.org/wiki/Morse_code).
|
||||
*
|
||||
* @details
|
||||
* Morse code is a method used in telecommunication to encode text characters
|
||||
* as standardized sequences of two different signal durations, called dots
|
||||
* and dashes or dits and dahs. Morse code is named after Samuel Morse, an
|
||||
* inventor of the telegraph.
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace morse
|
||||
* \brief Functions for [Morse Code]
|
||||
* (https://en.wikipedia.org/wiki/Morse_code).
|
||||
*/
|
||||
namespace morse {
|
||||
/**
|
||||
* Get the morse representation for given character.
|
||||
* @param c Character
|
||||
* @returns morse representation string of character
|
||||
*/
|
||||
std::string char_to_morse(const char &c) {
|
||||
// return corresponding morse code
|
||||
switch (c) {
|
||||
case 'a':
|
||||
return ".-";
|
||||
case 'b':
|
||||
return "-...";
|
||||
case 'c':
|
||||
return "-.-.";
|
||||
case 'd':
|
||||
return "-..";
|
||||
case 'e':
|
||||
return ".";
|
||||
case 'f':
|
||||
return "..-.";
|
||||
case 'g':
|
||||
return "--.";
|
||||
case 'h':
|
||||
return "....";
|
||||
case 'i':
|
||||
return "..";
|
||||
case 'j':
|
||||
return ".---";
|
||||
case 'k':
|
||||
return "-.-";
|
||||
case 'l':
|
||||
return ".-..";
|
||||
case 'm':
|
||||
return "--";
|
||||
case 'n':
|
||||
return "-.";
|
||||
case 'o':
|
||||
return "---";
|
||||
case 'p':
|
||||
return ".--.";
|
||||
case 'q':
|
||||
return "--.-";
|
||||
case 'r':
|
||||
return ".-.";
|
||||
case 's':
|
||||
return "...";
|
||||
case 't':
|
||||
return "-";
|
||||
case 'u':
|
||||
return "..-";
|
||||
case 'v':
|
||||
return "...-";
|
||||
case 'w':
|
||||
return ".--";
|
||||
case 'x':
|
||||
return "-..-";
|
||||
case 'y':
|
||||
return "-.--";
|
||||
case 'z':
|
||||
return "--..";
|
||||
case '1':
|
||||
return ".----";
|
||||
case '2':
|
||||
return "..---";
|
||||
case '3':
|
||||
return "...--";
|
||||
case '4':
|
||||
return "....-";
|
||||
case '5':
|
||||
return ".....";
|
||||
case '6':
|
||||
return "-....";
|
||||
case '7':
|
||||
return "--...";
|
||||
case '8':
|
||||
return "---..";
|
||||
case '9':
|
||||
return "----.";
|
||||
case '0':
|
||||
return "-----";
|
||||
default:
|
||||
std::cerr << "Found invalid character: " << c << ' ' << std::endl;
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get character from the morse representation.
|
||||
* @param s Morse representation
|
||||
* @returns corresponding character
|
||||
*/
|
||||
char morse_to_char(const std::string &s) {
|
||||
// return corresponding character
|
||||
if (s == ".-") {
|
||||
return 'a';
|
||||
} else if (s == "-...") {
|
||||
return 'b';
|
||||
} else if (s == "-.-.") {
|
||||
return 'c';
|
||||
} else if (s == "-..") {
|
||||
return 'd';
|
||||
} else if (s == ".") {
|
||||
return 'e';
|
||||
} else if (s == "..-.") {
|
||||
return 'f';
|
||||
} else if (s == "--.") {
|
||||
return 'g';
|
||||
} else if (s == "....") {
|
||||
return 'h';
|
||||
} else if (s == "..") {
|
||||
return 'i';
|
||||
} else if (s == ".---") {
|
||||
return 'j';
|
||||
} else if (s == "-.-") {
|
||||
return 'k';
|
||||
} else if (s == ".-..") {
|
||||
return 'l';
|
||||
} else if (s == "--") {
|
||||
return 'm';
|
||||
} else if (s == "-.") {
|
||||
return 'n';
|
||||
} else if (s == "---") {
|
||||
return 'o';
|
||||
} else if (s == ".--.") {
|
||||
return 'p';
|
||||
} else if (s == "--.-") {
|
||||
return 'q';
|
||||
} else if (s == ".-.") {
|
||||
return 'r';
|
||||
} else if (s == "...") {
|
||||
return 's';
|
||||
} else if (s == "-") {
|
||||
return 't';
|
||||
} else if (s == "..-") {
|
||||
return 'u';
|
||||
} else if (s == "...-") {
|
||||
return 'v';
|
||||
} else if (s == ".--") {
|
||||
return 'w';
|
||||
} else if (s == "-..-") {
|
||||
return 'x';
|
||||
} else if (s == "-.--") {
|
||||
return 'y';
|
||||
} else if (s == "--..") {
|
||||
return 'z';
|
||||
} else if (s == ".----") {
|
||||
return '1';
|
||||
} else if (s == "..---") {
|
||||
return '2';
|
||||
} else if (s == "...--") {
|
||||
return '3';
|
||||
} else if (s == "....-") {
|
||||
return '4';
|
||||
} else if (s == ".....") {
|
||||
return '5';
|
||||
} else if (s == "-....") {
|
||||
return '6';
|
||||
} else if (s == "--...") {
|
||||
return '7';
|
||||
} else if (s == "---..") {
|
||||
return '8';
|
||||
} else if (s == "----.") {
|
||||
return '9';
|
||||
} else if (s == "-----") {
|
||||
return '0';
|
||||
} else {
|
||||
std::cerr << "Found invalid Morse code: " << s << ' ' << std::endl;
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encrypt given text using morse code.
|
||||
* @param text text to be encrypted
|
||||
* @returns new encrypted text
|
||||
*/
|
||||
std::string encrypt(const std::string &text) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
// Going through each character of text and converting it
|
||||
// to morse representation
|
||||
for (const char &c : text) {
|
||||
encrypted_text += ciphers::morse::char_to_morse(c) + " ";
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given morse coded text.
|
||||
* @param text text to be decrypted
|
||||
* @returns new decrypted text
|
||||
*/
|
||||
std::string decrypt(const std::string &text) {
|
||||
// Going through each character of text and converting it
|
||||
// back to normal representation.
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
// Spliting string (with delimiter = " ") and storing it
|
||||
// in vector
|
||||
std::size_t pos_start = 0, pos_end = 0, delim_len = 1;
|
||||
std::vector<std::string> splits;
|
||||
while ((pos_end = text.find(' ', pos_start)) != std::string::npos) {
|
||||
std::string token = text.substr(pos_start, pos_end - pos_start);
|
||||
pos_start = pos_end + delim_len;
|
||||
splits.push_back(token);
|
||||
}
|
||||
|
||||
// Traversing through each morse code string
|
||||
for (const std::string &s : splits) {
|
||||
// Add corresponding character
|
||||
decrypted_text += ciphers::morse::morse_to_char(s);
|
||||
}
|
||||
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace morse
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Function to test above algorithm
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
std::string text1 = "01234567890";
|
||||
std::string encrypted1 = ciphers::morse::encrypt(text1);
|
||||
std::string decrypted1 = ciphers::morse::decrypt(encrypted1);
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1 << std::endl;
|
||||
std::cout << "Encrypted text : " << encrypted1 << std::endl;
|
||||
std::cout << "Decrypted text : " << decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string encrypted2 = ciphers::morse::encrypt(text2);
|
||||
std::string decrypted2 = ciphers::morse::decrypt(encrypted2);
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2 << std::endl;
|
||||
std::cout << "Encrypted text : " << encrypted2 << std::endl;
|
||||
std::cout << "Decrypted text : " << decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @file vigenere_cipher.cpp
|
||||
* @brief Implementation of [Vigenère cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher) algorithm.
|
||||
*
|
||||
* @details
|
||||
* The Vigenère cipher is a method of encrypting alphabetic text by using a series of interwoven vigenere
|
||||
* ciphers, based on the letters of a keyword. It employs a form of polyalphabetic substitution.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The encryption can also be represented using modular arithmetic by first transforming
|
||||
* the letters into numbers, according to the scheme, A → 0, B → 1, ..., Z → 25.
|
||||
* Encryption of \f$i^{th}\f$ character in Message M by key K can be described mathematically as,
|
||||
*
|
||||
* \f[ E_{K}(M_{i}) = (M_{i} + K_{i})\;\mbox{mod}\; 26\f]
|
||||
*
|
||||
* while decryption of \f$i^{th}\f$ character in Cipher C by key K can be described mathematically as,
|
||||
*
|
||||
* \f[ D_{k}(C_{i}) = (C_{i} - K_{i} + 26)\;\mbox{mod}\; 26\f]
|
||||
*
|
||||
* Where \f$K_{i}\f$ denotes corresponding character in key. If \f$|key| < |text|\f$ than
|
||||
* same key is repeated untill their lengths are equal.
|
||||
*
|
||||
* For Example,
|
||||
* If M = "ATTACKATDAWN" and K = "LEMON" than K becomes "LEMONLEMONLE".
|
||||
*
|
||||
* \note Rather than creating new key of equal length this program does this by using modular index for key
|
||||
* (i.e. \f$(j + 1) \;\mbox{mod}\; |\mbox{key}|\f$)
|
||||
*
|
||||
* \note This program implements Vigenère cipher for only uppercase English alphabet characters (i.e. A-Z).
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace vigenere
|
||||
* \brief Functions for [vigenère cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher) algorithm.
|
||||
*/
|
||||
namespace vigenere {
|
||||
namespace {
|
||||
/**
|
||||
* This function finds character for given value (i.e.A-Z)
|
||||
* @param x value for which we want character
|
||||
* @return corresponding character for perticular value
|
||||
*/
|
||||
inline char get_char(const int x) {
|
||||
// By adding 65 we are scaling 0-25 to 65-90.
|
||||
// Which are in fact ASCII values of A-Z.
|
||||
return char(x + 65);
|
||||
}
|
||||
/**
|
||||
* This function finds value for given character (i.e.0-25)
|
||||
* @param c character for which we want value
|
||||
* @return returns corresponding value for perticular character
|
||||
*/
|
||||
inline int get_value(const char c) {
|
||||
// A-Z have ASCII values in range 65-90.
|
||||
// Hence subtracting 65 will scale them to 0-25.
|
||||
return int(c - 65);
|
||||
}
|
||||
} // Unnamed namespace
|
||||
/**
|
||||
* Encrypt given text using vigenere cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param key to be used for encryption
|
||||
* @return new encrypted text
|
||||
*/
|
||||
std::string encrypt (const std::string &text, const std::string &key) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
// Going through each character of text and key
|
||||
// Note that key is visited in circular way hence j = (j + 1) % |key|
|
||||
for(size_t i = 0, j = 0; i < text.length(); i++, j = (j + 1) % key.length()) {
|
||||
int place_value_text = get_value(text[i]); // Getting value of character in text
|
||||
int place_value_key = get_value(key[j]); // Getting value of character in key
|
||||
place_value_text = (place_value_text + place_value_key) % 26; // Applying encryption
|
||||
char encrypted_char = get_char(place_value_text); // Getting new character from encrypted value
|
||||
encrypted_text += encrypted_char; // Appending encrypted character
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given text using vigenere cipher.
|
||||
* @param text text to be decrypted
|
||||
* @param key key to be used for decryption
|
||||
* @return new decrypted text
|
||||
*/
|
||||
std::string decrypt (const std::string &text, const std::string &key) {
|
||||
// Going through each character of text and key
|
||||
// Note that key is visited in circular way hence j = (j + 1) % |key|
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
for(size_t i = 0, j = 0; i < text.length(); i++, j = (j + 1) % key.length()) {
|
||||
int place_value_text = get_value(text[i]); // Getting value of character in text
|
||||
int place_value_key = get_value(key[j]); // Getting value of character in key
|
||||
place_value_text = (place_value_text - place_value_key + 26) % 26; // Applying decryption
|
||||
char decrypted_char = get_char(place_value_text); // Getting new character from decrypted value
|
||||
decrypted_text += decrypted_char; // Appending decrypted character
|
||||
}
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace vigenere
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::string text1 = "NIKOLATESLA";
|
||||
std::string encrypted1 = ciphers::vigenere::encrypt(text1, "TESLA");
|
||||
std::string decrypted1 = ciphers::vigenere::decrypt(encrypted1, "TESLA");
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1;
|
||||
std::cout << " , Encrypted text (with key = TESLA) : " << encrypted1;
|
||||
std::cout << " , Decrypted text : "<< decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "GOOGLEIT";
|
||||
std::string encrypted2 = ciphers::vigenere::encrypt(text2, "REALLY");
|
||||
std::string decrypted2 = ciphers::vigenere::decrypt(encrypted2, "REALLY");
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2;
|
||||
std::cout << " , Encrypted text (with key = REALLY) : " << encrypted2;
|
||||
std::cout << " , Decrypted text : "<< decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @file xor_cipher.cpp
|
||||
* @brief Implementation of [XOR cipher](https://en.wikipedia.org/wiki/XOR_cipher) algorithm.
|
||||
*
|
||||
* @details
|
||||
* In cryptography, the simple XOR cipher is a type of additive cipher, an encryption
|
||||
* algorithm that operates according to the principles:
|
||||
*
|
||||
* * \f$A {\oplus} 0 = A\f$
|
||||
* * \f$A {\oplus} A = 0\f$
|
||||
* * \f$ (A {\oplus} B) {\oplus} C = A {\oplus} (B {\oplus} C)\f$
|
||||
* * \f$ (B {\oplus} A) {\oplus} B = B {\oplus} 0 = B \f$
|
||||
*
|
||||
*
|
||||
* where \f$\oplus\f$ symbol denotes the exclusive disjunction (XOR) operation.
|
||||
* This operation is sometimes called modulus 2 addition (or subtraction, which is identical).
|
||||
* With this logic, a string of text can be encrypted by applying the bitwise XOR operator to
|
||||
* every character using a given key. To decrypt the output, merely reapplying the XOR function
|
||||
* with the key will remove the cipher.
|
||||
*
|
||||
* ### Algorithm
|
||||
* Choose the key for encryption and apply XOR operation to each character of a string.
|
||||
* Reapplying XOR operation to each character of encrypted string will give original string back.
|
||||
*
|
||||
* \note This program implements XOR Cipher for string with ASCII characters.
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace XOR
|
||||
* \brief Functions for [XOR cipher](https://en.wikipedia.org/wiki/XOR_cipher) algorithm.
|
||||
*/
|
||||
namespace XOR {
|
||||
/**
|
||||
* Encrypt given text using XOR cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param key to be used for encyption
|
||||
* @return new encrypted text
|
||||
*/
|
||||
std::string encrypt (const std::string &text, const int &key) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
for (auto &c: text) { // Going through each character
|
||||
char encrypted_char = char(c ^ key); // Applying encyption
|
||||
encrypted_text += encrypted_char; // Appending encrypted character
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given text using XOR cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param key to be used for decryption
|
||||
* @return new decrypted text
|
||||
*/
|
||||
std::string decrypt (const std::string &text, const int &key) {
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
for (auto &c : text) { // Going through each character
|
||||
char decrypted_char = char(c ^ key); // Applying decryption
|
||||
decrypted_text += decrypted_char; // Appending decrypted character
|
||||
}
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace XOR
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::string text1 = "Whipalsh! : Do watch this movie...";
|
||||
std::string encrypted1 = ciphers::XOR::encrypt(text1, 17);
|
||||
std::string decrypted1 = ciphers::XOR::decrypt(encrypted1, 17);
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1;
|
||||
std::cout << " , Encrypted text (with key = 17) : " << encrypted1;
|
||||
std::cout << " , Decrypted text : "<< decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "->Valar M0rghulis<-";
|
||||
std::string encrypted2 = ciphers::XOR::encrypt(text2, 29);
|
||||
std::string decrypted2 = ciphers::XOR::decrypt(encrypted2, 29);
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2;
|
||||
std::cout << " , Encrypted text (with key = 29) : " << encrypted2;
|
||||
std::cout << " , Decrypted text : "<< decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user