Cryptography - Ciphers I

In the previous article, I gave an introduction to cryptology and a demonstration of how ciphers work. I started with the very basic cipher, the Caesar cipher. In this article we will see how Caesar cipher can be improved and are introduced to other ciphers.

Poly-alphabetic Cipher

What makes Caesar cipher vulnerable? The fact that it can be cracked in only 25 attempts at the maximum or even less if you're smart. The polyalphabetic cipher comes to our rescue. In polyalphabetic cipher the key is a word rather than a number (shift amount, as in Caesar cipher). The key should be less than or equal to the plain-text we input.

Let us take a sample input: thisisamessage

And a sample key: secret

Each letter of the plain-text is first mapped to each letter from the key as follows:

t  h  i  s  i  s  a  m  e  s  s  a  g  e
20 8  9  19 9 19  1 13  5 19 19  1  7  5
s  e  c  r  e  t  s  e  c  r  e  t  s  e
19 5  3 18  5 20  19 5  3 18  5 20 19  5

As you can see if the length of text is not the exact multiple of the length of the key we simply use the letters of the key until the input text is completed, like for the last letters (ge) of the message as many letters of key (se) are used. The number under each letter represents its place of occurrence in the English alphabet. Now each letter is shifted by the amount of the letter of key under it. For example, t is shifted by 19 and becomes m, h by 5 and becomes m, i by 3 and becomes l and so on.

After the shift the table becomes:

t  h  i  s  i  s  a  m  e  s  s  a  g  e
20 8  9  19 9 19  1 13  5 19 19  1  7  5
s  e  c  r  e  t  s  e  c  r  e  t  s  e
19 5  3 18  5 20  19 5  3 18  5 20 19  5
m  m  l  k  n  m  t  r  h  k  x  u  z  j

And hence, the cipher text is computed to be: mmlknmtrhkxuzj

As you may have judged by now, this cipher is relatively tougher to crack than the Caesar cipher.

Here is an example JavaScript implementation, try it out:

Check the page source for the JavaScript code or check this open-source project I made for the poly-alphabetic cipher in Java.

The poly-alphabetic cipher, though better than Caesar cipher, is very vulnerable because in the end it is a substitution cipher and if the data is more then patterns can be guessed and the encryption can be cracked.

One Time Pad

The One time pad is also a substitution cipher but it is better than Caesar and the poly-alphabetic cipher in a way that every letter in the input message is shifted by a random amount and hence a key is generated which is equal to the input data. What makes this cipher secure is the randomness.

A n letter word in this case can have 26n possible outcomes which for just a six letter word is 308915776 possibilities. This number increases exponentially as the input data size increases. The downside of this cipher however is that it generates a key which is equal to the input data which doubles the amount of data to be handled and transmitted.

Here is an example for you to try:

# OneTimePad.py
# Abdul Fatir
import sys
import random
def shiftAlpha(alpha,shift):
  if ord(alpha)+shift > 122:
    return chr(ord(alpha)+shift-122+96)
  else:
    return chr(ord(alpha)+shift)
  plaintext = sys.argv[1]
  cipher = ''
  for i in range(len(plaintext)):
    cipher += shiftAlpha(plaintext[i],random.randint(1,26))
  print cipher

The ciphers about which we read till now were all substitution ciphers. The next cipher which we're going to read about is a type of symmetric key encryption.

Block Cipher

This is a type of symmetric key encryption which is in use even today. This encryption is based on the XOR logic gate. The beauty of the XOR logic gate is that this operation is symmetric i.e. (X [xor] Y) [xor] Y = X

Now if we XOR the plain-text with a key we get the cipher-text and XORing the cipher-text again with the key returns the plain-text.

Every ASCII alphabet (letters, alphabets, special chars etc.) has a value ranging from 0 to 255 hence every ASCII character can be represented by an 8 bit (1 byte) binary number. For example, A in ASCII is 65 which will be equal to 01000001 in a 8 bit binary notation.

First the input text is converted into binary. Let us take hello as the input text and key as the key.

hello: 01101000 01100101 01101100 01101100 01101111

Next, it is checked if the length of the plain-text is an exact multiple of the length of the key. If yes, we proceed to the next step. If no, a number of pad bytes are added to make the plain-text an exact multiple on the key.

In our example the length of the key is 3 and the plain-text is 5. Now, 5 is not a multiple of 3 and the next multiple is 6. The difference between 6 and 5 is 1 so we need to add one pad character to make the input an exact multiple of 3. The pad character is a null byte (00000000) i.e. a binary number with all bits 0.

After adding the padding we are:

01101000 01100101 01101100 01101100 01101111 00000000

Now we convert the key to binary

key: 01101011 01100101 01111001

Then we map each character of the plain-text with each character of the key repeatedly:

A: 01101000 01100101 01101100 01101100 01101111 00000000
B: 01101011 01100101 01111001 01101011 01100101 01111001

Then simply do C = A [xor] B:

A: 01101000 01100101 01101100 01101100 01101111 00000000
B: 01101011 01100101 01111001 01101011 01100101 01111001
C: 00000011 00000000 00010101 00000111 00001010 01111001

The C is cipher-text which in integers is equal to: 3 0 21 7 10 121

These ASCII codes of the cipher-text if converted to the character come out to be very weird characters. Just for the sake of the example 3 0 21 7 10 121 in ASCII characters is:

♥ \0 § \a \n y
# BlockCipher.py
# Abdul Fatir
import sys
plaintext = sys.argv[1]
while 1:
  key = raw_input("Please enter the key:")
  if len(key) <= len(plaintext):
    break
  print "The key-length should be less than or equal to the plaintext"

keyindex = 0
ciphertext = ''
# Add padding
extra_chars = len(plaintext)%len(key)
if extra_chars > 0:
  for i in range(len(key)-extra_chars):
    plaintext += chr(0)
for index in range(len(plaintext)):
  if keyindex==len(key):
    keyindex=0
  cipherletter = chr(ord(plaintext[index])^ord(key[keyindex]))
  ciphertext += cipherletter
  keyindex+=1
  for i in range(len(ciphertext)):
    print (ord(ciphertext[i])),

References:

Learn Cryptography