Jag vill låta användaren logga in till mitt program. För lösenordsinmatningen tänkte jag använda JPasswordField, vars metod getPassword() returnerar en char[], hur gör jag för att hasha detta lösenord till en SHA1-sträng på 40 tecken (SHA-1 160 bitar)? Har tittat lite på MessageDigest-paketet men får inte fram nåt vettigt.
JPasswordField till SHA1-sträng.
10 svar · 906 visningar · startad av erciz
Räcker det inte med SHA, som finns färdigt i Suns paket? Jag vet inte riktigt om det är någon skillnad mot SHA-1?
Helt otestat med SHA;
import java.security.MessageDigest;
...
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(new String(jPasswordField.getPassword()).getBytes());
byte[] hash = md.digest();
...
Tack SPiN, testade lite:
MessageDigest sha1 = null;
try {
sha1 = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
char[] data = passwordFld.getPassword();
sha1.update(new String(data).getBytes());
System.out.println("Password: " + new String(data));
System.out.println("Algorithm: " + sha1);
System.out.println("Digest: " + sha1.digest());
vilket resulterade i dessa utskrifter:
Password: Hej
Algorithm: SHA-1 Message Digest from SUN, <in progress>
Digest: [B@1e6e305
Jag antar att Digest är den binära hash-summan. Går det att få det i en sträng? så jag enklare kan spara den i XML och databaser, den ska ju vara 40 tecken då. Har bara gjort detta i PHP förut.
Konstruktorn till String tar en array av bytes, vilket du får ut av MessageDigest.digest().
Konstruktorn till String tar en array av bytes, vilket du får ut av MessageDigest.digest().
Då får jag
Digest: {Ï‚ù\ùf*™X·k€
Kom på att i PHP kanke SHA1-hashen är base64-kodad, ska testa med det. Finns det nån base64-funktion i Java:s standardbibliotek?
Ja, det är i rå-format du får ut informationen. Du borde kunna göra någon konverterare relativt enkelt (hittade något på nätet);
public String byteArrayToHexString(byte[] bytes) {
String hex = "";
for (byte b : bytes)
hex += Integer.toString((b & 0xFF) + 0x100, 16).substring(1);
return hex;
}
Du borde även kunna läsa med en java.io.ByteArrayInputStream, om det känns bättre.
PHPs motsvarigheter har hex-värdet som default returvärde, men man kan ange om man vill ha det i råformat eller inte.
Tack SPiN, jag kommer närmare ;)
PHP: 7bcf82f95cf9662a995805b76b80006c65a79718
Java: da39a3ee5e6b4b0d3255bfef95601890afd80709
Klartext: Hej
Det var med hexfunktionen du angav, så nu får jag bara leta på en kompatibel. Men är på rätt spår!
Raw-värdena för PHP och Java ser ut att bli likadana.
Ett alternativt sätt som tydligen ska vara effektivt;
String hex = new java.math.BigInteger(1, sha.digest()).toString(16);
Ett alternativt sätt som tydligen ska vara effektivt;
String hex = new java.math.BigInteger(1, sha.digest()).toString(16);
Ja, det var ju klart snyggare än de andra jag testat, har googlat lite, men alla metoder verkar ge samma resultat som jag redan skrivit för Java. Testade nu i MySQL och det gav samma svar som PHP, så det verkar som de använder nån annan algorithm för att göra om SHA-1 till Hex-sträng.
SELECT SHA1('Hej');
7bcf82f95cf9662a995805b76b80006c65a79718
Fick lite tips på denna sida: http://forums.sun.com/thread.jspa?threadID=5349070
Laddade ner "Jakarta Commons Codec", från Apache: http://commons.apache.org/codec/
Sen använde jag
DigestUtils.shaHex("Hej");
7bcf82f95cf9662a995805b76b80006c65a79718
Så nu funkar det, vet egentligen inte vad det var för fel innan, men vi gjorde väl inte hex-omvandlingen på "rätt sätt".
Jag letade runt lite, och har uppfattat det som att problemet beror på att Java "kastar bort" inledande 0. Så 0x01 resulterar i 1 och inte 01, t.ex.
Åtgärden verkar i de flesta fall (alla?) ha varit att göra precis som du gjort, använda sig av tredjeparts-biblioteket DigestUtils från Apache Commons. :)