Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
108 views
in Technique[技术] by (71.8m points)

c++ - 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 << '
';
    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 << '
';
}
  • 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() 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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...