This is an old revision of the document!


Lab 02

In this lab we'll do some exercises related to OTP and stream ciphers.

Exercise 1

Charlie manages to capture a last communication which turns out to be the most important, so it is crucial he decrypts it. However, this time Alice used the Vigenere cipher, with a key that Charlie knows has 7 characters.

The ciphertext is in the file attached. Try the method of multiplying probabilities as I explained in class and see if you can decrypt the ciphertext.

These are the known frequencies of the plaintext:

{'A': 0.07048643054277828,
'C': 0.01577161913523459,
'B': 0.012074517019319227,
'E': 0.13185372585096597,
'D': 0.043393514259429625,
'G': 0.01952621895124195,
'F': 0.023867295308187673,
'I': 0.06153403863845446,
'H': 0.08655128794848206,
'K': 0.007566697332106716,
'J': 0.0017594296228150873,
'M': 0.029657313707451703,
'L': 0.04609015639374425,
'O': 0.07679967801287949,
'N': 0.060217341306347746,
'Q': 0.0006382244710211592,
'P': 0.014357175712971482,
'S': 0.05892939282428703,
'R': 0.05765294388224471,
'U': 0.02749540018399264,
'T': 0.09984475620975161,
'W': 0.01892824287028519,
'V': 0.011148804047838086,
'Y': 0.023045078196872126,
'X': 0.0005289788408463661,
'Z': 0.00028173873045078196}

Exercise 2

In class we explained that the one time pad is malleable (i.e. we can easily change the encrypted plaintext by simply modifying the ciphertext). We have also discussed how the CRC was a very bad idea in the design of WEP due to its linearity.

You are given the following ciphertext in hexadecimal:

021e0e061d1694c9

which you know it corresponds to the concatenation of the message “floare” with its CRC-16 (in hexa “8E31”) obtained from this website: http://www.lammertbies.nl/comm/info/crc-calculation.html

If we need to modify the ciphertext so that a correct decryption outputs “albina” instead of “floare” and such that the CRC-16 calculation remains correct, what is the modification we need to perform?

Output the new ciphertext after the necessary modifications and show that it correctly leads to the plaintext “albina” and a correct computation of its CRC-16.

You might find this starting script useful:

ex2_draft.py
import sys
import random
import string
import operator
 
def strxor(a, b): # xor two strings (trims the longer input)
  return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])
 
def hexxor(a, b): # xor two hex strings (trims the longer input)
  ha = a.decode('hex')
  hb = b.decode('hex')
  return "".join([chr(ord(x) ^ ord(y)).encode('hex') for (x, y) in zip(ha, hb)])
 
def main():
 
  #Plaintexts
  s1 = 'floare'
  s2 = 'albina'
  G = '' #To find
 
  #Obtain crc of s1
  #See this site:
  #http://www.lammertbies.nl/comm/info/crc-calculation.html
  x1 = s1.encode('hex')
  x2 = s2.encode('hex')
  print "x1: " + x1
  crc1 = '8E31' #CRC-16 of x1
 
  #Compute delta (xor) of x1 and x2:
  xd = hexxor(x1, x2)
  print "xd: " + xd
 
 
if __name__ == "__main__":
  main()

Exercise 3

In this exercise we'll try to break a Linear Congruential Generator, that may be used to generate “poor” random numbers. We implemented such weak RNG to generate a sequence of bytes and then encrypted a plaintext message. The resulting ciphertext in hexadecimal is this:

a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8

You know that the LCG uses the following formula to produce each byte:

s_next = a * s_prev + b mod p

where both s_prev and s_next are byte values (between 0 and 255) and p is 257.

You also know that the first 16 letters of the plaintext are “Let all creation” and that the ciphertext was generated by xor-ing a string of consecutive bytes generated by the LCG with the plaintext.

Can you break the LCG and predict the RNG stream so that in the end you find the entire plaintext ?

You may use this starting code:

'ex3_weak_rng.py'
import sys
import random
import string
import operator
 
#Parameters for weak LC RNG
class WeakRNG:
    "Simple class for weak RNG"
    def __init__(self):
        self.rstate = 0
        self.maxn = 255
        self.a = 0 #Set this to correct value
        self.b = 0 #Set this to correct value
        self.p = 257
 
    def init_state(self):
        "Initialise rstate"
        self.rstate = 0 #Set this to some value
        self.update_state()
 
    def update_state(self):
        "Update state"
        self.rstate = (self.a * self.rstate + self.b) % self.p
 
    def get_prg_byte(self):
        "Return a new PRG byte and update PRG state"
        b = self.rstate & 0xFF
        self.update_state()
        return b
 
def strxor(a, b): # xor two strings (trims the longer input)
  return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])
 
def hexxor(a, b): # xor two hex strings (trims the longer input)
  ha = a.decode('hex')
  hb = b.decode('hex')
  return "".join([chr(ord(x) ^ ord(y)).encode('hex') for (x, y) in zip(ha, hb)])
 
def main():
 
  #Initialise weak rng
  wr = WeakRNG()
  wr.init_state()
 
  #Print ciphertext
  CH = 'a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8'
  print "Full ciphertext in hexa: " + CH
 
  #Print known plaintext
  pknown = 'Let all creation'
  nb = len(pknown)
  print "Known plaintext: " + pknown
  pkh = pknown.encode('hex')
  print "Plaintext in hexa: " + pkh
 
  #Obtain first nb bytes of RNG
  gh = hexxor(pkh, CH[0:nb*2])
  print gh
  gbytes = []
  for i in range(nb):
    gbytes.append(ord(gh[2*i:2*i+2].decode('hex')))
  print "Bytes of RNG: "
  print gbytes
 
  #Break the LCG here:
  #1. find a and b
  #2. predict/generate rest of RNG bytes
  #3. decrypt plaintext
 
  # Print full plaintext
  p = ''
  print "Full plaintext is: " + p
 
 
if __name__ == "__main__":
  main()  
sasc/laboratoare/02.1456845524.txt.gz · Last modified: 2016/03/01 17:18 by marios.choudary
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0