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 << '
';
auto plain = decryptUpper(cyphered1, key1);
std::cout << plain << '
';
std::string s2 = "hello";
std::string key2 = "atom";
auto cyphered2 = encryptLower(s2, key2);
std::cout << cyphered2 << '
';
auto plain2 = decryptLower(cyphered2, key2);
std::cout << plain2 << '
';
cyphered2 = encrypt(s2, key2);
std::cout << cyphered2 << '
';
plain2 = decryptLower(cyphered2, key2);
std::cout << plain2 << '
';
std::cout << "=========
";
auto c1 = encrypt(s1, key1);
auto p1 = decrypt(c1, key1);
std::cout << c1 << '
' << p1 << '
';
auto c2 = encrypt(s2, key2);
auto p2 = decrypt(c2, key2);
std::cout << c2 << '
' << p2 << '
';
}
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()
and decrypt
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 << '
'; // H
char p = 'h'; // 104
char k = 'a'; // 97
char c = (p + k) % 26; // 19
c += 'a'; // 19 + 'a' = t
std::cout << c << '
'; // t
Normally using a key a
or A
yields the cyphered character unchanged like in the uppercase one but why doesn't work with lowercase?
question from:
https://stackoverflow.com/questions/65926739/why-my-vigenere-encryption-function-for-small-letters-doesnt-work-correctly 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…