-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
vigenere_cipher.cpp
135 lines (132 loc) · 6.06 KB
/
vigenere_cipher.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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;
}