Showing posts with label Cryptography. Show all posts
Showing posts with label Cryptography. Show all posts

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

Cryptography - An Introduction

Cryptography, derived from the Greek κρυπτός (kruptós: hidden, private), is the practice of storing and transferring information securely and privately in presence of third parties who may harm or take undue advantages if the information falls in their hands. The terms cryptography and cryptology are generally interchangeably used but cryptography and cryptanalysis and considered the subset of cryptology. 

In earlier times cryptography was synonymous with encryption i.e. the conversion of plain text data into cipher text (some kind of encoded text) but now it has evolved into a bigger topic going far beyond but also encompassing encryption.

Cryptography can be broadly divided into:

a) Encryption: The conversion of messages and data into an encoded form such that only people authorized to view it can actually view it. The input data referred to as plain-text is converted into an unreadable form called cipher-text and is then transmitted. When reached the destination the data can be decrypted using certain methods to get back the plain-text. 

Encryption can be classified into:

  • Private Key or Symmetric Encryption: In this technique of encryption the same key is used to encrypt and decrypt the message. A specific private key must be decided before performing symmetric encryption.
  • Public Key Encryption: In this technique a user issues a public key which is used to encrypt the message. The private key is only with the user making him the sole party who can decrypt the encoded message. For instance, A issues a public key. B encrypts his message with A's public key and sends the encrypted message to A. A then decrypts the message using his private key.
b) Hashing: Hashing is the process in which arbitrary data is passed into an irreversible function which then produces a fixed length output which can act as a digital fingerprint of the input data. The input data is called the message and the output data is generally termed the message digest. It should however be noted that hashing is not a form of data compression which can convert data of any length into fixed small length data as the output data cannot be converted back to the input message. 

Hashing may initially seem hard to accept (how can you simply not get the data back?) but let us take up an example. Take the modulus function, f(x) = x % 3. Now f(4) maps to 1 and f(25) also maps to 1. If I tell you that this function mapped to 1 you simply cannot tell if the input was 4,7,25 or any other number of type 3k + 1.

What are the uses of hashing, you ask?

I can tell you of two immediately.

i) Passwords: We can simply not store passwords as plain texts. Hence, they are stored as hashes instead. The hash of the input password is compared with the stored hash to tell if the password was correct.

ii) Checking file integrity: We download numerous files from the internet. Some of the websites provides hashes of their files on their website. As the attacks on the internet have increased enormously we cannot guarantee the originality of the file. We can instead download it, hash it and compare it with the hash given on the website to ensure the file downloaded without any corruption or remove the suspicion of incomplete downloads. Two files with the same content will have same hashes so we can check for duplicate files too.

For example,
A asks B, "What is the value of x3 - 15 for x=4?". A does not provide B with the answer (i.e. 49) but instead hashes it using MD5 (a hash function) and provides B with the hash (i.e. f457c545a9ded88f18ecee47145a72c0). Now A can find his own answer and hash it with MD5 to see if it is the correct answer. 

c) Steganography: It is the art of concealing a message inside another message. The cover message may seem totally normal or total garbage at the first view but has useful information under it. A technique of steganography for example is writing a private letter in between the lines of a normal letter using invisible ink.

For example,
How arE you doIng Sir? THat pERson told mE you were not well.
The above text has a hidden message inside it formed by joining all the capitalized letters: he is there.

Ciphers : The Caesar Cipher


Just because the article has sounded too theoretical until now, here I introduce some practicality into it. During the earlier ages the encryption was pen and paper type which is too fragile for today's computer age. Today we have much advanced and unbreakable encryption techniques. However, we should know the basics before going into advanced study about the topic. The very trivial types of encryption (or ciphers) are called the substitution ciphers which work by replacement of each letter of the message with another letter. 

The simplest of substitution ciphers is the Caesar cipher (it was used by Julius Caesar for sending messages, hence the name). In this we shift every letter by specific amount in the English alphabet to get the cipher-text.

For example,
ABCXYZ becomes BCDYZA on a shift of 1.


The Caesar Cipher
It is known that Caesar used a shift of 3 in his messages before sending them. We can see however that this is an extremely weak encryption because we have only 25 possible shifts (the 26th one returns the message as it is). We can easily try all the possible shifts and decode the message. The cracking will be explained later in another article about Cryptanalysis.


Here is an example JavaScript Caesar Cipher, Just enter the message, choose the shift amount and it will encode it for you:





The Example Code

The following section provides example of Caesar cipher in Java, Python and JavaScript which shifts all the alphabets by the shift factor but has no effect on numbers or other symbols.

Java:

