Det finns en vanlig missuppfattning att hash och kryptering är samma sak. Det är de inte. Hash är irreversibel. Ta följande exempel som ett exempel:
$ echo-n Password123 | md5sum
42f749ade7f9e195bf475f37a44cafcb-
Vi skickar strängen "Password123" till MD5-algoritmen (algo), som utför matematiska operationer och returnerar den genererade hexadecimalkodade hash. Det enda sättet att få samma hash-utgångsvärde är att lägga in algo i den ursprungliga matningen. Det finns konflikter, men vi kan diskutera det senare.
Utmatningen från de flesta hashalgoritmer är en hexadecimalkodad binär sträng med fast längd. Andra, som det här exemplet, använder base64-kodade strängar som utdata. Observera att längden alltid är densamma:
{SHA} uNF8eZRJ8jmr8WTjyocRJPVpe7w =
{SHA} lqdu/Zr6o2dgIER8Up1/7lcUtgw =
{SHA} qYUOwLMlDEuukA5HCT4LR1kQzco =
{SHA} MXZBCpyWJ7TTs1w2kgGJslwNwTg =
{SHA} 2sAPLaUh9Mz0bI + XxKEg7qyABe8=
TL; Dr
Jag vill inte prata för mycket om kryptering (eftersom de där sakerna är för böcker), men det är viktigt att kunna skilja mellan hash-och krypterade strängar. Kryptering fyller vanligtvis en sträng för att uppfylla en viss längd innan kryptering sker. Det kräver också en nyckel (eller lösenord) för att dekryptera. Om du använder ett krypterat lösenord kommer strängen att ändras beroende på längden på inmatningen. Om du ser en massa chiffertextlösenord varierar längden och du kan arbeta med kryptering istället för hash. AES-256-CBC Exempel Krypterad sträng och tillhörande vanlig text (nyckeln är "ASDF"):
foobar | U2FsdGVkX19G + KtytNHdj6yH2AVvX26pEmtunS/PRnU = foobarfoobar | U2FsdGVkX18sPpIvN6nVh68lOUCcb3gR2fKbCCnBxog = foobarfoobarfoobar | U2FsdGVkX1/EOnUt57TCW4Rh0EdNnWX + ldatuqv2xexeaeoww0xg/EXJUe9aSUz $ katt krypterade_lösenord U2FsdGVkX19G + KtytNHdj6yH2AVvX26pEmtunS/PRnU = U2FsdGVkX18sPpIvN6nVh68lOUCcb3gR2fKbCCnBxog = U2FsdGVkX1/EOnUt57TCW4Rh0EdNnWX + lDatuQv2xEXXeAeowW0XG/EXJUe9aSUz $ för i i `cat encrypted_passwords`; gör echo $i | openssl enc -base64 -d -aes-256-cbc -pass pass:asdf; eko; Klar foobar foobarfoobar foobarfoobarfoobar
Nu kanske du tänker: du har nog rätt. Att nyckelmaterial ska vara tillgängligt för systemet innebär dock att det i huvudsak är ett vanligt textmasterlösenord som finns någonstans – oavsett om det är som en RSA-nyckel eller ett lösenord i en fil, inbäddat i en databas, hårdkodat i en applikation eller ett lösenord någonstans i minnet. pfft, ingen ' kommer att använda asdf som nyckeln för att kryptera sina användares ' lösenord
Använd samma sträng för MD5:
foobar | 3858f62230ac3c915f300c664312c63f foobarfoobar | 59faa421729e846dd800dce59943bfc0 foobarfoobarfoobar | 1352aadab322d1a033c27964be0965db
Hashlösenordet är långt ifrån perfekt, i själva verket är det lite dåligt, men det är värre än kryptering för vad det försöker uppnå. Användare väljer det absoluta minimikravet oftare än not och kan också använda det på flera webbplatser. Många "hacks" är faktiskt inget annat än legitimationsåteranvändningsattacker. Om den ursprungliga kompromissen är att använda kryptering, är den enda ansträngningen som angriparen måste göra att hitta nyckeln som dekrypterar alla lösenord. För hash måste de åtminstone anstränga sig för att knäcka dem. Vid användning med moderna algoritmer som sha512crypt, bcrypt, scrypt eller argon2 kan hash-värden kräva stor ansträngning att knäcka.
Att lägga till salt är att lägga till en sträng till lösenordet före hash. Saltet för varje hash ska vara unikt, vanligtvis slumpmässigt valt, eftersom poängen är att göra samma "lösenord"-hashvärde i klar text olika varje gång. Detta gör livet svårt för lösenordsknäckare, för för att kontrollera ordet "lösenord" för var och en av de 1000 användarna, som var och en har ett unikt SALT, måste de göra detta 1000 gånger-en gång per användare/SALT. Det betyder också att de inte kan använda förkompilerade ordböcker eller regnbågstabeller effektivt (vanligtvis...) eftersom de kräver en anpassad per salt.
Webbplatser skruvar ibland till detta och använder generiskt salt för alla användare; Detta strider mot syftet.
Följande är SHA1-hash med salt:
b353977827f67a4ae0318f3a9447fae1c13d9d90:b8d18ca |___________________________________________| hash | salt | separator
Klartexten för denna hash är "lösenord". Dess saltvärde är "b8d18ca" och används i SHA1 ($salt.$pass) API. Det betyder att algoritmen tar lösenordets klartext, genererar saltet och lägger till det framför klartexten. När en webbplats eller app försöker verifiera ditt lösenord i framtiden, tar den ditt lösenord i klar text som input, läser saltvärdet i den lagrade hashen, lägger till det framför det lösenord du väljer och jämför det genererade hashvärdet med det lagrade hashvärdet. Cracking Om du inte vet att en del av det är salt, kommer hashen att producera följande vanlig text:
b8d18capassword
Eftersom algoritmen gör vanlig textinmatning, salt och det genererade Hashvärdet kan förbli transparent för användaren. Vid cracking, om algoritmen är salt, måste vi känna till saltet så att vi kan tillhandahålla det när vi genererar kandidaten Plain Text.
Om det genomförs på rätt sätt kan saltning göra sprickningen mer tidskrävande. Med slumpmässiga salter tvingar du Cracker att slösa tid på att försöka knäcka hash-värden som saltet inte matchar. Detta fullbordar ungefär den ansträngning som krävs för device_speed/number_of_salts eftersom vi måste generera en kandidat för varje salt. Om saltet är statiskt är matematiken densamma... speed_of_device/1. Ett annat sätt att se detta:
vår GTX 980 sprickor SHA1 ($salt.$pass) vid 3576,8 MH/s eller 3,5 miljarder kandidater per sekund Vår hashlista innehåller 1000 unika salter 3 500 000 000 / 1000 = 3 500 000 kandidater per sekund
Detta är tre storleksordningar långsammare, en förlust på 99,9 %. Med statiskt salt ser det ut så här:
Vår GTX 980 sprickor SHA1 ($salt.$pass) vid 3576,8 MH/s eller 3,5 miljarder kandidater per sekund Vår hashlista innehåller 1 unik salt 3 500 000 000 / 1 = 3 500 000 000 kandidater per sekund
Om detta inte är meningsfullt, fortsätt läsa, vi kommer att ha ett snyggt diagram senare...
En annan vanlig förbättring jämfört med att helt enkelt "hash this plaintext" är att "hash this plaintext, hash sedan det resultatet, och sedan hash det resultatet" upprepas tusentals gånger. Detta gör att lösenordsbrytaren måste göra tusentals gånger när du försöker ett enda kandidatlösenord. Detta kallas iteration, loop eller variabel kostnad. Vissa lösenordshashalgoritmer använder hårdkodade iterationsrunder; Andra Git. Gör den konfigurerbar i en del av själva hashen. Till exempel använder md5crypt () MD5, inklusive salt, och slingrar exakt 1000 gånger. sha512crypt () använder sha512, inkluderar ett salt och slingar ett konfigurerbart antal gånger (standard är 5 000).
Iterationer påverkar främst beräkningscykelkostnaden för hashalgoritmen, snarare än dess minnesanvändning eller andra faktorer. Dessa är också viktiga attacker när designen är optimerad för att motstå vissa typer av hashtyper, men det här är för ogräs för att diskutera här.
Låt oss titta på några exempel för att demonstrera effekten av val av hash-algoritm, oavsett om det är saltat, med flera iterationer, etc. Antag att en angripare samlar in hashvärden för 1 000 användare från en infekterad webbplats och de vill bara utföra en enkel attack som testar varje lösenordshash-143 miljoner kandidatlösenord.
Den typ av hash som används av den infekterade webbplatsen kommer att ha en enorm inverkan på hur lång tid det tar för angriparen att passera attacken. Här är en (relativ, ungefär) diagram över hur många sekunder det tar att slutföra attacken, beroende på vilken typ av hash som används, där standard grafikkort:
Tja, det är värdelöst! De starkaste hash-typerna är mycket långsammare, men de snabbare typerna är bara platt till ingenting. Låt oss försöka samma dataskala igen med hjälp av logaritmisk x-axeltid. När staplarna flyttas från vänster till höger kommer de att öka med 10 till makten:
Så några poäng är: Enkelvarv är lättare än flera varv och saltfritt än med salt när du vill knäcka lite lösenordshash. Tvärtom, när vissa företag eller webbplatser meddelar ett dataintrång som innehåller användardata, a) lösenordet är bäst att ha hassats, inte bara vanlig text; b) De är helst saltade, inte bara hassade. c) Det är bättre att de har använt kraftfulla salthash med flera omgångar hela tiden, inte bara en enda omgång.
Innan man försöker knäcka en given lösenordshash är det upp till knäckaren att ta reda på vilken hashalgoritm som används för att implementera den. Att identifiera hash-typer är vanligtvis enkelt, men inte alltid. Crackers gör ofta välgrundade gissningar baserade på ledtrådar som hashlängd och format. I slutändan är det enda sättet att vara säker på att hash-typen är korrekt är om hashen är knäckt.
Några utmärkta resurser för denna uppgift finns här och här, och de visar båda hur vanliga hashvärden ser ut.
Paketet "hash-identifier" (tillgängligt här) finns i Kali Linux som hjälper till att identifiera okända hash-typer.
En kollision uppstår när två olika ingångar resulterar i samma hash-utgång. Det är dåligt (tydligen). För lösenord kan det innebära att jag kanske inte har knäckt ditt faktiska lösenord, men eftersom jag hittade en ingång som producerar samma hashvärde kan jag använda vanliga textvärden för att lura systemet att tro att lösenordet är legitimt.
Microsoft Office har i sitt dokumentskydd använt sig av en algoritm som under många år har varit utsatt för konflikter. Det är inte ovanligt att upptäcka flera konflikter för en enda hash, som alla låser upp dokumentet.
När en konflikt har upptäckts är algoritmen faktiskt förstörd. Om det händer en gång är det statistiskt sett mycket troligt att det kommer att hända igen. Det enda som står i vägen är tid och bearbetningsförmåga. När algoritmer blir mer robusta tar det mer kapacitet och tid att generera kandidatalgoritmer och jämföra hashutdata för att söka efter dem. Som ett resultat blir designers allt bättre på att skapa algoritmer som är mindre mottagliga för konflikter.