vigenere cipher 的 C++ 函数仅有时有效(适用于某些输入,跳过其他输入)

Posted

技术标签:

【中文标题】vigenere cipher 的 C++ 函数仅有时有效(适用于某些输入,跳过其他输入)【英文标题】:C++ function for vigenere cipher only sometimes working (works for some inputs, skips shifts for others) 【发布时间】:2019-06-19 21:28:09 【问题描述】:

对于课堂作业,我必须编写一个函数,该函数将用户输入字符串放入 vigenere 密码,并使用辅助函数的可选帮助。我能够使用一个辅助函数来获得部分解决方案,该函数根据字符在字母表中的位置以及另一个函数将字符串中的字符移动到这个位置(如果它们是字母)来获得正确的移位。

该程序仅偶尔适用于“Hello, world!”示例。将关键字“cake”正确加密为“Jevpq, Wyvnd!”,但是自动评分者输入“hDcT+T EtL5V71”和关键字“vpkbncc”返回“cSmU+V OuY5Q71”而不是“cSmU+ G GvG5K71"。我知道为什么会这样;每次迭代都会跳过第一个字符,因此“cake”最终会变成“ake”,但是我不知道如何解决这个问题。这是我的代码:

/*Author: Xavier f.*/

#include <iostream> 
#include <string>  
#include <cctype>  

using namespace std;

int getShift(char c); // helper function that converts chars into their place in the alphabet as an int 
char shiftChar(char c, int rshift); // this function handles the character value shifting part of the problem
string encryptVigenere(string plaintext, string keyword); //implemntation of Vigenere cypher  , needs to loop around keyword


int main() 

    string text, key, debug; 
    cout << "Enter a sentence: ";
    getline(cin, text); 
    cout << "Enter the keyword  : "; 
    getline(cin, key); 

    debug = encryptVigenere(text, key);
    cout << "Ciphertext     : " << debug;  

    return 0; 



int getShift(char c)  

    if (isupper(c))  

        return (int)c-(int)'A';
    
    else  

        return (int)c-(int)'a';

    


  

char shiftChar(char c, int rshift)  

    char shifted;


    if (isalpha(c))  //if it is a letter

        if (isupper(c))

            shifted = ((int)c + rshift - 'A')%26 + 'A';        //65-90 for uppercase , 97-122 for lowercase
         
        else  //dont have to put condition since if its not uppercase its obviously lowercase  

            shifted = ((int)c + rshift - 'a')%26 + 'a'; 

         

        return shifted;
     
    else  

        return c; 

     

 

string encryptVigenere(string plaintext, string keyword) 

    char encrypted;
    string vigenere; 
    int ciphercount = 0;

        for(int i = 0; i < plaintext.length(); ++i) 

            if(isalpha(plaintext[i])) 

                encrypted = shiftChar(plaintext[i], getShift(keyword[ciphercount])); 
                vigenere += encrypted; 
                ciphercount ++;

             
            else  
                ciphercount -= keyword.length();
                vigenere += plaintext[i]; 
            
            ciphercount = ciphercount % keyword.length();
          

    return vigenere;    


就像我之前提到的“你好,世界!”即使由于某种原因在 for 循环中跳过了 cake 中的第一个字符,示例仍然有效:

Enter a sentence: Hello, world!
Enter the keyword  : cake
Ciphertext     : Jevpq, wyvnd! 

debug: og ciphercount: c/ debug: plaintext[i]: H / debug: keyword[ciphercount]: a / debug: cyphercount isalpha: 1 / debug: encrypted: J / debug: vigenere: J
debug: cyphercount loop through: 1

但是随着自动评分者的输入,这个问题变得更加灾难性:

Enter a sentence: hDcT+T EtL5V71
Enter the keyword  : vpkbncc
Ciphertext     : cSmU+V OuY5Q71 

debug: og ciphercount: v / debug: plaintext[i]: h / debug: keyword[ciphercount]: p / debug: cyphercount isalpha: 1 / debug: encrypted: c / debug: vigenere: c
debug: cyphercount loop through: 1

输出应该是“cSmU+G GvG5K71”,但是由于第一个移位字符被跳过,所以文本被输入的是 pkbn_bn_c_p__ 这是错误的。

有谁知道我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

您的问题不是关键字的第一个字母被忽略(尝试fake 而不是cake 并确认它确实改变了输出)。

看来您真正的问题在于encryptVigenere 函数的编写方式。

我不是密码学专家,我无法告诉你这是否是实现 vigenere 密码的正确方法,但我无法理解这一行:

            ciphercount -= keyword.length();

事实证明,如果你删除它,你会得到你想要的结果。

所以,这是你的新 encryptVigenere 函数:

string encryptVigenere(string plaintext, string keyword) 

    char encrypted;
    string vigenere; 
    int ciphercount = 0;

        for(int i = 0; i < plaintext.length(); ++i) 

            if(isalpha(plaintext[i])) 
                encrypted = shiftChar(plaintext[i], getShift(keyword[ciphercount])); 
                vigenere += encrypted; 
                ciphercount ++;
             
            else  
                //ciphercount -= keyword.length();
                vigenere += plaintext[i]; 
            
            ciphercount = ciphercount % keyword.length();
          

    return vigenere;    


【讨论】:

谢谢你确实为它工作。该行最初是用于通过该函数的早期版本的关键字重置循环,但我想我忘了删除它,累了会对你这样做:/。由于该功能的部分要求是区分字母和非字母,我认为以这种方式重置非字母的计数会起作用,它适用于某些输入,但您的编辑使其适用于一切。

以上是关于vigenere cipher 的 C++ 函数仅有时有效(适用于某些输入,跳过其他输入)的主要内容,如果未能解决你的问题,请参考以下文章

C++ 链表凯撒密码 Vigenere Cipher

Vigenere Cipher Key 未按预期工作

具有所需功能的 Python Vigenere Cipher

Vigenere-cipher 错误输出

Vigenere Cipher - 解密(手动)

Vigenere Cipher - 解密(手动)