// Caesar.java - Abdul Fatir
import java.io.*;
public class Caesar
{
	public static void main(String argv[])throws IOException
	{
		final String message = argv[0];
		BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
		System.out.print("Please enter a shift amount:");
		int shift=Integer.parseInt(reader.readLine());
		String cipher="";
		for(int i=0;i<message.length();i++)
		{
			int char_code = (int)message.charAt(i);
			int encoded_char=0;
			if(char_code >= 65 && char_code <= 90)
			{
				if(char_code + shift <= 90)
				{
					encoded_char = char_code + shift;
					cipher += ((char)encoded_char);
				}
				else
				{
					encoded_char = char_code + shift - 90;
					encoded_char += 64;
					cipher += ((char)encoded_char);
				}
			}
			else if(char_code >= 97 && char_code <= 122)
			{
				if(char_code + shift <= 122)
				{
					encoded_char = char_code + shift;
					cipher += ((char)encoded_char);
				}
				else
				{
					encoded_char = char_code + shift - 122;
					encoded_char += 96;
					cipher += ((char)encoded_char);
				}
			}
			
			else
			{
				cipher += ((char)char_code);
			}
		}
		System.out.print("The cipher-text is: "+cipher);
	}
}

Python:

# Caesar.py - Abdul Fatir
import sys
message = sys.argv[1]
shift = int(raw_input("Please enter a shift amount:"))
cipher = ''
for i in range(len(message)):
	charASCIIcode = ord(message[i])
	if charASCIIcode >= ord('A') and charASCIIcode <= ord('Z'):
		if charASCIIcode + shift <= ord('Z'):
			cipher += chr(charASCIIcode+shift)
		else:
			cipher += chr(charASCIIcode+shift-ord('Z')+ord('A')-1)
	elif charASCIIcode >= ord('a') and charASCIIcode <= ord('z'):
		if charASCIIcode + shift <= ord('z'):
			cipher += chr(charASCIIcode+shift)
		else:
			cipher += chr(charASCIIcode+shift-ord('z')+ord('a')-1)
	else:
		cipher += chr(charASCIIcode)
print 'The cipher-text is: %s' % cipher

JavaScript:

<script type="text/javascript">
	function encodeData()
	{
		var input_data = document.getElementsByName('raw_data')[0].value;
		var shift_factor = parseInt(document.getElementsByName('shift_factor')[0].value);
		var encoded = "";
		for(var i=0;i<input_data.length;i++)
		{
			var char_code = input_data.charCodeAt(i);
			if(char_code >= 65 && char_code <= 90)
			{
				if(char_code + shift_factor <= 90)
				{
					encoded_char = char_code + shift_factor;
					encoded += String.fromCharCode(encoded_char);
				}
				else
				{
					encoded_char = char_code + shift_factor - 90;
					encoded_char += 64;
					encoded += String.fromCharCode(encoded_char);
				}
			}
			else if(char_code >= 97 && char_code <= 122)
			{
				if(char_code + shift_factor <= 122)
				{
					encoded_char = char_code + shift_factor;
					encoded += String.fromCharCode(encoded_char);
				}
				else
				{
					encoded_char = char_code + shift_factor - 122;
					encoded_char += 96;
					encoded += String.fromCharCode(encoded_char);
				}
			}
			
			else
			{
				encoded += String.fromCharCode(char_code);
			}
		}
		document.getElementsByName('encoded_data')[0].value = encoded;
	}
	</script>


References and Further Readings:
[1] learncryptography.com/
[2] http://en.wikipedia.org/wiki/Cryptography
[3] http://en.wikipedia.org/wiki/Encryption
[4] http://en.wikipedia.org/wiki/Cryptographic_hash_function
[5] www.garykessler.net/library/crypto.html

Calculate MD5 Checksum of a File in Python

With increased MITM (Man In The Middle) attacks it is essential that you check the authenticity of files you download from the Internet. One of the ways of doing so is checking the MD5 sum of the file and comparing it with the checksum given on the download providers website.

Here's how to perform this task in Python:

#! /usr/bin/env python
# ChecksumChecker.py
# Author: Abdul Fatir
# E-Mail: abdulfatirs@gmail.com

from threading import Thread
import hashlib
import optparse

def getChecksum(file_path,check_hash):
 file_handle = open(file_path,"rb")
 _md5 = hashlib.md5()
 while True:
  _buffer = file_handle.read()
  if not _buffer:
   break
  _md5.update(_buffer)
 digest = _md5.hexdigest()
 print "[ ] File's MD5 checksum is: " digest
 if (check_hash != None):
  if(check_hash.lower() == digest):
   print "[ ] Hash matched: The file is authentic."
  else:
   print "[-] Hash mis-match: The file is not authentic."

