Differences

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

Link to this comparison view

ic:labs:03 [2021/10/18 09:18]
razvan.smadu [Exercițiul 1]
ic:labs:03 [2023/10/16 20:53] (current)
razvan.smadu
Line 1: Line 1:
 ===== Laboratorul 03 - PRGs ===== ===== Laboratorul 03 - PRGs =====
  
-Prezentarea PowerPoint pentru acest laborator poate fi găsită [[https://​drive.google.com/​file/​d/​1IfyMkfV6jQDzW5KhS_B6wt_azV31SLjL/​view?​usp=sharing|aici]].+Prezentarea PowerPoint pentru acest laborator poate fi găsită [[https://​drive.google.com/​file/​d/​1IfyMkfV6jQDzW5KhS_B6wt_azV31SLjL/​view?​usp=sharing|aici]]. Puteți găsi o scurtă prezentare a noțiunii de avantaje în [[https://​drive.google.com/​file/​d/​1F_mtKi0zeAn1xYQs6Wc7IiiVX8ZW6aeG/​view?​usp=sharing|acest]] PDF.
  
 +
 +Puteți lucra acest laborator folosind platforma Google Colab, accesând [[https://​colab.research.google.com/​github/​ACS-IC-labs/​IC-labs/​blob/​main/​labs/​lab03/​lab3.ipynb
 +|acest]] link.
 +
 +<​hidden>​
 +<spoiler Click pentru a vedea utils.py>​
 <file python utils.py>​ <file python utils.py>​
 import base64 import base64
 +from typing import Generator
  
-# CONVERSION FUNCTIONS 
  
-def _chunks(stringchunk_size): +def _pad(data: strsize: int-> str
-    ​for i in range(0, ​len(string), chunk_size): +    ​reminder = len(data% size 
-        ​yield string[i:i+chunk_size]+    if reminder != 0
 +        ​data = "​0"​ * (size - reminder) ​data 
 +    return data
  
-def _hex(x): 
-    return format(x, '​02x'​) 
  
-def hex_2_bin(data): +def _chunks(data: str, chunk_size: int-> Generator[str,​ None, None]
-    ​return ''​.join(f'​{int(x16):​08b}' ​for in _chunks(data, ​2))+    ​data = _pad(datachunk_size) 
 +    ​for in range(0, len(data)chunk_size)
 +        yield data[i : i + chunk_size]
  
-def str_2_bin(data):​ 
-    return ''​.join(f'​{ord(c):​08b}'​ for c in data) 
  
-def bin_2_hex(data): +def _hex(data: int-> str
-    return ​''​.join(f'​{int(b2):02x}' for b in _chunks(data,​ 8))+    return ​format(data"02x")
  
-def str_2_hex(data):​ 
-    return ''​.join(f'​{ord(c):​02x}'​ for c in data) 
  
-def bin_2_str(data):​ +# Conversion functions
-    return ''​.join(chr(int(b,​ 2)) for b in _chunks(data,​ 8))+
  
-def hex_2_str(data):​ 
-    return ''​.join(chr(int(x,​ 16)) for x in _chunks(data,​ 2)) 
  
-# XOR FUNCTIONS+def hex_2_bin(data:​ str) -> str: 
 +    """​Converts a hexadecimal string to a binary representation.
  
-def strxor(a, b):  # xor two strings, trims the longer input +    Args: 
-    ​return ''​.join(chr(ord(x) ^ ord(y)) for (xy) in zip(a, b))+        data (str): The hexadecimal string to be converted. It should have an 
 +            even number of characters and only contain valid hexadecimal digits 
 +            ​(0-9, A-F, a-f).
  
-def bitxor(a, b) # xor two bit-stringstrims the longer input +    Returns: 
-    ​return ''​.join(str(int(x) ^ int(y)) for (x, y) in zip(a, b))+        str: The binary representation of the hexadecimal stringwhere each 
 +            pair of hexadecimal digits is encoded as an 8-bit binary number.
  
-def hexxor(a, b):  # xor two hex-strings,​ trims the longer input +    Examples: 
-    return ​''​.join(_hex(int(x, 16) ^ int(y, 16)) for (x, y) in zip(_chunks(a, 2), _chunks(b, 2)))+        >>>​ hex_2_bin("​01abcd"​) 
 +        '​000000011010101111001101'​ 
 +        >>>​ hex_2_bin("​0a"​) 
 +        '​00001010'​ 
 +    """​ 
 +    return ​""​.join(f"{int(x, 16):​08b}" ​for x in _chunks(data, 2))
  
-# BASE64 FUNCTIONS 
  
-def b64decode(data): +def bin_2_hex(data: str-> str
-    ​return bytes_to_string(base64.b64decode(string_to_bytes(data)))+    ​"""​Converts a binary string to a hexadecimal representation.
  
-def b64encode(data):​+    Args: 
 +        data (str): The binary string to be converted. It should have a multiple 
 +            of 8 characters and only contain valid binary digits (0 or 1). 
 + 
 +    Returns: 
 +        str: The hexadecimal representation of the binary string, where each 
 +            group of 8 binary digits is encoded as a pair of hexadecimal digits. 
 + 
 +    Examples: 
 +        >>>​ bin_2_hex("​000000011010101111001101"​) 
 +        '​01abcd'​ 
 +        >>>​ bin_2_hex("​00001010"​) 
 +        '​0a'​ 
 +    """​ 
 +    return ""​.join(f"​{int(b,​ 2):​02x}"​ for b in _chunks(data,​ 8)) 
 + 
 + 
 +def str_2_bin(data:​ str) -> str: 
 +    """​Converts a string to a binary representation. 
 + 
 +    Args: 
 +        data (str): The string to be converted. 
 + 
 +    Returns: 
 +        str: The binary representation of the string, where each character is 
 +            encoded as an 8-bit binary number. 
 + 
 +    Examples: 
 +        >>>​ str_2_bin("​Hello"​) 
 +        '​0100100001100101011011000110110001101111'​ 
 +        >>>​ str_2_bin("​IC"​) 
 +        '​0100100101000011'​ 
 +    """​ 
 +    return ""​.join(f"​{ord(c):​08b}"​ for c in data) 
 + 
 + 
 +def bin_2_str(data:​ str) -> str: 
 +    """​Converts a binary string to a string. 
 + 
 +    Args: 
 +        data (str): The binary string to be converted. It should have a multiple 
 +            of 8 characters and only contain valid binary digits (0 or 1). 
 + 
 +    Returns: 
 +        str: The string representation of the binary string, where each group 
 +            of 8 binary digits is decoded as a character. 
 + 
 +    Examples: 
 +        >>>​ bin_2_str("​0100100001100101011011000110110001101111"​) 
 +        '​Hello'​ 
 +        >>>​ bin_2_str("​0100100101000011"​) 
 +        '​IC'​ 
 +    """​ 
 +    return ""​.join(chr(int(b,​ 2)) for b in _chunks(data,​ 8)) 
 + 
 + 
 +def str_2_hex(data:​ str) -> str: 
 +    """​Converts a string to a hexadecimal representation. 
 + 
 +    Args: 
 +        data (str): The string to be converted. 
 + 
 +    Returns: 
 +        str: The hexadecimal representation of the string, where each character 
 +            is encoded as a pair of hexadecimal digits. 
 + 
 +    Examples: 
 +        >>>​ str_2_hex("​Hello"​) 
 +        '​48656c6c6f'​ 
 +        >>>​ str_2_hex("​IC"​) 
 +        '​4943'​ 
 +    """​ 
 +    return ""​.join(f"​{ord(c):​02x}"​ for c in data) 
 + 
 + 
 +def hex_2_str(data:​ str) -> str: 
 +    """​Converts a hexadecimal string to a string. 
 + 
 +    Args: 
 +        data (str): The hexadecimal string to be converted. It should have an 
 +            even number of characters and only contain valid hexadecimal digits 
 +            (0-9, A-F, a-f). 
 + 
 +    Returns: 
 +        str: The string representation of the hexadecimal string, where each 
 +            pair of hexadecimal digits is decoded as a character. 
 + 
 +    Examples: 
 +        >>>​ hex_2_str("​48656c6c6f"​) 
 +        '​Hello'​ 
 +        >>>​ hex_2_str("​4943"​) 
 +        '​IC'​ 
 +    """​ 
 +    return ""​.join(chr(int(x,​ 16)) for x in _chunks(data,​ 2)) 
 + 
 + 
 +# XOR functions 
 + 
 + 
 +def strxor(operand_1:​ str, operand_2: str) -> str: 
 +    """​Performs a bitwise exclusive OR (XOR) operation on two strings. 
 + 
 +    Args: 
 +        operand_1 (str): The first string to be XORed. 
 +        operand_2 (str): The second string to be XORed. 
 + 
 +    Returns: 
 +        str: The result of the XOR operation on the two strings, where each 
 +            character is encoded as an 8-bit binary number. The result has 
 +            the same length as the shorter input string. 
 + 
 +    Examples: 
 +        >>>​ strxor("​Hello",​ "​IC"​) 
 +        '​\\x01&'​ 
 +        >>>​ strxor("​secret",​ "​key"​) 
 +        '​\\x18\\x00\\x1a'​ 
 +    """​ 
 +    return ""​.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(operand_1,​ operand_2)) 
 + 
 + 
 +def bitxor(operand_1:​ str, operand_2: str) -> str: 
 +    """​Performs a bitwise exclusive OR (XOR) operation on two bit-strings. 
 + 
 +    Args: 
 +        operand_1 (str): The first bit-string to be XORed. It should only 
 +            contain valid binary digits (0 or 1). 
 +        operand_2 (str): The second bit-string to be XORed. It should only 
 +            contain valid binary digits (0 or 1). 
 + 
 +    Returns: 
 +        str: The result of the XOR operation on the two bit-strings,​ where each 
 +            bit is encoded as a character. The result has the same length as 
 +            the shorter input bit-string. 
 + 
 +    Examples: 
 +        >>>​ bitxor("​01001000",​ "​01000010"​) 
 +        '​00001010'​ 
 +        >>>​ bitxor("​10101010",​ "​00110011"​) 
 +        '​10011001'​ 
 +    """​ 
 +    return ""​.join(str(int(x) ^ int(y)) for (x, y) in zip(operand_1,​ operand_2)) 
 + 
 + 
 +def hexxor(operand_1:​ str, operand_2: str) -> str: 
 +    """​Performs a bitwise exclusive OR (XOR) operation on two hexadecimal 
 +    strings. 
 + 
 +    Args: 
 +        operand_1 (str): The first hexadecimal string to be XORed. It should 
 +            have an even number of characters and only contain valid hexadecimal 
 +            digits (0-9, A-F, a-f). 
 +        operand_2 (str): The second hexadecimal string to be XORed. It should 
 +            have an even number of characters and only contain valid 
 +            digits (0-9, A-F, a-f). 
 + 
 +    Returns: 
 +        str: The result of the XOR operation on the two hexadecimal strings, 
 +            where each pair of hexadecimal digits is encoded as a pair of 
 +            hexadecimal digits. The result has the same length as the shorter 
 +            input hexadecimal string. 
 + 
 +    Examples: 
 +        >>>​ hexxor("​48656c6c6f",​ "​42696e67"​) 
 +        '​0a0c020b'​ 
 +        >>>​ hexxor("​736563726574",​ "​6b6579"​) 
 +        '​18001a'​ 
 +    """​ 
 +    return ""​.join( 
 +        _hex(int(x, 16) ^ int(y, 16)) 
 +        for (x, y) in zip(_chunks(operand_1,​ 2), _chunks(operand_2,​ 2)) 
 +    ) 
 + 
 + 
 +# Python3 '​bytes'​ functions 
 + 
 + 
 +def bytes_to_string(bytes_data:​ bytearray | bytes) -> str: 
 +    """​Converts a byte array or a byte string to a string. 
 + 
 +    Args: 
 +        bytes_data (bytearray | bytes): The byte array or the byte string to be 
 +            converted. It should be encoded in Latin-1 format. 
 + 
 +    Returns: 
 +        str: The string representation of the byte array or the byte string, 
 +            decoded using Latin-1 encoding. 
 + 
 +    Examples: 
 +        >>>​ bytes_to_string(b'​Hello'​) 
 +        '​Hello'​ 
 +        >>>​ bytes_to_string(bytearray(b'​IC'​)) 
 +        '​IC'​ 
 +    """​ 
 +    return bytes_data.decode(encoding="​raw_unicode_escape"​) 
 + 
 + 
 +def string_to_bytes(string_data:​ str) -> bytes: 
 +    """​Converts a string to a byte string. 
 + 
 +    Args: 
 +        string_data (str): The string to be converted. 
 + 
 +    Returns: 
 +        bytes: The byte string representation of the string, encoded using 
 +        Latin-1 encoding. 
 + 
 +    Examples: 
 +        >>>​ string_to_bytes('​Hello'​) 
 +        b'​Hello'​ 
 +        >>>​ string_to_bytes('​IC'​) 
 +        b'​IC'​ 
 +    """​ 
 +    return string_data.encode(encoding="​raw_unicode_escape"​) 
 + 
 + 
 +# Base64 functions 
 + 
 + 
 +def b64encode(data: str-> str: 
 +    """​Encodes a string to base64. 
 + 
 +    Parameters:​ 
 +        data (str): The string to be encoded. 
 + 
 +    Returns: 
 +        str: The base64 encoded string, using Latin-1 encoding. 
 + 
 +    Examples: 
 +        >>>​ b64encode("​Hello"​) 
 +        '​SGVsbG8='​ 
 +        >>>​ b64encode("​IC"​) 
 +        '​SUM='​ 
 +    """​
     return bytes_to_string(base64.b64encode(string_to_bytes(data)))     return bytes_to_string(base64.b64encode(string_to_bytes(data)))
  
-# PYTHON3 '​BYTES'​ FUNCTIONS 
  
-def bytes_to_string(bytes_data): +def b64decode(data: str-> str
-    ​return bytes_data.decode() ​ # default utf-8+    ​"""​Decodes a base64 encoded string.
  
-def string_to_bytes(string_data): +    Args: 
-    return ​string_data.encode()  # default utf-8+        data (str): The base64 encoded string to be decoded. It should only 
 +            contain valid base64 characters (A-Z, a-z, 0-9, +, /, =). 
 + 
 +    Returns: 
 +        str: The decoded string, using Latin-1 encoding. 
 + 
 +    Examples: 
 +        >>>​ b64decode("​SGVsbG8="​) 
 +        '​Hello'​ 
 +        >>>​ b64decode("​SUM="​) 
 +        '​IC'​ 
 +    """​ 
 +    return ​bytes_to_string(base64.b64decode(string_to_bytes(data)))
 </​file>​ </​file>​
 +</​spoiler>​
  
-==== Exercițiul 1 ==== + 
-In acest exercitiu ​vom incerca sa spargem un LCG (Linear Congruential Generator)ce se poate folosi pentru a genera numere ​"slab" ​aleatoare. +==== Exercițiul 1 (3p) ==== 
-Am folosit un astfel de generator pentru a obtine ​secventa ​de octeti ​cu care a fost criptat un mesaj (plaintext). +În acest exercițiu ​vom încerca să spargem un LCG (Linear Congruential Generator, ​care se poate folosi pentru a genera numere ​slab” aleatoare. 
-Textul cifrat (ciphertext) ​in sistemul hexazecimal este urmatorul:+Am folosit un astfel de generator pentru a obține ​secvență ​de octeți ​cu care a fost criptat un mesaj (plaintext). 
 +Textul cifrat (ciphertext) ​în sistemul hexazecimal este următorul:
 <​code>​ <​code>​
 a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8 a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8
 </​code>​ </​code>​
  
-Dupa cum stiti, LCG foloseste urmatoare ​formula pentru a genera ​octeti:+ 
 + 
 +După cum știți, LCG folosește următoarea ​formula pentru a genera ​octeți:
  
 s_next = (a * s_prev + b) mod p s_next = (a * s_prev + b) mod p
  
-unde s_next ​si s_prev sunt octeti ​(0-255) ​generati, p = 257 iar a si b au valori ​intre si 256. +unde s_next ​și s_prev sunt octeți ​(0-255) ​generați, p = 257iar a și b au valori ​între ​și 256. 
  
-Mai stiti si ca primele 16 litere din plaintext sunt "Let all creation". Criptarea a fost obtinuta executand ​XOR intre plaintext ​si secventa ​de octeti ​consecutivi ​generati ​de LCG+Mai știți și că primele 16 litere din plaintext sunt Let all creation. Criptarea a fost obținută realizând ​XOR între ​plaintext ​și secvența ​de octeți ​consecutivi ​generați ​de LCG.
  
-Spargeti ​LCG astfel ​incat sa puteti ​prezice ​sirul de numere generate ​"​aleator"​. Care este mesajul ​initial?+Spargeți ​LCG astfel ​încât să puteți ​prezice ​șirul ​de numere generate ​“aleatoriu”. Care este mesajul ​inițial?
  
-Puteti ​folosi ​urmatorul ​schelet de cod:+Puteți ​folosi ​următorul ​schelet de cod:
 <code python '​ex1_weak_rng.py'>​ <code python '​ex1_weak_rng.py'>​
 +from typing import List, Tuple
 +
 from utils import * from utils import *
  
-#Parameters for weak LC RNG+
 class WeakRNG: class WeakRNG:
-    "​Simple class for weak RNG" +    ​""​"​Simple class for weak RNG"""​ 
-    def __init__(self):​+ 
 +    def __init__(self) ​-> None:
         self.rstate = 0         self.rstate = 0
         self.maxn = 255         self.maxn = 255
-        self.a = 0 #Set this to correct value +        self.a = 0  # Set this to correct value 
-        self.b = 0 #Set this to correct value+        self.b = 0  # Set this to correct value
         self.p = 257         self.p = 257
  
-    def init_state(self):​ +    def init_state(self, rstate: int-> None
-        "​Initialise rstate"​ +        ​""​"​Initialise rstate""​
-        self.rstate = #Set this to some value+        self.rstate = rstate  ​# Set this to some value
         self.update_state()         self.update_state()
  
-    def update_state(self):​ +    def update_state(self) ​-> None
-        "​Update state"+        ​""​"​Update state""​"
         self.rstate = (self.a * self.rstate + self.b) % self.p         self.rstate = (self.a * self.rstate + self.b) % self.p
  
-    def get_prg_byte(self):​ +    def get_prg_byte(self) ​-> int
-        "​Return a new PRG byte and update PRG state"+        ​""​"​Return a new PRG byte and update PRG state""​"
         b = self.rstate & 0xFF         b = self.rstate & 0xFF
         self.update_state()         self.update_state()
         return b         return b
  
-  ​ 
-def main(): 
  
-    ​#Initialise weak rng+def main() -> None: 
 +    ​# Initialise weak rng
     wr = WeakRNG()     wr = WeakRNG()
-    wr.init_state()+    wr.init_state(0)
  
-    #Print ciphertext +    # Print ciphertext 
-    CH = 'a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8' +    CH = "a432109f58ff6a0f2e6cb280526708baece6680acc1f5fcdb9523129434ae9f6ae9edc2f224b73a8" 
-    print("​Full ciphertext in hexa: " ​CH)+    print("​Full ciphertext in hexa:"CH)
  
-    #Print known plaintext +    # Print known plaintext 
-    pknown = 'Let all creation'+    pknown = "Let all creation"
     nb = len(pknown)     nb = len(pknown)
-    print("​Known plaintext: " ​pknown)+    print("​Known plaintext:"​pknown)
     pkh = str_2_hex(pknown)     pkh = str_2_hex(pknown)
-    print("​Plaintext in hexa: " ​pkh)+    print("​Plaintext in hexa:"pkh)
  
-    #Obtain first nb bytes of RNG +    # Obtain first nb bytes of RNG 
-    gh = hexxor(pkh, CH[0:nb*2])+    gh = hexxor(pkh, CH[0 : nb * 2])
     print(gh)     print(gh)
     gbytes = []     gbytes = []
     for i in range(nb):     for i in range(nb):
-        gbytes.append(ord(hex_2_str(gh[2*i:​2*i+2])))+        gbytes.append(ord(hex_2_str(gh[2 * i : 2 * i + 2])))
     print("​Bytes of RNG: ")     print("​Bytes of RNG: ")
     print(gbytes)     print(gbytes)
  
-    #Break the LCG here: +    # Break the LCG here: 
-    #1. find a and b +    # TODO 1: Find a and b, and set them in the RNG
-    #2. predict/​generate rest of RNG bytes +
-    #3. decrypt plaintext+
  
-    # Print full plaintext +    # TODO 2: Predict/​generate rest of RNG bytes 
-    p = ''​ + 
-    print("​Full plaintext is: " ​p)+    # TODO 3: Decrypt plaintext 
 + 
 +    # TODO 4: Print the full plaintext 
 +    p = ... 
 +    print("​Full plaintext is:"p)
  
  
 if __name__ == "​__main__":​ if __name__ == "​__main__":​
-    main() ​ +    main()
 </​code>​ </​code>​
  
-==== Exercițiul 2 ==== 
  
-Avantaje. Scopul acestui ​exercitiu e de a clarifica conceptul de avantaje prezentat la curs. Vom considera ​doua expermimente ​$\mathsf{EXP}(0)$ ​si $\mathsf{EXP}(1)$:​ +==== Exercițiul 2 (2p) ==== 
-  * In $\mathsf{EXP}(0)$ verificatorul ​da cu banul (probabilitate de $1/2$ pentru CAP si $1/2$ pentru ​PAJURAsi transmite rezultatul adversarului $\mathsf{A}$. + 
-  * In $\mathsf{EXP}(1)$ verificatorul ​intotdeauna ​va transmite ​PAJURA catre adversar.+Avantaje. Scopul acestui ​exercițiu este de a clarifica conceptul de avantaje prezentat la curs. Vom considera ​două experimente ​$\mathsf{EXP}(0)$ ​și $\mathsf{EXP}(1)$, astfel
 +  * În $\mathsf{EXP}(0)$ verificatorul ​dă cu banul (probabilitate de $1/2$ pentru CAP și $1/2$ pentru ​PAJURĂși transmite rezultatul adversarului $\mathsf{A}$. 
 +  * În $\mathsf{EXP}(1)$ verificatorul ​întotdeauna ​va transmite ​PAJURĂ către ​adversar.
  
-Consideram ​$r = 0$ pentru CAP si $r = 1$ pentru ​PAJURA. Jocul va arata astfel:+Considerăm ​$r = 0$ pentru CAP și $r = 1$ pentru ​PAJURĂ. Jocul va arăta ​astfel:
 {{:​sasc:​laboratoare:​adversar_prg.png?​400|}} {{:​sasc:​laboratoare:​adversar_prg.png?​400|}}
  
-Scopul adversarului este este sa diferentieze intre cele doua experimente:​ la finalul fiecarui experiment, adversarul ​returneaza ​un bit $\mathsf{b'​}$,​ $0$ sau $1$, in speranta ​de a ghici $\mathsf{EXP}(b) = \mathsf{EXP}(b'​)$. +Scopul adversarului este să diferențieze între ​cele două experimente:​ la finalul fiecarui experiment, adversarul ​returnează ​un bit $\mathsf{b'​}$,​ $0$ sau $1$, în speranța ​de a ghici experimentul în care se află (adică, ​$\mathsf{EXP}(b) = \mathsf{EXP}(b'​)$)
-Fie $W_{b}$ evenimentul ​cand in experimentul $\mathsf{EXP}(b)$ adversarul ​returneaza ​$b' = 1$. Adversarul vrea sa isi maximizeze avantajul de a distinge experimentele. Mai exact, el vrea sa maximizeze valoarea $\mathsf{Adv} = \left| \mathsf{Pr}\left[W_{0}\right] − \mathsf{Pr}\left[W_{1}\right] \right| \in \left[0, 1\right]$.+Fie $W_{b}$ evenimentul ​când în experimentul $\mathsf{EXP}(b)$ adversarul ​returnează ​$b' = 1$. Adversarul vrea să își maximizeze avantajul de a distinge experimentele. Mai exact, el vrea să maximizeze valoarea $\mathsf{Adv} = \left| \mathsf{Pr}\left[W_{0}\right] − \mathsf{Pr}\left[W_{1}\right] \right| \in \left[0, 1\right]$.
  
-Avantajul $\mathsf{Adv}$ ​reda capacitatea adversarului de a diferentia ​experimentele. ​Daca avantajul este $0$, atunci advesarul se comporta ​identic ​in ambele cazuri ​si nu poate sa le distingaDaca avantajul este $1$, atunci adversarul ​stie concret care este valoarea lui $b$. Daca avantajul este neglijabil pentru orice adversar eficient atunci putem spune ca nu se poate distinge ​intre experimente.+Avantajul $\mathsf{Adv}$ ​redă capacitatea adversarului de a diferenția ​experimentele. ​Dacă avantajul este $0$, atunci advesarul se comportă ​identic ​în ambele cazuri ​și nu poate să le distingăDacă avantajul este $1$, atunci adversarul ​știe concret care este valoarea lui $b$. Dacă avantajul este neglijabil pentru orice adversar eficient atunci putem spune că nu se poate distinge ​între ​experimente.
  
-a. Calculati ​avantajul pentru fiecare dintre ​urmatorii ​adversari:​ +a. Calculați ​avantajul pentru fiecare dintre ​următorii ​adversari:​ 
-  * A1: Returneaza ​mereu $b'​=1$. +  * A1: Returnează ​mereu $b'​=1$. 
-  * A2: Ignora ​valoarea ​primita ​de la verificator ​si returneaza aleator ​$0$ sau $1$ cu aceeasi ​probabilitate. +  * A2: Ignoră ​valoarea ​primită ​de la verificator ​și returnează aleatoriu ​$0$ sau $1$cu aceeași ​probabilitate. 
-  * A3: Returneaza ​$1$ daca a primit CAP ($r=0$) de la verificator,​ altfel ​returneaza ​$0$. +  * A3: Returnează ​$1$ dacă a primit CAP ($r=0$) de la verificator,​ altfel ​returnează ​$0$. 
-  * A4: Returneaza ​$0$ daca a primit CAP de la verificator,​ altfel ​returneaza ​$1$. +  * A4: Returnează ​$0$ dacă a primit CAP de la verificator,​ altfel ​returnează ​$1$. 
-  * A5: Daca a primit CAP returneaza ​$1$. Daca a primit ​PAJURA returneaza aleator ​$0$ sau $1$ cu aceeasi ​probabilitate. +  * A5: Dacă a primit CAP, returnează ​$1$. Dacă a primit ​PAJURĂ, returnează aleatoriu ​$0$ sau $1$ cu aceeași ​probabilitate. 
-  * A6: Daca a primit CAP returneaza aleator ​$0$ sau $1$ cu aceeasi ​probabilitate. ​Daca a primit ​PAJURA returneaza ​$0$.+  * A6: Dacă a primit CAP, returnează aleatoriu ​$0$ sau $1$cu aceeași ​probabilitate. ​Dacă a primit ​PAJURĂ, returnează ​$0$.
  
-b. Care este avantajul maxim pe care il poate obtine ​un adversar? De ce?+b. Care este avantajul maxim pe care îl poate obține ​un adversar? De ce?
  
 <note tip> <note tip>
-Incercati sa obtineti ​mai intai formula generala ​ce nu depinde de adversar.+Încercați să obtineți ​mai întai ​formulă generală ​ce nu depinde de adversar.
 </​note>​ </​note>​
  
-==== Exercise 3 ==== 
  
-aplicatie ​a avantajului ​in scheme ​criptografice este de a arata daca un $PRG$ este sigur sau nu. Amintiti-va din curs$G : K \rightarrow \{0, 1\}^n$ este un $PRG$ sigur daca pentru orice test statistic $\mathsf{A}$ eficient (care ruleaza in timp polinomial),​ avantajul $\mathsf{Adv_{PRG}[A,​ G]}$ este neglijabil. Un test statistic este de fapt un algoritm care incearca sa determine ​daca intrarea ​este aleatoarea ​sau nu. Acest algoritm poate fi definit:+==== Exercițiul 3 (2p) ==== 
 + 
 +aplicație ​a avantajului ​în schemele ​criptografice este de a arăta că un $PRG$ este sigur sau nu. Amintiți-vă de la curs că $G : K \rightarrow \{0, 1\}^n$ este un $PRG$ sigur dacă pentru orice test statistic $\mathsf{A}$ eficient (care rulează în timp polinomial),​ avantajul $\mathsf{Adv_{PRG}[A,​ G]}$ este neglijabil. Un test statistic este de fapt un algoritm care încearcă să determine ​dacă intrarea ​pare aleatoare ​sau nu. Acest algoritm poate fi definit ​astfel:
  
 \begin{equation*} \begin{equation*}
   A(x) =   A(x) =
     \begin{cases}     \begin{cases}
-      1 ,& \text{daca x e aleator}\\+      1 ,& \text{dacă x e aleatoriu}\\
       0 ,& \text{altfel}       0 ,& \text{altfel}
-    \end{cases} ​      ​+    \end{cases} ​
 \end{equation*} \end{equation*}
  
-Putem asocia pentru fiecare test statistic ​cate un adversar care incearca sa sparga ​$\mathsf{PRG}$-ul(i.e. poate distinge ​intre rezultatul $\mathsf{PRG}$-ului ​si un generator de numere complet aleatoare). ​In acest caz, vom defini experimentele:​ +Putem asocia pentru fiecare test statistic ​$A$ câte un adversar care încearcă să spargă ​$\mathsf{PRG}$-ul (adică ​poate distinge ​între ​rezultatul $\mathsf{PRG}$-ului ​și un generator de numere complet aleatoare). ​În acest caz, vom defini experimentele ​după cum urmează
-  * In $\mathsf{EXP}(0)$ verificatorul ​returneaza catre adversarul $\mathsf{A}$ valoarea $G(k)$ ​generata ​de $\mathsf{PRG}$;​ +  * În $\mathsf{EXP}(0)$ verificatorul ​trimite către ​adversarul $\mathsf{A}$ valoarea $G(k)$ ​generată ​de $\mathsf{PRG}$;​ 
-  * In $\mathsf{EXP}(1)$ verificatorul ​returneaza catre adversarul $\mathsf{A}$ o valoare $r$ generata ​de un generator de numere complet aleatoare. ​+  * În $\mathsf{EXP}(1)$ verificatorul ​trimite către ​adversarul $\mathsf{A}$ o valoare $r$ generată ​de un generator de numere complet aleatoare. ​ 
 + 
 +Ca mai devreme, $W_{b}$ este evenimentul în care adversarul spune că numărul este aleatoriu și a avut loc experimentul $b$. Dacă adversarul poate să distingă între $\mathsf{PRG}$ și un generator de numere complet aleatoare, atunci $\mathsf{PRG}$-ul nu e sigur. Așadar, avantajul devine:
  
-Ca si mai devreme, $W_{b}$ este evenimentul in care adversarul spune ca numarul este aleator si a avut loc experimentul $b$. Daca adversarul poate sa distinga intre $\mathsf{PRG}$ si un generator de numere complet aleatoare, atunci $\mathsf{PRG}nu e sigur. Asadar avantajul devine: +$$\mathsf{Adv_{PRG}[A,​ G]} = \left|\underset{k \leftarrow K}{Pr}[A(G(k)) = 1] - \underset{r \leftarrow \{0, 1\}^n}{Pr}[A(r) = 1] \right|$$
-$\mathsf{Adv_{PRG}[A,​ G]} = \left|\underset{k \leftarrow K}{Pr}[A(G(k)) = 1] - \underset{r \leftarrow \{0, 1\}^n}{Pr}[A(r) = 1] \right|$.+
  
-Chiar daca problema ​determinarii daca un $\mathsf{PRG}$ ​poate fi demonstrat ​ca sigur este echivalent cu a rezolva ​binecunoscuta problema ​$\mathsf{P}$ vs $\mathsf{NP}$, ​in practica exista ​$\mathsf{PRG}$-uri considerate sigure ​datorita ​unor euristici.+Deși problema ​determinării dacă există ​$\mathsf{PRG}$-uri care să poată ​fi demonstrate ​ca fiind sigure ​este echivalentă cu a rezolva ​bine-cunoscuta problemă ​$\mathsf{P}$ vs $\mathsf{NP}$, ​în practică există ​$\mathsf{PRG}$-uri considerate sigure ​prin folosirea ​unor euristici.
  
-In acest exercitiu, se da un $\mathsf{PRG}$ $G : \{0, 1\}^s \rightarrow \{0, 1\}^n$ sigur. Cu ajutorul acestuia, ​spuneti daca urmatoarele ​$\mathsf{PRG}$-uri sunt sigure.+În acest exercițiu, se dă un $\mathsf{PRG}$ $G : \{0, 1\}^s \rightarrow \{0, 1\}^n$ sigur. Cu ajutorul acestuia, ​spuneți dacă următoarele ​$\mathsf{PRG}$-uri sunt sigure.
   * $G_{1}(k) = G(k) \oplus 1^n$   * $G_{1}(k) = G(k) \oplus 1^n$
   * $G_{2}(k) = G(k) \| 0$   * $G_{2}(k) = G(k) \| 0$
Line 205: Line 468:
   * $G_{5}(k)=G(k) \| G(k)$   * $G_{5}(k)=G(k) \| G(k)$
  
-<​note>​Pentru ​doua siruri ​de biti $y$ si $z$ folosim $y \| z$ pentru a indica concatenarea ​intre $y$ si $z$.</​note>​+<​note>​Pentru ​două șiruri ​de biți $y$ și $z$ folosim $y \| z$ pentru a indica concatenarea ​între ​$y$ și $z$.</​note>​
  
-<note tip>​Pentru unele dintre ele nu nevoie ​sa calculati ​avantajul</​note>​+<note tip>​Pentru unele dintre ele nu este nevoie ​să calculați ​avantajul.</​note>​
  
-==== Exercițiul 4 ==== 
  
-Vom folosi experimentul definit mai devreme pentru a construi un pseudorandom generator ​($\mathsf{PRG}$)+==== Exercițiul 4 (3p====
-  - Se alege lungimea $n$ a sirului ce va fi generat +
-  - Se obtine un sir de biti $R$ de lungime $n$ (e.g. puteti folosi chiar si LCG-ul din Exercitiul 1) +
-  - Pentru fiecare bit $r$ din sirul $R$ generat anterior, $\mathsf{PRG}$-ul va intoarce un bit $b$ astfel: +
-  * daca bitul $r$ este $0$, atunci intoarce un bit aleator $b \in \{0, 1\}$ +
-  * daca bitul $r$ este $1$, atunci intoarce $1$+
  
-a. Implementati //​frequency ​(monobittest// asa cum e descris in articolul din [[http://​csrc.nist.gov/​publications/​nistpubs/​800-22-rev1a/​SP800-22rev1a.pdf | NIST (vezi section 2.1)]]. Verificati daca secventa generata de $\mathsf{PRG}$-ul ​de mai sus este aleatoare sau nu. (presupunem ​$n=100$)+Vom folosi experimentul definit mai devreme pentru ​construi un generator pseudoaleatoriu ​($\mathsf{PRG}$): 
 +  ​Se alege lungimea $n$ a șirului ce va fi generat 
 +  ​Se obține un șir de biți $R$ de lungime $n$ (de exemplu, puteți folosi chiar și LCG-ul din Exercițiul ​1) 
 +  - Pentru fiecare bit $r$ din șirul $R$ generat anterior, ​$\mathsf{PRG}$-ul ​va întoarce un bit $b$ astfel: 
 +    * dacă bitul $r$ este $0$, atunci întoarce un bit aleatoriu $b \in \{0, 1\}$ 
 +    * dacă bitul $r$ este $1$, atunci întoarce $1$
  
-bExecutati testul pe un sir aleator ​de biti (puteti folosi sirul R folosit in $\mathsf{PRG}$) ​si comparati rezultatele.+aImplementați //frequency (monobit) test// așa cum este descris ​de către [[http://​csrc.nist.gov/​publications/​nistpubs/​800-22-rev1a/​SP800-22rev1a.pdf | NIST (vezi secțiunea 2.1)]]. Verificați dacă secvența generată de $\mathsf{PRG}$-ul de mai sus este aleatoare sau nu (să presupunem pentru $n=100$).
  
-Daca rezultatele celor 2 experimente difera in mod regulat, acest test ofera un atacator care sparge ​$\mathsf{PRG}$-ul descris mai sus.+b. Executați testul pe un șir aleatoriu de biți (de exemplu, șirul R folosit în $\mathsf{PRG}$) și comparați rezultatele.
  
-<note tip>​Pentru a genera un sir aleator ​de bitiputeti ​folosi o functie ​de forma:+Dacă rezultatele celor două experimente diferă în mod regulat, acest test vă oferă un atacator care sparge $\mathsf{PRG}$-ul descris mai sus. 
 + 
 +<note tip>​Pentru a genera un șir aleatoriu ​de bițiputeți ​folosi o funcție ​de forma:
 <code python> <code python>
 import random import random
  
-def get_random_string(n): ​#​generate ​random bit string +def get_random_string(n: int-> str: 
-    ​bstr = bin(random.getrandbits(n)).lstrip('0b').zfill(n) +    """​Generate ​random bit string"""​ 
-    return bstr+    ​return ​bin(random.getrandbits(n)).lstrip("0b").zfill(n)
 </​code>​ </​code>​
 </​note>​ </​note>​
  
-<note tip>In Python ​puteti ​folosi ​functii ​precum sqrt, fabs sau erfc din modulul math+<note tip>În Python ​puteți ​folosi ​funcții ​precum sqrt, fabs sau erfc din modulul math.
 <code python> <code python>
 import math import math
Line 240: Line 504:
 </​note>​ </​note>​
  
-==== Exercițiul 5 (Bonus) ====+<file python ex4.py>​ 
 +import math 
 +import random
  
-In acest exercitiuveti incerca sa verificati daca intr-adevar Salsa20 stream cipher este mai rapid decat RC4. Descarcati ​{{:​ic:​laboratoare:​salsa20_rc4_surse_c.zip|aceasta}} arhiva+from utils import * 
-Rulati ​programul folosind ​acelasi fisier ​de intrare ​atat pentru Salsa20 ​cat si pentru RC4. Comparati ​timpul de executie in ambele cazuri.+ 
 + 
 +def get_random_string(n:​ int) -> str: 
 +    """​Generate random bit string"""​ 
 +    return bin(random.getrandbits(n)).lstrip("​0b"​).zfill(n) 
 + 
 + 
 +def main() -> None: 
 +    N_RUNS = 100  # the number of runs 
 +    N_BITS = 1000  # the number of bits to generate 
 + 
 +    # TODO: implement and run the multiple times (e.g., 100) the 
 +    # statistical tests 
 + 
 + 
 +if __name__ == "​__main__":​ 
 +    main() 
 +</​file>​ 
 +==== Exercițiul 5 - Bonus (2p) ==== 
 + 
 +În acest exercițiuveți încerca să verificați dacă într-adevar Salsa20 stream cipher este mai rapid decât ​RC4. Descărcați ​{{:​ic:​laboratoare:​salsa20_rc4_surse_c.zip|această}} arhivă
 +Rulați ​programul folosind ​același fișier ​de intrare ​atât pentru Salsa20, cât și pentru RC4. Comparați ​timpul de execuție în ambele cazuri.
  
 <note tip> <note tip>
-Pentru sistemele UNIX (si WSL), folositi ​scriptul **prepare.sh** pentru a complila sursele ​si a genera ​fisierele ​necesare.  +Pentru sistemele UNIX (și WSL), folosiți ​scriptul **prepare.sh** pentru a complila sursele ​și a genera ​fișierele ​necesare. 
-Daca nu folositi ​WSL pe Windows, scriptul **prepare.ps1** ​genereaza fisierele ​necesare dar **nu** ​si compileaza ​sursele.+Dacă nu folosiți ​WSL pe Windows, scriptul **prepare.ps1** ​generează fișierele ​necesaredar **nu** ​și compilează ​sursele.
 </​note>​ </​note>​
  
 <note tip> <note tip>
-Folositi optiunea ​"​-h"​ pentru a afisa lista tuturor argumentelor folosite de program.+Folosiți opțiunea ​"​-h"​ pentru a afișa ​lista tuturor argumentelor folosite de program.
 </​note>​ </​note>​
  
 <note tip> <note tip>
-Uitati-va in fisierul ​salsa20.h. Unde se executa ​rundele de criptare?+Uitați-vă în fișierul ​salsa20.h. Unde se execută ​rundele de criptare?
 </​note>​ </​note>​
  
-Incercati sa implementati aceeasi functionalitate folosint ​OpenSSL. OpenSSL ​suporta ​RC4 dar nu si Salsa20. ​Folositi ​ChaCha20 in loc de Salsa20, aceasta fiind o varianta imbunatatita ​a algoritmului.+Încercați să implementați aceeași funcționalitate folosind ​OpenSSL. OpenSSL ​suportă ​RC4dar nu și Salsa20. ​Folosiți ​ChaCha20 in loc de Salsa20, aceasta fiind o variantă îmbunătățită ​a algoritmului. 
 + 
 +</​hidden>​
ic/labs/03.1634537883.txt.gz · Last modified: 2021/10/18 09:18 by razvan.smadu
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