Differences

This shows you the differences between two versions of the page.

Link to this comparison view

sasc:laboratoare:03 [2016/02/21 19:07]
sergiu.costea
sasc:laboratoare:03 [2017/03/07 15:32] (current)
dan.dragan
Line 1: Line 1:
-===== Lab 03 =====+===== Lab 03 - PRGs =====
  
  
-==== Exercise 1 ====+==== Exercise 1 (4p) ====
  
-Advantage. The purpose of this problem is to clarify the concept of advantageCon- sider the following two experiments EXP(0) and EXP(1): +In this exercise we'll try to break a Linear Congruential Generator, that may be used to generate "​poor"​ random numbers
-  * In EXP(0) the challenger flips fair coin (probability 1/2 for HEADS and 1/2 for TAILS) and sends the result to the adversary A+We implemented such weak RNG to generate ​sequence of bytes and then encrypted a plaintext message
-  * In EXP(1) the challenger always sends TAILS to the adversary.+The resulting ciphertext in hexadecimal is this: 
 +<​code>​ 
 +a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8 
 +</​code>​
  
-The adversary’s goal is to distinguish these two experiments:​ at the end of each experiment ​the adversary outputs a bit 0 or 1 for its guess for which experiment it is in. For b = 0,1 let Wb be the event that in experiment b the adversary output 1. The adversary tries to maximize its distinguishing advantage, namely the quantity +You know that the LCG uses the following formula ​to produce each byte:
-Adv = | Pr[W0] − Pr[W1] | ∈ [0, 1] .+
  
-The advantage Adv captures the adversary’s ability to distinguish the two experiments. If the advantage is 0 then the adversary behaves exactly the same in both experiments and therefore does not distinguish between them. If the advantage is 1 then the adversary can tell perfectly what experiment it is in. If the advantage is negligible for all efficient adversaries ​(as defined in classthen we say that the two experiments are indistinguishable.+s_next = (a * s_prev + bmod p
  
-a. Calculate the advantage of each of the following adversaries:​ +where both s_prev ​and s_next are byte values (between ​and 255) and p is 257
-  * A1: Always output 1. +Both a and b are values between ​and 256.
-  * A2: Ignore the result reported by the challenger, ​and randomly output ​or 1 with even probability+
-  * A3: Output 1 if HEADS was received from the challenger, else output ​0+
-  * A4: Output 0 if HEADS was received from the challenger, else output 1. +
-  * A5: If HEADS was received, output 1. If TAILS was received, randomly output 0 or 1 with even probability.+
  
-b. What is the maximum advantage possible in distinguishing these two experiments?​ Explain why. 
  
-==== Exercise 2 ====+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.
  
-Let's use the experiment defined earlier as a pseudorandom generator (PRG) as follows: +Can you break the LCG and predict ​the RNG stream so that in the end you find the entire plaintext ?
-  - Set a desired output length n +
-  - Obtain a random sequence R of bits of length n (say flipping a coin, using a Linear-congruential generator, or any other method) +
-  - For each bit r in the random sequence R generated ​in the previous step, output a bit b as follows: +
-  * if the bit r is 0, then output a random bit b (e.g. flip a coin and output either 0 or 1 depending on its result) +
-  * if the bit r is 1, then output 1+
  
-a. Implement the frequency (monobit) test from NIST (see section 2.1)+You may use this starting code
-http://csrc.nist.gov/​publications/​nistpubs/​800-22-rev1a/​SP800-22rev1a.pdf+<code python '​ex1_weak_rng.py'>​ 
 +import sys 
 +import random 
 +import string 
 +import operator
  
-and check if a sequence generated by the above PRG (say n=100seems random or not.+#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
  
-b. Run the test on a random bitstring ​(e.ga string such as R used by the above PRG), and compare the result of the test.+    def init_state(self): 
 +        "​Initialise rstate"​ 
 +        self.rstate = 0 #Set this to some value 
 +        self.update_state()
  
-If the two results are different across many iterations, this test already gives you an attacker that breaks the PRG.+    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() ​  
 +</​code>​ 
 + 
 +==== Exercise 2 (3p) ==== 
 + 
 +Let's use the experiment defined earlier as a pseudorandom generator ($\mathsf{PRG}$) as follows: 
 +  - Set a desired output length $n$ 
 +  - Obtain a random sequence $R$ of bits of length $n$ (e.g. using the Linear-congruential generator from Exercise 1) 
 +  - For each bit $r$ in the random sequence $R$ generated in the previous step, output a bit $b$ as follows: 
 +  * if the bit $r$ is $0$, then output a random bit $b \in \{0, 1\}$ 
 +  * if the bit $r$ is $1$, then output $1$ 
 + 
 +a. Implement the frequency (monobit) test from [[http://​csrc.nist.gov/​publications/​nistpubs/​800-22-rev1a/​SP800-22rev1a.pdf | NIST (see section 2.1)]] and check if a sequence generated by the above $\mathsf{PRG}$ (say $n=100$) seems random or not. 
 + 
 +b. Run the test on a random bitstring (e.g. a string such as R used by the above $\mathsf{PRG}$),​ and compare the result of the test. 
 + 
 +If the two results are different across many iterations, this test already gives you an attacker that breaks the $\mathsf{PRG}$.
  
 <note tip>You may use a function like this to generate a random bitstring</​note>​ <note tip>You may use a function like this to generate a random bitstring</​note>​
-<​code>​+<​code ​python>
 import random import random
  
Line 51: Line 129:
 <note tip>​Also,​ in Python you may find the functions sqrt, fabs and erfc from the module math useful</​note>​ <note tip>​Also,​ in Python you may find the functions sqrt, fabs and erfc from the module math useful</​note>​
  
 +==== Exercise 3 - LFSR (3p) ====
  
 +In this exercise we'll build a simple Linear Feedback Shift Register (LFSR). LFSRs produce random bit strings with good statistical properties, but are very easy to predict.
  
 +The register is a sequence of $n$ bits; a LFSR is defined by:
 +  * an initial state (the initial bit contents of the register)
 +  * a polynomial that describes how bit shifts should be performed
  
 +For example, given an $18$ bit LFSRm the polynomial $X^{18} + X^{11} + 1$ and the initial state:
 +<​code>​
 +  state = '​001001001001001001'​
 +                     ​* ​     *
 +</​code>​
 +
 +we generate a new bit $b$ by $\mathsf{xor}$-ing bits $11$ ($0$) and $18$ ($1$), thus obtaining $b = 1$. We then shift the whole register to the right (thus dropping the right-most bit, which is the bit we add to the generated random sequence) and insert $b$ to the left. Thus, the new state is:
 +<​code>​
 +  state = '​100100100100100100'​
 +</​code>​
  
 +The process is repeated until the desired number of bits have been generated.
  
  
 +Using the above starting state and polynomial, generate $100$ random bits and run the monobit statistical test from the previous exercise to see if their frequency seems random.
sasc/laboratoare/03.1456074462.txt.gz · Last modified: 2016/02/21 19:07 by sergiu.costea
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