Itachi Uchiwa
Itachi Uchiwa

Reputation: 3164

Why my Vigenere encryption function for small letters doesn't work correctly?

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';
}

And decryption:

  Di = (Ei - Ki + 26) mod 26

Upvotes: 1

Views: 407

Answers (1)

Henk
Henk

Reputation: 846

Consider the Ascii Table: http://www.asciitable.com/. If you write the characters as (65+i) and (65+j) and add them, with your uppercase method, you are getting 65+(65+i)+(65+j) \equiv 65+i+j \mod 26. You are lucky that 65 + 65 is divisible by 26 in the uppercase case!

For lowercases we do not have 97+97 divisible by 26.

Some tips for debugging and posting code on SO: The output of your code was wrong in the first letter of the method, so something was going wrong there. If you just consider that minimal example, it is much easier to spot the mistake. So try to produce a minimal reproducible example.

Upvotes: 2

Related Questions