Patru pisici au invadat Facultatea de Automatică și Calculatoare. Țelul lor este să acapareze toate clădirile facultății fără a fi descoperite. Rolul vostru e de a le ajuta să se plimbe prin campus neobservate. Pentru a considera o clădire cucerită, trebuie să le ajutați să rezolve câte o problemă întrucât ele nu știu să scrie cod în limbaj de asamblare.
Tema este formată din 4 exerciții independente. Fiecare task constă în implementarea unei sau mai multor funcții în limbaj de asamblare. Implementarea se realizează în fișierele puse la dispoziție pentru fiecare exercițiu.
IOCLA RULZ!
Sursee dorește să ajungă pe catedra din PR001 așa că trebuie să trimită mesaje criptate studenților că să afle cine o poate ajuta. Ea vrea să folosească simple cipher pentru a transmite mesajele.
Acest algoritm de criptare presupune shiftarea la dreapta în cadrul alfabetului a fiecărui caracter de un anumit număr de ori. De exemplu, textul ANABANANA se transformă în BOBCBOBOB când pasul este 1. Astfel, o criptare cu pasul 26 nu modifică litera, întrucât alfabetul englez are 26 de caractere.
Pentru acest task va trebui să implementați în fișierul simple.asm funcția simple(), care criptează un string folosind metoda descrisă mai sus.
Antetul funcției este:
void simple(int n, char* plain, char* enc_string, int step)
Semnificația argumentelor este:
Diablo, mâncăciosul, vrea să ajungă la cantina din EC pentru a-și pune lăbuțele pe un meniu de mâncare proaspătă. Ajutați-l să găsească cel mai scurt drum de la intrarea în facultate până la cantină.
Prin intermediul acestui task se dorește aprofundarea lucrului cu structuri.
Se dă structura unui punct în coordonate carteziene:
struct point{ short x; short y; };
https://ocw.cs.pub.ro/courses/iocla/laboratoare/laborator-07
Pentru această parte a task-ului aveți de implementat funcția points_distance() din fișierul points-distance.asm, care va calcula distanța dintre două puncte aflate pe o dreapta paralelă cu axele OX sau OY.
Antetul funcției este:
void points_distance(struct point *p, int *rez);
Semnificația argumentelor este:
În continuarea exercițiului 1, acum trebuie să implementati funcția road() din fișierul road.asm, care va calcula distanța dintre punctele dintr-un vector. Astfel, pentru un vector de 4 puncte (A,B,C,D), se vor calcula 3 distanțe: *A-B* , *B-C*, *C-D*. Perechile de puncte se află pe drepte paralele cu axele.
Antetul funcției este:
void road(struct point* points, int len, int* distances);
Semnificația argumentelor este:
Ultima parte a task-ului presupune analizarea fiecărei distanțe calculate anterior pentru a determina dacă este pătrat perfect. Trebuie să implementati funcția is_square() din fișierul is_square.asm.
Antetul funcției este:
void is_square(int *dist, int n, int *rez);
Semnificația argumentelor este:
Swaro a aflat că cifrul folosit de Sursee a fost spart, așa că vă roagă să îi trimiteți mesaje cifrate folosind criptarea Beaufort, pentru a nu îi fi descoperit planul de a se infiltra în corpul ED.
Algoritmul de criptare Beaufort pleacă de la un string în clar (numit și plain text) și un string secundar (numit cheie) și obține un text criptat, de lungime identică cu string-ul în clar, prin înlocuirea caracter cu caracter a literelor din textul inițial.
De exemplu, să zicem că vrem să criptăm textul DEFENDTHEEASTWALLOFTHECASTLE, utilizând cheia FORTIFICATION.
Regula după care se face înlocuirea folosește o matrice de caractere, numită tabula recta, în care fiecare linie și fiecare coloană au asociate câte o literă a alfabetului limbii engleze. Aceasta are formatul de mai jos:
Criptarea fiecărui caracter se realizează aplicând următorii pași:
DEFENDTHEEASTWALLOFTHECASTLE FORTIFICATIONFORTIFICATIONFO
Pentru caracterul D:
Criptând fiecare caracter folosind pașii de mai sus, obținem string-ul criptat. Pe exemplul nostru:
CKMPVCPVWPIWUJOGIUAPVWRIWUUK
Pentru acest task, va trebui să implementați în fișierul beaufort.asm funcția beaufort() care criptează un string în clar, folosind metoda descrisă mai sus.
Antetul funcției este:
void beaufort(int len_plain, char *plain, int len_key, char *key, char tabula_recta[26][26], char *enc)
Semnificația argumentelor este:
Îngeraș, care este capul răutăților, vrea să cucerească toate laboratoarele din EG. Știe că are nevoie de o modalitate sigură de a transmite mesaje celorlalte pisici. Ajutați-o să trimită mesaje folosind spiral encryption.
O criptare prin substituție (în care înlocuim caracter cu caracter literele din textul în clar) e cu atât mai eficientă cu cât unui atacator îi e mai greu să decodifice mesajul inițial, chiar dacă are acces la cheie și la mesajul criptat. Pentru asta, putem alege moduri cât mai “ezoterice” de utilizare a cheii, iar spiral encryption e un algoritm care face tocmai acest lucru.
Vom pleca de la un text în clar de dimensiune N ^ 2. Cheia în acest caz va fi o matrice de întregi de dimensiune N * N. Un caracter din textul în clar va fi criptat adunând la codul său ASCII valoarea întreagă din cheie care îi corespunde. Spre exemplu, dacă pentru caracterul `A` avem asociată în cheie valoarea 2, caracterul criptat va fi `C`. De asemenea, dacă avem caracterul `Z` cu cheia asociată 1, caracterul criptat va fi `[`.
Partea specială la acest algoritm este modul în care asociem caracterelor din textul plain valori din cheie. Pentru asta, vom parcurge textul în clar secvențial (de la primul la ultimul caracter), iar în același timp vom parcurge cheia în spirală, similar cu figura de mai jos:
Astfel, ținând cont de dimensiunea matricii care reprezintă cheia și de dimensiunea textului (mereu vor fi corelate astfel încât numărul de elemente din matrice să fie egal cu numărul de litere din text) obținem întregul text criptat.
Pe exemplul de mai sus, rezultatul va fi:
MUeVSVWb\i^KU^DYbbLYXRH_D
Sarcina voastră este să completați funcția spiral() din fișierul spiral.asm, astfel încât aceasta să cripteze un text în clar cu ajutorul unei chei date, folosind algoritmul prezentat mai sus. Antetul funcției este:
void spiral(int N, char *plain, int key[N][N], char *enc_string)
Semnificația argumentelor este:
În schelet este inclus şi checker-ul, împreună cu testele folosite de acesta. Pentru a executa toate testele, se poate executa direct scriptul `checker.sh` din rădăcina temei:
./checker.sh
Pentru a testa task-uri individual, folosiți:
./checker.sh <număr_task>
Pentru a scrie rezolvarea unui task, intrați în directorul asociat task-ului respectiv și scrieți cod în fișierele în limbaj de asamblare indicate în enunț. NU modificați alte fișiere C, script-uri etc!
Formatul fişierelor de intrare pentru Simple Cipher este:
len_plaintext step plaintext
Formatul fişierelor de intrare pentru Points este:
nr_points points
Formatul fişierelor de intrare pentru Beaufort Encryption este:
len_plaintext len_key plaintext key
Formatul fişierelor de intrare pentru Spiral Encryption este:
N plain key
Pentru matricea alocată static: 1 2 3 4 5 6 7 8 9 Avem de fapt în memorie un șir continuu de forma: 1 2 3 4 5 6 7 8 9
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ă:
simple.asm points-distance.asm road.asm is_square.asm beaufort.asm spiral.asm
README
ce conține descrierea implementăriiPunctajul final acordat pe o temă este compus din:
Scheletul şi checker-ul sunt disponibile pe repository-ul de IOCLA.