0% found this document useful (0 votes)
8 views

Experiment-2

Uploaded by

mohammed.ansari
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

Experiment-2

Uploaded by

mohammed.ansari
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

Experiment - 2

Name: Ansari Mohammed Shanouf Valijan


Class: B.E. Computer Engineering, Semester - VII
UID: 2021300004
Batch: VII

Aim:
To implement different transposition techniques.

Theory:
Transposition techniques are methods of encryption where the positions of the characters
in the plaintext are shifted according to a specific system or key, without altering the actual
characters themselves. Unlike substitution ciphers, which replace characters, transposition
techniques maintain the original content but rearrange it to obfuscate the message. These
methods rely on rearranging the plaintext in a systematic manner, making it harder for an
unauthorized person to decipher it without knowing the key. The security of transposition
ciphers often lies in the complexity of the rearrangement pattern used, and they are
commonly used in combination with other cryptographic methods to enhance security..
Following are the transposition techniques taken into consideration for the experiment-

Rail Fence Cipher


The Rail Fence Cipher is a simple transposition technique where the plaintext is written in a
zigzag or "rail" pattern across multiple rows, and then read off row by row to create the
ciphertext. For example, in a 3-rail fence cipher, the text is written diagonally in three rows
and then read sequentially across the rows. This method is relatively easy to break since it
uses a fixed pattern, but it's still a classic example of how transposition ciphers work by
rearranging the order of letters.

Row-Column Cipher
The Row-Column transposition cipher involves writing the plaintext in a grid of a fixed
number of rows and columns, then reading the columns in a specific order to create the
ciphertext. The key for this cipher is the order in which the columns are read. This method
can significantly scramble the plaintext, making it difficult to decipher without knowing the
exact dimensions and the order of columns used in the encryption process.

Double Row-Column Cipher


The Double Row-Column Cipher is an extension of the row-column method, where the
transposition is applied twice. First, the plaintext is written into a grid, and the columns are
read in a certain order to generate an intermediate ciphertext. This intermediate ciphertext
is then written back into another grid, and another round of columnar transposition is
applied. By performing two rounds of transposition, the security of the cipher is enhanced,
making it harder to break through frequency analysis or pattern recognition techniques.

Implementation:
Following are the codes for encryption and decryption for all the techniques taken into
consideration-
[1] Rail Fence Cipher
from random import randint
from math import ceil

def encrypt(plaintext, depth):


plaintextlen = len(plaintext)
lencycle = 2*(depth - 1)

reqchars = ceil((plaintextlen - 1)/lencycle)*lencycle - plaintextlen + 1


for _ in range(reqchars):
plaintext += chr(randint(97, 122))

plaintextlen += reqchars
ciphertext = ''
offset = 1
for i in range(depth):
if i == 0:
for j in range(0, plaintextlen, lencycle):
ciphertext += plaintext[j]
elif i < depth - 1:
for j in range(0, plaintextlen - 1, lencycle):
ciphertext += plaintext[j + offset]
ciphertext += plaintext[j + lencycle - offset]
offset += 1
else:
for j in range(0, plaintextlen - 1, lencycle):
ciphertext += plaintext[j + offset]

return ciphertext.upper()
def decrypt(ciphertext, depth):
ciphertextlen = len(ciphertext)
lencycle = 2*(depth - 1)

ciphertext = ciphertext.lower()
plaintext = ''
numCycles = (ciphertextlen - 1)//lencycle
charDistribution = []
currIndex = numCycles + 1
for i in range(depth):
if i == 0:
charDistribution.append(ciphertext[0:numCycles+1])
elif i < depth - 1:
charDistribution.append(ciphertext[currIndex:currIndex + 2*numCycles])
currIndex += 2*numCycles
else:
charDistribution.append(ciphertext[currIndex:])

