public SaltedPass flavorWithSalt(String passwd) throws Exception {
final Random rand = new Random();
final MessageDigest m = MessageDigest.getInstance("MD5");
final byte[] salt = new byte[12];
rand.nextBytes(salt);
m.update(salt);
m.update(passwd.getBytes("UTF8"));
byte hash[] = m.digest();
return new SaltedPass(toHex(salt), toHex(hash));
}
Der Methode
flavorWithSalt
wird das gewünschte Benutzerpasswort im Klartext übergeben. Die Methode generiert einen Zufallswert, der als Salt verwendet und beim Hashen einbezogen wird, sowie den Hash selbst. Die Anwendung darf nur den zurückgegeben Hash und den Salt speichern.Für die Authentifizierung ist die Passworteingabe im Klartext und der Salt erforderlich. Beides ergibt wieder einen Hash, der mit dem gespeicherten Hash verglichen wird. Sind die Hashes identisch, ist die Authentifizierung erfolgreich.
public boolean validate(String passwd, SaltedPass flavored) throws Exception {
final MessageDigest m = MessageDigest.getInstance("MD5");
final byte[] salt = fromHex(flavored.salt);
m.update(salt);
m.update(passwd.getBytes("UTF8"));
byte hash[] = m.digest();
if(toHex(hash).equals(flavored.hash)) {
return true;
}
return false;
}
Damit das ganze compiliert, sind noch die Methoden zum Wandeln der Byte-Arrays in ihre hexadezimale String-Representation und zurück, sowie die Klasse
SaltedPass
, die als Dataholder dient, erforderlich. private String toHex(byte[] bytes) {
final StringBuilder result = new StringBuilder(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
result.append(Integer.toHexString((0x000000ff & bytes[i]) | 0xffffff00).substring(6));
}
return result.toString();
}
public static byte[] fromHex(String hexString) {
final char[] hex = hexString.toCharArray();
final int length = hex.length / 2;
final byte[] raw = new byte[length];
for (int i = 0; i < length; i++) {
int high = Character.digit(hex[i * 2], 16);
int low = Character.digit(hex[i * 2 + 1], 16);
int value = (high << 4) | low;
if (value > 127) {
value -= 256;
}
raw[i] = (byte) value;
}
return raw;
}
private class SaltedPass {
private String salt;
private String hash;
SaltedPass(String salt, String hash) {
this.salt=salt;
this.hash = hash;
}
public String toString() {
return "salt:" + salt + " hash:" + hash;
}
}
Und zuletzt noch die Main-Methode zum Ausprobieren:
public static void main(String[] args) throws Exception {
String pass = "testpass";
SaltedPass flavorWithSalt = new SaltTrialout().flavorWithSalt(pass);
System.out.println(flavorWithSalt);
boolean validate = new SaltTrialout().validate(pass, flavorWithSalt);
System.out.println(validate);
}
Update 30.3.11
Source zum Download
Hallo,
AntwortenLöschenSchöner Artikel und gut erklärt. Noch besser wäre noch der Download einer fertigen .java-Datei, so wäre ein besserer Überblick über die Import-Statements möglich.
Gruß Maik
Danke, habe ich ergänzt.
AntwortenLöschenSuper Artikel von Heise zu dem Thema: http://www.heise.de/security/artikel/Passwoerter-unknackbar-speichern-1253931.html?artikelseite=1
AntwortenLöschen