Skip to content

Commit d017444

Browse files
committed
2023-04-10 18:19:23
1 parent 58b9a26 commit d017444

File tree

5 files changed

+38
-38
lines changed

5 files changed

+38
-38
lines changed

docs/cracking/21.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
### 使用字典攻击暴力破解维吉尼亚密码
2727

28-
我们将首先使用字典攻击来破解维吉尼亚密码。字典文件`dictionary.txt` (可在本书网站`www.nostarch.com/crackingcodes`)约有 45000 个英语单词。我的电脑只需不到五分钟就能完成对一个长段落大小的信息的所有解密。这意味着,如果使用一个英语单词来加密一个维吉尼亚密文,该密文容易受到字典攻击。让我们来看一个使用字典攻击来破解维吉尼亚密码的程序的源代码。*
28+
我们将首先使用字典攻击来破解维吉尼亚密码。字典文件`dictionary.txt` (可在本书网站`www.nostarch.com/crackingcodes`约有 45000 个英语单词。我的电脑只需不到五分钟就能完成对一个长段落大小的信息的所有解密。这意味着,如果使用一个英语单词来加密一个维吉尼亚密文,该密文容易受到字典攻击。让我们来看一个使用字典攻击来破解维吉尼亚密码的程序的源代码。*
2929

3030
### 维吉尼亚字典破解程序的源代码
3131

@@ -95,7 +95,7 @@ Copying hacked message to clipboard:
9595
The real secrets are not the ones I tell.
9696
```
9797

98-
程序建议的第一个关键字(`ASTROLOGY`)不起作用,所以用户按`回车`让黑客程序继续,直到找到正确的解密密钥(`ASTRONOMY`)
98+
程序建议的第一个关键字(`ASTROLOGY`不起作用,所以用户按`回车`让黑客程序继续,直到找到正确的解密密钥(`ASTRONOMY`
9999

100100
### 关于维吉尼亚字典破解计划
101101

@@ -127,7 +127,7 @@ SPILLTHEBEANSSPILLT
127127
LWMNLMPWPYTBXLWMMLZ
128128
```
129129
130-
注意,字母`LWM`重复了两次。原因是在密文中,`LWM`是使用与密钥相同的字母(SPI)加密的明文,因为密钥恰好在第二次加密时重复。从第一个`LWM`开始到第二个`LWM`开始的字母数,我们称之为*间距*,是 13。这表明用于该密文的密钥有 13 个字母长。只要看看重复的序列,你就能算出钥匙的长度。
130+
注意,字母`LWM`重复了两次。原因是在密文中,`LWM`是使用与密钥相同的字母(SPI加密的明文,因为密钥恰好在第二次加密时重复。从第一个`LWM`开始到第二个`LWM`开始的字母数,我们称之为*间距*,是 13。这表明用于该密文的密钥有 13 个字母长。只要看看重复的序列,你就能算出钥匙的长度。
131131
132132
然而,在大多数密文中,密钥不会方便地与重复的字母序列对齐,或者密钥可能在重复序列之间重复多次,这意味着重复字母之间的字母数量将等于密钥的倍数,而不是密钥本身。为了解决这些问题,让我们看一个更长的例子,在这个例子中,我们不知道键是什么。
133133
@@ -155,13 +155,13 @@ LWMNLMPWPYTBXLWMMLZ
155155
156156
正如所料,这两个密钥产生了两种不同的密文。当然,黑客不会知道原始消息或密钥,但他们会在`TIGGSLGULTIGFEY`密文中看到序列`TIG`出现在索引 0 和索引 9 处。因为`90 = 9`,这些序列之间的间距是 9,这似乎表明原始键是一个九个字母的键;在这种情况下,指示是正确。
157157
158-
然而,`QFDAMFXLCQFDZYS`密文也会产生一个重复序列(`QFD`),出现在索引 0 和索引 9 处。这些序列之间的间距也是 9,这表明该密文中使用的密钥也是 9 个字母长。但是我们知道密钥只有三个字母长:`XYZ`
158+
然而,`QFDAMFXLCQFDZYS`密文也会产生一个重复序列(`QFD`,出现在索引 0 和索引 9 处。这些序列之间的间距也是 9,这表明该密文中使用的密钥也是 9 个字母长。但是我们知道密钥只有三个字母长:`XYZ`
159159
160-
当消息中的相同字母(在我们的示例中为)用密钥中的相同字母(在我们的示例中为 ABC 和 XYZ)加密时,会出现重复序列,这发生在消息和密钥中的相似字母“排列”并加密到相同序列时。这种对齐可以发生在任意倍数的真实密钥长度上(比如 3、6、9、12 等等),这就是为什么三个字母的密钥可以产生间隔为 9 的重复序列。
160+
当消息中的相同字母(在我们的示例中为)用密钥中的相同字母(在我们的示例中为 ABCXYZ加密时,会出现重复序列,这发生在消息和密钥中的相似字母“排列”并加密到相同序列时。这种对齐可以发生在任意倍数的真实密钥长度上(比如 36912 等等),这就是为什么三个字母的密钥可以产生间隔为 9 的重复序列。
161161
162162
因此,可能的密钥长度不仅取决于间距,还取决于间距的任何因素。9 的因数是 931。因此,如果您发现间距为 9 的重复序列,您必须考虑密钥的长度可能是 93。我们可以忽略 1,因为只有一个字母密钥的维吉尼亚密码就是凯撒密码。
163163
164-
卡西斯基检验的第 2 步包括找出每个间距的因子(不包括 1),如表 20-2 所示。
164+
卡西斯基检验的第 2 步包括找出每个间距的因子(不包括 1,如表 20-2 所示。
165165
166166
**20-2**: 各间距的因子
167167
@@ -271,7 +271,7 @@ B OZDAZAZMYHZGZJCWZZZJHT 1
271271
| `QQGKUGJTJVVVCGUTUVCQP` | C |
272272
| `CVYMYBOSYRORTDOLVRVPO` | k,N,R,V,Y |
273273
274-
因为第一个子密钥有五个可能的子密钥,第二个子密钥有两个,第三个子密钥有一个,第四个子密钥有五个,所以组合的总数是 50(我们将所有可能的子密钥相乘得到 5 × 2 × 1 × 5)。换句话说,我们需要暴力破解 50 个可能的密钥。但是这比强行通过 26 × 26 × 26 × 26(或 456,976)个可能的键要好得多,如果我们没有缩小可能的子项列表的话。如果维吉尼亚调更长,这种差异会变得更大!
274+
因为第一个子密钥有五个可能的子密钥,第二个子密钥有两个,第三个子密钥有一个,第四个子密钥有五个,所以组合的总数是 50(我们将所有可能的子密钥相乘得到 5 × 2 × 1 × 5。换句话说,我们需要暴力破解 50 个可能的密钥。但是这比强行通过 26 × 26 × 26 × 26(或 456976个可能的键要好得多,如果我们没有缩小可能的子项列表的话。如果维吉尼亚调更长,这种差异会变得更大!
275275
276276
#### 强行通过可能的密钥
277277
@@ -611,7 +611,7 @@ computer scientist. He was highly influential in the development of computer
611611
--snip--
612612
```
613613

614-
### 导入模块并设置 main()函数
614+
### 导入模块并设置`main()`函数
615615

616616
让我们看看维吉尼亚黑客程序的源代码。黑客程序导入了许多不同的模块,包括一个名为`itertools`的新模块,您将很快了解到更多信息:
617617

@@ -755,7 +755,7 @@ def getUsefulFactors(num):
755755
756756
如果它不是`1`,第 73 行追加该值。我们排除了`1`,因为如果维吉尼亚密钥的长度为 1,那么维吉尼亚密码将与凯撒密码没有什么不同!
757757
758-
#### 用 set()函数删除重复
758+
#### 用`set()`函数删除重复
759759
760760
回想一下,作为卡西斯基检查的一部分,我们需要知道最常见的因素,因为最常见的因素几乎肯定是维吉尼亚键的长度。然而,在我们分析每个因素的频率之前,我们需要使用`set()`函数从`factors`列表中删除任何重复的因素。例如,如果`getUsefulFactors()`被传递给`num`参数的`9`,那么`9 % 3 == 0`将是`True`,并且`i``otherFactor`都将被附加到`factors`。但是`i``int(num / i)`都等于`3`,所以`3`会被追加到列表中两次。为了防止重复的数字,我们可以将列表传递给`set()`,它返回一个列表作为设置的数据类型。*集合*数据类型类似于列表数据类型,除了集合值只能包含唯一值。
761761
@@ -893,7 +893,7 @@ def kasiskiExamination(ciphertext):
893893
['cat', 'dog', 'mouse', 1, 2, 3]
894894
```
895895
896-
如您所见,`eggs` ( `1``2``3`)中的所有值都作为离散项追加到`spam`中。
896+
如您所见,`eggs` ( `1``2``3`中的所有值都作为离散项追加到`spam`中。
897897
898898
#### 扩展重复序列空间字典
899899
@@ -933,7 +933,7 @@ def kasiskiExamination(ciphertext):
933933
934934
131 行的`for`循环遍历`factorsByCount`中的每个元组,并将元组的索引`0`项附加到`allLikelyKeyLengths`的末尾。在这个`for`循环完成后,`allLikelyKeyLengths`变量应该包含`factorsByCount`中的所有整数因子,这些因子作为一个列表从`kasiskiExamination()`返回。
935935
936-
尽管我们现在有能力找到消息加密时可能使用的密钥长度,但我们需要能够从消息中分离出使用相同子密钥加密的字母。回想一下,用密钥`'XYZ'`加密`'THEDOGANDTHECAT'`最终会使用密钥中的`'X'`来加密索引`0``3``6``9``12`处的消息字母。因为来自原始英文消息的这些字母是用相同的子密钥(`'X'`)加密的,所以解密的文本应该具有类似于英文的字母频率计数。我们可以使用这些信息来找出子密钥。
936+
尽管我们现在有能力找到消息加密时可能使用的密钥长度,但我们需要能够从消息中分离出使用相同子密钥加密的字母。回想一下,用密钥`'XYZ'`加密`'THEDOGANDTHECAT'`最终会使用密钥中的`'X'`来加密索引`0``3``6``9``12`处的消息字母。因为来自原始英文消息的这些字母是用相同的子密钥(`'X'`加密的,所以解密的文本应该具有类似于英文的字母频率计数。我们可以使用这些信息来找出子密钥。
937937
938938
### 获取用相同子密钥加密的信件
939939
@@ -1080,7 +1080,7 @@ def attemptHackWithKeyLength(ciphertext, mostLikelyKeyLength):
10801080
10811081
`vigenereHacker.py`程序使用`itertools.product()`函数来测试所有可能的子密钥组合。
10821082
1083-
##### ITER tools . product()函数
1083+
##### `itertools.product()`函数
10841084
10851085
`itertools.product()`函数产生列表或类似列表的值中所有可能的项目组合,比如字符串或元组。这样的项目组合被称为*笛卡尔积*,这也是该函数得名的原因。该函数返回一个 itertools 产品对象值,该值也可以通过传递给`list()`转换成一个列表。在交互式 shell 中输入以下内容以查看示例:
10861086
@@ -1299,7 +1299,7 @@ def hackVigenere(ciphertext):
12991299
                    break
13001300
```
13011301
1302-
245 行开始一个`for`循环,只要不在`allLikelyKeyLengths`中,就为`keyLength`(范围从`1`到`MAX_KEY_LENGTH`)的每个值调用`attemptHackWithKeyLength()`。原因是`allLikelyKeyLengths`中的密钥长度已经在第 233238 行的代码中试过了。
1302+
245 行开始一个`for`循环,只要不在`allLikelyKeyLengths`中,就为`keyLength`(范围从`1`到`MAX_KEY_LENGTH`的每个值调用`attemptHackWithKeyLength()`。原因是`allLikelyKeyLengths`中的密钥长度已经在第 233238 行的代码中试过了。
13031303
13041304
最后,`hackedMessage`中的值在第 253 行返回:
13051305

docs/cracking/22.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ Python 3.6 和更高版本有`secrets`模块,它使用操作系统的真正随
105105

106106
你已经学会了如何破解维吉尼亚密码。如果我们可以证明两次填充密码和维吉尼亚密码是一样的,我们就可以用破解维吉尼亚密码的相同技术来证明它是可破解的。
107107

108-
为了解释为什么两次性密码本就像维吉尼亚密码一样是可破解的,让我们回顾一下维吉尼亚密码在加密长度超过密钥的消息时是如何工作的。当我们用完了密钥中用于加密的字母时,我们返回到密钥的第一个字母并继续加密。例如,要用 10 个字母的密钥(如 YZNMPZXYXY)加密 20 个字母的消息(如蓝碘 INBOUND CAT ),前 10 个字母(蓝碘)用 YZNMPZXYXY 加密,然后接下来的 10 个字母(INBOUND CAT)也用 YZNMPZXYXY 加密。图 21-3 显示了这种环绕效果。
108+
为了解释为什么两次性密码本就像维吉尼亚密码一样是可破解的,让我们回顾一下维吉尼亚密码在加密长度超过密钥的消息时是如何工作的。当我们用完了密钥中用于加密的字母时,我们返回到密钥的第一个字母并继续加密。例如,要用 10 个字母的密钥(如 YZNMPZXYXY加密 20 个字母的消息(如蓝碘 INBOUND CAT ),前 10 个字母(蓝碘)用 YZNMPZXYXY 加密,然后接下来的 10 个字母(INBOUND CAT也用 YZNMPZXYXY 加密。图 21-3 显示了这种环绕效果。
109109

110110
![Images](img/bab228282655653e32398856b6118805.png)
111111

@@ -117,11 +117,11 @@ Python 3.6 和更高版本有`secrets`模块,它使用操作系统的真正随
117117

118118
*图 21-4:使用一次性密码本密钥加密明文产生的密文与维吉尼亚密码相同。*
119119

120-
当我们将图 21-3 (ZKHQXNAGKCGMOAJMAAXR)中所示的维吉尼亚密码的密文与图 21-4 (ZKHQXNAGKC GMOAJMAAXR)中所示的一次性密码的密文进行比较时,我们可以看到它们是完全相同的。这意味着,因为两次密码本密码与维吉尼亚密码具有相同的属性,所以我们可以使用相同的技术来破解它!
120+
当我们将图 21-3 (ZKHQXNAGKCGMOAJMAAXR中所示的维吉尼亚密码的密文与图 21-4 (ZKHQXNAGKC GMOAJMAAXR中所示的一次性密码的密文进行比较时,我们可以看到它们是完全相同的。这意味着,因为两次密码本密码与维吉尼亚密码具有相同的属性,所以我们可以使用相同的技术来破解它!
121121

122122
### 总结
123123

124-
简而言之,一次性密码本(one-time pad)是一种通过使用与消息长度相同、真正随机且仅使用一次的密钥来使维吉尼亚密码加密不受黑客攻击的方法。当这三个条件都满足时,一次性密码本就不可能破了。不过因为用起来太不方便了,所以没有用于日常加密。通常,一次性密码本会亲自分发,并包含一系列钥匙。但要确保这份名单不会落入坏人之手!
124+
简而言之,一次性密码本(one-time pad是一种通过使用与消息长度相同、真正随机且仅使用一次的密钥来使维吉尼亚密码加密不受黑客攻击的方法。当这三个条件都满足时,一次性密码本就不可能破了。不过因为用起来太不方便了,所以没有用于日常加密。通常,一次性密码本会亲自分发,并包含一系列钥匙。但要确保这份名单不会落入坏人之手!
125125

126126
**练习题**
127127

docs/cracking/23.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,15 @@ def isPrimeTrialDiv(num):
275275
    return True
276276
```
277277

278-
第 18 行使用 mod 操作符(`%`)检查余数是否为 0。如果余数为 0,`num`可被`i`整除,因此不是质数,循环返回`False`。如果第 17 行上的`for`循环没有返回`False`,则该函数返回第 20 行上的`True`以指示`num`可能是质数。
278+
第 18 行使用 mod 操作符(`%`检查余数是否为 0。如果余数为 0,`num`可被`i`整除,因此不是质数,循环返回`False`。如果第 17 行上的`for`循环没有返回`False`,则该函数返回第 20 行上的`True`以指示`num`可能是质数。
279279

280280
函数`isPrimeTrialDiv()`中的试除法算法很有用,但它不是测试素性的唯一方法。你也可以用厄拉多塞筛找到质数。
281281

282282
### 厄拉多塞的筛子
283283

284284
厄拉多塞的筛子(发音为“era-taws-thuh-knees”)是一种算法,可以找到一个数字范围内的所有质数。为了了解这个算法是如何工作的,想象一组盒子。每个盒子里装的是从 1 到 50 的整数,都标为质数,如图 22-2 所示。
285285

286-
为了实施厄拉多塞筛,我们从我们的范围中排除非质数,直到只剩下质数。因为 1 从来不是质数,所以让我们先把数字 1 标为“不是质数”那我们就把所有 2 的倍数(除了 2)都标为“不是质数。”这意味着我们将把整数 4 (2 × 2)、6 (2 × 3)、8 (2 × 4)、10、12 等等直到 50 标记为“非质数”,如图 22-3 所示。
286+
为了实施厄拉多塞筛,我们从我们的范围中排除非质数,直到只剩下质数。因为 1 从来不是质数,所以让我们先把数字 1 标为“不是质数”那我们就把所有 2 的倍数(除了 2都标为“不是质数。”这意味着我们将把整数 4`2 × 2`)、6(`2 × 3`)、8(`2 × 4`、10、12 等等直到 50 标记为“非质数”,如图 22-3 所示。
287287

288288
![Images](img/136ba5c2ec9cf06a7d9174c29f20f971.png)
289289

0 commit comments

Comments
 (0)