流加密的密文解密

流加密的密文解密

解密目标

给出十篇加密的样例密文,求解密一篇特定的密文

解密前提

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

解密过程分析

首先,这些加密方式都是异或加密,使用的是同一个Key。我们从异或加密的一些方法进行入手,异或有以下的特征。

公式一:
\[(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 原文\]

从这个推论我们可以问题简化为,只需要知道原文和对应的密文,也就能知道了密钥,最后再用密钥异或待解密的密文,就能反向得到其对应的原文了。

现在问题就变成了,如何知道密文对应的原文?

由于原文绝大多数的内容都是以字母和空格为主,所以可以利用空格ASCII码异或的一个特点进行入手。先分析一下ASCII码:

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\]

这个推论表明了,在大部分情况下,如果异或得到的结果是字母,则双方应该一方是空格,另一方是对应字母的大小写。(特殊情况为,标点符号的ASCII码为001XXXXX,效果等同于space,只是不能对应大小写转换,这就是这次实验结果的干扰项,可以看到有时候的确解出来了原文的字母,但是原文的字母明显是错的,不符合英文语法)

因此,找到空格就约等于破解了Key。

解密流程

说明

空格的概率:某一篇的特定一位和其余的各篇异或操作,如果结果是字母,则认为它是空格的概率提高。由于只需要比较大小,程序中没有除以总的篇数,仅仅是比较分子大小。

阈值的选择:在这里我选择的阈值是至少两篇异或得出字母。

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

程序结构

封装了一个解密类,用户需要调用addCiphertext()方法添加样例密文,添加越多,解密效果越好;然后调用decrypt()方法即可完成解密工作。getKey()方法和printKey()方法可以查看Key,如果有待解密的密文,使用addTargetCiphertext()方法添加后调用decryptTarget()即可解密,解密效果根据样例密文决定。

封装了一个单词拼写类,但这不是主要实验内容,使用了KMP搜索算法中的替换法则。

主要函数解析

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