From cf562f224473f25f6ecb7b7034fb07a9b02eb61f Mon Sep 17 00:00:00 2001 From: Deep Raval Date: Mon, 20 Jul 2020 23:20:40 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20Add=20Vigen=C3=A8re=20cipher=20(#962)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Vigenere Cipher * Added size_t instead of int in for loop * Update ciphers/vigenere_cipher.cpp Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * Update ciphers/vigenere_cipher.cpp Co-authored-by: David Leal Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Co-authored-by: David Leal --- ciphers/vigenere_cipher.cpp | 135 ++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 ciphers/vigenere_cipher.cpp diff --git a/ciphers/vigenere_cipher.cpp b/ciphers/vigenere_cipher.cpp new file mode 100644 index 000000000..cb5b959b6 --- /dev/null +++ b/ciphers/vigenere_cipher.cpp @@ -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 +#include +#include + +/** \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; +}