Hvad er en hashfunktion?

En hashfunktion er en algoritme, der tager et input af vilkårlig størrelse og omdanner det til et output af fast længde. Outputtet kaldes et hash, en digest eller et fingeraftryk. Uanset om du hasher et enkelt bogstav eller en fil på flere gigabyte, har resultatet altid samme længde.

Hashfunktioner findes i to ret forskellige verdener. Almindelige hashfunktioner bruges til at organisere data effektivt, for eksempel i hashtabeller, hvor formålet bare er hurtige opslag. Kryptografiske hashfunktioner stiller langt strengere krav, fordi de skal kunne bruges som et pålideligt fingeraftryk, man kan basere sikkerhed på. Denne artikel handler især om den kryptografiske slags.

En naturlig følge af, at outputtet har fast længde, mens inputtet kan være vilkårligt stort, er at der findes uendeligt mange flere mulige input end mulige hashværdier. Derfor vil der findes input, der deler samme hash. Det er matematisk uundgåeligt. Hele kunsten ved en god kryptografisk hashfunktion er ikke at undgå, at sådanne sammenfald eksisterer, men at gøre det så regnetungt at finde dem, at ingen i praksis kan. Den dag det alligevel lykkes, sådan som det skete for SHA-1, holder funktionen op med at være sikker til de formål, der afhænger af netop den modstand.

De centrale egenskaber

En kryptografisk hashfunktion skal opfylde flere egenskaber samtidigt. Det er kombinationen, ikke en enkelt af dem, der gør funktionen brugbar.

Deterministisk

Det samme input giver altid det samme output. Det lyder selvfølgeligt, men det er afgørende: kan to maskiner ikke nå frem til det samme hash for den samme fil, kan hashet ikke bruges til at sammenligne data på tværs af tid og sted.

Hurtig at beregne

Det skal være effektivt at udregne et hash fra et input. Hashing bruges konstant, ofte på store datamængder, og en langsom funktion ville være upraktisk i de fleste sammenhænge.

Modstand mod preimage

Givet et hash skal det i praksis være umuligt at finde et input, der frembringer netop det hash. Funktionen kan beregnes forlæns, men ikke vendes om. Det er denne egenskab, der gør det forsvarligt at gemme eller offentliggøre et hash uden at afsløre det underliggende data.

Modstand mod second preimage

Givet et bestemt input skal det være praktisk umuligt at finde et andet input med samme hash. Forskellen fra preimage er, at angriberen her allerede kender ét gyldigt input og forsøger at finde et alternativ, der kolliderer med netop det. Denne egenskab beskytter mod, at en kendt fil byttes ud med en anden, der bærer samme fingeraftryk.

Modstand mod kollisioner

Det skal være praktisk umuligt at finde to vilkårlige forskellige input, der giver det samme hash. Dette er et stærkere krav end second preimage, fordi angriberen her frit kan vælge begge input. Det var netop kollisionsmodstanden, SHA-1 mistede, da SHAttered-angrebet i 2017 fremstillede to forskellige filer med samme SHA-1-hash.

Lavineeffekt

En lille ændring i inputtet, helt ned til en enkelt bit, skal ændre omkring halvdelen af bittene i outputtet. Resultatet er, at to næsten identiske input giver to hash, der ser fuldstændig urelaterede ud. Lavineeffekten er grunden til, at man ikke kan gætte sig til, hvor ens to input er, ved at kigge på deres hash.

Forskellen på kryptografiske og ikke-kryptografiske hashfunktioner

Det er værd at skille de to typer skarpt ad, fordi de let forveksles.

En ikke-kryptografisk hashfunktion, som dem der bruges internt i programmeringssprog til hashtabeller, er optimeret til hastighed og til at fordele værdier jævnt. Den behøver ikke modstå en angriber. Det er fuldt acceptabelt, at man let kan finde kollisioner, så længe almindelige data fordeles pænt. Eksempler er funktioner designet udelukkende til opslag og checksummer, der kun skal opdage tilfældige fejl, ikke bevidst manipulation.

