|
25 | 25 |
|
26 | 26 | ### 使用字典攻击暴力破解维吉尼亚密码 |
27 | 27 |
|
28 | | -我们将首先使用字典攻击来破解维吉尼亚密码。字典文件`dictionary.txt` (可在本书网站`www.nostarch.com/crackingcodes`)约有 45000 个英语单词。我的电脑只需不到五分钟就能完成对一个长段落大小的信息的所有解密。这意味着,如果使用一个英语单词来加密一个维吉尼亚密文,该密文容易受到字典攻击。让我们来看一个使用字典攻击来破解维吉尼亚密码的程序的源代码。* |
| 28 | +我们将首先使用字典攻击来破解维吉尼亚密码。字典文件`dictionary.txt` (可在本书网站`www.nostarch.com/crackingcodes`)约有 45000 个英语单词。我的电脑只需不到五分钟就能完成对一个长段落大小的信息的所有解密。这意味着,如果使用一个英语单词来加密一个维吉尼亚密文,该密文容易受到字典攻击。让我们来看一个使用字典攻击来破解维吉尼亚密码的程序的源代码。* |
29 | 29 |
|
30 | 30 | ### 维吉尼亚字典破解程序的源代码 |
31 | 31 |
|
@@ -95,7 +95,7 @@ Copying hacked message to clipboard: |
95 | 95 | The real secrets are not the ones I tell. |
96 | 96 | ``` |
97 | 97 |
|
98 | | -程序建议的第一个关键字(`ASTROLOGY`)不起作用,所以用户按`回车`让黑客程序继续,直到找到正确的解密密钥(`ASTRONOMY`)。 |
| 98 | +程序建议的第一个关键字(`ASTROLOGY`)不起作用,所以用户按`回车`让黑客程序继续,直到找到正确的解密密钥(`ASTRONOMY`)。 |
99 | 99 |
|
100 | 100 | ### 关于维吉尼亚字典破解计划 |
101 | 101 |
|
@@ -127,7 +127,7 @@ SPILLTHEBEANSSPILLT |
127 | 127 | LWMNLMPWPYTBXLWMMLZ |
128 | 128 | ``` |
129 | 129 |
|
130 | | -注意,字母`LWM`重复了两次。原因是在密文中,`LWM`是使用与密钥相同的字母(SPI)加密的明文,因为密钥恰好在第二次加密时重复。从第一个`LWM`开始到第二个`LWM`开始的字母数,我们称之为*间距*,是 13。这表明用于该密文的密钥有 13 个字母长。只要看看重复的序列,你就能算出钥匙的长度。 |
| 130 | +注意,字母`LWM`重复了两次。原因是在密文中,`LWM`是使用与密钥相同的字母(SPI)加密的明文,因为密钥恰好在第二次加密时重复。从第一个`LWM`开始到第二个`LWM`开始的字母数,我们称之为*间距*,是 13。这表明用于该密文的密钥有 13 个字母长。只要看看重复的序列,你就能算出钥匙的长度。 |
131 | 131 |
|
132 | 132 | 然而,在大多数密文中,密钥不会方便地与重复的字母序列对齐,或者密钥可能在重复序列之间重复多次,这意味着重复字母之间的字母数量将等于密钥的倍数,而不是密钥本身。为了解决这些问题,让我们看一个更长的例子,在这个例子中,我们不知道键是什么。 |
133 | 133 |
|
@@ -155,13 +155,13 @@ LWMNLMPWPYTBXLWMMLZ |
155 | 155 |
|
156 | 156 | 正如所料,这两个密钥产生了两种不同的密文。当然,黑客不会知道原始消息或密钥,但他们会在`TIGGSLGULTIGFEY`密文中看到序列`TIG`出现在索引 0 和索引 9 处。因为`9 – 0 = 9`,这些序列之间的间距是 9,这似乎表明原始键是一个九个字母的键;在这种情况下,指示是正确。 |
157 | 157 |
|
158 | | -然而,`QFDAMFXLCQFDZYS`密文也会产生一个重复序列(`QFD`),出现在索引 0 和索引 9 处。这些序列之间的间距也是 9,这表明该密文中使用的密钥也是 9 个字母长。但是我们知道密钥只有三个字母长:`XYZ`。 |
| 158 | +然而,`QFDAMFXLCQFDZYS`密文也会产生一个重复序列(`QFD`),出现在索引 0 和索引 9 处。这些序列之间的间距也是 9,这表明该密文中使用的密钥也是 9 个字母长。但是我们知道密钥只有三个字母长:`XYZ`。 |
159 | 159 |
|
160 | | -当消息中的相同字母(在我们的示例中为)用密钥中的相同字母(在我们的示例中为 ABC 和 XYZ)加密时,会出现重复序列,这发生在消息和密钥中的相似字母“排列”并加密到相同序列时。这种对齐可以发生在任意倍数的真实密钥长度上(比如 3、6、9、12 等等),这就是为什么三个字母的密钥可以产生间隔为 9 的重复序列。 |
| 160 | +当消息中的相同字母(在我们的示例中为)用密钥中的相同字母(在我们的示例中为 ABC 和 XYZ)加密时,会出现重复序列,这发生在消息和密钥中的相似字母“排列”并加密到相同序列时。这种对齐可以发生在任意倍数的真实密钥长度上(比如 3、6、9、12 等等),这就是为什么三个字母的密钥可以产生间隔为 9 的重复序列。 |
161 | 161 |
|
162 | 162 | 因此,可能的密钥长度不仅取决于间距,还取决于间距的任何因素。9 的因数是 9、3 和 1。因此,如果您发现间距为 9 的重复序列,您必须考虑密钥的长度可能是 9 或 3。我们可以忽略 1,因为只有一个字母密钥的维吉尼亚密码就是凯撒密码。 |
163 | 163 |
|
164 | | -卡西斯基检验的第 2 步包括找出每个间距的因子(不包括 1),如表 20-2 所示。 |
| 164 | +卡西斯基检验的第 2 步包括找出每个间距的因子(不包括 1),如表 20-2 所示。 |
165 | 165 |
|
166 | 166 | **表 20-2**: 各间距的因子 |
167 | 167 |
|
@@ -271,7 +271,7 @@ B OZDAZAZMYHZGZJCWZZZJHT 1 |
271 | 271 | | `QQGKUGJTJVVVCGUTUVCQP` | C | |
272 | 272 | | `CVYMYBOSYRORTDOLVRVPO` | k,N,R,V,Y | |
273 | 273 |
|
274 | | -因为第一个子密钥有五个可能的子密钥,第二个子密钥有两个,第三个子密钥有一个,第四个子密钥有五个,所以组合的总数是 50(我们将所有可能的子密钥相乘得到 5 × 2 × 1 × 5)。换句话说,我们需要暴力破解 50 个可能的密钥。但是这比强行通过 26 × 26 × 26 × 26(或 456,976)个可能的键要好得多,如果我们没有缩小可能的子项列表的话。如果维吉尼亚调更长,这种差异会变得更大! |
| 274 | +因为第一个子密钥有五个可能的子密钥,第二个子密钥有两个,第三个子密钥有一个,第四个子密钥有五个,所以组合的总数是 50(我们将所有可能的子密钥相乘得到 5 × 2 × 1 × 5)。换句话说,我们需要暴力破解 50 个可能的密钥。但是这比强行通过 26 × 26 × 26 × 26(或 456,976)个可能的键要好得多,如果我们没有缩小可能的子项列表的话。如果维吉尼亚调更长,这种差异会变得更大! |
275 | 275 |
|
276 | 276 | #### 强行通过可能的密钥 |
277 | 277 |
|
@@ -611,7 +611,7 @@ computer scientist. He was highly influential in the development of computer |
611 | 611 | --snip-- |
612 | 612 | ``` |
613 | 613 |
|
614 | | -### 导入模块并设置 main()函数 |
| 614 | +### 导入模块并设置`main()`函数 |
615 | 615 |
|
616 | 616 | 让我们看看维吉尼亚黑客程序的源代码。黑客程序导入了许多不同的模块,包括一个名为`itertools`的新模块,您将很快了解到更多信息: |
617 | 617 |
|
@@ -755,7 +755,7 @@ def getUsefulFactors(num): |
755 | 755 |
|
756 | 756 | 如果它不是`1`,第 73 行追加该值。我们排除了`1`,因为如果维吉尼亚密钥的长度为 1,那么维吉尼亚密码将与凯撒密码没有什么不同! |
757 | 757 |
|
758 | | -#### 用 set()函数删除重复 |
| 758 | +#### 用`set()`函数删除重复 |
759 | 759 |
|
760 | 760 | 回想一下,作为卡西斯基检查的一部分,我们需要知道最常见的因素,因为最常见的因素几乎肯定是维吉尼亚键的长度。然而,在我们分析每个因素的频率之前,我们需要使用`set()`函数从`factors`列表中删除任何重复的因素。例如,如果`getUsefulFactors()`被传递给`num`参数的`9`,那么`9 % 3 == 0`将是`True`,并且`i`和`otherFactor`都将被附加到`factors`。但是`i`和`int(num / i)`都等于`3`,所以`3`会被追加到列表中两次。为了防止重复的数字,我们可以将列表传递给`set()`,它返回一个列表作为设置的数据类型。*集合*数据类型类似于列表数据类型,除了集合值只能包含唯一值。 |
761 | 761 |
|
@@ -893,7 +893,7 @@ def kasiskiExamination(ciphertext): |
893 | 893 | ['cat', 'dog', 'mouse', 1, 2, 3] |
894 | 894 | ``` |
895 | 895 |
|
896 | | -如您所见,`eggs` ( `1`、`2`和`3`)中的所有值都作为离散项追加到`spam`中。 |
| 896 | +如您所见,`eggs` ( `1`、`2`和`3`)中的所有值都作为离散项追加到`spam`中。 |
897 | 897 |
|
898 | 898 | #### 扩展重复序列空间字典 |
899 | 899 |
|
@@ -933,7 +933,7 @@ def kasiskiExamination(ciphertext): |
933 | 933 |
|
934 | 934 | 第 131 行的`for`循环遍历`factorsByCount`中的每个元组,并将元组的索引`0`项附加到`allLikelyKeyLengths`的末尾。在这个`for`循环完成后,`allLikelyKeyLengths`变量应该包含`factorsByCount`中的所有整数因子,这些因子作为一个列表从`kasiskiExamination()`返回。 |
935 | 935 |
|
936 | | -尽管我们现在有能力找到消息加密时可能使用的密钥长度,但我们需要能够从消息中分离出使用相同子密钥加密的字母。回想一下,用密钥`'XYZ'`加密`'THEDOGANDTHECAT'`最终会使用密钥中的`'X'`来加密索引`0`、`3`、`6`、`9`和`12`处的消息字母。因为来自原始英文消息的这些字母是用相同的子密钥(`'X'`)加密的,所以解密的文本应该具有类似于英文的字母频率计数。我们可以使用这些信息来找出子密钥。 |
| 936 | +尽管我们现在有能力找到消息加密时可能使用的密钥长度,但我们需要能够从消息中分离出使用相同子密钥加密的字母。回想一下,用密钥`'XYZ'`加密`'THEDOGANDTHECAT'`最终会使用密钥中的`'X'`来加密索引`0`、`3`、`6`、`9`和`12`处的消息字母。因为来自原始英文消息的这些字母是用相同的子密钥(`'X'`)加密的,所以解密的文本应该具有类似于英文的字母频率计数。我们可以使用这些信息来找出子密钥。 |
937 | 937 |
|
938 | 938 | ### 获取用相同子密钥加密的信件 |
939 | 939 |
|
@@ -1080,7 +1080,7 @@ def attemptHackWithKeyLength(ciphertext, mostLikelyKeyLength): |
1080 | 1080 |
|
1081 | 1081 | `vigenereHacker.py`程序使用`itertools.product()`函数来测试所有可能的子密钥组合。 |
1082 | 1082 |
|
1083 | | -##### ITER tools . product()函数 |
| 1083 | +##### `itertools.product()`函数 |
1084 | 1084 |
|
1085 | 1085 | `itertools.product()`函数产生列表或类似列表的值中所有可能的项目组合,比如字符串或元组。这样的项目组合被称为*笛卡尔积*,这也是该函数得名的原因。该函数返回一个 itertools 产品对象值,该值也可以通过传递给`list()`转换成一个列表。在交互式 shell 中输入以下内容以查看示例: |
1086 | 1086 |
|
@@ -1299,7 +1299,7 @@ def hackVigenere(ciphertext): |
1299 | 1299 | break |
1300 | 1300 | ``` |
1301 | 1301 |
|
1302 | | -第 245 行开始一个`for`循环,只要不在`allLikelyKeyLengths`中,就为`keyLength`(范围从`1`到`MAX_KEY_LENGTH`)的每个值调用`attemptHackWithKeyLength()`。原因是`allLikelyKeyLengths`中的密钥长度已经在第 233 到 238 行的代码中试过了。 |
| 1302 | +第 245 行开始一个`for`循环,只要不在`allLikelyKeyLengths`中,就为`keyLength`(范围从`1`到`MAX_KEY_LENGTH`)的每个值调用`attemptHackWithKeyLength()`。原因是`allLikelyKeyLengths`中的密钥长度已经在第 233 到 238 行的代码中试过了。 |
1303 | 1303 |
|
1304 | 1304 | 最后,`hackedMessage`中的值在第 253 行返回: |
1305 | 1305 |
|
|
0 commit comments