User Tools

Site Tools


aes

This is an old revision of the document!


AES

AES (Advanced Encryption Standard), poznat i pod svojim originalnim nazivom Rijndael, sustav je simetrične kriptografije temeljen na supstitucijsko-permutacijskim poljima.
 Shema supstitucijsko-permutacijskog polja AES koristi fiksnu veličinu bloka od 128 bitova te veličinu ključa od 128, 192 ili 256 bitova. Provodi se nad matricom 4×4, odnosno nad pravokutnim nizom bajtova u 4 retka i 4 stupca. Na sličan način tretira se i ključ koji je pohranjen u 4 retka i N stupaca, gdje je N ovisan o veličini ključa i može biti 4,6 ili 8. AES se pri enkripciji koristi operacijama zamjene znakova, posmicanja redova, miješanja stupaca te dodavanja potključa.
 AES enkripcijski postupak

Funkcije koje AES koristi matematički su opisane u nastavku:
1) Zamjena znakova

znak = Sbox[znak] 

2) Dodaj potključ

blok = blok ⊕ potključ[i]

3) Posmakni redove
Rotira (kružno posmiče) znakove ulijevo u svim retcima osim prvog za unaprijed poznati broj mjesta koji je ovisan o N.

4) Pomiješaj stupac bloka
Množi se stupac po stupac bloka s fiksnim polinomom:

a(x) = 03Hx3 + 01Hx2 + 01Hx + 02H mod x4+1 

Odnosno, za svaki stupac bloka računa se stupac novog stanja:

Postoje razni načini AES kriptiranja koji određuju kako se ulazni podatci dijele u blokove, kako se blokovi kriptiraju i kombiniraju, kako enkripcija upravlja problemima kao što su integritet podataka ili inicijalizacijski vektori (IV) i slično.

Često korišteni AES načini kriptiranja su:
1) ECB (Electronic Codebook)

  • Svaki blok teksta kriptira se odvojeno s istim ključem
  • Identični blokovi jasnog teksta rezultiraju identičnim blokovima skrivenog teksta
  • Nije siguran za enkripciju većih količina ulaznih podataka zbog mogućnosti ponavljanja uzoraka
  • Korištenje ovog načina kriptiranja se ne preporučuje

 ECB shema

2) CBC (Cipher Block Chaining)

  • Svaki blok jasnog teksta se XOR-a sa skrivenim tekstom prošlo kruga enkripcije
  • Potreban je inicijalizacijski vektor IV koji se mora izabrati nasumično
  • IV se šalje zajedno sa skrivenim tekstom
  • Potrebno nadopuniti poruku tako da je duljina višekratnik veličine bloka
  • Sigurna enkripcija pod razumnim pretpostavkama

 CBC shema

3) CFB (Cipher Feedback) i OFB (Output Feedback)

  • Slični protočnoj enkripciji, tj. jednokratnoj bilježnici
  • Dekripcija jednaka enkripciji
  • Trebalo bi svaki put koristiti različit inicijalizacijski vektor

 CFB/OFB shema

4) CTR (Counter Mode)

  • sličan protočnoj enkripciji, tj. jednokratnoj bilježnici
  • na temelju ključa i IV izračuna se niz bitova koji se XOR-a s jasnim tekstom
  • može se paralelizirati
  • ne zahtijeva nadopunjavanje poruke (eng. padding)

 CTR shema

5) GCM (Galois/Counter Mode)

  • način autentifikacijskog kriptiranja koji je primjenjiv samo za simetrične blok algoritme s veličinom bloka od 128 bitova
  • samo za autentifikaciju – koristi MAC
  • ulaz: jasni tekst, IV, povezani autentifikacijski podaci (Associated Data, AD), duljina povezanih podataka i duljina kriptiranog teksta
  • izlaz: autentifikacijska značka (Auth Tag)

 GCM shema

Generalno se ne preporučuje koristiti način kriptiranja ECB. Inicijalizacijski se vektor ne smije ponavljati i mora biti generiran slučajno, a ne smije se ponavljati ni simetrični ključ.

PRIMJER -Zadatak s Hacknite platforme - AES kriptirana poruka

Ivan je na faksu učio o modernim kriptografskim algoritmima. Toliko je očaran AES algoritmom da je odlučio
samostalno napraviti program za šifriranje svojih najtajnijih informacija. Pokušaj dešifrirati ciphertext
kako bi provjerio je li Ivanov program zaista siguran.

