Tema 2

Enunț

Să se implementeze un program care decodează o serie de șiruri codificate prin diferite metode criptografice.

Structură și detalii de implementare

Tema este formată din mai multe subpuncte, fiecare subpunct constând în decodarea unui șir codificat printr-o metodă specificată. Subpunctele pot fi rezolvate independent, însă puteți refolosi fragmente din rezolvarea unui subpunct în rezolvarea altor subpuncte acolo unde considerați necesar.

1. XOR între două șiruri de octeți - 10p

Multe metode de codificare folosite în criptografie utilizează operația XOR datorită proprietăților matematice ale acesteia. Una dintre metodele cele mai simple folosite în criptografie constă în realizarea operației XOR între fiecare octet din mesaj cu octetul corespondent din cadrul cheii. În mod uzual, pentru această metodă, cheia are aceiași lungime cu mesajul și este folosită în criptarea unui singur mesaj. Această tehnică poartă denumirea de one time pad.

Pentru acest subpunct, este necesară implementarea unei funcții care primește mesajul criptat și cheia folosită la criptare, ambele în reprezentare binară, și decodează mesajul in-place (mesajul decriptat va suprascrie mesajul criptat).

Pentru acest task va trebui sa completati sectiunile marcate cu TODO TASK 1 pentru a implementa si apela functia xor_strings ce are urmatoarea definitie:

void xor_strings(char *encoded_string, char *key);

Hint: (x ⊕ k) ⊕ k = x

2. Rolling XOR - 10p

O altă tehnică folosită în criptografie presupune folosirea rezultatului criptării unui bloc de date în criptarea următorului bloc. Mai exact, se efectuează întâi operația XOR între rezultatul respectiv și blocul ce urmează a fi criptat, după care are loc criptarea propriu-zisă folosind o cheie de criptare. Această tehnică se numește cipher block chaining.

Pentru simplitate, în cadrul acestui subpunct, un bloc de date va fi format dintr-un singur octet, iar pasul de criptare va fi omis. Astfel, algorimtul de criptare poate fi sumarizat după cum urmează:

  • c1 = m1
  • c2 = m2 ⊕ c1 ( = m2 ⊕ m1)
  • c3 = m3 ⊕ c2 ( = m3 ⊕ m2 ⊕ m1)
  • ș.a.m.d.

Unde cn reprezintă octetul de pe poziția n din rezultatul operației de criptare, iar mn reprezintă octetul de pe poziția n din mesajul inițial.

Pentru acest subpunct, se cere implementarea functiei rolling_xor care primește un mesaj criptat prin algoritmul descris mai sus și face decodarea in-place (mesajul decriptat va suprascrie mesajul criptat) a acestuia.

Functia rolling_xor trebuie sa aiba urmatorul prototip:

void rolling_xor(char *encoded_string);

3. XOR între două șiruri reprezentate prin caractere hexazecimale - 10p

Acest subpunct presupune realizarea unei operații similare subpunctului 1. Diferența constă în modul de reprezentare a datelor. Atât mesajul criptat cât și cheia care a fost folosită la criptare vor fi reprezentate prin caractere hexazecimale, fiind necesară conversia datelor în formă binară.

Spre exemplu, șirul “deadbeef” va fi convertit în șirul format din octeții 0xde, 0xad, 0xbe, 0xef.

Si pentru acest task va trebui sa completati sectiunile marcate cu TODO TASK 3 pentru a implementa si apela functia xor_hex_strings ce are urmatoarea definitie:

void xor_hex_strings(char *encoded_string, char *key);

4. Decodificarea unui șir în reprezentare base32 - 20p

base32, la fel ca mai cunoscutul base64, este o metodă de codificare de tip binary to text, însemnând că transformă un sir de date binare într-unul care conține doar caractere tipăribile. Utilitatea acestei codificări nu este neapărat legată de domeniul criptografiei, ci de o gamă mai largă de domenii în care reprezentarea sub formă de caractere ASCII a datelor binare este necesară.