isForward = True
currIndex = 0
while len(charDistribution[0]) != 0:
if isForward:
plaintext += charDistribution[currIndex][0]
charDistribution[currIndex] = charDistribution[currIndex][1:]
currIndex += 1
if currIndex == depth:
isForward = False
currIndex = depth - 1
else:
currIndex -= 1
plaintext += charDistribution[currIndex][0]
charDistribution[currIndex] = charDistribution[currIndex][1:]
if currIndex == 0:
isForward = True
currIndex = 1

return plaintext

print('\n\n')
plaintext = 'meetingatwestminsterbridgeateight'
key = 6
print(f'Plain Text --> {plaintext}')
print('Key --> ', key)
print('Encrpyted Text --> ', encrypt(plaintext, key))
print('Decrypted Text --> ', decrypt('MEBGVEWSRRIHBETTEIETZTAMTDTHAIGISGASPNNEX',
key))
print('\n\n')

[2] Row-Column Cipher


from random import randint
from math import ceil
from itertools import permutations

def encrypt(plaintext, key):


numColumns = len(key)
plaintextlen = len(plaintext)
numCharsReq = ceil(plaintextlen/numColumns)*numColumns - plaintextlen

for _ in range(numCharsReq):
plaintext += chr(randint(97, 122))

plaintextlen += numCharsReq
charMatrix = []
for i in range(0, plaintextlen, numColumns):
charMatrix.append([plaintext[j] for j in range(i, i + numColumns)])

keychars = [char for char in key]


ciphertext = ''
for char in keychars:
for i in range(len(charMatrix)):
ciphertext += charMatrix[i][ord(char) - 49]

return ciphertext.upper()

def decrypt(ciphertext, key):


ciphertext = ciphertext.lower()
ciphertextlen = len(ciphertext)
numRows = ciphertextlen//len(key)

charMatrix = []
for i in range(0, ciphertextlen, numRows):
charMatrix.append([ciphertext[j] for j in range(i, i + numRows)])

keychars = [ord(char) - 48 for char in key]


charMatrix = [x for _, x in sorted(zip(keychars, charMatrix))]

plaintext = ''
for col in range(numRows):
for row in range(len(key)):
plaintext += charMatrix[row][col]

return plaintext

print('\n\n')
plaintext = 'answerinfivewords'
key = '2413'
print(f'Plain Text --> {plaintext}')
print('Key --> ', key)
print('Encrpyted Text --> ', encrypt(plaintext, key))
print('Decrypted Text --> ', decrypt('NRIOYWNEDHAEFWSSIVRF', key))
print('\n\n')
[3] Double Row-Column Cipher
from random import randint
from math import ceil
from itertools import permutations

def encryptutil(plaintext, key):


numColumns = len(key)
plaintextlen = len(plaintext)
numCharsReq = ceil(plaintextlen/numColumns)*numColumns - plaintextlen

for _ in range(numCharsReq):
plaintext += chr(randint(97, 122))

plaintextlen += numCharsReq
charMatrix = []
for i in range(0, plaintextlen, numColumns):
charMatrix.append([plaintext[j] for j in range(i, i + numColumns)])

keychars = [char for char in key]


ciphertext = ''
for char in keychars:
for i in range(len(charMatrix)):
ciphertext += charMatrix[i][ord(char) - 49]

return ciphertext.upper()

def decryptutil(ciphertext, key):


ciphertext = ciphertext.lower()
ciphertextlen = len(ciphertext)
numRows = ciphertextlen//len(key)

charMatrix = []
for i in range(0, ciphertextlen, numRows):
charMatrix.append([ciphertext[j] for j in range(i, i + numRows)])

keychars = [ord(char) - 48 for char in key]


charMatrix = [x for _, x in sorted(zip(keychars, charMatrix))]

plaintext = ''
for col in range(numRows):
for row in range(len(key)):
plaintext += charMatrix[row][col]

return plaintext

def encrypt(plaintext, key):