ciphertext (u zasebnoj datoteci):
991262a3123d702aaa296e36e4054dcb0031479d8affcae34dd12757b19868eee63f79e83e9687e10fc74dbd3c1a61bfdb4ec98a75
38f2c75eed1402d3edfd8dc28531c6d75a3786750afa0f48524d9adb4ec98a7538f2c75eed1402d3edfd8ddb4ec98a7538f2c75eed
1402d3edfd8d64019b35eac50ab04f0239080a879f000b42253688df27967c492e721c9e91407edcf9ebd01fd7a17bc0219784322b
5f0b42253688df27967c492e721c9e91402b5bebae08f2851e97e139390d4d6245925a96bbca45277ebecfd06fa54b510edb4ec98a
7538f2c75eed1402d3edfd8d7edcf9ebd01fd7a17bc0219784322b5f3454fe7467cd0e2b6036f48a3c2246930b42253688df27967c
492e721c9e91403856820345c0e11691b05d22b6005906668020a4b98905a562e051955ea720177edcf9ebd01fd7a17bc021978432
2b5fec0e366b9ea7d725dc81fdec29b57bb3

Napomena: u ciphertextu nema znakova novog reda, ali su ovdje dodani radi lakše čitljivosti.

telnet chal.platforma.hacknite.hr 8083
netcat chal.platforma.hacknite.hr 8083

Flag je u formatu CTF2022[brojevi]

U prilogu se nalazi i datoteka encrypt.py.

Pokušajmo se spojiti na chal.platforma.hacknite.hr i port 8083. Imamo mogućnost pisanja, a kao rezultat dobijemo ispis kodiranog teksta koji smo unijeli. U encrypt.py datoteci. vidimo da se koristi AES ECB mod (linija 19: cipher = AES.new(key, AES.MODE_ECB)) te da se svaki znak jasnog teksta tretira kao zasebni blok. U ECB načinu rada se svaki isti blok jasnog teksta uvijek šifrira u isti ciphertext. Uvjerimo se da je zaista tako. Upišimo jedno slovo, a zatim ponovimo to isto slovo tri puta:

Vidimo da se svaka pojava istog znaka šifrira jednako, što i odgovara AES ECB modu. Sad upišimo dio flaga koji znamo, a zatim i cijeli ciphertext da vidimo gdje u njemu počinje flag:

Vidimo da počne odmah na početku. Sad nam preostaje dešifrirati ostatak teksta da bismo dobili flag. Napišimo jednostavnu Python skriptu za to:

data = "CTF2022["
import subprocess
def get_enc(i):
    return str(subprocess.check_output(f"echo \"{i}\" | nc chal.platforma.hacknite.hr 8083",
     shell=True))[2:-3]
 
cipher = open("ciphertext", "r").read()
 
while data[-1] != "]":
    #print(data)
    for x in "123456789[]":
        #print(data + x)
        r = get_enc(data + x)
        if cipher.startswith(r):
            data += x
            break
print(data)

Objasnimo što skripta radi. Kao podatak (data) uzeli smo dio zastavice koji nam je poznat. Nakon toga, dok ne dođemo do kraja flaga (znak “]”), uključujući i njega, brute force pogađamo koji je idući znak u skupu svih mogućih znakova koji se mogu pojaviti u flagu (brojevi i uglate zagrade). Svaki taj mogući znak kodiramo (funkcija get_enc) i, ako se kod poklapa s onime što slijedi u tekstu, znači da je taj znak idući i dodajemo ga na konačni flag. Funkcija get_enc jednostavno se spaja netcatom na stranicu zadanu u zadatku i ispisuje rezultat koji se dobije kodiranjem trenutnog znaka. Važno je napomenuti da uzima samo od indeksa 2 s početka do trećeg znaka od kraja jer python dodaje stringovima b' na početak stringa i '\n na kraj pa da se i ti znakovi ne kodiraju.
Zakomentirani printovi služe za bolje razumijevanje skripte. Poželjno je dodati sleep() između svake iteracije petlje kako se poslužitelj ne bi preopteretio prevelikim brojem zahtjeva.

PRIMJER -Zadatak s Hacknite platforme - Brojač

Mnogi od vas već znaju AES ECB način rada nesiguran. 
Zato smo odlučili šifrirati tajnu poruku koristeći AES CTR načina rada. 
Dostupan ti je ciphertext, djelomični plaintext te program koji se koristio za šifriranje poruke, 
ali ne i tajni AES ključ.

Možeš li dešifrirati poruku?

Ideja zadatka jest pronaći ranjivost u AES implementaciji s CTR načinom rada. CTR način rada jest definiran sljedećom formulom za enkripciju:

C = P ^ AES(key,CTR)

gdje je C ciphertext, P plaintext, a CTR kombinacija noncea i countera (u implementaciji nonce[i]^counter). AES funkcija vraća keystream (tj. ključ za tu specifičnu iteraciju). AES ne procesuira cijeli plaintext odjednom već radi u blokovima od 16 bajtova. Prvi ciphertext blok jest veličine 16 te je nastao xoranjem keystreama (za prvu iteraciju) s prvim blokom (također 16 bajtova) plaintexta, drugi ciphertext xoranjem keystreama (za drugu iteraciju) s drugim blokom plaintexta itd… U odnosu na CBC način rada, gdje se svaki novi blok xora s prijašnjim, CTR-om nastali blokovi nisu međusobno ovisni.

