3 个版本 (稳定版)
使用旧的Rust 2015
1.0.1 | 2018年12月7日 |
---|---|
1.0.0 | 2018年12月3日 |
0.1.0 | 2018年4月23日 |
#1301 in 密码学
41KB
883 行代码
盗贼密语
布鲁斯·施奈尔设计的Solitaire密码的Rust实现。
摘要
Solitaire密码是由著名的密码学家布鲁斯·施奈尔为尼尔·斯蒂芬森的小说《密码宇宙》发明的。它涉及使用标准的52张扑克牌牌组,以及两张(最好是不同的)小丑牌来生成密钥流,该密钥流与明文消息结合以产生加密的密文。您可以在这里了解更多关于Solitaire密码的信息。
算法
Solitaire密码中有三种不同的操作:初始化牌组、加密明文和解密密文。每个操作都使用了许多相同的步骤,只有一两个不同。以下是详细步骤:
初始化牌组
要开始生成密钥流,用户必须首先正确地初始化牌组。通常使用密码;一个单词或句子。在我们的例子中,我们将使用密码 SOLITAIRE
。从第一步开始,然后对密码中的每个字母重复第二步至第六步。在我们的例子中,您将执行这些步骤九次。请注意,您始终以牌面向上工作,因此牌组顶部的牌始终对您可见。
-
重新排列牌组。按照面值和花色重新排列牌组:从A到K,每个花色按桥牌顺序(梅花、方块、红心、黑桃)。最后是两张小丑牌,称为A和B(如何区分小丑牌由您决定,但您必须始终如一地确定A和B是哪两张小丑牌)。
-
移动小丑A。在牌组中找到小丑A,并将其向下移动一个位置;也就是说,将其与下面的牌交换。如果小丑A是牌组中的最后一张牌,将其放在牌组的顶部下面。
-
移动小丑B。在牌组中找到小丑B,并将其向下移动两个位置。如果小丑B是牌组的倒数第二张牌,将其放在牌组的顶部下面。如果小丑B是牌组中的最后一张牌,将其放在从顶部数第二张牌的下面。
-
进行三次分割。将牌堆中第一张Joker牌之上的所有牌(无论哪张Joker牌)与第二张Joker牌之下的所有牌进行交换。例如:如果牌堆排列如下
4 of spades, 3 of clubs, Joker B, ...rest of the cards..., Joker A, King of diamonds, Queen of
Hearts
执行三次分割后,牌堆将看起来像这样
King of diamonds, Queen of Hearts, Joker B, ...rest of the cards..., Joker A, 4 of spades, 3 of
clubs
- 进行计数分割。查看牌堆中的最后一张牌,并使用下方的卡片值表将其转换为数字。然后,从牌堆顶部开始向下数这么多张牌,并在那里分割牌堆。将分割后的牌放在牌堆的最后一张牌之前。例如,如果您的牌堆排列如下
3 of clubs, 2 of hearts, 9 of spades, ...rest of the cards..., 2 of clubs
执行计数分割后,牌堆将看起来像这样
9 of spades, ...rest of the cards..., 3 of clubs, 2 of hearts, 2 of clubs
卡片值表
A | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | J | Q | K | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
黑桃 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
红心 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
方块 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
梅花 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
注意,无论哪张,Jokers的值都是53。
- 进行值分割。值分割与计数分割非常相似,只是它使用密码中的字母值来确定在牌堆中分割的位置。要确定在牌堆中分割的位置,请参考下方的字母值表。分割牌堆后,将卡片放在牌堆的最后一张牌之前,就像进行计数分割时那样。例如,使用上面的密码
SOLITAIRE
,以字母S
为密钥,您向下数十九张牌,分割牌堆,然后将这十九张牌放在牌堆的最后一张牌之前。
字母值表
字母 | 值 |
---|---|
A | 1 |
B | 2 |
C | 3 |
D | 4 |
E | 5 |
F | 6 |
G | 7 |
H | 8 |
I | 9 |
J | 10 |
K | 11 |
L | 12 |
M | 13 |
N | 14 |
O | 15 |
P | 16 |
Q | 17 |
R | 18 |
S | 19 |
T | 20 |
U | 21 |
V | 22 |
W | 23 |
X | 24 |
Y | 25 |
Z | 26 |
加密明文
要加密明文,您必须首先生成一个与要加密的明文长度相同的密钥流。然后,对于明文消息中的每个字符,将其与相应的密钥流字符相加,以产生加密的密文字符。具体步骤如下
- 编码特殊字符。Solitaire密码不支持对非字母(A-Z)字符进行操作。因此,您必须首先将任何特殊字符编码为一系列字母字符的组合。Thieves' Cant只支持有限的非字母字符子集,如下方的非字母编码表所示。例如:消息
HELLO WORLD
将被编码为HELLOXZAWORLD
。
非字母编码表
字符 | 编码 |
---|---|
(空格) | XZA |
. | XZB |
, | XZC |
' | XZD |
? | XZE |
! | XZF |
-
分组明文字符。按照惯例,明文消息应分成每组五个字符。如果最后一个组中没有五个字符,则使用'Z'字符填充消息。例如:消息
HELLOXZAWORLD
被分成字符串HELLO XZAWO RLDZZ
。 -
将每个字符转换为数字。使用上面的字母值表,将明文中的每个字母转换为相应的数字值。
-
设置牌堆。使用上面的步骤,使用给定的密码设置牌堆。
-
找到输出牌。按照“键入牌组”操作中的步骤2-6进行操作。然后,为了找到输出牌,首先查看牌组的顶部牌,并使用上面的牌值表将其转换为数字。然后,向下数这么多张牌,并记录你数过的牌之后的牌。例如,如果你有以下牌组
3 of clubs, 2 of diamonds, ace of spades, 9 of hearts, ...rest of the cards...
输出牌将是红桃9
,其值为35
。
-
生成密文字符。将输出牌的值加上明文字符的值。如果得到的总和大于26,则从总和减去26,直到值小于或等于26。使用上面的字母值表将该值转换为字符。
-
重复操作。对明文信息中的每个字符重复步骤5和6。
按照上述步骤,使用密钥SOLITAIRE
对文本HI THERE
进行加密,将得到密文OEPXV NZLBM
。
解密密文
为了解密密文,用户应遵循上面“加密明文”部分中的所有步骤。然而,在第4步生成明文值时,你应从牌输出值中减去密文字符的值。如果得到的结果小于1,则将26加到该值上,直到它在1到26之间。然后使用字母值表将该值转换为字符。请记住从明文的末尾移除任何'Z'填充字符,并将特殊字符编码解码为正确的字符。
用法
$ tvct deck -n // Generate a new, randomly shuffled deck.
$ tvct deck -n -f key.deck // Generate a new, randomly shuffled deck, in a new location.
$ tvct deck -n -k "SOLITAIRE" -f key.deck // Generate a new deck, keyed using the string "SOLITAIRE", with a new file location.
$ tvct deck // Print out the order of the cards within the deck.
$ tvct encrypt "HELLO WORLD" // Encrypt a message; output: OAHBF TUMYB BELRT
$ tvct encrypt -f key.deck "HELLO WORLD" // Encrypt the message using a different key file
$ tvct decrypt "OAHBF TUMYB BELRT" // Decrypt the ciphertext, output: HELLO WORLD
$ tvct decrypt -f key.deck "OOAHBF TUMYB BELRT" // Decrypt the ciphertext with a different key file
依赖项
~3.5–4.5MB
~70K SLoC