Puteți lucra acest laborator folosind și platforma Google Colab, accesând acest link, cu excepția exercițiului bonus și eventual 0/0b. Un scurt tutorial pentru utilizarea platformei poate fi găsit aici.
Tutorialul poate fi găsit aici. La laboratoare vom folosi Python 3.10 sau mai nou.
În timpul laboratoarelor, va trebui să convertim datele dintr-un format în altul. Cele mai utilizate formate pentru păstrarea datelor sunt:
Mai jos găsiți câteva funcții utile pentru conversii și operații de XOR pentru date de diferite formate:
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.
b) Doar textul de pe slide criptat, codificat Base64 (ca în slide-ul 3).
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).
Î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.
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.
Зяонмэцъ СъюъНсръ прЫрюср ыънгмЦ Ыъэят, фрмробъ, эчгэ нэъмцуасцФц нэрц, эбдуц сЯэНмОЪжл шъсцил. ПГМа цч сци юбуц съоячлтсб, я пгма — тлыоБ. Съоячлтсбъ эчгуц нэъМцуасцфЦ нэРц, Ср съ эчгуц н нрЮрх тянуя. Тлыобъ шъ эчГуЦ тянур э нрнЛыяи этънмъ нр нэЪмцУасцфятц нЭрцТЦ. Шъсци рпРчыяу, Ц энъ рсц чяыоътЯуц Ц лНслуЦ. Ц э пРусРжа оячЫяунг фоцФ: эРм, шЪсЦи цыщм; эбирыцмъ сяэнмоъжЛ Ътл! Мрьыя энъ мЪ ыъэб ЭнМЯуц Ц прпояЭцуц нэъмцуАсцфЦ нэрц. Ц съоячлтсБъ нфячяуц тлыОбт: ыяхМъ сят тянуя эядъьР, прМртл жмр нэъмцуасЦфц сядц ьяНслм. Ср тлыобъ рмэъжяуц цт: съм, жМРюб съ юбур СъырнмямРжСр сц Сят, сц ЭЯТ. Улждъ цыцмъ ф порыяДгцТ Ц флпцмъ НъЮъ. Ц фрьЫЯ рсц Прдуц прфЛпяма, поцДщу шъСци, ц мъ, фмР юбу ьрмрэ, ЭрдуЦ н сцт сЯ ЮояжСбх пцО; ц Ыэъоа чЯмэроцуЯна. Ц ПрмрТ поцдуЦ ц ыольцъ ыъэБ, ьрэрог: Ьрнпрыц, ЬрнПрыц, рмфорх сят! Ц Рс, рмэъжяг, Нфячяу: цнмцсср ЬрэроД эят: Г съ чСяд эян. ЮрыонмэЛХмъ Шъ, Цюр съ чсяъмъ Сц ысг, сц жяня, фрьыя Поцыщм Нбс ЖъУРэъжънфцх
Să considerăm exemplele de mai jos:
text1 = "Ana are mere" text2 = b"Ana are mere" print(type(text1)) # <class 'str'> print(type(text2)) # <class '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.
Decodificați următoarele stringuri:
C1 = "010101100110000101101100011010000110000101101100011011000110000100100001" C2 = "526f636b2c2050617065722c2053636973736f727321" C3 = "WW91IGRvbid0IG5lZWQgYSBrZXkgdG8gZW5jb2RlIGRhdGEu"
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”.
C1 = "000100010001000000001100000000110001011100000111000010100000100100011101000001010001100100000101" C2 = "02030F07100A061C060B1909"
Unul dintre cele mai cunoscute și mai simple scheme de criptare este 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$.
Să începem cu un exemplu simplu:
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" def caesar_enc(letter: str) -> str: if not "A" <= letter <= "Z": raise ValueError("Invalid letter") return ALPHABET[(ord(letter) - ord("A") + 3) % len(ALPHABET)]
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:
shell$ ls caesar.py shell$ python >>>
Importați simbolurile din fișierul caesar.py:
>>> from caesar import *
Testați următoarele comenzi în consolă:
>>> print(ALPHABET) >>> len(ALPHABET) >>> ALPHABET[0] >>> ord("A") >>> ord("D") - ord("A") >>> 26 % 26 >>> 28 % 26 >>> -1 % 26
Testați funcția de criptare pe câteva exemple:
>>> caesar_enc("D")
>>> caesar_enc("Z")
>>> caesar_enc("B")
Adăugați o funcție 'caesar_dec' în fișierul 'caesar.py' care decriptează o singură literă criptată folosind cifrul lui Cezar.
Vom extinde funcția definită anterior pentru a permite primirea unui string ca parametru.
def caesar_enc_string(plaintext: str) -> str: ciphertext = "" for letter in plaintext: ciphertext += caesar_enc(letter) return ciphertext
Testați codul de mai sus într-un interpretor de Python:
shell$ python -i caesar.py # run the script in interactive mode >>> test = "HELLO" >>> test += "WORLD" >>> caesar_enc_string(test)
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" def caesar_enc(letter: str) -> str: 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: ciphertext += caesar_enc(letter) return ciphertext def main() -> None: m = "BINEATIVENIT" c = caesar_enc_string(m) print(c) if __name__ == "__main__": main()
Apoi, puteți rula programul dintr-un terminal folosind:
python test_caesar.py
Scrieți funcția de decriptare numită 'caesar_dec_string'.
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.
def caesar_enc(letter: str, k: int = 3) -> str: if not "A" <= letter <= "Z": raise ValueError("Invalid letter") return ALPHABET[(ord(letter) - ord("A") + k) % len(ALPHABET)] def caesar_enc_string(plaintext: str, k: int = 3) -> str: ciphertext = "" for letter in plaintext: ciphertext += caesar_enc(letter, k) return ciphertext
Pentru a testa noile funcții, încercați comenzile de mai jos:
shell$ python -i caesar.py >>> 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", k=1) # pass the key as a keyword (named) argument
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.
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?
Decriptați ultimul ciphertext știind că toate mesajele au fost criptate cu aceeași cheie folosind OTP.
8841a58f876901c9e195d1e320e0c30a017bec11b0643d30533adcb0475e85a820d64e1a0869963453b490933b7005839f7d8a9571c8a890d75773bc2acc11d5cb3259f0610e95ad6ae1ec8445fc836b661b9c0554494c430210989e4a42ff7b4c19338945a68653c89d783e8460935c93896a3d73d9bc84a8e381951443ab8ada62c5d662d43c0da848c3602d 8e14e681d0651cd5fb99d1a87cee972b4436fe19b22c3d1e7a75c2a6155ac4fa06d74e07042889300ab490d226614c818574d99a38d8a899d45478f83cca04818a3549f061079bb139a5f78542eac63873499513460d48534345addf5f42b632475623d14fb49c16c1913d7fca019f59d09b253c3c98a480e1e3829c0942bec2da478bcc6bd42a00e953883a622497 e332a0cad0610ad6e691c6b967ad90634c73ec04fe216e586272dcb0474f98b336de5252042895310ab48c93277d4089d061968e76cbe194da0174f97dc512cd8e7b59bf351a8dad39acfdcb04edc62a275695045c4e405f4910bb9e4746f27915541fc653b5c81ec09f7f22ca2d945c9c916a2a7397bc8da4add1990945b7869c4a969a7a9c3f06a846882c6c28d6f9e6255ec96dd0b50e378054b2c89f6ee255312d330508e9cf4d43db 8812e8c6842612d5a895c3a87ca28230557fe717fe2b75117571d0ad475985ae3bd04550041d8e2744a5d5ca3c60058e9e6c96db379ceb90df427df9338850c7842948a6701dd0e853b4eb9f45ffc6386e56800c5001095d4544ad934e06f3385d1f25c243a9c653eed23b3983239a589ec23d206891e882a2e3869b1445bbc38907c2d461d42c0dfb57c7207e2adbfeaa2a4bc37ccceb5777cf36f58f8776a75b242a7d105babd2564d959b79b8bd 8008ac83d06f079cfbd0dba27aee89365262a904b62d740a3679dab01305cabb3ed30b0a4c2c92270aa581d227660586827dd99e2eddeb8cda5836e835c150d28a3648fe352698e878afe19f0df7882c2b1b9914125e09500c52b08b0b5db63a5e13348952af891d8f9f37229e609254868b26206698bc85a2ad82d3465cbccf9d4396c922d42d01e644cd6e7424ccb7b12c518d6d9faf166fc538bacc947fb149773f7c444ae7c95609959776b9e028502e45e0f6186c4fa51f4c80834f373d1f0b6130b770b6e1ce87 9603efdd952614d4e69ed4ed66af95260171e61cba687b0a797795a4154893fa33cc0b094125977b0a8f9ac673745782d074968c76d3e6d8d14e7af8628438c0833a45b1351b9bbd6daef69849be9f2e6653dc4042425b425810a99e474bb7325b0566c048e79c1bcad23f308725dd1db9c52769689ca480a4ad96d41f58a786974a8c942ebd7904e407db2b632f99eea9361fd976d2a25771c574ab81 8907a18f9d671a9bfa95c5a86aabcf634072fc50b1686f177778d4e3174583b433910b2e4820953415f6a5df3a7b44c7936dd9983383a8bbc34c36ff288413c4c77b4ea5350c9be86db3fd8910f7836a277a9101544c4411455ead9a474fa075153e27c006aa891a8f803d218f24941d93976a3b7398aa8deda29895481793c58f46c2d66bd43f1afd49cb2f606bc9f2e6255ad87cdeb4036bc138abcad76ead5b232e3d446ee2cf190c8d9b76a8b37b5e7c0bf6b71d7d42a50105c1964739224a1230 960ea9dbd04e169bec9fd0be2ea790635263fb00ac216e11787d9bed47618ffa35d65d1b57699a3b45a29dd62135428e966cd8db14c9fcd8c2497fef7dc319c79f7b44a3350b97ae7fa4ea8e0beac865274c9801410d6e5e4810be965d4fa07b5c0566e14faa9b16c3947671be28941db88d393d3cb1a181bea69d924654bdcb9f58c2ce61d43407e1498827636bcdffa3634cda76d6ab127d8068badd8363ec b952fa8f836e1cccfbd0c0bd2ebd8c635925bb50bf3a78587c6fc6b74768b9991bf60b1d4c28893449a290c120355688d074908f33cee994da5836e835c150d29f2944be724f86fc2be1f19845f0893f27499117154f50454910bf90590ae17b461966c543b3cf008f95377188219256d083242d3c95a783a6e390804658a7d4da588adf62983d07ec42882f6a2ad0f9e8 a20cbb9f953f1083e283dfba3afbcf6e142fff1aa964304c606edffa574286f7608248121622916118e28580637348cb982dc9936581bd8edb0d31ff2ec2038cdf37168b385bceba2ab5fb9e48f9952c3c57833d120d6a6375608db07469871d4e3823df43b5bd00cabd16149e299c58a0a30e2672b4bd80b9aa8198037ab7d5894a85df7dd57f15
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 aici:
Rulare:
git clone https://github.com/ACS-IC-labs/MTP.git cd MTP pip install . mtp <ciphertexts filename> # OR python3 -m manytime <ciphertexts filename>