Differences

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

Link to this comparison view

ic:labs:04 [2021/10/14 22:32]
philip.dumitru [Exercise 2-3-4]
ic:labs:04 [2023/10/09 23:21] (current)
razvan.smadu
Line 3: Line 3:
 Prezentarea PowerPoint pentru acest laborator poate fi găsită [[https://​drive.google.com/​file/​d/​1mjbkxFqYNB-lRRXGAhsdh1vK9nwbnDuS/​view?​usp=sharing|aici]]. Prezentarea PowerPoint pentru acest laborator poate fi găsită [[https://​drive.google.com/​file/​d/​1mjbkxFqYNB-lRRXGAhsdh1vK9nwbnDuS/​view?​usp=sharing|aici]].
  
 +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/​lab04/​lab4.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(string,​ chunk_size):​ 
-    for i in range(0, len(string),​ chunk_size):​ 
-        yield string[i:​i+chunk_size] 
  
-THIS ONE IS NEW +def _pad(data: str, size: int) -> str: 
-def byte_2_bin(bval):​ +    reminder = len(data) % size 
-    """​ +    if reminder != 0: 
-      Transform ​a byte (8-bit) value into bitstring+        data = "​0"​ * (size - reminder) + data 
 +    return data 
 + 
 + 
 +def _chunks(data:​ str, chunk_size: int) -> Generator[str,​ None, None]: 
 +    data = _pad(data, chunk_size) 
 +    for i in range(0, len(data), chunk_size):​ 
 +        yield data[i : i + chunk_size] 
 + 
 + 
 +def _hex(data: int) -> str: 
 +    return format(data,​ "​02x"​) 
 + 
 + 
 +Conversion functions 
 + 
 + 
 +def byte_2_bin(bval: int-> str
 +    """​Converts ​a byte value to a binary string. 
 + 
 +    Args: 
 +        bval (int)
 +            The byte value to be converted. It should be an integer between 
 +            0 and 255. 
 + 
 +    Returns: 
 +        str: The binary string representation of the byte value, where each bit 
 +        is encoded as character. The result has a fixed length of 8 characters 
 +        and is padded with leading zeros if necessary. 
 + 
 +    Examples: 
 +        >>>​ byte_2_bin(72) 
 +        '​01001000'​ 
 +        >>>​ byte_2_bin(66) 
 +        '​01000010'​
     """​     """​
     return bin(bval)[2:​].zfill(8)     return bin(bval)[2:​].zfill(8)
  
-def _hex(x): 
-    return format(x, '​02x'​) 
  
-def hex_2_bin(data):​ +def hex_2_bin(data: str-> str
-    ​return ''​.join(f'​{int(x,​ 16):​08b}'​ for x in _chunks(data,​ 2))+    ​"""​Converts a hexadecimal string to a binary representation.
  
-def str_2_bin(data): +    Args: 
-    return ''​.join(f'​{ord(c):​08b}'​ for c in data)+        ​data (str): The hexadecimal string to be convertedIt should have an 
 +            even number of characters and only contain valid hexadecimal digits 
 +            ​(0-9, A-F, a-f).
  
-def bin_2_hex(data)+    Returns
-    ​return ''​.join(f'​{int(b,​ 2):02x}' for b in _chunks(data, 8))+        strThe binary representation of the hexadecimal stringwhere each 
 +            pair of hexadecimal digits is encoded as an 8-bit binary number.
  
-def str_2_hex(data): +    Examples: 
-    ​return ​''​.join(f'{ord(c):02x}' ​for in data)+        >>>​ hex_2_bin("​01abcd"​
 +        '000000011010101111001101' 
 +        >>>​ hex_2_bin("​0a"​) 
 +        '​00001010'​ 
 +    """​ 
 +    return ""​.join(f"{int(x, 16):08b}" ​for in _chunks(data, 2))
  
-def bin_2_str(data):​ 
-    return ''​.join(chr(int(b,​ 2)) for b in _chunks(data,​ 8)) 
  
-def hex_2_str(data): +def bin_2_hex(data: str-> str
-    ​return ''​.join(chr(int(x,​ 16)) for x in _chunks(data,​ 2))+    ​"""​Converts a binary string to a hexadecimal representation.
  
-# XOR FUNCTIONS +    Args: 
-def strxor(a, b):  # xor two strings, trims the longer input +        ​data ​(str): The binary string to be converted. It should have a multiple 
-    ​return ''​.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b))+            of 8 characters and only contain valid binary digits ​(0 or 1).
  
-def bitxor(a, b) # xor two bit-strings,​ trims the longer input +    Returns
-    ​return ''​.join(str(int(x) ^ int(y)) for (xy) in zip(a, b))+        str: The hexadecimal representation of the binary stringwhere each 
 +            group of 8 binary digits is encoded as pair of hexadecimal digits.
  
-def hexxor(a, b):  # xor two hex-strings,​ trims the longer input +    Examples: 
-    return ​''​.join(_hex(int(x16) ^ int(y, 16)) for (x, y) in zip(_chunks(a2), _chunks(b, 2)))+        >>>​ bin_2_hex("​000000011010101111001101"​) 
 +        '​01abcd'​ 
 +        >>>​ bin_2_hex("​00001010"​) 
 +        '​0a'​ 
 +    """​ 
 +    return ​""​.join(f"{int(b2):​02x}" ​for in _chunks(data8))
  
-# BASE64 FUNCTIONS 
-def b64decode(data):​ 
-    return bytes_to_string(base64.b64decode(string_to_bytes(data))) 
  
-def b64encode(data):​+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):​ 
-    return bytes_data.decode() ​ # default utf-8 
  
-def string_to_bytes(string_data): +def b64decode(data: str-> str
-    ​return string_data.encode()  # default utf-8+    ​"""​Decodes a base64 encoded string. 
 + 
 +    Args: 
 +        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>​
  
 +<note tip>
 In acest laborator veti avea niste exercitii ce folosesc PRFs, PRPs si DES. Puteti sa va uitati in cursul de  [[https://​drive.google.com/​file/​d/​1Fjybv6k5QudRB1bkAi5shVUGlUyTO_0U/​view?​usp=sharing|aici]] ca sa va aduceti aminte lucrurile de baza.  In acest laborator veti avea niste exercitii ce folosesc PRFs, PRPs si DES. Puteti sa va uitati in cursul de  [[https://​drive.google.com/​file/​d/​1Fjybv6k5QudRB1bkAi5shVUGlUyTO_0U/​view?​usp=sharing|aici]] ca sa va aduceti aminte lucrurile de baza. 
 +</​note>​
 +
 +==== Exercițiul 1 (4p) ====
  
-==== Exercise 1 (4p) ==== 
 Fie $F : K × X \to Y$ un $PRF$ sigur cu $K = X = Y = \{0, 1\}^{n}$. Fie $F : K × X \to Y$ un $PRF$ sigur cu $K = X = Y = \{0, 1\}^{n}$.
-  * a) Aratati ca $F_1(k,x) = F(k,x) \| 0$ nu e un $PRF$ sigur. +  * a) Arătați că $F_1(k,x) = F(k,x) \| 0$ nu e un $PRF$ sigur. 
-  * b) Aratati ca $F_2(k, x) = F \left(k, x \oplus 1^{n}\right)$ este un $PRF$ sigur. ​+  * b) Arătați că $F_2(k, x) = F \left(k, x \oplus 1^{n}\right)$ este un $PRF$ sigur. ​
 <note tip> <note tip>
-Hint: Ca sa aratati ​ca e sigur, ​folositi ​metoda reducerii la absurd: ​existenta ​unui adversar $A$ care sparge $F_2$ implica existenta ​unui alt adversar $B$ care care sparge $F$ intr-un timp similar. ​+Hint: Ca să arătați ​ca e sigur, ​folosiți ​metoda reducerii la absurd: ​existența ​unui adversar $A$ care sparge $F_2$ implică existența ​unui alt adversar $B$ care care sparge $F$ într-un timp similar. ​
 </​note>​ </​note>​
-  * c) Fie $K_3 = \{0, 1\}^{n+1}$. ​Construiti ​un nou $PRF$ $F_3 : K_3 \times X \to Y$ care sa aiba urmatoarea ​prorprietate: $PRF$-ul $F_3$ este sigur, dar daca adversarul ​afla ultimul bit din cheie atunci $PRF$-ul nu mai e sigur. ​Puteti ​astfel observa ​ca pana si aflarea unui singur bit din cheia secreta ​poate compromite ​siguranta ​unui $PRF$ . +  * c) Fie $K_3 = \{0, 1\}^{n+1}$. ​Construiți ​un nou $PRF$ $F_3 : K_3 \times X \to Y$ care să aibă urmatoarea ​proprietate: $PRF$-ul $F_3$ este sigur, dar dacă adversarul ​află ultimul bit din cheie atunci $PRF$-ul nu mai e sigur. ​Puteți ​astfel observa ​că până și aflarea unui singur bit din cheia secretă ​poate compromite ​siguranța ​unui $PRF$ . 
 <note tip> <note tip>
