Een geschiedenis van hasj
Een generieke hash-functie is een speciaal type programmeerfunctie die wordt gebruikt om gegevens van willekeurige grootte toe te wijzen aan gegevens van een vaste maat. Hash-functies zijn ontstaan vanuit een behoefte aan samendrukken gegevens om de hoeveelheid geheugen te verminderen die nodig is om grote bestanden op te slaan. De meest populaire use-case voor een hash-functie is voor een andere specifieke gegevensstructuur genaamd a hash-tabel, die veel wordt gebruikt voor het snel opzoeken van gegevens. Hash-functies helpen het opzoeken van een tabel of database te versnellen door twee exact dezelfde hashes te detecteren.
Ze helpen ook bij het verkleinen van tags voor enorme bestanden zoals mp3’s, pdf’s of afbeeldingen om het werken met deze vrij grote bestandstypen beheersbaar te maken. Voor snelle identificatie is een belangrijke vereiste van hash-functies dat ze voer een reeks alfanumerieke tekens met een vaste lengte uit.
Hoewel de belangrijkste reden voor het begin van een hash-functie voortkwam uit de behoefte om inhoud te comprimeren, werd een secundair voordeel al snel een hoofdbestanddeel van hashing: uniek-unieke identificatoren. Idealiter zouden bij het hashen van meerdere berichten nooit twee verschillende berichten dezelfde hash mogen retourneren. Twee verschillende hash-berichten die resulteren in dezelfde output-hash wordt een genoemd botsing.
Vanuit het oogpunt van databasebeheer zou dit betekenen dat twee verschillende objecten uiteindelijk in dezelfde cel worden opgeslagen – niet goed als men op zoek is naar het definiëren van enkelvoudig unieke identificatoren. Als we een hash-functie beschouwen met oneindige ingangen (wat betekent dat we elke string kunnen hashen), kunnen we precies afleiden waarom botsingen in feite zijn onvermijdelijk.
Pigeonhole-principe
Binnen cryptografische wiskunde bestaat er een concept genaamd de hokje principe waarin staat dat als we (n) elementen in (m) ruimtes passen waar n > m, dan bestaat er in principe ten minste één ruimte (m) die wordt ingenomen door meer dan twee elementen (n).
Vijf personen controleren bijvoorbeeld hun jassen in een van de drie beschikbare vachtkaarten. Volgens het principe van een hokje, aangezien het aantal opgeslagen jassen (n) groter is dan de beschikbare kaarten (m), is het gegarandeerd dat ten minste één hokje meer dan een enkele vacht kan bevatten.
Meestal zijn software-ingenieurs geïnteresseerd in hash-functies met een oneindig domein (dat wil zeggen dat ze als invoertekenreeksen van alle mogelijke lengtes nemen) en een eindig bereik. Opnieuw volgens het duiventilprincipe, aangezien ons assortiment (n) kleiner is dan ons domein (m), volgt daaruit dat bij er moet minimaal één botsing zijn. Een effectieve hash-functie probeert daarom alleen het aantal botsingen te minimaliseren – waarom dit zo belangrijk zal worden, zal zo dadelijk duidelijker worden, maar laten we nu teruggaan naar de geschiedenis van hashes.
Terwijl hash-functies strikt afkomstig zijn van het onderhoud van de database & beheerbehoeften, die vooral de snelheid begunstigden, evolueerde hun nut snel. Een speciale tak van hash-functies die privacy en veiligheid bevorderden, & transparantie kwam al snel in het veld; een tak van hash-functies die de focus van dit artikel zal blijven: cryptografische hashfuncties.
Cryptografische hash
Cryptografische hash-functies, zoals de naam treffend aangeeft, bevorderen het behoud van absoluut ononderbroken berichten. Hoewel het minimaliseren van botsingen een goede gewoonte is voor andere hashfuncties, is het minimaliseren van botsingen voor specifiek cryptografische functies een vereiste. In plaats van het hulpprogramma te maximaliseren voor een snel database- of tabelzoekscenario, worden cryptografische hashfuncties gebouwd met een vijandig scenario in gedachten: een scenario waarin een codebreker (cryptoanalyticus) actief probeert een botsing te veroorzaken. We gaan nu standaard hash-functienotaties definiëren & stel hashfunctieprincipes vast binnen het cryptografisch perspectief.
Hash-functienotatie
Een generieke cryptografische hashfunctie heeft twee ingangen: het bericht dat het gaat comprimeren of hash (x) & een openbare sleutel (s) die de uitvoer met vaste lengte van onze hash in alfanumerieke tekens vertegenwoordigt. Ons gehashte resultaat wordt de berichtsamenvatting of eenvoudigweg digest (x *) genoemd. Dit ziet er als volgt uit:
H (s, x) = x *
Laten we deze notatie verdoezelen door door een realistisch voorbeeld te lopen dat een string hashing met behulp van een voorheen standaard hashing-functie genaamd MD5. Stel dat we MD5 willen gebruiken om een ”Hallo wereld!” draad. We weten ook dat MD5 standaard altijd een reeks van 128 bits (nullen & 1’s). Deze notatie zou er als volgt uitzien:
H (128, x) = ed076287532e86365e841e92bfc50d8c
In feite, als je doorgaat & probeer te voorzien de MD5-hashfunctie “Hallo wereld!” zelf zou je exact dezelfde resulterende hash moeten zien. Geweldig. Laten we nu verder gaan met het instellen van de notatie voor een botsing; naast eerdere variabelen H, s, x, & x * we introduceren nu een tweede bericht (x ’). Numeriek treedt een botsing op wanneer twee verschillende berichten (x & x ‘) resulteert in exact dezelfde berichtsamenvatting (x *):
Als H (128, x) = H (128, x ’), zou onze hash-functie (H) een botsing hebben op x & X’.
We hebben nu de notatie ingesteld voor de huidige kenmerkende standaard van hash-functiecryptografie; als een tegenstander (rekenkundig gesproken) een aanrijding kan veroorzaken, een hash-functie wordt niet langer als praktisch veilig beschouwd.
Gedachten sluiten tot de volgende keer
De laatste wiskundige definitie is waar de fascinerende catch-22 voor de praktische bruikbaarheid van hasj leeft. Hash-functies zijn ontstaan vanuit de behoefte om te comprimeren & output gestandaardiseerde uniforme gegevens voor opslag gemak, wat betekent dat ze pseudowillekeurige strings van een vaste lengte. Maar om een volledig botsbestendig hash-functie, zou elk bericht (x) een gehashte uitvoer van de dezelfde lengte als de invoer. Zonder hashes van een vaste lengte verliezen we ons vermogen om ze te gebruiken als een handige datastructuur, maar door een vaste lengte toe te kennen, maken we onze hashfunctie niet volledig botsingsvrij.
PS – Ik weet zeker dat sommigen van jullie slimme cookies hebben opgemerkt dat we in ons MD5-voorbeeld een hash-functie hebben genoteerd die een string met lengte retourneert 128, maar onze “Hallo wereld!” hash heeft een 32 alfanumerieke tekenreeks. Kom de volgende keer terug & we gaan dieper in op hashfuncties om uit te leggen waar dit verschil vandaan kwam.