# 流加密的密文解密

### 解密前提

1. 全部密文使用同一Key加密
2. 加密的方法只是简单的异或操作
3. 原文绝大多数的内容都是以字母和空格为主

### 解密过程分析

$(A \otimes C) \otimes (B \otimes C) = A \otimes B$

$(A \otimes B) \otimes A = B$

$(原文_1 \otimes 密钥) \otimes (原文_2 \otimes 密钥) = 原文_1 \otimes 原文_2 = 密文_1 \otimes 密文_2$

$(原文 \otimes 密钥) \otimes 原文 = 密钥 = 密文 \otimes 原文$

Char ASCII code Hex
Space 32 00100000
a~z 97~122 01100001~01111010
A~Z 65~90 01000001~01011010

$Space \otimes alpha = 01XXXXXX$

$Alpha \otimes alpha = 00XXXXXX$

### 解密流程

Key正确的概率：大量实验结果表明，50%是最好的判决点！再次声明，这个50%不是随便选的，是经过了大量的实验结果表明的，我也不知道它为什么就是50%，显得我很不专业。

### 主要函数解析

void DecryptHelper::decryptKeyAtPosition(int position) {
int maxCiphertext = ciphertextInt.size();
int *spaceRatio = new int[maxCiphertext];
int maxSpaceRatio = 0, maxSpaceRatioIndex = -1;
// Statistics the space ratio for every ciphertext
for (int i = 0; i < maxCiphertext; i++) {
spaceRatio[i] = 0;
if (position < ciphertextInt[i].size()) {
int firstChar = ciphertextInt[i][position];
for (int j = 0; j < ciphertextInt.size(); j++) {
if (position < ciphertextInt[j].size() && j != i) {
int secondChar = ciphertextInt[j][position];
if (isalpha(firstChar ^ secondChar)) {
spaceRatio[i]++;
if (spaceRatio[i] >= 2 && spaceRatio[i] > maxSpaceRatio) {
maxSpaceRatio = spaceRatio[i];
maxSpaceRatioIndex = i;
}
}
}
}
}
}
// Try to update the key
while (maxSpaceRatioIndex != -1) {
// Test if it is a real SPACE char
int tryKey = ciphertextInt[maxSpaceRatioIndex][position] ^ SPACE;
if (testKeyAtPosition(tryKey, position)) {
key[position] = tryKey;
break;
}
// Find another maxSpaceRatio key
spaceRatio[maxSpaceRatioIndex] = 0;
maxSpaceRatio = 0, maxSpaceRatioIndex = -1;
for (int i = 0; i < maxCiphertext; i++) {
if (spaceRatio[i] >= 2 && spaceRatio[i] > maxSpaceRatio) {
maxSpaceRatio = spaceRatio[i];
maxSpaceRatioIndex = i;
}
}
}

delete [] spaceRatio;
}
bool DecryptHelper::testKeyAtPosition(int tryKey, int position) {
int textCount = 0, alphaCount = 0;
for (int i = 0; i < ciphertextInt.size(); i++) {
if (position < ciphertextInt[i].size()) {
textCount++;
if (isalpha(ciphertextInt[i][position] ^ tryKey)) {
alphaCount++;
}
}
}
if (alphaCount * 2 > textCount) {
return true;
}
return false;
}

### 运行结果

Key的长度我声明为300，因此后面会有比较多的*是因为没有这么长的样例密文来求解。破解率为：26/31=0.8387=83.87%，尽管不尽如意，但是已经能够通过英文语法规则来获知真正的内容。单词拼写检查设置为最多替换两个字符，再多了也没有意义，在80%+的破解率下运行良好。

### 一些心得

• 许多空格问题
这其实是由算法决定的，如果算法的思路是仅仅找到三个字符，一个是空格两个字母的话，能够很好的解决这一问题。但是，这个问题出现是小概率事件，一般情况下的解密效果会变差，所以多空格程序会认为找不到破解Key的关键，因为找到的决策是异或出现字母。

• 没有空格问题
这个问题我觉得没有什么讨论的意义，连空格都没有，只能说解不出来好吧。哪怕刚刚好两个字符异或得到是字母，但是你会发现，最后解密的效果都是错的[手动笑脸]。

• 其他字符问题
上文的讨论中我也已经提到了，标点符号的ASCII码是001XXXXX，异或字母的结果还是字母，所以能够在一定程度上影响解密效果。但是，符号的出现概率还是相对比较小，而且经过了测试函数对这个可能的Key进行过滤处理，能够在一定程度上消除这个影响，从而更好地解密。

### 附录

• build
• main.exe （可执行程序）
• ciphertexts
• multi-ciphertext.txt （样例密文）
• multi-targetCiphertext.txt （待解密密文）
• result
• final.txt （10篇待解密密文解密出来的原文）
• model
• small.txt （正确单词的单词库）
• DecryptHelper.h （解密类声明）
• DecryptHelper.cpp （解密类实现）
• main.cpp （主函数）
• Makefile （编译文件）