This shows you the differences between two versions of the page.
|
ic:labs:01 [2021/10/04 12:22] razvan.smadu [Bonus - Many-Time Pad] |
ic:labs:01 [2026/02/27 08:07] (current) razvan.smadu [Laboratorul 01 - Introducere] |
||
|---|---|---|---|
| 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/github/ACS-IC-labs/IC-labs/blob/main/labs/lab01/lab1.ipynb|acest]] link, cu excepția exercițiului bonus și eventual 0/0b. 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(a, b): # xor two strings, trims the longer input | + | |
| - | return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)) | + | Returns: |
| - | + | str: The binary representation of the hexadecimal string, where each | |
| - | def bitxor(a, b): # 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(a, b)) | + | |
| - | + | Examples: | |
| - | def hexxor(a, b): # 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: 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 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 == | + | |
| + | === Exercițiul #0 - O criptare (2p) === | ||
| + | |||
| + | Folosiți orice cod vreți, generat cum vreți voi (GenAI, etc.), pentru a cripta slide-ul de titlu din curs (slide 4) https://curs.upb.ro/2025/mod/resource/view.php?id=120046 astfel încât să obțineți două variante diferite: | ||
| + | |||
| + | a) Slide-ul criptat ca în slide-ul 2 (se vede ceva dar nu se înțelege). Salvați slide-ul ca o imagine (e.g., screenshot) și apoi faceți criptarea. | ||
| + | |||
| + | <note tip> | ||
| + | Ca să obțineți ceva asemănător cu slide-ul 2, folosiți un block cipher dar fără random IV (e.g. mod ECB). | ||
| + | </note> | ||
| + | |||
| + | b) Doar textul de pe slide criptat, codificat Base64 (ca în slide-ul 3). | ||
| + | |||
| + | === Exercițiul #0b - Statistici în alte limbi (3p) === | ||
| + | |||
| + | Precum am arătat la curs, faceți tabelul de frecvențe pentru următoarele limbi: engleză, română și rusă. | ||
| + | |||
| + | Pentru asta folosiți orice text (suficient de lung) doriți de pe internet (Wikipedia, Enciclopedii, Pagini, Cărți, etc.). | ||
| + | |||
| + | Apoi decriptați următoarele string-uri care au fost criptate cu substitution cipher fiecare în limba lor. O metodă simplă este să mapați frecvențele: litera cu frecvența cea mai mare în textul criptat (ciphertext) corespunde cu litera cea mai frecventă în text-ul necriptat (tabel făcut de voi). | ||
| + | |||
| + | <note> | ||
| + | Este posibil să nu meargă foarte bine din prima. Posibile lucruri de folos: | ||
| + | - să vă asigurați că ați generat tabelul de frecvențe cu un text suficient de lung în limba respectivă (eventual comparați și cu ce mai găsiți gata făcut pe internet); | ||
| + | - să folosiți și un tabel de frecvență cu câte 2 (eventual și 3) litere și astfel să corectați maparea inițială. | ||
| + | </note> | ||
| + | |||
| + | <file text ciphertext1.txt> | ||
| + | ÎsDăhăţrX mQhaHryoh gq Fx xgqsăNX ma tqmq pqmroxhQ, mxHq Yaânl mxnlqyqyq yoh, xa rqŞrb în înbâsdrnxhqx srhqYAR. MrnmR îngă lRnbhq qYq qhxa păhă srnbq, rxh MrNmr înŢqyQdBq. MăMr mqyq păhă srnbq, Yaânl mXnlqyQyq, n-Xa yaxb mA grnq anBlqyqsn. Rxh mqyq îNţqyqdbq xa Yaxb anblqyqsn în fxGq, olxbĂ ma mxNlqyqyq yoh. Lxh srhqyQ înbÂhtrrnl, xa xţrdRb boxBQ Şr xa xlohsrb. RXh yX srqtay NOdţrr g-X Pămab gbhRzxhq: Rxbă, srhQyq frnq! RqşRţr înbha îNbâsdrnxhqx Yar! XbaNmr g-xa lqşbQdbxb boXbq xmqyq pqmRoxhq şr xA îsdolovrb mxNlqyqyq yoH. Şr mqYq păhă srNbq Xa trg Măbhq mqyq înţqyqdbq: Lxţr-nq lrN anblQyqsNay fogbha, mă gQ gbrnz mxnlqyQyq noxGbHq. LxH mQyQ înţqyqdbQ Yq-xa hăgdanG, tRmânl: Na, mx nA maSFx gă na Nq xUanzĂ nrmr noaă şR nrmr foaă. Sxr vrnq sqHzqţr yX mqr mq fânL şR masdăhxŢr dqnbha for. LqmR dYqmânl qyq mX gă mAsdqhq, X fqnrb srHqyq şR mQYq mq Qhxa zxbx xa rnbhxb ma qy YX nanbă şr aşx g-x înmwrg. RXh sxr dQ ahsă, xA GogrB şr mqyqyXybq pqmroXhq, trmânl: Loxsnq, Loxsnq, lqgmwrlq-nq noAă. Rxh qy, hĂgdaNtânl, x trg: Xlqfăhxb trm foaă: Na fă Manogm dq for. LhQdb xmqqx, dHrfqzwqxţr, mă na şbrţr trax, nrMR mqxgaY mânl fRnq PrAy OsayAr. | ||
| + | </file> | ||
| + | |||
| + | <file text ciphertext2.txt> | ||
| + | Bwq kRnzlOs op wqxfqn cryy vq yrkq bqn frhZrng cwo book bwqrh yxsdg Xnl cQnb oab bo sqqb BwQ vhrlqzhoOs. Prfq op bWqS cqhq PooyrGw xnL pRfq cqhq crGq. Poh Bwq poOyrgw boOk bwqrH yxSdG xnl boOk No ORy crBW bwqs. VAb bwq crGq bOok ory Rn fqggQYg Crbw bwqrh Yxsdg. Vab bwq vhRlqzhoOs CXg yxbq, xNl bwqi xyy gyasVqhql xnl gyqDb. Xnl xb srLnrzWb Bwqhq cxg x MHi sxlq, VqwoyL, bwq vhRlqZhoOs mOsqbw; zo iQ oAB bo sqqb WRs. Bwqn xYy bwogq frhzRng xhogq Xnl bhrssql bwqrh yxsDg. Xnl Bwq pOoYrgw gxrl anbo bwq CRgq, Zrfq ag op ioah ory; pOH oah yxsdg Xhq zornz oab. Vab bwq crgq xngcqHQl Bwqs, GxiRnz, Nxi; yqgb bwqhq vq nob qnoazw poh ag Xnl ioA. Zo iq hxbWqh bo bWQs bwxB gqyy, Xnl vAi pOH ioahgQyfQg. Xnl CwrYq bWqi cqnB bO vai, bwq vhrLqzhoos mXsq, xnl bwqI bwxB cQhq hqxli cqnb Rn crbw wrs bo bwQ sxhhRxzq: xnl Bwq looh Cxg gwaB. Xnl XPbqhcxhl mxsq xygO bwq obwqh frhZrng, gXirnz, YOhl, Yohl, odqN bO aG. Xnl wq xNgcqhql Xnl gxrl, Fqhryi R gXI anbo ioa, R knoc Ioa nob. Cxbmw bwqHQpohq, poh iq knoc nQRbwqh bwq lxI noh bwq Woah cwqhqrn bwq GoN op sxn Mosqbw. | ||
| + | </file> | ||
| + | |||
| + | <file text ciphertext3.txt> | ||
| + | Зяонмэцъ СъюъНсръ прЫрюср ыънгмЦ Ыъэят, фрмробъ, эчгэ нэъмцуасцФц нэрц, эбдуц сЯэНмОЪжл шъсцил. ПГМа цч сци юбуц съоячлтсб, я пгма — тлыоБ. Съоячлтсбъ эчгуц нэъМцуасцфЦ нэРц, Ср съ эчгуц н нрЮрх тянуя. Тлыобъ шъ эчГуЦ тянур э нрнЛыяи этънмъ нр нэЪмцУасцфятц нЭрцТЦ. Шъсци рпРчыяу, Ц энъ рсц чяыоътЯуц Ц лНслуЦ. Ц э пРусРжа оячЫяунг фоцФ: эРм, шЪсЦи цыщм; эбирыцмъ сяэнмоъжЛ Ътл! Мрьыя энъ мЪ ыъэб ЭнМЯуц Ц прпояЭцуц нэъмцуАсцфЦ нэрц. Ц съоячлтсБъ нфячяуц тлыОбт: ыяхМъ сят тянуя эядъьР, прМртл жмр нэъмцуасЦфц сядц ьяНслм. Ср тлыобъ рмэъжяуц цт: съм, жМРюб съ юбур СъырнмямРжСр сц Сят, сц ЭЯТ. Улждъ цыцмъ ф порыяДгцТ Ц флпцмъ НъЮъ. Ц фрьЫЯ рсц Прдуц прфЛпяма, поцДщу шъСци, ц мъ, фмР юбу ьрмрэ, ЭрдуЦ н сцт сЯ ЮояжСбх пцО; ц Ыэъоа чЯмэроцуЯна. Ц ПрмрТ поцдуЦ ц ыольцъ ыъэБ, ьрэрог: Ьрнпрыц, ЬрнПрыц, рмфорх сят! Ц Рс, рмэъжяг, Нфячяу: цнмцсср ЬрэроД эят: Г съ чСяд эян. ЮрыонмэЛХмъ Шъ, Цюр съ чсяъмъ Сц ысг, сц жяня, фрьыя Поцыщм Нбс ЖъУРэъжънфцх | ||
| + | </file> | ||
| + | |||
| + | <hidden> | ||
| + | Latin Alphabet (Used for Romanian & English) | ||
| + | | Original | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | | ||
| + | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | ||
| + | | Cipher | X | V | M | L | Q | P | Z | W | R | U | K | Y | S | N | O | D | J | H | G | B | A | F | C | E | I | T | | ||
| + | |||
| + | Cyrillic Alphabet (Used for Russian) | ||
| + | | Оригинал | А | Б | В | Г | Д | Е | Ё | Ж | З | И | Й | К | Л | М | Н | О | П | Р | С | Т | У | Ф | Х | Ц | Ч | Ш | Щ | Ъ | Ы | Ь | Э | Ю | Я | | ||
| + | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | ||
| + | | Шифр | Я | Ю | Э | Ь | Ы | Ъ | Щ | Ш | Ч | Ц | Х | Ф | У | Т | С | Р | П | О | Н | М | Л | К | И | З | Ж | Д | Г | В | Б | А | Е | Д | Г | | ||
| + | |||
| + | Text 1: | ||
| + | |||
| + | "Împărăţia cerurilor se va asemăna cu zece fecioare, care luând candelele lor, au ieşit în întâmpinarea mirelui. Cinci însă dintre ele erau fără minte, iar cinci înţelepte. Căci cele fără minte, luând candelele, n-au luat cu sine untdelemn. Iar cele înţelepte au luat untdelemn în vase, odată cu candelele lor. Dar mirele întârziind, au aţipit toate şi au adormit. Iar la miezul nopţii s-a făcut strigare: Iată, mirele vine! Ieşiţi întru întâmpinarea lui! Atunci s-au deşteptat toate acele fecioare şi au împodobit candelele lor. Şi cele fără minte au zis către cele înţelepte: Daţi-ne din untdelemnul vostru, că se sting candelele noastre. Dar cele înţelepte le-au răspuns, zicând: Nu, ca nu cumva să nu ne ajungă nici nouă şi nici vouă. Mai bine mergeţi la cei ce vând şi cumpăraţi pentru voi. Deci plecând ele ca să cumpere, a venit mirele şi cele ce erau gata au intrat cu el la nuntă şi uşa s-a închis. Iar mai pe urmă, au sosit şi celelalte fecioare, zicând: Doamne, Doamne, deschide-ne nouă. Iar el, răspunzând, a zis: Adevărat zic vouă: Nu vă cunosc pe voi. Drept aceea, privegheaţi, că nu ştiţi ziua, nici ceasul când vine Fiul Omului." | ||
| + | |||
| + | |||
| + | |||
| + | Text 2: | ||
| + | |||
| + | "The kingdom of heaven will be like ten virgins who took their lamps and went out to meet the bridegroom. Five of them were foolish and five were wise. For the foolish took their lamps and took no oil with them. But the wise took oil in vessels with their lamps. But the bridegroom was late, and they all slumbered and slept. And at midnight there was a cry made, Behold, the bridegroom cometh; go ye out to meet him. Then all those virgins arose and trimmed their lamps. And the foolish said unto the wise, Give us of your oil; for our lamps are going out. But the wise answered them, saying, Nay; lest there be not enough for us and you. Go ye rather to them that sell, and buy for yourselves. And while they went to buy, the bridegroom came, and they that were ready went in with him to the marriage: and the door was shut. And afterward came also the other virgins, saying, Lord, Lord, open to us. And he answered and said, Verily I say unto you, I know you not. Watch therefore, for ye know neither the day nor the hour wherein the Son of man cometh." | ||
| + | |||
| + | |||
| + | |||
| + | Text 3: | ||
| + | |||
| + | "Царствие Небесное подобно десяти девам, которые, взяв светильники свои, вышли навстречу жениху. Пять из них были неразумны, а пять — мудры. Неразумные взяли светильники свои, но не взяли с собой масла. Мудрые же взяли масло в сосудах вместе со светильниками своими. Жених опоздал, и все они задремали и уснули. И в полночь раздался крик: вот, жених идёт; выходите навстречу ему! Тогда все те девы встали и поправили светильники свои. И неразумные сказали мудрым: дайте нам масла вашего, потому что светильники наши гаснут. Но мудрые отвечали им: нет, чтобы не было недостаточно ни нам, ни вам. Лучше идите к продающим и купите себе. И когда они пошли покупать, пришёл жених, и те, кто был готов, вошли с ним на брачный пир; и дверь затворилась. И потом пришли и другие девы, говоря: Господи, Господи, открой нам! И Он, отвечая, сказал: истинно говорю вам: Я не знаю вас. Бодрствуйте же, ибо не знаете ни дня, ни часа, когда придёт Сын Человеческий" | ||
| + | |||
| + | </hidden> | ||
| + | |||
| + | |||
| + | === Bytes în Python === | ||
| Să considerăm exemplele de mai jos: | Să considerăm exemplele de mai jos: | ||
| <code python> | <code python> | ||
| 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 (1p) === | ||
| Decodificați următoarele stringuri: | Decodificați următoarele stringuri: | ||
| Line 107: | Line 427: | ||
| </code> | </code> | ||
| - | === Exercițiul #2 - But XOR-ing is cool === | + | === Exercițiul #2 - But XOR-ing is cool (1p) === |
| 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 118: | Line 438: | ||
| ==== 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 baza este de a transforma fiecare litera 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$. | + | 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 125: | Line 445: | ||
| <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> | ||
| Line 150: | Line 470: | ||
| Testați următoarele comenzi în consolă: | Testați următoarele comenzi în consolă: | ||
| <code python> | <code python> | ||
| - | >>> print(alphabet) | + | >>> print(ALPHABET) |
| - | >>> len(alphabet) | + | >>> len(ALPHABET) |
| - | >>> alphabet[0] | + | >>> ALPHABET[0] |
| - | >>> ord('A') | + | >>> ord("A") |
| - | >>> ord('D') - ord('A') | + | >>> ord("D") - ord("A") |
| >>> 26 % 26 | >>> 26 % 26 | ||
| >>> 28 % 26 | >>> 28 % 26 | ||
| Line 162: | Line 482: | ||
| Testați funcția de criptare pe câteva exemple: | Testați funcția de criptare pe câteva exemple: | ||
| <code> | <code> | ||
| - | >>> caesar_enc('D') | + | >>> caesar_enc("D") |
| - | >>> caesar_enc('Z') | + | >>> caesar_enc("Z") |
| - | >>> caesar_enc('B') | + | >>> caesar_enc("B") |
| </code> | </code> | ||
| - | === Exercițiul #3 - Decriptarea unei litere === | + | === Exercițiul #3 - Decriptarea unei litere (1p) === |
| Adăugaț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. | ||
| Line 178: | Line 498: | ||
| <code Python> | <code Python> | ||
| - | def caesar_enc_string(plaintext): | + | def caesar_enc_string(plaintext: str) -> str: |
| - | 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 189: | Line 509: | ||
| <code Python> | <code Python> | ||
| shell$ python -i caesar.py # run the script in interactive mode | 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> | ||
| Line 198: | Line 518: | ||
| <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 229: | Line 551: | ||
| </note> | </note> | ||
| - | === Exercițiul #4 - Decriptarea unui string === | + | === Exercițiul #4 - Decriptarea unui string (1p) === |
| Scrieți funcția de decriptare numită 'caesar_dec_string'. | Scrieți funcția de decriptare numită 'caesar_dec_string'. | ||
| Line 241: | Line 563: | ||
| <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): | + | |
| - | ciphertext = '' | + | def caesar_enc_string(plaintext: str, k: int = 3) -> str: |
| + | 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 259: | Line 580: | ||
| <code Python> | <code Python> | ||
| shell$ python -i caesar.py | shell$ python -i caesar.py | ||
| - | >>> caesar_enc_string('HELLO') # use the default value for k | + | >>> caesar_enc_string("HELLO") # use the default value for k |
| - | >>> caesar_enc_string('HELLO', 0) # pass the key as a positional argument | + | >>> caesar_enc_string("HELLO", 0) # pass the key as a positional argument |
| - | >>> caesar_enc_string('HELLO', k=1) # pass the key as a keyword (named) argument | + | >>> 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 (1p) === |
| Folosind valori implicite, extindeți funcția `caesar_dec_string` pentru a decripta mesaje criptate cu 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 cipher, astfel î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 cheie, folosind 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 291: | Line 620: | ||
| * 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/ACS-IC-labs/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/ACS-IC-labs/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> | ||
| Line 307: | Line 636: | ||
| - Rulați: | - Rulați: | ||
| <code> | <code> | ||
| - | pip install urwid # OR pip3 install urwid | + | git clone https://github.com/ACS-IC-labs/MTP.git |
| - | git clone https://github.com/cosminacho/MTP.git | + | |
| cd MTP | cd MTP | ||
| - | python mtp.py <ciphertexts filename> # OR python3 mtp.py <ciphertexts filename> | + | pip install . |
| + | mtp <ciphertexts filename> # OR python3 -m manytime <ciphertexts filename> | ||
| </code> | </code> | ||
| + | <note info> | ||
| + | `<ciphertexts filename>` trebuie să conțină cele 10 texte cifrate de mai sus. Aveți în repository `ciphertexts.txt` care conține aceste texte cifrate. | ||
| + | </note> | ||