Differences

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

Link to this comparison view

ic:labs:01 [2021/10/02 18:54]
razvan.smadu
ic:labs:01 [2023/10/01 23:03] (current)
razvan.smadu [Python3 Crash Course]
Line 1: Line 1:
 ===== Laboratorul 01 - Introducere ===== ===== Laboratorul 01 - Introducere =====
 +
 +Puteți lucra acest laborator folosind și platforma Google Colab, accesând [[https://​colab.research.google.com/​drive/​1G8ycsy34UwwQqJHp2DgL5MtGERWzkhN_|acest]] link, cu excepția exercițiului bonus. Un scurt tutorial pentru utilizarea platformei poate fi găsit [[https://​docs.google.com/​document/​d/​1Dcnyv9wTfWJx8CEgnR6OgLbHAO7XD1BXGjwOAMAEmlc/​edit|aici]]. ​
  
 ==== Python3 Crash Course ==== ==== Python3 Crash Course ====
  
-Tutorialul poate fi găsit [[ic:​resurse:​python|aici]].+Tutorialul poate fi găsit [[ic:​resurse:​python|aici]]. La laboratoare vom folosi Python 3.10 sau mai nou.
  
 ==== Codificare vs Criptare ==== ==== Codificare vs Criptare ====
Line 24: Line 26:
   * Binar (01010101)   * Binar (01010101)
   * Hexazecimal [0-9a-fA-F]   * Hexazecimal [0-9a-fA-F]
-  * Base64 [a-zA-Z0-9] împreună cu '​+'​ și '/'​. În general, ​Base64 ​se termină cu '​='​ sau '​=='​ reprezentând padding. Este foarte folosit în web deoarece HTTP este un protocol de transfer text.+  * Base64 [a-zA-Z0-9] împreună cu '​+'​ și '/'​. În general, ​base64 ​se termină cu '​='​ sau '​=='​ reprezentând padding. Este foarte folosit în web deoarece HTTP este un protocol de transfer text.
  
  
 Mai jos găsiți câteva funcții utile pentru conversii și operații de XOR pentru date de diferite formate: Mai jos găsiți câteva funcții utile pentru conversii și operații de XOR pentru date de diferite formate:
  
 +<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):​ +def _pad(data: str, size: 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 
-def _hex(x): +    return data 
-    return format(x'02x'+ 
-  + 
-def hex_2_bin(data):​ +def _chunks(data: str, chunk_size: int-> Generator[str,​ None, None]: 
-    ​return ​''​.join(f'{int(x, 16):08b}' ​for x in _chunks(data,​ 2)) +    data = _pad(data, chunk_size) 
-  +    for i in range(0, len(data), chunk_size):​ 
-def str_2_bin(data): +        yield data[i : i + chunk_size] 
-    ​return ''​.join(f'{ord(c):08b}' for c in data+ 
-  + 
-def bin_2_hex(data): +def _hex(data: int-> str
-    ​return ​''​.join(f'{int(b, 2):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) +# Conversion functions 
-  + 
-def bin_2_str(data):​ + 
-    ​return ​''​.join(chr(int(b,​ 2)) for b in _chunks(data,​ 8)) +def hex_2_bin(data: str-> str
-  +    ​"""​Converts a hexadecimal string to a binary representation. 
-def hex_2_str(data): + 
-    return ''​.join(chr(int(x,​ 16)) for x in _chunks(data,​ 2)) +    Args: 
-  +        data (str): The hexadecimal string to be converted. It should have an 
-# XOR FUNCTIONS +            even number of characters and only contain valid hexadecimal digits 
-  +            (0-9, A-F, a-f). 
-def strxor(ab):  # xor two strings, ​trims the longer ​input + 
-    ​return ​''​.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(ab)) +    Returns: 
-  +        str: The binary representation of the hexadecimal string, where each 
-def bitxor(ab):  # xor two bit-strings, ​trims the longer ​input +            pair of hexadecimal digits is encoded as an 8-bit binary number. 
-    ​return ​''​.join(str(int(x) ^ int(y)) for (x, y) in zip(ab)) + 
-  +    Examples: 
-def hexxor(ab):  # xor two hex-strings, ​trims the longer ​input +        >>>​ hex_2_bin("​01abcd"​) 
-    ​return ​''​.join(_hex(int(x,​ 16) ^ int(y, 16)) for (x, y) in zip(_chunks(a, 2), _chunks(b, 2))) +        ​'000000011010101111001101' 
-  +        >>>​ hex_2_bin("​0a"​) 
-BASE64 FUNCTIONS +        '​00001010'​ 
-  +    """​ 
-def b64decode(data): +    return ""​.join(f"{int(x, 16):08b}" ​for x in _chunks(data,​ 2)) 
-    ​return ​bytes_to_string(base64.b64decode(string_to_bytes(data))) + 
-  + 
-def b64encode(data):​+def bin_2_hex(data: str-> str
 +    ​"""​Converts a binary string to a hexadecimal representation. 
 + 
 +    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: stroperand_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_1operand_2)) 
 + 
 + 
 +def bitxor(operand_1: stroperand_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_1operand_2)) 
 + 
 + 
 +def hexxor(operand_1: stroperand_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 b64decode(data: str-> str
-def bytes_to_string(bytes_data): +    ​"""​Decodes a base64 encoded string. 
-    ​return bytes_data.decode()  # default utf-8 + 
-  +    Args: 
-def string_to_bytes(string_data): +        data (str): The base64 encoded string to be decoded. It should only 
-    return ​string_data.encode()  # default utf-8+            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>​
  
 == Bytes în Python == == Bytes în Python ==
Line 92: Line 342:
 text1 = "Ana are mere" text1 = "Ana are mere"
 text2 = b"Ana are mere" text2 = b"Ana are mere"
-type(text1) # <class '​str'>​ +print(type(text1))  ​# <class '​str'>​ 
-type(text2) # <class '​bytes'>​+print(type(text2))  ​# <class '​bytes'>​
 </​code>​ </​code>​
  
 Ambele variabile stochează aceeași informație. Diferența constă în modul cum sunt păstrate datele intern, cele două texte fiind codificate în 2 obiecte de tipuri diferite (string și bytes). În timpul laboratoarelor vom lucra de foarte multe ori cu tipul string, dar unele biblioteci externe pot necesita transformarea datelor din formatul string în formatul bytes. Ambele variabile stochează aceeași informație. Diferența constă în modul cum sunt păstrate datele intern, cele două texte fiind codificate în 2 obiecte de tipuri diferite (string și bytes). În timpul laboratoarelor vom lucra de foarte multe ori cu tipul string, dar unele biblioteci externe pot necesita transformarea datelor din formatul string în formatul bytes.
  
-=== Exercițiul #1 - Encoding is nice ===+=== Exercițiul #1 - Encoding is nice (2p) ===
  
 Decodificați următoarele stringuri: Decodificați următoarele stringuri:
Line 107: Line 357:
 </​code>​ </​code>​
  
-=== Exercițiul #2 - But XOR-ing is cool ===+=== Exercițiul #2 - But XOR-ing is cool (2p) ===
  
 Găsiți mesajele în clar pentru următoarele ciphertexturi,​ știind că cifrul este operația XOR (ciphertext = plaintext XOR key), iar cheia este "​abcdefghijkl"​. Găsiți mesajele în clar pentru următoarele ciphertexturi,​ știind că cifrul este operația XOR (ciphertext = plaintext XOR key), iar cheia este "​abcdefghijkl"​.
Line 117: Line 367:
  
 ==== Hail, Caesar! ==== ==== Hail, Caesar! ====
 +
 +Unul dintre cele mai cunoscute și mai simple scheme de criptare este [[https://​en.wikipedia.org/​wiki/​Caesar_cipher|Cifrul lui Cezar]]. Ideea de bază este de a transforma fiecare literă din plaintext prin deplasarea la stânga a poziției literei curente cu trei poziții. Cu alte cuvinte, A devine D, B devine E, C devine F, și așa mai departe. Operația de criptare a unei litere $m$ este definită prin relația $Enc(m) = (m + 3)\ mod\ 26 $. Analog, pentru a decripta un text, trebuie să facem deplasarea la dreapta cu 3 poziții. Deci, operația de decriptare pentru fiecare literă $c$ dintr-un ciphertext este dată de relația $Dec(c) = (c - 3)\ mod\ 26$.
  
 === Criptarea unei litere === === Criptarea unei litere ===
Line 123: Line 375:
  
 <code python> <code python>
-alphabet ​= "​ABCDEFGHIJKLMNOPQRSTUVWXYZ"​ +ALPHABET ​= "​ABCDEFGHIJKLMNOPQRSTUVWXYZ"​ 
-def caesar_enc(letter):​ + 
-    if letter < 'A' or letter ​> 'Z'+ 
-        ​print("​Invalid letter"​) +def caesar_enc(letter: str-> str
-        return +    if not "A" <= letter ​<= "Z"
-    ​else: +        ​raise ValueError("​Invalid letter"​) 
-        ​return ​alphabet[(ord(letter) - ord('A') + 3) % len(alphabet)]+    return ​ALPHABET[(ord(letter) - ord("A") + 3) % len(ALPHABET)]
 </​code>​ </​code>​
  
-Creați un fișier nou caesar.py care să conțină codul de mai sus. Testați codul prin a deschide ​interpretorul de Python și încercați următoarele comenzi:+Creați un fișier nou caesar.py care să conțină codul de mai sus. Deschideți interpretorul de python în directorul în care ați salvat fișierul:
  
-<​code ​python>+<​code>​ 
 +shell$ ls 
 +caesar.py
 shell$ python shell$ python
 +>>>​
 +</​code>​
 +
 +Importați simbolurile din fișierul caesar.py:
 +<code python>
 >>>​ from caesar import * >>>​ from caesar import *
->>>​ print(alphabet+</​code>​ 
->>> ​alphabet[0] + 
->>>​ ord('A') +Testați următoarele comenzi în consolă: 
->>>​ len(alphabet+<code python>​ 
->>>​ ord('D') - ord('A')+>>>​ print(ALPHABET
 +>>> ​len(ALPHABET) 
 +>>>​ ALPHABET[0] 
 +>>>​ ord("A"
 +>>>​ ord("D") - ord("A")
 >>>​ 26 % 26 >>>​ 26 % 26
 >>>​ 28 % 26 >>>​ 28 % 26
 >>>​ -1 % 26 >>>​ -1 % 26
->>>​ caesar_enc('​D'​) 
->>>​ caesar_enc('​Z'​) 
->>>​ caesar_enc('​B'​) 
 </​code>​ </​code>​
  
-=== Exercițiul #3 - Decriptarea unei litere ===+Testați funcția de criptare pe câteva exemple: 
 +<​code>​ 
 +>>>​ caesar_enc("​D"​) 
 +>>>​ caesar_enc("​Z"​) 
 +>>>​ caesar_enc("​B"​) 
 +</​code>​ 
 + 
 +=== Exercițiul #3 - Decriptarea unei litere ​(2p) ===
  
-Adaugați o funcție '​caesar_dec'​ în fișierul '​caesar.py'​ care decriptează o singură literă criptată folosind cifrul lui Cezar.+Adăugați o funcție '​caesar_dec'​ în fișierul '​caesar.py'​ care decriptează o singură literă criptată folosind cifrul lui Cezar.
  
 +<note tip> Implementarea funcției de decriptare este similară cu cea a funcției de criptare. Diferă doar relația matematică. </​note>​
  
 === Criptarea unui string === === Criptarea unui string ===
Line 160: Line 428:
  
 <code Python> <code Python>
-alphabet='​ABCDEFGHIJKLMNOPQRSTUVWXYZ'​ +def caesar_enc_string(plaintext: str-> str
-def caesar_enc_string(plaintext):​ +    ciphertext = ""​
-    ciphertext = ''​+
     for letter in plaintext:     for letter in plaintext:
-        ​ciphertext = ciphertext + caesar_enc(letter)+        ciphertext +caesar_enc(letter)
     return ciphertext     return ciphertext
 </​code>​ </​code>​
Line 171: Line 438:
  
 <code Python> <code Python>
-linux$ python -i caesar.py +shell$ python -i caesar.py ​# run the script in interactive mode 
->>>​ test = 'HELLO' +>>>​ test = "HELLO" 
->>>​ test += 'WORLD'+>>>​ test += "WORLD"
 >>>​ caesar_enc_string(test) >>>​ caesar_enc_string(test)
 </​code>​ </​code>​
  
 +<note tip>
 O altă modalitate de a rula diverse lucruri în Python, care poate fi foarte folositoare în general, este de a folosi o funcție main() și să avem un script precum cel de mai jos: O altă modalitate de a rula diverse lucruri în Python, care poate fi foarte folositoare în general, este de a folosi o funcție main() și să avem un script precum cel de mai jos:
  
 <file Python test_caesar.py>​ <file Python test_caesar.py>​
-alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'+ALPHABET ​"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  
-def caesar_enc(letter):​ 
-    if letter < '​A'​ or letter > '​Z':​ 
-        print('​Invalid letter'​) 
-        return 
-    else: 
-        return alphabet[(ord(letter) - ord('​A'​) + 3) % len(alphabet)] 
  
-def caesar_enc_string(plaintext):​ +def caesar_enc(letter:​ str) -> str: 
-    ciphertext = ''​+    if not '​A'​ <= letter <= '​Z':​ 
 +        raise ValueError('​Invalid letter'​) 
 +    return ALPHABET[(ord(letter) - ord('​A'​) + 3) % len(ALPHABET)] 
 + 
 + 
 +def caesar_enc_string(plaintext: str-> str
 +    ciphertext = ""​
     for letter in plaintext:     for letter in plaintext:
-        ​ciphertext = ciphertext + caesar_enc(letter)+        ciphertext +caesar_enc(letter)
     return ciphertext     return ciphertext
  
-def main(): + 
-    m = 'BINEATIVENIT'+def main() ​-> None
 +    m = "BINEATIVENIT"
     c = caesar_enc_string(m)     c = caesar_enc_string(m)
     print(c)     print(c)
-  ​+ 
 if __name__ == "​__main__":​ if __name__ == "​__main__":​
     main()     main()
Line 209: Line 479:
 python test_caesar.py python test_caesar.py
 </​code>​ </​code>​
 +</​note>​
  
-=== Exercițiul #4 - Decriptarea unui string ===+=== Exercițiul #4 - Decriptarea unui string ​(2p) ===
  
 Scrieți funcția de decriptare numită '​caesar_dec_string'​. Scrieți funcția de decriptare numită '​caesar_dec_string'​.
Line 217: Line 488:
 === Shift ciphers === === Shift ciphers ===
  
-Python ne permite să pasăm valori implicite ca parametri. Putem folosi ​valorile ​implicite pentru a extinde funcția noastră '​caesar_enc'​ astfel încât să permită primirea cheii ca un parametru adițional, fără a afecta compatibilitatea cu codul anterior.+Așa cum am văzut mai sus, Cifrul lui Cezar folosește o cheie fixată $k=3$. Putem însă generaliza pe mai multe valori ale cheii (adică, în cazul alfabetului englez, putem avea valori de la 0 la 25). Această modalitate de criptare este numită Shift Cipher. Pentru a cripta un mesaj, pentru fiecare literă aplicăm $Enc(m, k) = (m + k)\ mod\ 26$, iar pentru decriptare, folosim $Dec(c, k) = (c - k)\ mod\ 26$. 
 + 
 +Python ne permite să pasăm valori implicite ca parametri. Putem folosi ​valori ​implicite pentru a extinde funcția noastră '​caesar_enc'​ astfel încât să permită primirea cheii ca un parametru adițional, fără a afecta compatibilitatea cu codul anterior.
  
 <code Python> <code Python>
-def caesar_enc(letter,​ k = 3): +def caesar_enc(letter: str, k: int = 3) -> str
-    if letter < 'A' or letter ​> 'Z'+    if not "A" <= letter ​<= "Z"
-        ​print('Invalid letter') +        ​raise ValueError("Invalid letter"
-        return None +    return ​ALPHABET[(ord(letter) - ord("A") + k) % len(ALPHABET)] 
-    ​else: +
-        ​return ​alphabet[(ord(letter) - ord('A') + k) % len(alphabet)]+
  
-def caesar_enc_string(plaintext,​ k = 3): +def caesar_enc_string(plaintext: str, k: int = 3) -> str
-    ciphertext = ''​+    ciphertext = ""​
     for letter in plaintext:     for letter in plaintext:
-        ​ciphertext = ciphertext + caesar_enc(letter,​ k)+        ciphertext +caesar_enc(letter,​ k)
     return ciphertext     return ciphertext
 </​code>​ </​code>​
Line 238: Line 510:
 <code Python> <code Python>
 shell$ python -i caesar.py shell$ python -i caesar.py
->>>​ caesar_enc_string('HELLO'+>>>​ caesar_enc_string("HELLO"      # use the default value for k 
->>>​ caesar_enc_string('HELLO', 0) +>>>​ caesar_enc_string("HELLO", 0)    # pass the key as a positional argument 
->>>​ caesar_enc_string('HELLO', 1)+>>>​ caesar_enc_string("HELLO"k=1)  # pass the key as a keyword (named) argument
 </​code>​ </​code>​
  
-=== Exercițiul #5 - Shift Ciphers ===+=== Exercițiul #5 - Shift Ciphers ​(2p) ===
  
-Folosind valori implicite, extindeți funcția ​de decriptare folosind ​shift cipher astfel încât să suporte chei arbitrare.+Folosind valori implicite, extindeți funcția ​`caesar_dec_string` pentru a decripta mesaje criptate cu shift cipherastfel încât să suporte chei arbitrare.
  
  
-==== Bonus - Many-Time Pad ====+==== Bonus - Many-Time Pad (2p) ====
  
-Decriptați ultimul ciphertext știind că toate mesajele au fost criptate cu aceeași cheiefolosind OTP (One Time Pad).+OTP (One Time Pad) este o tehnică de criptare care lucrează pe streamuri de date (adica, este un stream cipher). In OTP, mesajul și cheia trebuie să aibă aceeași dimensiune în număr de biți, iar algoritmul de criptare este operația XOR: $OTP(k, m) = k \oplus m$. 
 + 
 +Avantajul folosirii OTP este dată de proprietatea de perfect secrecy: atâta timp cât nu cunoaștem cheia de criptare, un ciphertext poate corespunde oricărui mesaj posibil, cu aceeași probabilitate. Cu alte cuvinte, dacă avem acces la un ciphertext criptat cu OTP, nu putem ști care este mesajul din spate, fără a-l decripta. Această proprietate nu mai este adevărată în cazul în care folosim cheia de mai multe ori (de unde și numele de one-time pad).  
 + 
 +Ideea de atac din spatele many-time pad (MTP) se bazează pe faptul că dacă $C1 = K \oplus M1$, iar $C2 = K \oplus M2$, atunci $C1 \oplus C2 = K \oplus M1 \oplus K \oplus M2 = M1 \oplus M2$. Cum vă poate ajuta această observație în a sparge MTP? 
 + 
 +<​note>​Simbolul $\oplus$ reprezintă operația XOR.</​note>​ 
 + 
 +Decriptați ultimul ciphertext știind că toate mesajele au fost criptate cu aceeași cheie folosind OTP.
  
  
Line 270: Line 550:
   * Ce se întâmplă dacă faceți XOR între un caracter [a-z] cu caracterul ' ' (spațiu)? Verificați de asemenea pentru [A-Z].   * Ce se întâmplă dacă faceți XOR între un caracter [a-z] cu caracterul ' ' (spațiu)? Verificați de asemenea pentru [A-Z].
   * Nu puteți scrie un algoritm perfect care să rezolve problema din prima încercare, cel mai probabil va trebui să ghiciți. De ce?   * Nu puteți scrie un algoritm perfect care să rezolve problema din prima încercare, cel mai probabil va trebui să ghiciți. De ce?
-  * Provocarea este interesantă,​ dar poate deveni muncitorească. Din fericire pentru noi, există o implementare open source care poate fi găsită [[https://​github.com/​cosminacho/​MTP|aici]]. Vedeți mai jos cum poate fi rulat.+  * Provocarea este interesantă,​ dar poate deveni muncitorească. Din fericire pentru noi, există o implementare open source care poate fi găsită [[https://​github.com/​cosminacho/​MTP|aici]]. Vedeți mai jos cum poate fi rulat. Acest tool se folosește de observațiile de mai sus pentru a [[https://​github.com/​cosminacho/​MTP/​blob/​master/​manytime/​analysis.py#​L34-L55|recupera câteva litere]] din cheie. Posibil ca nu toate literele deja existente să fie puse corect.
  
 </​note>​ </​note>​
 === Cum se rulează === === Cum se rulează ===
  
-Pe Windows puteți să activați WSL (Windows Linux Subsystem) cum este detaliat [[https://​docs.microsoft.com/​en-us/​windows/​wsl/​install-win10|aici]], dacă vă este mai ușor să folosiți linia de comandă din linux+Pentru a rula utilitarul, trebuie să folosiți un sistem de operare unix-like (Linux, OSX, Cygwin). ​Pe Windows puteți să activați WSL (Windows Linux Subsystem) cum este detaliat [[https://​docs.microsoft.com/​en-us/​windows/​wsl/​install-win10|aici]]:​ 
-    - Căutați în bara de căutare din Windows "Turn Windows features on/off"+    - Căutați în bara de căutare din Windows "Turn Windows features on or off"
     - Activați "​Containers"​ și "​Windows Subsystem for Linux"     - Activați "​Containers"​ și "​Windows Subsystem for Linux"
-    - Restartați sistemul și instalați Ubuntu din Windows Store +    - Restartați sistemul și instalați Ubuntu din [[https://​www.microsoft.com/​store/​productId/​9NBLGGH4MSV6|Windows Store]] 
-    - Deschideți un terminal (de exemplu, Command Prompt, PowerShell, Windows Terminal) și scrieți ubuntu +    - Deschideți un terminal (de exemplu, Command Prompt, PowerShell, ​[[https://​www.microsoft.com/​store/​productId/​9n0dx20hk701|Windows Terminal]]) și rulați "ubuntu" 
-    - Așteptați ​că instalarea să se termine și nu uitați să rulați "sudo apt-get ​upgrade" și "sudo apt-get ​update"+    - Așteptați ​ca instalarea să se termine și nu uitați să rulați "sudo apt-get ​update" și "sudo apt-get ​upgrade"
  
-Pe orice sistem de operare:+Rulare:
   - Verificați că aveți instalat Python3, pip (python package manager) și git   - Verificați că aveți instalat Python3, pip (python package manager) și git
   - Rulați:   - Rulați:
 <​code>​ <​code>​
-pip install urwid+pip install urwid  # OR pip3 install urwid
 git clone https://​github.com/​cosminacho/​MTP.git git clone https://​github.com/​cosminacho/​MTP.git
-python mtp.py <​ciphertexts filename>​+cd MTP 
 +python ​mtp.py <​ciphertexts filename> ​ # OR python3 ​mtp.py <​ciphertexts filename>​
 </​code>​ </​code>​
  
 +<note info>
 +`<​ciphertexts filename>​` trebuie să conțină cele 10 texte cifrate de mai sus.
 +</​note>​
 +
 +<note info>
 +În cazul în care programul trebuie să afișeze caractere non-printabile,​ posibil să crape. Există un [[https://​github.com/​CameronLonsdale/​MTP/​issues/​14|issue]] deschis pe GitHub în acest sens, dar nu a fost rezolvat încă.
 +</​note>​
  
ic/labs/01.1633190087.txt.gz · Last modified: 2021/10/02 18:54 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