-Hint: Fie $k_3 = k \| b$ unde $k \in \{0,​1\}^{n}$ ​si $b \in \{0,​1\}$. ​Definiti ​$F_3(k_3,​x)$ ca fiind identic cu $F (k, x)$ pentru toate $x \neq 0^{n}$. Acum trebuie ​sa mai definit ​$F_3\left(k_3,​ 0^{n}\right)$ astfel ​incat $F_3$ este un PRF sigur, dar poate fi diferentiat ​de o functie ​aleatoare ​daca ultimul bit din cheie este cunoscut. ​Aratati ca $F_3$ e sigur prin reducere la absurd.+Hint: Fie $k_3 = k \| b$ unde $k \in \{0,​1\}^{n}$ ​și $b \in \{0,​1\}$. ​Definiți ​$F_3(k_3,​x)$ ca fiind identic cu $F (k, x)$ pentru toate $x \neq 0^{n}$. Acum trebuie ​să mai definim ​$F_3\left(k_3,​ 0^{n}\right)$ astfel ​încât ​$F_3$ este un PRF sigur, dar poate fi diferențiat ​de o funcție ​aleatoare ​dacă ultimul bit din cheie este cunoscut. ​Arătați că $F_3$ e sigur prin reducere la absurd.
 </​note>​ </​note>​
