Skip to content →

solitaiRe encryption in R

Out of sheer boredom, I decided to try my hand at implementing the Solitaire encryption algorithm in R. Solitaire was developed by Bruce Schneier for Neil Stephenson’s Crytonomicon, and is designed to be implemented using only a deck of cards. My R implementation is still in alpha, but so far it seems to run successfully.

Installation

The package is hosted on github at https://github.com/areshenk/solitaiRe, and can be installed and loaded using the devtools package

devtools::install_github('areshenk/solitaiRe')
library(solitaiRe)

The package implements an S4 class “deck” containing a standard set of 52 playing cards, plus 2 jokers, in standard bridge order. Solitaire operations are implemented as S4 methods. The package also contains a few convenience functions for converting text data into an appropriate format for encryption.

Using the package

As an example, suppose we want to encrypt the following passage from Cormac McCarthy’s Outer Dark

message <- "The tinker in his burial tree was a wonder 
to the birds. The vultures that came by day to nose with 
their hooked beaks among his buttons and pockets like 
outrageous pets soon left him naked of his rags and 
flesh alike. Black mandrake sprang beneath the tree as 
it will where the seed of the hanged falls and in spring 
a new branch pierced his breast and flowered in a green
boutonnière perennial beneath his yellow grin. He took 
the sparse winter snows upon what thatch of hair still 
clung to his dried skull and hunters that passed that 
way never chanced to see him brooding among his barren
limbs. Until wind had tolled the thinker's bones and 
seasons loosed them one by one to the ground below and 
his bleached and weathered brisket hung in that 
lonesome wood like a bone birdcage."

The first step is to strip it of all non-alphabetic characters, convert it to lower case, and (optionally, but conventionally), separate it into five character chunks padded with X’s.

plaintext <- stripText(x = message)
plaintext <- chunkText(plaintext, chunk.length = 5,
                       pad = T)

which gives

## [1] "theti nkeri nhisb urial treew asawo ndert otheb irdst hevul tures thatc ameby dayto nosew ithth eirho okedb eaksa mongh isbut tonsa ndpoc ketsl ikeou trage ouspe tssoo nleft himna kedof hisra gsand flesh alike black mandr akesp rangb eneat hthet reeas itwil lwher ethes eedof theha ngedf allsa ndins pring anewb ranch pierc edhis breas tandf lower edina green bouto nnièr epere nnial benea thhis yello wgrin hetoo kthes parse winte rsnow supon whatt hatch ofhai rstil lclun gtohi sdrie dskul landh unter sthat passe dthat wayne verch anced tosee himbr oodin gamon ghisb arren limbs until windh adtol ledth ethin kersb onesa ndsea sonsl oosed themo nebyo netot hegro undbe lowan dhisb leach edand weath eredb riske thung intha tlone somew oodli keabo nebir dcage "

We can then create the deck which will be used to generate the key, using the newDeck() function. By default, newDeck creates an unshuffled deck in standard bridge order

newDeck()
## An object of class "deck"
## Slot "cards":
##  [1] "CA"  "C2"  "C3"  "C4"  "C5"  "C6"  "C7"  "C8"  "C9"  "C10" "CJ" 
## [12] "CQ"  "CK"  "DA"  "D2"  "D3"  "D4"  "D5"  "D6"  "D7"  "D8"  "D9" 
## [23] "D10" "DJ"  "DQ"  "DK"  "HA"  "H2"  "H3"  "H4"  "H5"  "H6"  "H7" 
## [34] "H8"  "H9"  "H10" "HJ"  "HQ"  "HK"  "SA"  "S2"  "S3"  "S4"  "S5" 
## [45] "S6"  "S7"  "S8"  "S9"  "S10" "SJ"  "SQ"  "SK"  "J1"  "J2"

where the first letter indicates the suit (C = Clubs, D = Diamonds, H = Hearts, S = Spades), and the second denotes the card value. The jokers are denoted “J1” and “J2”.

We can create a randomly shuffled deck using