Codificarea base32 funcționează în baza următorului algoritm: pentru fiecare 5 octeți, se vor genera 8 valori cuprinse între 0 și 31 (inclusiv), conform schemei de mai jos. Valorile generate vor fi folosite ca indecși în alfabetul base32 pentru a determina cele 8 caractere care vor fi folosite pentru codificarea datelor.

                    1        2        3      3
  0        8        6        4        2      9
 +--------+--------+--------+--------+--------+
 |< 1 >< 2| >< 3 ><|.4 >< 5.|>< 6 ><.|7 >< 8 >|
 +--------+--------+--------+--------+--------+
             1    1     2     2    3     3   3
  0    5     0    5     0     5    0     5   9

Caracterul ‘|’ delimitează octeții din datele de intrare, iar parantezele '< >' delimitează cele 8 valori rezultate: prima de la bitul 0 la 4 inclusiv, a doua de la bitul 5 la 9 inclusiv, ș.a.m.d până la ultima valoare, formată din biții 35 până la 39 inclusiv.

   Value Encoding  Value Encoding  Value Encoding  Value Encoding
       0 A             9 J            18 S            27 3
       1 B            10 K            19 T            28 4
       2 C            11 L            20 U            29 5
       3 D            12 M            21 V            30 6
       4 E            13 N            22 W            31 7
       5 F            14 O            23 X
       6 G            15 P            24 Y
       7 H            16 Q            25 Z
       8 I            17 R            26 2

