Pozor, v Gitu je víc operací, které lze nazvat podpisem.
Jednak lze ke zprávě commitu přidat řádek "Signed-off-by: jméno email". To není nijak kryptograficky silné, můžu klidně předstírat že jsem Linus a poslat své commity do světa.
Pak je možné podepsat commity pomocí GPG a tam je to na GPG co vloží do zprávy a bude to tak silné jak silné je GPG. Potíž je v tom, že autor v tu chvíli podepisuje SHA1 hash, který je sám o sobě prolomen, takže vlastně neví co podepisuje. Jinými slovy - když Alice podepíše pomocí GPG nějaký commit, Bob může vytvořit úplně jiný commit v jiné repo a předstírat, že mu to Alice podepsala.
Ohledně užití SHA1 v Gitu Linus prohlašuje, že tam prolomení nevadí, protože lze těžko provést útok, kterým by se podvržená data zpropagovala do repozitářů. Když už někdo má v repo commit s daným SHA1, při případném stahování z napadené repo se podvržený commit s podvrženými daty nestáhne, protože to Git vyhodnotí jako že už to má. Je na každém posoudit jak moc věří této obhajobě a svým remote repozitářům.
také chce vzít na vědomí, že k fungování tohoto útoku je potřeba mít binární data na vhodném místě, které je možné modifikovat. V případě gitu to ale má jiný rozměr, tam se hashuje nějaká předem daná textová struktura (hlavička, velikost, jméno souboru atd.). Linux na první zranitelnost před pár lety odpovídal takhle:
https://marc.info/?l=git&m=148787047422954
On je dobrý důvod, aby ve zdrojových kódech nebyly binární data, bez nich je útok o mnoho obtížnější a ještě se taková věc neobjevila. Při přinulém problém s sha1 se na tohle v gitu objevila funkce v git fsck, která dělá částečnou kontrolu.
V jednom z případů autoři využili obrázku JPG (respektive prostor za koncem obrázku). Pokud je hash tvořen pouze z viditelných hodnot, tak by neměl být problém. Ale když už jde prakticky generovat výsledky otisku na požádání, je na čase přejít na nový algoritmus. Vlastně už jen to, že lze předvídat změnu otisku při konkrétní změně vstupu, je selhání algoritmu.
> Pokud je hash tvořen pouze z viditelných hodnot, tak by neměl být problém.
To by vyžadovalo mít parser na všechny možné typy dokumentů, který řekne, co je a co není viditelné. A někdy to ani nemusí jít snadno určit -- třeba tam mohou být nějaké komentáře, které skoro nikdo nečte. A někdy tam mohou být naprosto oprávněně pseudonáhodná data, třeba kryptografické klíče.
> Ale když už jde prakticky generovat výsledky otisku na požádání
Nejde, a to ani u slabší a déle zlomené MD5. Jde udělat, aby dva výpočty zkonvergovaly do stejného otisku, ale nemůžeš si vybrat, jaký ten otisk bude. Takže si třeba nemůžeš najít Linusův podpis otisku ABCD123 a vygenerovat jiný dokument s tímto otiskem. Ale i tak se s tím už dají dělat některé útoky - viz červ Flame, kde generovali kolizní (MD5) certifikáty.
> Vlastně už jen to, že lze předvídat změnu otisku při konkrétní změně vstupu, je selhání algoritmu.
Co tím myslíš? To, jak se změní otisk při změně vstupu, zjistím vždycky prostě tím, že ten hash znova spočítám.
Textová data jsou jen speciálním případem binárních dat
Ano, může tu být praktická komplikace, že textová data s potřebnými vlastnostmi je těžší vygenerovat než obecná binární data. Záleží i na kódování. Jiná omezení klade UTF-8 a jiná klade pouhý zákaz 0x00.
Použití textových dat tak sice může být určitým faktorem, který ztěžuje útok, ale rozhodně si nemyslím, že by to měl být důvod pro použití textových dat. Ono podobně je v principu možné hashovaná data před hashováním třeba proložit nějakými specifickými byty (třeba každý druhý bude 0x06) nebo převést do base64. Toto je zjevnější vlastnost návrhu, lze tomu lépe nastavit požadované parametry a nerozsype se to při změně kódování. I to bych ale bral spíše jako nouzovku, kterou si člověk kupuje čas. Co víme o těchto útocích? Jsme si jisti, že nepůjde rozumně cílit nějaký specifický druh dat bez přílišného nárůstu výpočetní a finanční náročnosti? Možná. Tedy nevíme.
Navíc takovéto opatření předem předpokládá, že se hashovací funkce neplní svůj účel správně. Může to znít jako další (vedlejší) úroveň obrany, ale:
1. Když už, takovéto věci mají řešit kryptologové, kteří navrhují hashovací funkce. Ne každý po svém s různými chybami. Rozhodně to nemá ovlivňovat návrh přes X dalších vrstev.
2. Lze to řešit i lépe, třeba použitím několika různých hashovacích funkcí. Pokud jsou na sobě nezávislé, je možné je i vzájemně xorovat.
3. Mám tušení, že něco jako (2) už používá třeba SHA-3.
jinak u gitu právě použití více nezávislých hashovacích funkcí a vzití 160b z výsledku právě v dané konverzaci navrhoval kdysi sám Linus.
Je samozřejmě pravda, že ochcávka s textovými daty kulhá na obě nohy, avšak u gitu zatím reálně funguje, podle všeho.
Sha-1 je již řadu let nedoporučované, podobné útoky se nejspíš budou i nadále objevovat a už se dávno mělo přejít. Kombinace více hashovacích funkcí opět posouvá náročnost, stejně tak ale posouvá schopnost vůbec říct o kolik a jestli to nemá přesně opačný efekt.
> jestli to nemá přesně opačný efekt.
Jediný problém by mohl být, kdyby ty hashovací funkce měly podobnou konstrukci. Pak by jednotlivé bity mohly být korelované a vzájemně se vyrušit (1^1 = 0^0 = 0). Myslím si ale, že něco takového udělat by muselo být celkem nápadné každému, kdo vidí více do hloubky jednotlivých hashovacích funkcí. Pro opatrnost bych tedy nevolil kombinace jako SHA-256 a SHA-512 (obojí patří do SHA2), ale třeba SHA2 s SHA3 by mělo být OK.
Jinak v tom problém nevidím. Budou-li funkce produkovat nekorelovaný výstup, pak snad jakékoliv selhání kterékoliv funkce zachrání přítomnost alespoň jedné dobré funkce.
V případě sřetězení místo xoru dokonce ani nevadí korelovaný výstup, akorát dostaneme delší hash.
Nelze ovšem moc spoléhat, že takto ze dvou nebezpečných hashovacích funkcí (např. MD5 a SHA1) vznikne jedna bezpečná. Útok to může ztížit, ale zrovna u MD5 a SHA1 jsem po zceřejnění Shattered popisoval, že najít současnou kolizi MD5 s SHA1 je zřejmě realizovatelné s dostatečným (byť ne malým) rozpočtem. Stručně, je potřeba najít několik (na sobě závislých) kolizí SHA1, z toho spočítat multikolize (počet kolizních párů nám naroste exponenciálně) a následně mezi nimi dělat kolize MD5 hrubou silou. Kolize MD5 hrubou silou sice může znít jako špatný vtip, ale je to díky narozeninovému paradoxu zvládnutelné a lépe to neumím, pokud chci vybírat z kolizních párů pro SHA1.
Sřetězením jsem myslel concat. Když najdete kolizi (jakéhokoliv druhu), znamená to, že máte kolizi toho druhu pro oba algoritmy, navíc současně (jedna kolize použitelná samostatně u obou základních algoritmů). Obdobně i u preimage, pokud původní vstup nelze uhodnout.
Komplikovanější to může být u odolnosti vůči length extension attack (tam podobná úvaha neplatí, byť protipříklady budou asi spíše teoretického rázu, jako že vezmeme zleva ořezanou sha-512 na 256b a zprava ořezanou sha-512 na 256b).
Bude to komplikovanější i pro hledání preimage z malé množiny, jako se dělá u lámání hesel – tam nalezení preimage nejspíš znamená nalezení původního vstupu a stačí nám to najít pro jednu z těch funkcí a pro druhou to bude automaticky sedět. Ale pro tyto účely jsou již nějakou dobu klasické hashovací funkce považovány za nevhodné, protože z hlediska rychlosti sledují opačný cíl – být co nejrychlejší.
Uznávám, že u xoru to může být komplikovanější, jak jsem sám zmiňoval.
Z článku bych nepochopil pokrok oproti SHAttered, který chápu takto:
SHAttered bylo:
SHA1(vybraná_zpráva_1 || pseudonáhodná_data_1 || vybraná_zpráva_2) == SHA1(vybraná_zpráva_1 || pseudonáhodná_data_2 || vybraná_zpráva_2)
Tohle je:
SHA1(vybraná_zpráva_1 || pseudonáhodná_data_1 || vybraná_zpráva_2) == SHA1(vybraná_zpráva_3 || pseudonáhodná_data_2 || vybraná_zpráva_2)
(pozn. to že můžete appendovat cokoli (stejného) a rovnost hashů se nezmění je normální očekávaná vlastnost této konstrukce (length extension), je to i v SHA-2 by design a opravuje to až SHA-3, příp. double-SHA2 používaná např. v Bitcoinu)
tj. můžu si vybrat dva libovolné začátky. Tím je to mnohem použitelnější na praktické útoky, protože SHAttered šlo použít jen na ty formáty dokumentů, kde po vygenerování hlavičky a následného pseudonáhodného balastu se můžu na tento balast odkazovat a podle něj rozhodovat.
Tohle ti nějak nesedí. SHAttered bylo podle mě takhle:
SHA1(kolizní_jádro_1 || zpráva) == SHA1(kolizní_jádro_2 || zpráva)
Jinak by nemohly fungovat ty webové generátory kolizních dokumentů, které vzaly jádra ze zveřejněného PoC a následně editovaly hodnotu zpráva
.
Shambles jsem pochopil takto:
SHA1(zpráva || kolizní_suffix_1) == SHA1(zpráva || kolizní_suffix_2)
U SHAttered je rozdíl mezi bajty 0xc0 a 0x130, zbytek souborů je totožný kolidovat bude bez ohledu na obsahu od bajtu 0x130 dále, pokud je v obou souborech shodný.
U Shambles přiznávám, že jsem to nezkoumal.
Snížení na úroveň MD5 – no, to mi přijde jako možná až moc zjednodušující. Věřím, že jsou situace, kdy útok na SHA1 bude out of budget, zatímco na MD5 to bude dosažitelné. Zvlášť pokud útočník těch kolizí potřebuje více.
Uznávám ale, že z pozice obránce by měl být typicky přístup k oběma funkcím stejný.