-  * d) Construiti ​un nou $PRF$ $F_4 : K × X \to Y$ care ramane ​sigur chiar si atunci ​cand atacatorul ​cunoaste ​unul (oricare) dintre ​bitii cheieiFunctia voastra ​$F_4$ trebuie ​sa cheme o singura data functia ​$F$. Explicati ​de ce ramane ​un $PRF$ sigur chiar si dupa aceasta ​scurgere de informatie.+  * d) Construiți ​un nou $PRF$ $F_4 : K × X \to Y$ care rămâne ​sigur chiar și atunci ​când atacatorul ​cunoaște ​unul (oricare) dintre ​biții cheiiFuncția voastră ​$F_4$ trebuie ​să cheme o singură dată funcția ​$F$. Explicați ​de ce rămâne ​un $PRF$ sigur chiar și după această ​scurgere de informație.
  
-<​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>​
  
-==== Exercise ​2-3-4 ====+==== Exercițiile ​2-3-4 ====
  
-Vom analiza acum retele substitutie-permutare(SPN - substitution-permutation networks)+Vom analiza acum rețele substituție-permutare (SPN - substitution-permutation networks)
  
 ==== SPN 1 (3p) ==== ==== SPN 1 (3p) ====
  
-We have the SPN from this figure:+Avem următorul ​SPN din figură: 
 {{:​sasc:​laboratoare:​spn_1r_reduced_2s.png|}} {{:​sasc:​laboratoare:​spn_1r_reduced_2s.png|}}
  
