Skip to content

Commit 3b965cc

Browse files
committed
2023-04-10 18:26:36
1 parent f175f76 commit 3b965cc

File tree

4 files changed

+9
-9
lines changed

4 files changed

+9
-9
lines changed

docs/cracking/20.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
*图 19-2:典型英文文本中出现频率最高和最低的字母*
4545

46-
在破解维吉尼亚密码时,频率分析非常有用,因为它可以让我们一次一个地暴力破解每个子密钥。例如,如果一条消息是用密钥 PIZZA 加密的,我们需要用 26 个 <sup class="calibre21">5 个</sup>或 11,881,376 个密钥来一次找到整个密钥。然而,为了只暴力破解五个子密钥中的一个,我们只需要尝试 26 种可能性。对五个子密钥中的每一个都这样做意味着我们只需要暴力破解 26 × 5 或 130 个子密钥。
46+
在破解维吉尼亚密码时,频率分析非常有用,因为它可以让我们一次一个地暴力破解每个子密钥。例如,如果一条消息是用密钥 PIZZA 加密的,我们需要用`26 ** 5`或 11,881,376 个密钥来一次找到整个密钥。然而,为了只暴力破解五个子密钥中的一个,我们只需要尝试 26 种可能性。对五个子密钥中的每一个都这样做意味着我们只需要暴力破解 26 × 5 或 130 个子密钥。
4747

4848
使用密钥 PIZZA,消息中从第一个字母开始的每第五个字母用 P 加密,从第二个字母开始的每第五个字母用 I 加密,依此类推。我们可以通过用所有 26 个可能的子密钥解密密文中的每五个字母来暴力破解第一个子密钥。对于第一个子密钥,我们会发现 P 产生的解密字母比其他 25 个可能的子密钥更匹配英语的字母频率。这将是 P 是第一个子密钥的一个强有力的指示。然后,我们可以对其他子项重复此操作,直到获得整个项。
4949

docs/cracking/21.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,9 +1034,9 @@ def attemptHackWithKeyLength(ciphertext, mostLikelyKeyLength):
10341034
10351035
在第 161 行的`for`循环完成后,`allFreqScores`应该包含与`mostLikelyKeyLength`中的整数值相等的多个列表值。例如,如果`mostLikelyKeyLength`是`3`,`allFreqScores`将是三个列表的列表。第一个列表值保存完整维吉尼亚键的第一个子密钥的前三个最高匹配子密钥的元组。第二个列表值保存完整维吉尼亚键的第二个子密钥的前三个最高匹配子密钥的元组,依此类推。
10361036
1037-
最初,如果我们想要暴力破解整个维吉尼亚密钥,可能的密钥数量将是 26 的密钥长度次方。例如,如果密钥是长度为 7ROSEBUD,则可能有 26 <sup class="calibre21">7</sup>,即 8031810176 个密钥。
1037+
最初,如果我们想要暴力破解整个维吉尼亚密钥,可能的密钥数量将是 26 的密钥长度次方。例如,如果密钥是长度为 7ROSEBUD,则可能有`26 ** 7`,即 8031810176 个密钥。
10381038
1039-
但是检查英语频率匹配有助于确定每个子项的四个最可能的字母。继续 ROSEBUD 的例子,这意味着我们只需要检查 4<sup class="calibre21">7</sup>,或者 16384 个可能的键,这比 80 亿个可能的键有了巨大的改进!
1039+
但是检查英语频率匹配有助于确定每个子项的四个最可能的字母。继续 ROSEBUD 的例子,这意味着我们只需要检查`4 ** 7`,或者 16384 个可能的键,这比 80 亿个可能的键有了巨大的改进!
10401040
10411041
#### end 关键字自变量为 print()
10421042
@@ -1100,7 +1100,7 @@ def attemptHackWithKeyLength(ciphertext, mostLikelyKeyLength):
11001100
   'C', 'C')]
11011101
```
11021102
1103-
`'ABC'``repeat`关键字参数的整数`4`传递给`itertools` `.product()`会返回一个 itertools 产品对象 ➊,当转换为一个列表时,该对象包含四个值的元组,每个值都有`'A'``'B'``'C'`的可能组合。这产生了一个总共有 3<sup class="calibre21">4</sup>81 个元组的列表。
1103+
`'ABC'``repeat`关键字参数的整数`4`传递给`itertools` `.product()`会返回一个 itertools 产品对象 ➊,当转换为一个列表时,该对象包含四个值的元组,每个值都有`'A'``'B'``'C'`的可能组合。这产生了一个总共有`3 ** 4`81 个元组的列表。
11041104
11051105
还可以将列表值传递给`itertools.product()`以及一些类似于列表的值,比如从`range()`返回的 range 对象。在交互式 shell 中输入以下内容,看看当列表和类似列表的对象被传递给这个函数时会发生什么:
11061106

docs/cracking/22.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
*图 21-1:使用一次性密码本加密一个示例消息*
4141

42-
现在想象一个密码分析者得到了密文(SHOM TDEC)...).他们怎么能攻击密码呢?强行通过按键是行不通的,因为即使对计算机来说,按键也太多了。密钥的数量将等于消息中字母总数的 26 次方。因此,如果在我们的示例中消息有 55 个字母,那么总共有 26 个 <sup class="calibre21">55 个</sup>,即 666091878431395624153823182526730590376250379528249805353030484209594192
42+
现在想象一个密码分析者得到了密文(SHOM TDEC)...).他们怎么能攻击密码呢?强行通过按键是行不通的,因为即使对计算机来说,按键也太多了。密钥的数量将等于消息中字母总数的 26 次方。因此,如果在我们的示例中消息有 55 个字母,那么总共有`26 ** 55`,即 666091878431395624153823182526730590376250379528249805353030484209594192
4343

4444
即使密码分析员有一台足够强大的计算机来尝试所有的密钥,它仍然无法破解*一次性密码本*,因为对于任何密文,所有可能的明文消息都有相同的概率。
4545

docs/cracking/25.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
>>> blockInteger = blockInteger + 7
8080
```
8181

