Příspěvek volně navazuje na předchozí díly útoků na hesla, často se totiž setkáme s obrazy hesel, které vznikly za pomocí hashovacích funkce nebo šifry. V tomto příspěvku se seznámíme s terminologií a hashovacími funkcemi MD5 a SHA-1.
Základní pojmy
Šifra
Šifra je kryptografický algoritmus, který vezme prostý text a převede jej na nečitelný šifrovaný text. Takový algoritmus ke svoji činnosti dále potřebuje klíč, který reprezentuje tajnou informaci, bez které není možné získat původní prostý text. Klíč je intergální součást šifrovacího algortimu a jeho hodnota ovlivňuje nastavení šifrovací a dešifrovací operace. Díky klíči nemusíme šifrovací algortimus tajit. Šifry dále rozlišujeme podle symetrie algoritmu a zda jsou blokové nebo proudové.
Symetrické šifry používají jeden klíč pro obě operace, tj. šifrujeme a dešifrujeme stejným klíčem. Příkladem symetrických šifer jsou algoritmy DES, 3DES (triple des) a AES.
Asymetrické šifry používají dva různé klíče veřejný a privátní, který nikdy nezveřejňujeme. Asymetrické šifrovací algoritmy jsou založeny na matematických modelech, které umožňují použítí odlišných klíčů (proměnných) pro různé operace. Nejznámnějším je šifra RSA využívající faktorizaci prvočísel.
Bloková šifra je taková, která „rozseká“ prostý text do menších bloků a provádí šifrovací nebo dešifrovací operaci na úrovni jednotlivých bloků. Zajímavé na blokových šifrách je, že mají více módů zapojení bloků.
Proudová šifra je taková, která provádí operaci šifrování nebo dešifrování na úrovni jednotlivých bitů prostého textu.
Hashovací funkce
Hashovací funkce je jednosměrná kryptografická funkce, která jako vstupní parametr přijímá zprávu a udělá z ní otisk do velmi malého prostoru, typicky 32 hexadecimálních znaků a více. Jednosměrná funkce znamená, že ji nelze reverzovat a získat zprávu na základě jejího otisku. Další vlastností hashovací funkce je její rozptyl do prostoru otisků. Pro dvě velmi podobné zprávy dostaneme úplně jiné otisky. Z podstaty menšího prostoru otisků, v porovnáním s prostorem zpráv, je jasné, že musí docházet ke kolizím, kdy dvě odlišné zprávy mohou mít společný otisk. Určitá míra kolize je akceptovatelná. Hashovací funkce používáme například ke kontrole intergity souborů nebo k podpisům zpráv. Příkladem hashovacích funkcí jsou funkce MD5 a SHA-1.
Kód
Kód vyjadřuje původní informaci jiným způsobem. Kódování je aplikace algoritmu, který mění podobu prostého textu na jeho zakódovanou podobu bez použití klíče. To znamená, že cílem kódování není informaci tajit. Kdokoliv identifikuje použitý algoritmus kódování, je schopen původní informaci přečíst. K čemu je tedy kódování dobré? Kódování informace se používá například k jejímu efektivnímu uložení nebo jde o ochranu ve smyslu lepší odolnosti před nežádoucími vlivy, které se vyskytují při transportu informace informačním kanálem. Kódování může k původní informaci přidat další údaje, které umožní detekovat chybu při přenosu nebo dokonce část poškozené informace opravit. Kódování potkáme nejčastěji v aplikačních protokolech, například URL kódování, BASE64, kódování znaků na HTML entity apod.
Intuitivně kódy vnímáme jako cokoliv, co není čitelné, protože nejsme schopni na první pohled rozlišit, zda se jedná o kódovaný nebo šifrovaný text. Kódem můžeme mít také na mysli „vstupní kód“, tj. tajnou informaci k povolení určité operace. Pokud si tyto souvislosti uvědomíme, neměly by nám kódy překážet v dalším porozumění.
Python – jazyk na pokusy
Na naše pokusy budeme potřebovat interpretovaný jazyk Python ve verzi 2.7. Uživatelé MS Windows si mohou stáhnout Python instalátor, který by měl obsahovat většinu potřebných knihoven.
Uživatelé OS Linux mají již Python předinstalovaný, pokud vám chybí knihovny, použijte PIP manažera. Následující příklad je pro linuxovou distribuci Ubuntu a „dotáhne“ do systému jazyk python, manažera balíčků pip a python knihovnu hashlib.
1 2 |
apt-get install python2.7 python-dev python-pip pip install hashlib |
Máme-li připravené prostředí python a knihovnu hashlib, můžeme se vrhnout na příklady.
Hashovací funkce MD5
Přepíšeme is následující program a jdeme testovat chování funkce MD5.
Skript md5.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#!/usr/bin/python # md5.py # @author - Petr Juhanak, https://blog.hackerlab.cz # @date 17.1.2016 import hashlib import sys import os.path def napoveda(chyba=""): print "" print "Syntaxe:",sys.argv[0],"zprava | -f soubor" if chyba != "": print "---" print "[!] Chyba -",chyba print "---" # zadal uzivatel nejaky vstup? if len(sys.argv) < 2: napoveda("Chybejici paramtry \"Zprava\" nebo -f soubor") sys.exit(1) else: if (sys.argv[1] == "-f" and len(sys.argv) >= 2): # -f soubor # zprava je ulozena v souboru soubor = sys.argv[2] if not os.path.isfile(soubor): napoveda("Nemohu precist soubor!") sys.exit(2) f = open(soubor,"r") zprava = f.read() f.close() else: # zprava je na prikazove radce zprava=sys.argv[1] # vypocet m=hashlib.md5() m.update(zprava) # tisk print "HASH MD5:", m.hexdigest() print "VELIKOST:", len(m.hexdigest()) |
Nejdříve vyzkoušíme otisk zprávy „koala“. Zprávu obalujeme pro jistotu do uvozovek, abychom donutili interpreter shellu předat celou zprávu jako jeden argument, jinak by náš program nemusel fungovat správně v případě, kdy by zpráva obsahovala více slov oddělených mezerou.
Příklad 1 – MD5 – Opakovaná volání
1 2 3 4 5 6 |
python md5.py "koala" HASH MD5: a564de63c2d0da68cf47586ee05984d7 VELIKOST: 32 python md5.py "koala" HASH MD5: a564de63c2d0da68cf47586ee05984d7 VELIKOST: 32 |
Z výpisu vidíme, že zpráva „koala“ vytvoří otisk o délce 32 znaků. Můžeme dále usoudit, že tato hashovací funkce v otiscích používá pouze hexadecimální znaky (vidíme číslice 0-9 a A-F). Opakujeme-li volání programu, otisk je stále stejný.
Příklad 2 – MD5 – Nepatrná změna zprávy
Nyní vyzkoušíme zprávu nepatrně změnit, abychom porovnali, jak se změní otisky. Použijeme zprávu „koala“ a „kaola“.
1 2 3 4 5 6 |
python md5.py "koala" HASH MD5: a564de63c2d0da68cf47586ee05984d7 VELIKOST: 32 python md5.py "kaola" HASH MD5: ffd11199b517ddffb8070f7f7c77ddc6 VELIKOST: 32 |
Z výpisu vidíme, že otisky obou zpráv jsou zcela odlišné.
Příklad 3 – MD5 – Kolize
Pro nalezení kolize budeme potřebovat delší vstupní text a pomůžeme si zdokumentovaným nálezem MD5 kolize Marca Stevense.
Nejprve stáhneme příklady obou zpráv message1.bin a message2.bin do pracovního adresáře s našim skriptem md5.py. Spočítáme jednotlivě MD5 otisky pro oba soubory.
1 2 3 4 5 6 7 8 9 10 |
python md5.py -f message1.bin HASH MD5: 008ee33a9d58b51cfeb425b0959121c9 VELIKOST: 32 python md5.py -f message2.bin HASH MD5: 008ee33a9d58b51cfeb425b0959121c9 VELIKOST: 32 diff message1.bin message2.bin Binární soubory message1.bin a message2.bin jsou rozdílné |
Z výpisu vidíme, že oba otisky jsou naprosto stejné! Příklazem diff jsme ověřili, že oba vstupní soubory jsou rozdílné.
Hashovací funkce SHA-1
Pro seznámení s hashovací funkcí SHA-1 mírně upravíme náš předchozí program v části výpočet a nazveme jej sha1.py.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#!/usr/bin/python # sha1.py # @author - Petr Juhanak, https://blog.hackerlab.cz # @date 17.1.2016 import hashlib import sys import os.path def napoveda(chyba=""): print "" print "Syntaxe:",sys.argv[0],"zprava | -f soubor" if chyba != "": print "---" print "[!] Chyba -",chyba print "---" # zadal uzivatel nejaky vstup? if len(sys.argv) < 2: napoveda("Chybejici paramtry \"Zprava\" nebo -f soubor") sys.exit(1) else: if (sys.argv[1] == "-f" and len(sys.argv) >= 2): # -f soubor # zprava je ulozena v souboru soubor = sys.argv[2] if not os.path.isfile(soubor): napoveda("Nemohu precist soubor!") sys.exit(2) f = open(soubor,"r") zprava = f.read() f.close() else: # zprava je na prikazove radce zprava=sys.argv[1] # vypocet m=hashlib.sha1() m.update(zprava) # tisk print "HASH SHA-1:", m.hexdigest() print " VELIKOST:", len(m.hexdigest()) |
Vyzkoušíme SHA-1 na zprávě „pejsek a kočička“.
1 2 3 |
python sha1.py "pejsek a kočička" HASH SHA-1: 0dcda975520516a92d48e6b7b93cc7f6d030c985 VELIKOST: 40 |
Vidíme, že otisk SHA-1 je opět v hexadecimálním tvaru, zabírá 40 hexadecimálních znaků na rozdíl od hashovací funkce MD5, která měla 32 hexadecimálních znaků. Další testy by byly obdobné jako u příkladů s hashovací funkcí MD5 a pro jejich jednoduchost je vypustíme.
Knihovna hashlib dokumentuje další kryptografické funkce a prozrazuje něco i o struktuře jejich algoritmů. Například velikost atribut block_size může napovědět, zda jde o kryptografický algoritmus využívající bloky.
Závěr
V tomto příspěvku jsme se stručně seznámili s rozdělením pojmů kód, šifra a hashovací funkce. Vyzkoušeli jsme si na příkladech použití hashovacích funkcí MD5 a SHA-1.
Pro úplnost musíme dodat, že použití hashovací funkcí MD5 a SHA-1 již není bezpečné, protože existuje alespoň teoretická možnost provedení útoku.
Pochybnost o bezpečnosti SHA-1 byla vyjádřena odborníky v roce 2005. Hashovací funkce MD5 ztratila kredit mnohem dříve a to v roce 1996. První praktický útok na funkci MD5 byl prokázán v roce 2005.