def Main():
 parser = optparse.OptionParser('usage: %prog -f <filename> [-m <md5 hash>]')
 parser.add_option('-f', dest='file_path', type='string', help='Please specify a file')
 parser.add_option('-m', dest='check_hash', type='string')
 (options,arg) = parser.parse_args()
 if (options.file_path == None):
  print parser.usage
  exit(0)
 else:
  file_path = options.file_path
  check_hash = options.check_hash
 print "[*] Hashing file '"  file_path  "'...."
 hash_thread = Thread(target=getChecksum,args=(file_path,check_hash))
 hash_thread.start()
 hash_thread.join()
if __name__  == '__main__':
 Main()

Please don't copy paste this code, download it from pastebin.

Usage examples:

Suppose you downloaded a file named hello.exe which has an MD5 hash 5D41402ABC4B2A76B9719D911017C592 given on the Internet then to check if you downloaded the correct file use ChecksumChecker.py as follows:

$ python ChecksumChecker.py -f <path to hello.exe> -m 5D41402ABC4B2A76B9719D911017C592

To simply get the MD5 sum of a file, do:

$ python ChecksumChecker.py -f <path to hello.exe>

Note:

  1. This is a prototype. You can added more algorithms like SHA1 and SHA256 as per your requirements.
  2. This code executes in Python 2.7.x

Dictionary Attack in Python

Got an MD5 or SHA1 password hash and a password dictionary? Want to crack the hashed password but don't want to use tools like Cain or Hydra? Here's how to write a hash cracker in python from scratch:

#! /usr/bin/env python
# HashCrack.py
# Author: Abdul Fatir
# E-Mail: abdulfatirs@gmail.com

import hashlib
import optparse

def crackMD5Hash(_file,_hash):
 _wordlistfile = open(_file,"r")
 cracked = False
 for word in _wordlistfile:
  _purgedword = word.strip()
  md5 = hashlib.md5()
  md5.update(_purgedword)
  _wordhash = md5.hexdigest()
  if _wordhash == _hash:
   
   print "[ ] Hash (" _hash  ") cracked: " _purgedword
   cracked = True
   break
 if(not cracked):
  print "[-] Unable to crack the hash."
  
def crackSHA1Hash(_file,_hash):
 _wordlistfile = open(_file,"r")
 cracked = False
 for word in _wordlistfile:
  _purgedword = word.strip()
  sha1 = hashlib.sha1()
  sha1.update(_purgedword)
  _wordhash = sha1.hexdigest()
  if _wordhash == _hash:
   print "[ ] Hash (" _hash  ") cracked: " _purgedword
   cracked = True
   break
 if(not cracked):
  print "[-] Unable to crack the hash."

def Main():
 argparser = optparse.OptionParser("usage %prog -f <wordlist file> -p <hash to be cracked> -a <hash algorithm>")
 argparser.add_option('-f', dest='filename',type='string',help='Please specify a word list')
 argparser.add_option('-p', dest='passhash',type='string',help='Please specify a password hash to be cracked')
 argparser.add_option('-a', dest='hashalgo',type='string',help='Please specify a hash algorithm')
 (options, arg) = argparser.parse_args()
 if (options.filename == None) | (options.passhash == None) | (options.hashalgo == None):
  print argparser.usage
  exit(0)
 else:
  filename = options.filename
  passhash = options.passhash
  hashalgo = options.hashalgo
 print "[*] Cracking hash ..."
 if (hashalgo == 'MD5')|(hashalgo == 'md5'):
  crackMD5Hash(filename,passhash)
 elif (hashalgo == 'SHA1')|(hashalgo == 'sha1'):
  crackSHA1Hash(filename,passhash)
 
if __name__ == '__main__':
 Main()

Download this code from pastebin.

Notes:

  1. This is a mere prototype of how to perform a manual dictionary attack. This can be improved to much extent and more hashing algorithms can be added to it. Also consider using separate threads for searching password than the main thread in case of large dictionaries.
  2. This code requires Python 2.7.x.

Suggested Further Readings:

  1. Read more about python's hashlib and threading modules to improve this code.
  2. Read more on cryptographic hashing and other hashing algorithms. Refer to http://learncryptography.com for basic knowledge about cryptography.

Image Encoding & Decoding in Python

Wondering what the image is?

That's HELLO.THERE.YOU.ARE.AWESOME encoded in this image.

The encoding is:

The pixels in the above image are numbered 0..99 for the first row, 100..199 for the second row etc.
White pixels represent ASCII codes.
The ASCII code for a particular white pixel is equal to the offset from the last white pixel.
For example, the first white pixel at location 65 would represent ASCII code 65 ('A'), the next at location 131 would represent ASCII code (131 - 65) = 66 ('B') and so on.
The text contained in the image is the answer encoded in Morse, where "a test" would be encoded as ".- / - . ... -"

