Vigenere Cipher加解密程序逻辑故障求助:无法还原原消息
问题排查与解决方案
我帮你仔细梳理了代码里的问题,主要有几个关键点导致加密后解密无法还原原消息,下面逐一说明并给出修复方案:
1. 字符未转换为0-25范围直接计算
不管加密还是解密,你直接用字符的ASCII值进行加减取模,但大写字母的ASCII是从65('A')开始的,直接相加会远大于26,完全偏离了维吉尼亚密码的计算逻辑。
加密函数的错误
原代码:
int x = (message[i] + key[i]) %26;
正确做法:先把每个字符转换成0-25的偏移量(减去'A'),再执行加密计算:
int x = ( (message[i] - 'A') + (key[i] - 'A') ) % 26;
解密函数的错误
原代码:
int x = (message[i] - key[i] + 26) %26;
同样需要先转成0-25的偏移量,加26是为了避免负数取模的异常:
int x = ( (message[i] - 'A') - (key[i] - 'A') + 26 ) % 26;
2. 密钥扩展逻辑错误
你当前的密钥扩展循环逻辑有问题,应该基于原始密钥的长度来循环重复,而不是消息长度。原代码里的重置条件if (x == i) i = 0;(x是消息长度)会导致错误的密钥重复模式,比如密钥长度为3、消息长度为5时,会生成不符合预期的扩展密钥。
修正后的密钥扩展逻辑可以简化为:
int originalKeyLen = key.size(); while (key.size() < message.size()) { key.push_back(key[key.size() % originalKeyLen]); }
3. 未统一转换输入为大写
虽然提示里说会将消息转成大写,但代码里没有处理这个逻辑。如果用户输入小写字母,ASCII值和大写不同,会直接导致计算错误。我们可以添加一个辅助函数统一转换大小写:
string toUpperCase(string s) { for (char &c : s) { c = toupper(c); } return s; }
然后在获取输入时调用这个函数,确保消息和密钥都是大写格式。
修正后的完整代码
#include <iostream> #include <string> #include <cctype> using namespace std; // 辅助函数:转换字符串为大写 string toUpperCase(string s) { for (char &c : s) { c = toupper(c); } return s; } // 给用户展示信息 int giveInfo(){ cout << "\nThe Vigenere Cypher is a polyalphabetic encryption/decryption method. It utilizes a 'key' (provided by the user, \nany word of any length) to determine which letters will replace others. This means in order to decrypt a message,\n one will need the key the person who encrypted the message used, ensuring a secure encryption. To use this program, \nyou will need to enter your message (this will be converted into all capital letters) and a key which you would like to use. Do not use any spaces in your message.\n\n\n"; return 0; } // 获取用户消息 string messageInput(){ string userMessage; cout << "What is the message you would like to encrypt/decrypt?\n"; cin >> userMessage; return toUpperCase(userMessage); } // 获取用户密钥 string keyInput(){ string userKey; cout << "What is the key you would like to use?\n"; cin >> userKey; return toUpperCase(userKey); } // 解密函数 void decrypt(string message, string key){ // 扩展密钥到消息长度 int originalKeyLen = key.size(); while (key.size() < message.size()) { key.push_back(key[key.size() % originalKeyLen]); } string orig_text; for (int i = 0 ; i < message.size(); i++) { // 转换为0-25范围计算 int x = ( (message[i] - 'A') - (key[i] - 'A') + 26 ) % 26; // 转换回ASCII大写字母 x += 'A'; orig_text.push_back(x); } cout << "\n\nEncrypted Code: " << message << "\n"; cout << "Key: " << key << "\n"; cout << "Decrypted message: " << orig_text << "\n"; } // 加密函数 void encrypt(string message, string key){ // 扩展密钥到消息长度 int originalKeyLen = key.size(); while (key.size() < message.size()) { key.push_back(key[key.size() % originalKeyLen]); } string cipher_text; for (int i = 0; i < message.size(); i++) { // 转换为0-25范围计算 int x = ( (message[i] - 'A') + (key[i] - 'A') ) % 26; // 转换回ASCII大写字母 x += 'A'; cipher_text.push_back(x); } cout << "\n\nOriginal message: " << message << "\n"; cout << "Key: " << key << "\n"; cout << "Encrypted message: " << cipher_text << "\n"; } // 获取用户选择 int userChoice(){ int choice; cout << "Would you like to encrypt a message or decrypt a message? (1 = encrypt, 2 = decrypt)\n"; cin >> choice; return choice; } int main(){ giveInfo(); // 循环支持多次加密解密 int counter = 1; int userCounter; while (counter == 1){ int choice = userChoice(); if(choice == 1){ string inputMessage = messageInput(); string inputKey = keyInput(); encrypt(inputMessage, inputKey); } else { string inputMessage = messageInput(); string inputKey = keyInput(); decrypt(inputMessage, inputKey); } cout << "Would you like to decrypt/encrypt another message? (1 = yes, 2 = no)"; cin >> userCounter; counter = userCounter; system("CLS"); } return 0; }
测试验证
比如输入消息HELLO,密钥KEY:
- 加密后会得到
RIJVS - 用密钥
KEY解密RIJVS,会正确还原为HELLO
现在修正后的代码应该可以正常工作了,你可以测试看看。
内容的提问来源于stack exchange,提问作者Clyde Tamburro
相关产品推荐
相关产品推荐