În cazul în care dimensiunea datelor de intrare nu este multiplu de 5, se va realiza padding cu caractere ‘=’ după o regulă prestabilită (a se vedea https://tools.ietf.org/html/rfc3548#page-7).

Pentru acest subpunct, se cere implementarea funcției base32decode care realizează decodificarea unui șir codificat base32. Prototipul acestei functii trebuie sa fie urmatorul:

void base32decode(char *encoded_string);

5. Bruteforce pe XOR cu cheie de un octet - 10p

În mod uzual în criptografie, dimensiunea cheii de criptare va fi mai mică decât a datelor de intrare. Există mai multe mecanisme care permit folosirea unei chei mai scurte decât mesajul pentru a realiza criptarea. Cel mai simplu dintre acestea reprezintă construirea unei noi chei prin repetarea cheii actuale până se ajunge la dimensiunea necesară. Vulnerabilitatea acestei abordări constă în faptul că este suficientă pentru un potențial atacator obținerea unui substring (din mesajul decriptat) de lungime mai mare sau egală decât cheia intială pentru a putea determina cheia prin brute force.

Pentru a exemplifica, vom folosi o cheie de un octet din care vom obține prin repetare o cheie de dimensiunea mesajului. Criptarea se va face apoi prin XOR între mesaj și cheia rezultată.

Pentru acest subpunct, funcția bruteforce_singlebyte_xor care trebuie implementată va primi un mesajul criptat și trebuie să returneze cheia folosită în criptarea mesajului, precum și mesajul decriptat in-place. Prototipul acesteia este urmatorul:

int bruteforce_singlebyte_xor(char *encode_string);

Hint: mesajul decriptat este în limba engleză și conține ”force”.

6. Vigenere Cipher - 20p

In laboratorul 8 ati avut ocazia sa implementati rot13, o metoda de criptare ce inlocuieste fiecare litera intalnita cu litera ce se afla cu 13 pozitii dupa ea in alfabet. Caesar shift este forma generalizata a rot13, in care se poate ajusta numarul de pozitii cu care se executa rotatia.

Urmatorul algoritm pe scara complexitatii este Vigenere Cipher, ce pe langa sirul de codificat va primi ca si input o cheie ce va fi folosita, byte cu byte, ca si valoare numerica a shiftarii. Luam exemplul urmator:

 plaintext: "vine iarna"
 cheie:     "boo"

Fiecare caracter din cheie poate fi vazut ca si offset-ul literei respective fata de litera 'a'. Astfel, cheia de mai sus se poate transforma in: 1,14,14 ('b' este la offset 1 fata de 'a', 'o' este la offset 14 fata de 'a').

Orice caracter non-alfabetic din stringul de intrare nu sufera transformari de rotatie si nu se contorizeaza la incrementarea indicelui din cheie insa se va transpune nemodificat in stringul de iesire.

Repetand cheia primita ca si input pana cand aceasta devine de aceeasi lungime cu sirul de criptat, putem cripta textul primit ca si input astfel:

plaintext:   "vine iarna"
string key:  "boob ooboo"
offset key:   1,14,14,1,0,14,14,1,14,14
encoded:     "wwbf wosbo"

Mai exact, se va shifta litera 'v' cu o pozitie (1) si astfel va deveni 'w' in sirul criptat. Litera 'i' se va shifta cu 14 pozitii si va deveni litera 'w' in output.

Puteti gasi aici o resursa online pentru a va testa intelegerea algoritmului.

Puteți să presupuneți că alfabetul pentru acest task este format doar din litere mici.

Pentru acest subpunct, se cere implementarea funcției decode_vigenere care realizează decodificarea unui șir construit prin algoritmul descris mai sus. Prototipul acestei functii trebuie sa fie urmatorul:

void decode_vigenere(char *encoded_string, char *key);

Precizări suplimentare

Toate variabilele, datele, rezultatele parțiale, în afară de cele deja declarate, trebuie stocate pe stivă, nu în secțiunea de date.

Aveți voie (și se recomandă) să împlementați oricâte funcții adiționale care să vă ajute în rezolvarea mai multor task-uri, însă structura din main (în sensul de apeluri de funcții) trebuie să rămână neschimbată (excepție făcând rezervarea de spațiu pe stivă pentru variabile auxiliare, și apeluri de funcții auxiliare care să separe sau să determine lungimile șirurilor de intrare).

Scheletul de cod deschide fișierul ”inputX.dat”, unde X este un parametru de intrare primit de catre program ce determina task-ul testat. Fisierul inputX.dat conține string-urile necesare task-ului respectiv , atat sirurile codificate cat si cheia aferenta unde este cazul, separate prin '\0' (adică byte-ul cu valoare 0x00). Vă puteți folosi de această informație pentru a vă putea delimita șirurile/intrările.

Pentru claritate, structura fisierelor de input este urmatoarea:

  • input1.dat: encoded_string 0x00 key 0x00
  • input2.dat: encoded_string 0x00
  • input3.dat: encoded_string 0x00 key 0x00
  • input4.dat: encoded_string 0x00
  • input5.dat: encoded_string 0x00
  • input6.dat: encoded_string 0x00 key 0x00

Trimitere și notare

Temele vor trebui încărcate pe platforma vmchecker (în secțiunea IOCLA) și vor fi testate automat. Arhiva încărcată va fi o arhivă .zip care trebuie să conțină:

  • fișierul sursă ce conține implementarea temei: tema2.asm
  • Makefile
  • README ce conține descrierea implementării

Punctajul final acordat pe o temă este compus din:

  • punctajul obținut prin testarea automată de pe vmchecker - 80%
  • coding style - 10%.

Se va ține cont de:

  • claritatea codului
  • indentare coerentă
  • comentarii
  • nume sugestive pentru label-uri
  • fișier README - 10%

Temele care nu trec de procesul de asamblare (build) nu vor fi luate în considerare.

Mașina virtuală folosită pentru testarea temelor de casă pe vmchecker este descrisă în secțiunea Mașini virtuale din pagina de resurse.

Resurse

Data ultimei actualizări a checker-ului: 24.11.2018 17:15pm

Arhiva ce conține fișierele de la care puteți începe implementarea este aici.

iocla/teme/tema-2.txt · Last modified: 2018/12/06 18:50 by razvan.nitu1305
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