3.25 写一个程序,无须人工干预,对加法密码实现字母频率攻击。软件按可能性大小的顺序给出可能的明文。如果用户界面允许用户定义 “给出前 10个可能明文”,则更好。
我的答案:
一、信息(题目的有用信息)
这段代码实现了一种简化版的英语字母频率分析方法,用于破解加密文本。主要组件包括:
- 英文字母的标准频率表
standardFrequencies
。 calculateFrequency
函数,计算给定文本的字母频率。decryptCaesarCipher
函数,尝试解密给定的凯撒密码文本。compareFrequencies
函数,比较两个频率分布的差异。- 主函数
main
,接受用户输入的密文,尝试各种移位解密,并根据频率分析的结果排序。
二、分析(包括每个信息的作用和思考过程和分析过程)
- 标准频率表:为比较提供基准,因为自然语言中字母出现的频率是有特定模式的。
calculateFrequency
函数:理解密文或解密文本的特征,为找出正确的移位提供依据。decryptCaesarCipher
函数:核心解密机制,通过遍历所有可能的移位来找到可能的明文。compareFrequencies
函数:通过比较解密文本的频率与标准频率的差异,评估每个解密选项的可能性。- 主函数:用户交互的接口,收集密文,执行解密尝试,并展示可能的解密结果。
三、算法设计
- 输入密文:从用户那里获取需要解密的文本。
- 遍历所有可能的移位:从0到25,尝试每种可能的移位。
- 对每种移位解密并计算频率:使用
decryptCaesarCipher
解密文本,然后用calculateFrequency
计算频率。 - 评估与标准频率的差异:用
compareFrequencies
比较当前解密文本的频率与标准频率的差异。 - 记录和排序结果:将每次尝试的解密文本及其差异记录下来,并根据差异排序。
- 输出最可能的解密文本:显示差异最小的前N个解密选项。
四、代码实现(用C++)
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <cmath>
// 英语字母频率(简化版)
const std::map<char, double> standardFrequencies = {
{'A', 8.167}, {'B', 1.492}, {'C', 2.782}, {'D', 4.253}, {'E', 12.702},
{'F', 2.228}, {'G', 2.015}, {'H', 6.094}, {'I', 6.966}, {'J', 0.153},
{'K', 0.772}, {'L', 4.025}, {'M', 2.406}, {'N', 6.749}, {'O', 7.507},
{'P', 1.929}, {'Q', 0.095}, {'R', 5.987}, {'S', 6.327}, {'T', 9.056},
{'U', 2.758}, {'V', 0.978}, {'W', 2.360}, {'X', 0.150}, {'Y', 1.974},
{'Z', 0.074}
};
// 计算一个字符串的字母频率
std::map<char, double> calculateFrequency(const std::string& text) {
std::map<char, double> freq;
for (char c : text) {
if (isalpha(c)) {
c = toupper(c); // 将所有字母转换为大写
freq[c]++;
}
}
int total = text.size();
for (auto& pair : freq) {
pair.second = (pair.second / total) * 100; // 转换为百分比
}
return freq;
}
// 解密加法密码给定特定的移位
std::string decryptCaesarCipher(const std::string& text, int shift) {
std::string decrypted;
for (char c : text) {
if (isalpha(c)) {
char base = isupper(c) ? 'A' : 'a';
c = ((c - base - shift + 26) % 26) + base;
}
decrypted += c;
}
return decrypted;
}
// 比较两个频率分布,返回它们的差异
double compareFrequencies(const std::map<char, double>& freq1, const std::map<char, double>& freq2) {
double diff = 0;
for (auto& pair : freq1) {
char letter = pair.first;
double freq = pair.second;
diff += std::abs(freq - freq2.at(letter));
}
return diff;
}
int main() {
std::string ciphertext;
std::cout << "请输入密文: ";
getline(std::cin, ciphertext);
std::vector<std::pair<std::string, double>> possiblePlaintexts;
// 尝试每个可能的移位
for (int shift = 0; shift < 26; ++shift) {
std::string decrypted = decryptCaesarCipher(ciphertext, shift);
std::map<char, double> decryptedFreq = calculateFrequency(decrypted);
double diff = compareFrequencies(decryptedFreq, standardFrequencies);
possiblePlaintexts.push_back(std::make_pair(decrypted, diff));
}
// 根据差异对候选明文进行排序
sort(possiblePlaintexts.begin(), possiblePlaintexts.end(), [](const auto& a, const auto& b) {
return a.second < b.second; // 按照差异排序
});
// 输出前N个结果
int N;
std::cout << "请输入你想查看的可能明文数量:";
std::cin >> N;
std::cout << "可能的明文:" << std::endl;
for (int i = 0; i < N && i < possiblePlaintexts.size(); ++i) {
std::cout << i + 1 << ": " << possiblePlaintexts[i].first << " (差异: " << possiblePlaintexts[i].second << ")" << std::endl;
}
return 0;
}
密文生成:(读者如果想先用凯撒密码加密可以看我这篇文章传送门:第三章编程习题 之 广义Caesar密码实现)
明文生成:
五、实现代码过程中可能遇到的问题
- 性能问题:频繁的字符串操作和频率计算可能会导致效率问题,特别是对于较长的文本。
- 大小写敏感性:代码当前假设所有英文字母都是大写的,如果输入小写字母可能无法正确计算频率。
- 非字母字符处理:代码只处理字母并忽略其他字符,对于包含非字母字符的文本,频率计算可能不准确。
- 固定的语言模型:标准频率表是基于一般英语文本的,可能不适合所有类型和风格的文本。
六、学到了什么?
-
编程基础:
- C++语言应用:了解和实践C++语言的基本语法和结构,包括向量、映射、字符串处理等。
- 函数编写:学习如何将问题拆分成子问题,通过编写和调用函数解决每个子问题。
-
算法思维:
- 解决问题的步骤:通过分析问题,设计出一步步解决问题的算法。
- 循环和条件:理解如何使用循环遍历所有可能性,并使用条件语句选择最佳解。
-
数据结构应用:
- 映射(Map):利用映射来存储和快速访问字母频率。
- 向量(Vector):使用向量存储和处理多个可能的解。
-
密码学基础:
- 凯撒密码原理:了解凯撒密码的加密和解密原理,即字母表的简单替换。
- 频率分析:认识到在某些语言中,字母出现的频率是有规律的,这个特性可以用来破解替换密码。
-
数学应用:
- 模运算:在进行字母替换时,理解和应用模运算来处理字母表的循环。
- 频率计算:通过数学方式计算和比较字母频率。
-
问题解决技能:
- 调试和测试:在编写和运行代码的过程中,学会如何调试和测试以确保代码的正确性。
- 性能考虑:了解代码效率对于解决问题的重要性,尤其是在处理大量数据时。
-
实际应用与批判性思维:
- 安全意识:理解简单密码的脆弱性,提高对信息安全和加密技术的认识。
- 算法的局限性:意识到算法可能不适用于所有情况,例如语言或文本风格的变化可能影响破解效果。