2.2. Rail Fence Cipher#
One common transposition method is known as the rail fence method. In this method, the message is written with alternate letters being placed into separate upper and lower lines. The half of the message written on the lower line is appended to the first half found on the upper line. This is called a 2-row railfence method since the plaintext message is divided into 2 rows.
plaintext: a rose by any other name would smell as sweet
2-row separation: A O E Y N O H R A E O L S E L S W E
R S B A Y T E N M W U D M L A S E T
ciphertext: AOEYN OHRAE OLSEL SWERS BAYTE NMWUD MLASE T
This same method could be modified to have 3 or more rows. Notice the “zig-zag” pattern that the text follows as it goes from the upper row, to the middle row, to the lower row, then back to the middle row before returning to the upper row.
plaintext: a rose by any other name would smell as sweet
3-row separation: A E N H A O S L W
R S B A Y T E N M W U D M L A S E T
O Y O R E L E S E
ciphertext: AENHA OSLWR SBAYT ENMWU DMLAS ETOYO RELES E
When using a rail fence cipher, the key is the number of rows that the plaintext was divided into to complete the transposition. Both the sender and the receiver need this key in order to encipher and decipher their respective messages.
Since the key is the number of rows used, that sets a limit on the number of possible keys. Take our example message of 36 characters. Since you can’t have a key value of 0, there’s a theoretical limit of 36 possible keys, some more useful than others. Below you’ll find all possible encryptions that use keys from 1 to 36. Are there any values that don’t seem like very good choices?
plaintext = 'a rose by any other name would smell as sweet'
plaintext = plaintext.replace(' ', '').upper()
mykey = 2
# Python3 program to illustrate
# Rail Fence Cipher Encryption
# and Decryption
# function to encrypt a message
def encryptRailFence(text, key):
# create the matrix to cipher
# plain text key = rows ,
# length(text) = columns
# filling the rail matrix
# to distinguish filled
# spaces from blank ones
rail = [['\n' for i in range(len(text))]
for j in range(key)]
# to find the direction
dir_down = False
row, col = 0, 0
for i in range(len(text)):
# check the direction of flow
# reverse the direction if we've just
# filled the top or bottom rail
if (row == 0) or (row == key - 1):
dir_down = not dir_down
# fill the corresponding alphabet
rail[row][col] = text[i]
col += 1
# find the next row using
# direction flag
if dir_down:
row += 1
else:
row -= 1
# now we can construct the cipher
# using the rail matrix
result = []
for i in range(key):
for j in range(len(text)):
if rail[i][j] != '\n':
result.append(rail[i][j])
return("" . join(result))
print("Key: 01 Ciphertext: ", plaintext)
for i in range(2, len(plaintext)+1):
print("Key:", str(i).zfill(2), "Ciphertext: ", encryptRailFence(plaintext, i) )
Key: 01 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMELLASSWEET
Key: 02 Ciphertext: AOEYNOHRAEOLSELSWERSBAYTENMWUDMLASET
Key: 03 Ciphertext: AENHAOSLWRSBAYTENMWUDMLASETOYORELESE
Key: 04 Ciphertext: AYHESSRBATEMWDMASTOENORAOLELWESYNULE
Key: 05 Ciphertext: ANASWRAYNMDMSEOYORELESESBTEWULATEHOL
Key: 06 Ciphertext: AOOSRYTWUASONHELLWSAEMDLEEYRASEEBNMT
Key: 07 Ciphertext: AHSRTEDMTOORLEESYNULEENAOLWBAMWASYES
Key: 08 Ciphertext: ARLRENLAOHAESSTMMSEOESWBYWDEYNOLEAUT
Key: 09 Ciphertext: AAWRNMSEORESESEWATEHOLBTULYOLEAYDMNS
Key: 10 Ciphertext: AERMWTOAOESNUEERLWBEDSYHSSATMANOELYL
Key: 11 Ciphertext: AORWUOELSMDEASBNMTYREEAELENHLWYTASOS
Key: 12 Ciphertext: ALRUDOOSSWMEEEBMLYALANANRSYESTOHWETE
Key: 13 Ciphertext: ASRDMOLESULEOLBWAYESAMSNAWYNEORETETH
Key: 14 Ciphertext: AERMLOSLSDAELSBUSYOWAWENEEYMTOATNHRE
Key: 15 Ciphertext: ALRLAOESSMSESWBDEYLEAUTNOYWOETMHAENR
Key: 16 Ciphertext: ASRASOLWSLEEEEBMTYSADNLYUOOTWHEEMRAN
Key: 17 Ciphertext: AWRSEOSESATELBLYEAMNSYDOLTUHOEWRENMA
Key: 18 Ciphertext: AERETOWSSESBAYLALNEYMOSTDHLEURONWAEM
Key: 19 Ciphertext: ARTOESEEWBSYSAANLYLOETMHSEDRLNUAOMWE
Key: 20 Ciphertext: AROSTEEBEYWASNSYAOLTLHEEMRSNDALMUEOW
Key: 21 Ciphertext: AROSEBTYEAENWYSOSTAHLELRENMASMDELWUO
Key: 22 Ciphertext: AROSEBYATNEYEOWTSHSEARLNLAEMMESWDOLU
Key: 23 Ciphertext: AROSEBYANYTOETEHWESRSNAALMLEEWMOSUDL
Key: 24 Ciphertext: AROSEBYANYOTTHEEERWNSASMAELWLOEUMLSD
Key: 25 Ciphertext: AROSEBYANYOTHETRENEAWMSESWAOLULLEDMS
Key: 26 Ciphertext: AROSEBYANYOTHERNTAEMEEWWSOSUALLDLSEM
Key: 27 Ciphertext: AROSEBYANYOTHERNAMTEEWEOWUSLSDASLMLE
Key: 28 Ciphertext: AROSEBYANYOTHERNAMEWTOEUELWDSSSMAELL
Key: 29 Ciphertext: AROSEBYANYOTHERNAMEWOUTLEDESWMSESLAL
Key: 30 Ciphertext: AROSEBYANYOTHERNAMEWOULDTSEMEEWLSLSA
Key: 31 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMTEELELWASS
Key: 32 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMELTLEAESWS
Key: 33 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMELLATSESEW
Key: 34 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMELLASSTWEE
Key: 35 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMELLASSWETE
Key: 36 Ciphertext: AROSEBYANYOTHERNAMEWOULDSMELLASSWEET
It would appear by the time you exceed a key value of 18, or half the largest possible key value, you can start to see fragments of the plaintext emerging. This is because with a key value of 19, thus creating 19 rows to fill, the zig zag pattern doesn’t have enough letters to complete one full pass from the top row to the bottom and back to the top. As a result, when reading across the rows, the first few rows only contain a single letter. For example:
A
R T
O E
S E
E W
B S
Y S
A A
N L
Y L
O E
T M
H S
E D
R L
N U
A O
M W
E
So, in general a message of length \(n\) has \(n\) possible keys, but any key value larger than \(n/2\) will begin to leak information about the plaintext. Additionally, a key value of 1 does not encrypt the message at all. If you knew that a message was enciphered using a rail fence method, it wouldn’t take too long to try all possible key lengths up to \(n/2\) and see which one produces a readable plaintext message.