mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
feat: Add Vigenère cipher (#962)
* 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 <halfpacho@gmail.com> Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com>
This commit is contained in:
parent
193f9c466a
commit
cf562f2244
135
ciphers/vigenere_cipher.cpp
Normal file
135
ciphers/vigenere_cipher.cpp
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user