I've tried implementing Vigenere's Cypher. I found out that it is used with Uppercase letters but I've made it to work for capital and small letters but the characters of a plain or cyphered text must be the same as their corresponding ones in the Key. So I've done this:
std::string encryptUpper(std::string const& plain, std::string const& key){
std::string cyphered;
for(std::size_t i = 0, j = 0, plainLen = plain.length(), keyLen = key.length();
i != plainLen; ++i, ++j){
if(j == keyLen)
j = 0;
cyphered += ( (plain.at(i) + key.at(j) ) % 26) + 'A';
}
return cyphered;
}
std::string decryptUpper(std::string const& cyphered, std::string const& key){
std::string plain;
for(std::size_t i = 0, j = 0, cypheredLen = cyphered.length(), keyLen = key.length();
i != cypheredLen; ++i, ++j){
if(j == keyLen)
j = 0;
plain += ( ( (cyphered.at(i) - key.at(j) + 26) % 26) + 'A');
}
return plain;
}
std::string encryptLower(std::string const& plain, std::string const& key){
std::string cyphered;
for(std::size_t i = 0, j = 0, plainLen = plain.length(), keyLen = key.length();
i != plainLen; ++i, ++j){
if(j == keyLen)
j = 0;
cyphered += ( (plain.at(i) + key.at(j) ) % 26) + 'a';
}
return cyphered;
}
std::string decryptLower(std::string const& cyphered, std::string const& key){
std::string plain;
for(std::size_t i = 0, j = 0, cypheredLen = cyphered.length(), keyLen = key.length();
i != cypheredLen; ++i, ++j){
if(j == keyLen)
j = 0;
plain += ( (cyphered.at(i) - key.at(j) + 26 ) % 26) + 'a';
}
return plain;
}
std::string encrypt(std::string const& plain, std::string const& key){
std::string cyphered;
for(std::size_t i = 0, j = 0, plainLen = plain.length(), keyLen = key.length();
i != plainLen; ++i, ++j){
if(j == keyLen)
j = 0;
cyphered += ( (plain.at(i) - (std::isupper(plain.at(i)) ? 'A' : 'a') + key.at(j) - (std::isupper(plain.at(i)) ? 'A' : 'a') ) % 26) +
(std::isupper(plain.at(0)) ? 'A' : 'a');
}
return cyphered;
}
std::string decrypt(std::string const& cyphered, std::string const& key){
std::string plain;
for(std::size_t i = 0, j = 0, cypheredLen = cyphered.length(), keyLen = key.length();
i != cypheredLen; ++i, ++j){
if(j == keyLen)
j = 0;
plain += ( (cyphered.at(i) - key.at(j) + 26 ) % 26) +
(std::isupper(cyphered.at(i)) ? 'A' : 'a');
}
return plain;
}
int main(){
std::string s1 = "HELLO";
std::string key1 = "ATOM";
auto cyphered1 = encryptUpper(s1, key1);
std::cout << cyphered1 << '\n';
auto plain = decryptUpper(cyphered1, key1);
std::cout << plain << '\n';
std::string s2 = "hello";
std::string key2 = "atom";
auto cyphered2 = encryptLower(s2, key2);
std::cout << cyphered2 << '\n';
auto plain2 = decryptLower(cyphered2, key2);
std::cout << plain2 << '\n';
cyphered2 = encrypt(s2, key2);
std::cout << cyphered2 << '\n';
plain2 = decryptLower(cyphered2, key2);
std::cout << plain2 << '\n';
std::cout << "=========\n";
auto c1 = encrypt(s1, key1);
auto p1 = decrypt(c1, key1);
std::cout << c1 << '\n' << p1 << '\n';
auto c2 = encrypt(s2, key2);
auto p2 = decrypt(c2, key2);
std::cout << c2 << '\n' << p2 << '\n';
}
Why
encryptLower()
encrypts lowercase text in a wrong way? Although we know that the rule is:Ei = (Pi + Ki) mod 26
And decryption:
Di = (Ei - Ki + 26) mod 26
Why when encrypting small letters I need to subtract the value of
a
from both the key and plain text characters then sum and mod 26? and why with capital letter I don't need so?Are my generic
encrypt()
anddecrypt
functions correct? Thank you!I am sure the problem is here:
char P = 'H'; // 72 char K = 'A'; // 65 char C = (P + K) % 26; // 7 C += 'A'; // 7 + 'A' = H std::cout << C << '\n'; // H char p = 'h'; // 104 char k = 'a'; // 97 char c = (p + k) % 26; // 19 c += 'a'; // 19 + 'a' = t std::cout << c << '\n'; // t
Normally using a key
a
orA
yields the cyphered character unchanged like in the uppercase one but why doesn't work with lowercase?