result = encryptutil(plaintext, key)
return encryptutil(result.lower(), key)

def decrypt(ciphertext, key):


result = decryptutil(ciphertext, key)
return decryptutil(result.upper(), key)

print('\n\n')
plaintext = 'picktheboxesattheeitherendsoftherow'
key = '1423'
print(f'Plain Text --> {plaintext}')
print('Key --> ', key)
print('Encrpyted Text --> ', encrypt(plaintext, key))
print('Decrypted Text --> ', decrypt('PERHEXDERAFSOHECIWTHKTYTTESONBEIEOTH', key))
print('\n\n')

Testing:
Following are the images depicting encryption and decryption tests that were carried out to
confirm the proper functioning of the codes-

[1] Rail Fence Cipher

[2] Row-Column Cipher

[3] Double Row-Column Cipher


Attack:
[1] Rail Fence Cipher

def brute_force_attack(ciphertext):
print('\n\n')
for i in range(2, 10):
print(f'depth --> {i}, decrypted message --> {decrypt(ciphertext, i)}')
print('\n\n')

brute_force_attack('PFEARIWSURJSOSTWYTROSNQRIAEDM')

Following is an image depicting the brute-force attack on Rail Fence cipher (key was
constrained to be a single digit positive integer greater than 2)-

Decrypted text found when key was set as 8.


Decrypted text: Password is your first name.

[2] Row-Column Cipher

def brute_force_attack(ciphertext):
print('\n\n')
allperms = list(permutations(['1','2','3','4']))
for perm in allperms:
key = ''
for char in perm:
key += char
print(f'key --> {key}, decrypted message --> {decrypt(ciphertext, key)}')
print('\n\n')

brute_force_attack('COMALTIMANUIOISB')
Following shows a list of trials with different keys (actual key being constrained to contain
only 1, 2, 3 and 4), the decrypted message being ‘Location is Mumbai’ when key is ‘3142’-

[3] Double Row-Column Cipher

def brute_force_attack(ciphertext):
print('\n\n')
allperms = list(permutations(['1','2','3','4']))
for perm in allperms:
key = ''
for char in perm:
key += char
print(f'key --> {key}, decrypted message --> {decrypt(ciphertext, key)}')
print('\n\n')

brute_force_attack('EWRTAMLICSHOGDEGCENONMTAHIHR')

The decrypted message was found at key ‘4123’ (same constraints as mentioned
previously), the message being ‘Who is the commander in charge’. Following shows the
brute-force attack as attempted-
Plots:
For the purpose of understanding the nature of substitution cipher techniques, a text
containing about 17000 characters was processed to obtain the plaintext, the code of which
is as follows-

import re

with open('text_to_encrypt.txt', 'r', encoding="utf-8") as file:


text = file.read()

text = text.lower()
processed_text = re.sub(r'[^a-z]', '', text)

with open('plaintext.txt', 'w') as file:


file.write(processed_text)

Further, the generated plaintext was converted to cipher text using various techniques
mentioned above. Each of the text files were analysed for the frequency of all the
characters (a to z) in them.
Following are the bar graphs showing the frequency of each letter in the text files-
Following is a plot depicting the relative frequency of letters in case of cipher texts
generated using the techniques mentioned above (ranked in the descending order)-

As can be observed above and as expected, the frequency of letters in all the cipher texts is
almost the same and matches with that of the plaintext. This is because in case of
transposition ciphers, the characters in the plaintext are just being shuffled is a particular
manner rather than introducing new characters for the old ones (as was done in case of
substitution ciphers).

Conclusion:
By performing this experiment, I was able to understand various transposition cipher
techniques that can be used to encode messages. I was able to write the implementation
logic for the above-mentioned transposition techniques and verify their proper functioning
using simple examples. Further, I was able to perform brute-force attack on each of the
implementations by setting certain constrains on the key (ignoring which would make brute-
force a highly impractical approach to attack).

You might also like