Crates.io | thieves-cant |
lib.rs | thieves-cant |
version | 1.0.1 |
source | src |
created_at | 2018-04-23 20:12:47.462264 |
updated_at | 2018-12-07 21:20:30.805083 |
description | A Rust implementation of the Solitaire Cipher designed by Bruce Schneier. |
homepage | |
repository | https://gitlab.com/zcdziura/thieves-cant |
max_upload_size | |
id | 62014 |
size | 76,629 |
A Rust implementation of the Solitaire Cipher designed by Bruce Schneier.
The Solitaire Cipher was invented by famed cryptographer Bruce Schneier for Neal Stephenson's novel Cryptonomicon. It involves using a standard 52-card deck of playing cards, plus two (preferably distinct) Joker cards used to generate a keystream which is combined with the plaintext message to produce encrypted ciphertext. You can read more about the Solitaire Cipher here.
There are three distinct operations within the Solitaire Cipher: keying the deck, encrypting plaintext, and decrypting ciphertext. Each of these operations use many of the same steps, with only one or two differing between them. The steps are detailed below:
To begin generating a keystream, the user must first properly key the deck. You
typically use a passphrase; either a single word or sentence. For our example,
we will be using the passphrase SOLITAIRE
. Start with step one, and then
repeat steps two through six for each letter within the passphrase. In our
example, you will perform these steps nine times. Note that you will always work
with the deck face up, so the top card within the deck will always be visible to
you.
Rearranging the Deck. Rearrange the deck in order of face value and suit: from Ace to King and each suit in Bridge Order (Clubs, Diamonds, Hearts, Spades). Last should be the two Jokers, dubbed A and B (how you distinguish the jokers is up to you, but you MUST remain consistent with which Joker cards are A and B).
Move Joker A. Find Joker A in the deck, and move it down one position; that is, swap it with the card directly beneath. If Joker A is the last card on the deck, place it below the top card in the deck.
Move Joker B. Find Joker B in the deck, and move it down two positions. If Joker B is the second-to-last card in the deck, place it below the top card. If Joker B is the last card in the deck, place it below the second card from the top.
Perform a Triple Cut. Swap all of the cards above the first Joker card from the top of the deck (regardless of which joker it is) with all of the cards below the second Joker card. For example: if the deck is arranged like so:
4 of spades, 3 of clubs, Joker B, ...rest of the cards..., Joker A, King of diamonds, Queen of
Hearts
After performing the triple cut, the deck will look like this:
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
After performing the count cut, the deck will look like this:
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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Clubs | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
Diamonds | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
Hearts | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
Spades | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
Note that Jokers, no matter which one, have a value of 53.
SOLITAIRE
from above, keying
the deck with the letter S
, you count down nineteen cards, cut the deck,
and then place those nineteen cards before the last card in the deck.Letter | Value |
---|---|
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 |
To encrypt plaintext, you must first generate a keystream with the same length as the plaintext that they want to encrypt. Then, for each character in the plaintext message, add it to the corresponding keystream character in order to produce an encrypted ciphertext character. The exact steps are detailed below:
HELLO WORLD
will be encoded as HELLOXZAWORLD
.Character | Encoding |
---|---|
(Space) | XZA |
. | XZB |
, | XZC |
' | XZD |
? | XZE |
! | XZF |
Group Plaintext Characters. By convention, the plaintext message should
be broken up into groups of five characters. If the last group doesn't have
five characters in it, pad the message with 'Z' characters. For example: the
message HELLOXZAWORLD
is broken up into the string HELLO XZAWO RLDZZ
.
Translate Each Character into a Number. Use the Letter Value Table above and translate each letter in the plaintext into its corresponding numeric value.
Key the Deck. Using the steps above, key the deck using the given passphrase.
Find the Output Card. Follow steps 2-6 from the "Keying the Deck" operation. Then, to find the output card, first look at the top card in the deck, and convert it to a number using the Card Value Table above. Then, count down that many cards and record the card that comes AFTER the cards you have counted down. For example, if you have the following deck:
3 of clubs, 2 of diamonds, ace of spades, 9 of hearts, ...rest of the cards...
the output card will be the 9 of hearts
, with the value of 35
.
Generate Ciphertext Character. Add the value of the output card to the value of the character in the plaintext. If the resulting sum is greater than 26, then subtract 26 from the sum until the value is less-than-or-equal-to 26. Convert that value into a character using the Letter Value Table above.
Rinse and Repeat. Repeat steps 5 and 6 for each character in the plaintext message.
Following the steps above, encrypting the text HI THERE
using the key
SOLITAIRE
will result in the ciphertext OEPXV NZLBM
.
To decrypt ciphertext, users should follow all of the steps found within the
Encrypting Plaintext
section above. However, on step 4, when generating the
plaintext value, you instead subtract the value of the ciphertext character from
the card output value. If the resulting difference is less than 1, add 26 to
that value until it's between 1 and 26. Then convert the value into a character
using the Letter Value Table. Remember to strip away any 'Z' padding characters
from the end of the plaintext, and decode the special character encodings into
the proper character.
$ 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