82-
然后我们为`'Howdy'`中的第二个字符`'o'`找到符号集索引。因为这是消息的第二个字符,我们将`'o'`的符号集索引乘以 66 <sup class="calibre21">1</sup> 而不是 66 <sup class="calibre21">0</sup> ,然后将其添加到块中:
82+
然后我们为`'Howdy'`中的第二个字符`'o'`找到符号集索引。因为这是消息的第二个字符,我们将`'o'`的符号集索引乘以`66 ** 1`而不是`66 ** 0`,然后将其添加到块中:
8383

8484
```py
8585
>>> SYMBOLS.index('o')
@@ -167,7 +167,7 @@ M = C^d mod n
167167

168168
比如我们把五个字符的字符串`'Howdy'`加密后发给爱丽丝。当转换为整数块时,消息为`[957285919]`(完整的消息适合一个块,所以列表值中只有一个整数)。Alice 的公钥是 64 位,太小了,不安全,但是我们将使用它来简化本例中的输出。其`n`为 116284564958604315258674918142848831759`e`为 13805220545651593223。(对于 1024 位密钥,这些数字会大得多。)
169169

170-
要加密,我们通过将这些数字传递给 Python 的`pow()`函数,计算957285919<sup class="calibre21">13805220545651593223</sup>)% 116284564958604315258674918142848831759,就像这样:
170+
要加密,我们通过将这些数字传递给 Python 的`pow()`函数,计算`(957285919 ** 13805220545651593223) % 116284564958604315258674918142848831759`,就像这样:
171171

172172
```py
173173
>>> pow(957285919, 13805220545651593223,
@@ -208,7 +208,7 @@ Python 的`pow()`函数使用了一种叫做模幂运算的数学技巧来快速
208208
'y'
209209
```
210210

211-
下一步是将块整数乘以 66 <sup class="calibre21">4</sup> 以获得下一个块整数。计算 957285919 % (66 <sup class="calibre21">4</sup> 得到 8,549,119,这恰好是字符串`'Howd'`的块整数值。我们可以用66 <sup class="calibre21">3</sup> 的底除法来确定这个方块的最后一个字符。为此,请在交互式 shell 中输入以下内容:
211+
下一步是将块整数乘以`66 ** 4`以获得下一个块整数。计算`957,285,919 % (66 ** 4)`得到 8,549,119,这恰好是字符串`'Howd'`的块整数值。我们可以用`66 ** 3`的底除法来确定这个方块的最后一个字符。为此,请在交互式 shell 中输入以下内容:
212212

213213
```py
214214
>>> blockInteger = 8549119
@@ -694,7 +694,7 @@ def getTextFromBlocks(blockInts, messageLength, blockSize):
694694
        for i in range(blockSize - 1, -1, -1):
695695
```
696696
697-
`getTextFromBlocks()`中的代码将每个块整数分割成`blockSize`个整数,每个整数代表一个字符的符号集索引。我们必须反向工作以从`blockInt`中提取符号集索引,因为当我们加密消息时,我们从较小的指数(66 <sup class="calibre21">0</sup>66 <sup class="calibre21">1</sup>66 <sup class="calibre21">2</sup> 等等)开始,但是当解密时,我们必须首先使用较大的指数进行除法和模运算。这就是为什么第 59 行上的`for`循环从`blockSize - 1`开始,然后在每次迭代中减去`1`,直到(但不包括)`-1`。这意味着最后一次迭代中`i`的值是`0`。
697+
`getTextFromBlocks()`中的代码将每个块整数分割成`blockSize`个整数,每个整数代表一个字符的符号集索引。我们必须反向工作以从`blockInt`中提取符号集索引,因为当我们加密消息时,我们从较小的指数(`66 ** 0``66 ** 1``66 ** 2`等等)开始,但是当解密时,我们必须首先使用较大的指数进行除法和模运算。这就是为什么第 59 行上的`for`循环从`blockSize - 1`开始,然后在每次迭代中减去`1`,直到(但不包括)`-1`。这意味着最后一次迭代中`i`的值是`0`。
698698
699699
在我们将符号集索引转换为字符之前,我们需要确保解码的块没有超过`message`的长度。为此,我们检查到目前为止已经从块中翻译出来的字符数`len(message) + i`,仍然少于第 60 行的`messageLength`
700700

0 commit comments

Comments
 (0)