En kryptografisk hashfunktion antager derimod, at der findes en modstander, som aktivt forsøger at fremstille kollisioner eller regne baglæns. Derfor skal den modstå preimage-, second-preimage- og kollisionsangreb. SHA-256 og SHA-3 er eksempler.

Forskellen er ikke akademisk. Bruger man en simpel checksum eller en ikke-kryptografisk hash, hvor sikkerhed kræves, åbner man for, at en angriber bevidst fremstiller data med det forventede fingeraftryk. Et fingeraftryk er kun en garanti, hvis det er beregnet med en funktion, der er bygget til at modstå netop den slags angreb.

Hvor hashfunktioner bruges

Kryptografiske hashfunktioner er nogle af de mest anvendte byggesten i moderne it-sikkerhed. Et par af de vigtigste anvendelser:

Opbevaring af adgangskoder med salt

Veldrevne systemer gemmer ikke adgangskoder i klartekst. I stedet gemmer de et hash af adgangskoden. Når du logger ind, hashes det, du indtaster, og sammenlignes med det gemte hash. Lækker databasen, afslører hashene ikke umiddelbart de oprindelige kodeord.

For at gøre dette sikkert tilføjer man en salt, en tilfældig værdi, der er unik for hver bruger og blandes ind før hashing. Salt sikrer, at to brugere med samme adgangskode får forskellige hash, og forhindrer angribere i at bruge forudberegnede tabeller. I praksis anvendes ofte specialiserede, bevidst langsomme funktioner til adgangskoder, men det grundlæggende princip hviler på hashing.

Integritetskontrol

Når en fil hentes eller overføres, kan man beregne dens hash før og efter og sammenligne. Stemmer de to hash overens, er filen uændret. Det bruges til alt fra softwaredownloads til kontrol af, om sikkerhedskopier er intakte.

Digitale signaturer

I stedet for at signere en hel besked signerer man hashet af beskeden. Det er hurtigere og lige så sikkert, så længe hashfunktionen er stærk. Hvis hashfunktionen tillader kollisioner, opstår der derimod et hul, hvor en signatur sat på ét dokument kan misbruges på et andet med samme hash.

Blockchains

Kryptovalutaer og andre blockchains bruger hashing til at lænke blokke sammen. Hver blok indeholder et hash af den foregående, så hele kæden hænger sammen. Ændrer nogen et historisk data, ændres hashet, og uoverensstemmelsen afsløres straks længere fremme i kæden. Hashing er dermed selve limen, der gør en blockchain svær at forfalske.

Når en hashfunktion svigter

Egenskaberne ovenfor er idealer, en funktion skal leve op til. Når den ikke længere gør det, holder anvendelserne op med at være sikre. SHA-1 er det tydeligste eksempel: da kollisioner blev praktisk mulige, kunne den ikke længere bruges dér, hvor sikkerhed afhænger af, at to forskellige input ikke kan dele fingeraftryk.

Lærdommen er, at valget af hashfunktion betyder noget, og at det bør revurderes over tid. En funktion, der var sikker for et årti siden, kan være svag i dag, fordi regnekraften er vokset, og angrebsmetoderne er blevet skarpere. Derfor anbefales i dag funktioner som SHA-256 og SHA-3, og derfor er det klogt at skifte væk fra ældre algoritmer, før nogen offentligt demonstrerer, at de kan brydes.

Sådan vælger man en hashfunktion

For den praktiske bruger kan rådene koges ned til nogle få tommelfingerregler. Brug en anerkendt, moderne hashfunktion frem for hjemmestrikkede løsninger eller forældede algoritmer. Til generel integritet og signaturer er SHA-256 et solidt standardvalg, og stærkere varianter som SHA-512 og SHA-3 findes, hvis der er behov. Til adgangskoder bør man ikke bruge en almindelig hurtig hashfunktion alene, men en specialiseret, bevidst langsom funktion kombineret med salt, fordi hastighed her er en ulempe snarere end en fordel. Og uanset valget bør man holde øje med, om algoritmen stadig anses for sikker, og være parat til at skifte, hvis billedet ændrer sig. En hashfunktion er et fundament, og fundamenter bør efterses, før de begynder at slå revner.