-where denotes the AES S-box (we'll discuss this in some detail during the next lecture), and '​Permutation' ​is a simple permutation block that simply shifts the input 4 bits to the right as in a queueBoth this S-box and the permutation are invertible and known by the attacker ​(you). Each input (x1, x2) is 8-bit (1 byte), as well as the keys k1, k2, and the outputs ​y1, y2.+unde este un S-box din AES (detalii vor fi prezentate la curs), iar '​Permutation' ​este un bloc care doar șiftează ​toți biții cu 4 poziții la dreapta în mod ciclicAtât S-boxurile cât și permutarea sunt inversabile și cunoscute de atacator ​(de voi). Fiecare intrare ​(x1, x2) are biți (1 byte). Cheile ​k1, k2, și ieșirile ​y1, y2 au de asemenea dimensiunea de 1 byte.
  
-  - How can you find the key +  - Cum puteți determina cheia
-  - Given the message/​ciphertext ​pair ('​Hi'​ - as characters, 0xba52 - as hex number), find the key bytes k1 and k2. Print them in ascii.+  - Fiind dată o pereche mesaj/ciphertext ('​Hi'​ - char, 0xba52 - hex), găsiți ​k1 și k2. Afișați-le în ASCII.
  
 <note tip> <note tip>
-For these exercises you can use the following helper/​starter code: +Puteți porni de la urmatorul schelet de cod:
-</​note>​+
  
 +<spoiler Click pentru a vedea spn1.py>
 <code python spn1.py> <code python spn1.py>
 +from typing import List
 +
 from utils import * from utils import *
  
 +# fmt: off
 # Rijndael S-box # Rijndael S-box
 sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67,
Line 153: Line 431:
          0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,          0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,
          0x21, 0x0c, 0x7d]          0x21, 0x0c, 0x7d]
 +# fmt: on
  
  