So, how do we decode this image into readable form?

Program? Yes, you're right but which language? You can use any language out there and analyze the image but python with PIL (Python Imaging Library) makes it incredibly simple task.

Here is the python code to do this:

#ImageDecoder.py

from PIL import Image
import optparse

morse_dict={
 'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.',
 'G':'--.','H':'....','I':'..','J':'.---','K':'-.-','L':'.-..',
 'M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.',
 'S':'...','T':'-','U':'..-','V':'...-','W':'.--','X':'-..-',
 'Y':'-.--','Z':'--..','0':'-----','1':'.----','2':'..---','3':'...--',
 '4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.',
 '.':'.-.-.-',',':'--..--','?':'..--..',"'":'.----.','/':'-..-.','(':'-.--.-',
 ')':'-.--.-',':':'---...',';':'-.-.-.','=':'-...-',' ':'.-.-.','-':'-....-',
 '_':'..--.-','"':'.-..-.','$':'...-..-','':''
 }
def getLetterForMorse(l):
 
 for key, value in morse_dict.iteritems():
  if(value == l):
   return str(key)
def Main():
 parser = optparse.OptionParser('usage: python ImageDecoder.py -i <input PNG image name>')
 parser.add_option('-i',dest='inPNG',type='string',help='Please specify the input image file')
 (options,arg) = parser.parse_args()
 if (options.inPNG == None):
  print parser.usage
  exit(0)
 else:
  inPNG = options.inPNG
 _img = Image.open(inPNG)
 W = _img.size[0]
 H = _img.size[1]
 _pixs = _img.load()
 lastOff = 0
 _letter = ""
 answer = ""

 for y in range(H):
  for x in range(W):
   if(_pixs[x,y] == (255,255,255)):
    offset = y*100   x - lastOff
    lastOff = y*100   x
    _char = chr(offset)
    if(_char != ' '):
     _letter  = _char
    else:
     answer  = getLetterForMorse(_letter)
     _letter = ""

 print answer
 
if __name__ == '__main__':
 Main()

Download ImageDecoder.py from pastebin.

Okay, now when we did it we think of creating an encoder which can encode text into such kind of images.

Python again. Here we go:

#ImageEncoder.py 

from PIL import Image
import optparse

morse_list={
'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.',
'G':'--.','H':'....','I':'..','J':'.---','K':'-.-','L':'.-..',
'M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.',
'S':'...','T':'-','U':'..-','V':'...-','W':'.--','X':'-..-',
'Y':'-.--','Z':'--..','0':'-----','1':'.----','2':'..---','3':'...--',
'4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.',
'.':'.-.-.-',',':'--..--','?':'..--..',"'":'.----.','/':'-..-.','(':'-.--.-',
')':'-.--.-',':':'---...',';':'-.-.-.','=':'-...-',' ':'.-.-.','-':'-....-',
'_':'..--.-','"':'.-..-.','$':'...-..-','':''
}

def EncodeToImage(data,_PNG):
 letters = list(data)
 pixsum = 0
 whitePixels = []
 for letter in letters:
  _lettermorse = morse_list[letter]
  _morsechars = list(_lettermorse)
  for morsechar in _morsechars:
   intval = ord(morsechar)
   pixsum  = intval
   whitePixels.append(pixsum)
  pixsum  = 32
  whitePixels.append(pixsum)
 W = 100
 H = whitePixels[len(whitePixels)-1]/100   1
 img = Image.new( 'RGB', (W,H), "black")
 pixels = img.load()
 
 for whitePixel in whitePixels:
  y = whitePixel/100
  x = whitePixel%100
  pixels[x,y] = (255,255,255)
 img.save(_PNG)

def Main():
 parser = optparse.OptionParser('usage: python ImageEncoder.py -o <output PNG image name>')
 parser.add_option('-o',dest='outPNG',type='string',help='Please specify the output image file')
 (options,arg) = parser.parse_args()
 if (options.outPNG == None):
  print parser.usage
  exit(0)
 else:
  outPNG = options.outPNG
 datatoencode = raw_input("Please enter data to encode (without spaces):")
 EncodeToImage(datatoencode.upper(),outPNG)
 
if __name__ == '__main__':
 Main()

Download ImageEncoder.py from pastebin.

Notes:

  1. The concept for this encoding has been taken from Hack This Site's programming challenge 2 and the first part i.e. the ImageDecoder.py is also the solution of this HTS challenge. I took it further to create an encoder to have fun.
  2. You need to install Python 2.7.x and PIL (Python Imaging Library) for this to work.