newDeck(method = 'shuffle')
## An object of class "deck"
## Slot "cards":
##  [1] "D3"  "D4"  "SJ"  "C4"  "H7"  "CA"  "DJ"  "SA"  "C8"  "C5"  "S5" 
## [12] "D6"  "SK"  "S7"  "CJ"  "H8"  "SQ"  "C2"  "CQ"  "DA"  "C6"  "H9" 
## [23] "S8"  "S2"  "C10" "S9"  "H2"  "HA"  "D10" "D2"  "HK"  "H4"  "S6" 
## [34] "H5"  "D8"  "DQ"  "H10" "H3"  "C9"  "J2"  "H6"  "S10" "D7"  "CK" 
## [45] "HJ"  "S4"  "D9"  "S3"  "C7"  "C3"  "DK"  "J1"  "D5"  "HQ"

We can also specify the deck manually using method = ‘fixed’ and passing an argument cards containing a character vector.

Alternatively, we can create a deck keyed by a passphrase (see the link above for a description of the procedure). To do this, we pass newDeck() an argument key containing the passphrase. Note that spaces and non-alphabetic text will be stripped from the passphrase automatically.

passphrase <- 'outerdark'
deck <- newDeck(method = 'key', key = passphrase)
deck
## An object of class "deck"
## Slot "cards":
##  [1] "HK"  "SA"  "S2"  "S3"  "S4"  "S5"  "S6"  "S7"  "D7"  "SK"  "SQ" 
## [12] "C3"  "C4"  "C10" "C7"  "C8"  "C9"  "D6"  "CQ"  "CK"  "DA"  "D2" 
## [23] "D3"  "D4"  "D5"  "CA"  "C2"  "D9"  "D10" "DJ"  "CJ"  "J1"  "HA" 
## [34] "S8"  "D8"  "S9"  "S10" "C5"  "C6"  "J2"  "DQ"  "SJ"  "H2"  "H3" 
## [45] "H4"  "H5"  "H6"  "H7"  "H8"  "H9"  "H10" "HJ"  "HQ"  "DK"

The message is then encrypted using

cryptotext <- encrypt(deck, plaintext)
print(chunkText(cryptotext, chunk.length = 5))
## [1] "swcrr jzedh iybet itckg caxxs embxu rdcgn leiff ftkad jiasn viobo shtdy kcali kqouk haqtq chhff crksh zosce vaqwb quuvb dpcub vvjhd agssp yvnnn bmihv mzedb dsxdm ttyho nrojg wvvux fmnta hjxfp hcqvs wipne kfvet lcaru cprxv acwpf eqelb qydim yamsy twgku dbifa wnuhp lhpux ktzia lwssr pngxz jucgh pqzro fjldj ygdxz ghrxc fokmc wmume sscdl tvtaq qntgy keydt swicj nqnen upcym gtvxq oblfx kalox ejbyw vitde jgjdd dfewf xpozo jnggj flncm eyzkq uxptj eotrv knlqm jhodv tguah dkwki xaxhm xivkm lldzf htlbb qarnl fvsjv hlumv unpcv bbker zmoup afjgr xpyvq yylob kflnq dtois vjnsf narit rjqri twqch foeio ynwzu aylpc dssho zpssg zygdl xouax sxebe uyxra uwdsq kwbjl rsxxi crfro hcvia mvuex agsxw xhdva jkxuf yfznf rihaq firhd uawpx snkat vqdhe kuero qpzmt slakr ervwa uejmk "

And decrypted using the same deck:

decrypted <- decrypt(deck, cryptotext)
print(chunkText(decrypted, chunk.length = 5))
## [1] "theti nkeri nhisb urial treew asawo ndert otheb irdst hevul tures thatc ameby dayto nosew ithth eirho okedb eaksa mongh isbut tonsa ndpoc ketsl ikeou trage ouspe tssoo nleft himna kedof hisra gsand flesh alike black mandr akesp rangb eneat hthet reeas itwil lwher ethes eedof theha ngedf allsa ndins pring anewb ranch pierc edhis breas tandf lower edina green bouto nnifr epere nnial benea thhis yello wgrin hetoo kthes parse winte rsnow supon whatt hatch ofhai rstil lclun gtohi sdrie dskul landh unter sthat passe dthat wayne verch anced tosee himbr oodin gamon ghisb arren limbs until windh adtol ledth ethin kersb onesa ndsea sonsl oosed themo nebyo netot hegro undbe lowan dhisb leach edand weath eredb riske thung intha tlone somew oodli keabo nebir dcage "

Published in Blog

Comments are closed.