-def permute4(s):​ 
-    """​ 
-      Perform a permutatation by shifting all bits 4 positions right. 
-      The input is assumed to be a 16-bit bitstring 
-    """​ 
-    ps = ''​ 
-    ps = ps + s[12:16] 
-    ps = ps + s[0:12] 
-    return ps 
  
  
-def permute_inv4(s): +def permute4(s: str-> str
-    """​ +    """​Perform ​a permutatation by shifting all bits 4 positions right. 
-      ​Perform ​the inverse of permute4 + 
-      The input is assumed to be a 16-bit bitstring +    Args: 
-    """​ +        s (str): ​The input is assumed to be a 16-bit bitstring.
-    ps = ''​ +
-    ps = ps + s[4:16] +
-    ps = ps + s[0:4] +
-    return ps+
  
 +    Raises:
 +        TypeError: Expected input to be a string.
 +        ValueError: Expected input to have length 16.
  
-def spn_1r_reduced_2s(k,​ x):+    Returns: 
 +        str: The permuted string by shifting all bits 4 positions right.
     """​     """​
-      Performs an encryption with a substitution-permutation network. +    if not isinstance(s,​ str): 
-      Key k = {k1k2}, total of 16 bits (2 x 8 bits+        raise TypeError( 
-      Input x {x1, x2}, total of 16 bits (2 x 8 bits) +            f"​Invalid type for the input. Expected `str`but got `{type(s)}`." 
-      Both k and x are assumed ​to be bitstrings.+        ) 
 +    if len(s) != 16
 +        raise ValueError
 +            ​f"​Invalit input length. Expected ​to be 16, but got {len(s)}.
 +        ) 
 +    return s[12:16] + s[0:12]
  
-      Return+ 
-      a 16-bit bitstring ​containing the encryption y = {y1, y2}+def permute_inv4(s:​ str) -> str
 +    """​Perform the inverse of permute4. 
 + 
 +    Args: 
 +        s (str): The input is assumed to be a 16-bit bitstring
 + 
 +    Raises: 
 +        TypeError: Expected input to be a string. 
 +        ValueError: Expected input to have length 16. 
 + 
 +    Returns: 
 +        str: The permuted string by shifting all bits 4 positions left.
     """​     """​
 +    if not isinstance(s,​ str):
 +        raise TypeError(
 +            f"​Invalid type for the input. Expected `str`, but got `{type(s)}`."​
 +        )
 +    if len(s) != 16:
 +        raise ValueError(
 +            f"​Invalit input length. Expected to be 16, but got {len(s)}."​
 +        )
 +    return s[4:16] + s[0:4]
  
 +
 +def spn_1r_reduced_2s(k:​ str, x: str) -> str:
 +    """​Performs an encryption with a substitution-permutation network.
 +
 +    Args:
 +        k (str): Key k = {k1, k2}, total of 16 bits (2 x 8 bits). Assumed to be
 +            bitstring.
 +        x (str): Input x = {x1, x2}, total of 16 bits (2 x 8 bits). Assumed to
 +            be bitstring.
 +
 +    Returns:
 +        str: a 16-bit bitstring containing the encryption y = {y1, y2}
 +    """​
     # Split input and key     # Split input and key
-    x1 = x[0:8] +    x1, x2 = x[0:8]x[8:16] 
-    x2 = x[8:16] +    k1, k2 = k[0:8]k[8:16]
-    k1 = k[0:8] +
-    k2 = k[8:16]+
  
     # Apply S-box     # Apply S-box
Line 210: Line 516:
  
  
-def spn_1r_full_2s(k,​ x): +def spn_1r_full_2s(k: str, x: str-> str
-    """​ +    """​Performs an encryption with a substitution-permutation network.
-      ​Performs an encryption with a substitution-permutation network+
-      Key k = {k1, k2, k3, k4}, total of 32 bits (4 x 8 bits) +
-      Input x = {x1, x2}, total of 16 bits (2 x 8 bits) +
-      Both k and x are assumed to be bitstrings.+
  
-      Return+    Args
-      a 16-bit ​bitstring ​containing the encryption y = {y1y2+        k (str): Key k = {k1, k2, k3, k4}, total of 32 bits (4 x 8 bits). 
-    """​+            Assumed to be bitstring
 +        x (str): Input x = {x1x2}, total of 16 bits (2 x 8 bits). 
 +            ​Assumed to be bitstring.
  
 +    Returns:
 +        str: a 16-bit bitstring containing the encryption y = {y1, y2}
 +    """​
     # Split input and key     # Split input and key
-    x1 = x[0:8] +    x1, x2 = x[0:8]x[8:16] 
-    x2 = x[8:16] +    k1, k2, k3, k4 = k[0:8]k[8:16]k[16:24]k[24:32]
-    k1 = k[0:8] +
-    k2 = k[8:16] +
-    k3 = k[16:24] +
-    k4 = k[24:32]+
  
     # Apply S-box     # Apply S-box
Line 248: Line 551:
     y2 = bitxor(po2, k4)     y2 = bitxor(po2, k4)
  
-    return y1+y2+    return y1 + y2
  
  
-def main(): 
  
 +
 +def main() -> None:
     # Run reduced 2-byte SPN     # Run reduced 2-byte SPN
-    msg = 'Hi' +    msg = "Hi" 
-    key = '??' ​ # Find this +    key = "??" ​ # Find the key that should replace ??
-    xs = str_2_bin(msg)+
     ks = str_2_bin(key)     ks = str_2_bin(key)
 +
 +    # TODO 1: Find the key in the reduced 2-byte SPN
 +
 +
 +    xs = str_2_bin(msg)
     ys = spn_1r_reduced_2s(ks,​ xs)     ys = spn_1r_reduced_2s(ks,​ xs)
-    print('Two y halves of reduced SPN: ' + ys[0:​8] ​+ ' ​(hex: ' + bin_2_hex( +    print( 
-        ​ys[0:​8]) ​+ '), ' + ys[8:​16] ​+ ' ​(hex: ' + bin_2_hex(ys[8:​16]) ​+ ')')+        "Two y halves of reduced SPN:
 +        f" {ys[0:8](hex: {bin_2_hex(ys[0:​8])}),
 +        f" {ys[8:16](hex: {bin_2_hex(ys[8:​16])})
 +    ​)
  
     # Run full 2-byte SPN     # Run full 2-byte SPN
-    msg = 'Om' +    msg = "Om" 
-    key = '????' ​ # Find this +    key = "????" ​ # Find the key that should replace ????
-    xs = str_2_bin(msg)+
     ks = str_2_bin(key)     ks = str_2_bin(key)
 +
 +    # TODO 2: Find the key in the full 2-byte SPN
 +
 +    xs = str_2_bin(msg)
     ys = spn_1r_full_2s(ks,​ xs)     ys = spn_1r_full_2s(ks,​ xs)
-    print('Two y halves of full SPN (2 bytes): ​' + ys[0:​8] ​+ ' ​(hex: ' + bin_2_hex( +    print( 
-        ​ys[0:​8]) ​+ '), ' + ys[8:​16] ​+ ' ​(hex: ' + bin_2_hex(ys[8:​16]) ​+ ')')+        "Two y halves of full SPN (2 bytes):
 +        f" {ys[0:8](hex: {bin_2_hex(ys[0:​8])}),
 +        f" {ys[8:16](hex: {bin_2_hex(ys[8:​16])})
 +    ​) 
  
  
 if __name__ == "​__main__":​ if __name__ == "​__main__":​
-    main() ​ +    main()
 </​code>​ </​code>​
 +</​spoiler>​
 +
 +</​note>​
  
 ==== SPN 2 (3p) ==== ==== SPN 2 (3p) ====
 +Vom folosi acum un SPN mai mai bun unde rezultatul permutarilor este XOR-at cu alți 2 octeți din cheie k3 și k4, ca în figură:
  
-Now we have a better SPN, where the output of the permutation is XOR-ed with another 2 key bytes, as in the following figure: 
 {{:​sasc:​laboratoare:​spn_1r_full_2s.png|}} {{:​sasc:​laboratoare:​spn_1r_full_2s.png|}}
  
-  - Try to find the key in this case, when given the following message/​ciphertext ​pairs: ('​Om',​ 0x0073), ('​El',​ 0xd00e), ('​an',​ 0x855b). ​Print the key in ascii.+  - Găsiți cheia știind următoarele perechi mesaj/​ciphertext:​ ('​Om',​ 0x0073), ('​El',​ 0xd00e), ('​an',​ 0x855b). ​Afișați-o în ASCII 
 + 
 +<note tip>O să trebuiască să faceți căutare brute-force.</​note>​
  
-<note tip>You may try some kind of brute-force search</​note>​+==== SPN 3 Bonus (2p) ====
  
-==== SPN 3 (Bonus) ====+În acest exercițiu vom folosi un bloc mai mare. În acest SPN sunt introduși 4 octeți x=[x1 || x2 || x3 || x4], iar cheia folosită conține 8 octeți k=[k1 || k2 || k3 || k4 || k5 || k6 || k7 || k8] ca în figură:
  
-As another example, which uses a larger block size, let's use an SPN that takes a 4-byte input x=[x1 || x2 || x3 || x4] and an 8-byte key k=[k1 || k2 || k3 || k4 || k5 || k6 || k7 || k8] as in this figure: 
 {{:​sasc:​laboratoare:​spn_1r_full_4s.png|}} {{:​sasc:​laboratoare:​spn_1r_full_4s.png|}}
  
-Note that in this 4-byte ​SPN, the permutation operates on all 4 bytes, similarly to the 2-byte SPN: that isit shifts all bits four bits to the right.+Ca și în SPN-ul precedentpermutarea rotește ​toți octeții la dreapta cu 4 biți.
  
-  - Try to find the key in this case as well, using the following message/​ciphertext ​pairs: ('​Omul',​ 0xddcf7bc7),​ ('​stea',​ 0x96d58b43),​ ('​luna',​ 0x9c3f2303) ​. Again print the key in ascii.+  - Găsiți cheia știind următoarele perechi mesaj/​ciphertext:​ ('​Omul',​ 0xddcf7bc7),​ ('​stea',​ 0x96d58b43),​ ('​luna',​ 0x9c3f2303)
  
-<note tip> ​This time you cannot (easily) do a brute-force ​on all the bytes of the last XOR. However, you may try to attack one S-box at a timeThink of the bits that affect one such S-box and find an efficient attackSuppose you brute force k5 and k6, is it possible to find out k1?+<note tip> ​ 
 +De data aceasta nu se poate executa o cautare ​brute-force ​pe toți octeții de XOR. Încercați să atacați câte un S-box pe rândGandiți-vă ce biți sunt afectați de fiecare ​S-box pentru a construi un atac eficientCe se întâmplă dacă faceți ​brute force pe k5 și k6? Puteți să aflați ​k1?
 </​note>​ </​note>​
 +</​hidden>​
ic/labs/04.1634239934.txt.gz · Last modified: 2021/10/14 22:32 by philip.dumitru
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