AES je funkcija koja prima dva parametra, key i CTR. CTR jest kombinacija noncea i countera. Nonce jest fiksna vrijednost koja se nikada ne mijenja tijekom enkripcije i dekripcije svih blokova, a counter jest vrijednost koja se inkrementira sa svakom novom iteracijom (krećući od 0 u implementaciji). Key jest tajna koja se koristi za enkripciju i dekripciju te se također nikada ne mijenja. AES je funkcija koja interno ne koristi randomizirane vrijednost jer dekripcija ne bi bila moguća. Proces dekripcije je opisan sljedećom formulom (suprotan proces od enkripcije):

P = C ^ AES(key,CTR)

Dakle, kako bi dekripcija bila moguća, za isti broj iteracije enkripcije i dekripcije koristi se isti keystream.

Unutar zipa dan je algoritam za enkripciju, cijeli ciphertext te parcijalni plaintext. Unutar plaintexta ispisan je Lorem ipsum te se na kraju nalazi tekst “Zastavica je”. Kako bi se pronašao flag potrebno je dekriptirati blok iz ciphertexta u kojem je nalazio u cjelovitom plaintextu. Ispis “stat partial_plaintext.txt” vraća da je veličina datoteke 4138 bajtova, što je 16*258.625, odnosno 259 AES blokova (gdje je zadnji parcijalan). Ispis naredbe “grep -bo -f partial_plaintext.txt -e 'Zastavica je'” vraća “4124:Zastavica je”. Duljina “Zastavica je ” jest 13, stoga zaključujemo da zastavica započinje na indexu 4137 što je unutar 259. bloka. Jer je sveukupna veličina datoteke 4138, a zastavica nije duljine 2 bajta, unutar parcijalne datoteke nedostaje 260. blok.

Do rješenja se dolazi tako da se dekriptira 259. i 260. blok ciphertexta. Jedini način na koji se ti blokovi mogu dekriptirati jest ako se pronađe keystream za njihove iteracije. Jer counter počinje od 0, to će onda biti iteracije s counterom 258 i 259.

Kod za enkripciju unutar encrypt.c jest sljedeći:

AES_EncryptInit(&ctx, key); 
    
    
    unsigned char counter = 0;
    for (unsigned int offset = 0; offset < (4160); offset += AES_BLOCK_SIZE) { //CTR mode
	unsigned char nonce_xor_counter[AES_BLOCK_SIZE];
	unsigned char enc_output[AES_BLOCK_SIZE];
	for(int i=0;i<16;i++){
	    nonce_xor_counter[i] = nonce[i] ^ counter;
	}
	counter +=1;
	AES_Encrypt(&ctx, nonce_xor_counter, enc_output);
	for(int i=offset;i<(offset+AES_BLOCK_SIZE);i++){ 
	    ciphertext[i] = enc_output[i%16]^plaintext[i];
	}
    }
    output("\nEncrypted: 0x", ciphertext, (4160));

Ranjivost implementacije zamaskirana je u primitivnom tipu countera. Char jest veličine bajt, odnosno prima vrijednosti 0-255. Zbog toga, nakon vrijednosti 255 inkrementiranjem nastaje integer overflow te se vrijednost resetira na 0. To znači da je counter za iteraciju 258/259 zapravo 2/3 što onda znači da je keystream za navedene parove iteracija isti. Jer nam je dan rezultat ciphertexta te imamo parcijalni plain text, moguće je doći do keystreama:

C ^ P = AES(key,CTR)

Za iteraciju 2/258 xoraju se 3. blokovi ciphertexta i plaintexta. Za iteraciju 3/259 4. blokovi. Jednom kada se keystream dobije, sve što je preostalo jest xorati ciphertext 259 i 240. bloka s odgovarajućim keystreamovima kako bi se dobili njihovi plaintextovi.

TODO: OVO TREBA PRIKAZATI BOLJE

Izvori

[1] Christof Paar, Jan Pelzl, Understanding Cryptography, Springer-Verlag Berlin Heidelberg, 2009.
[2] https://platforma.hacknite.hr/challenges
[3] Kriptografija i kriptoanaliza, predavanja, FER
[4] Budin, L.; Golub, M; Jakobović, D., Jelenković, L (2010.) (2013.), Operacijski sustavi, Element, Zagreb
[5] https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf

aes.1737475410.txt.gz · Last modified: 2025/12/01 11:40 (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki