95 lines
2.4 KiB
Java
95 lines
2.4 KiB
Java
package achievements.misc;
|
|
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.SecureRandom;
|
|
import java.util.Random;
|
|
|
|
public class Password {
|
|
|
|
private static final Random RANDOM = new SecureRandom();
|
|
|
|
public final String salt;
|
|
public final String hash;
|
|
|
|
private Password(String salt, String hash) {
|
|
this.salt = salt;
|
|
this.hash = hash;
|
|
}
|
|
|
|
public static Password generate(String password) {
|
|
// Generate the salt
|
|
var salt = new byte[16]; // 128 bits
|
|
RANDOM.nextBytes(salt);
|
|
|
|
return new Password(
|
|
encode(salt),
|
|
encode(hash(salt, password.getBytes()))
|
|
);
|
|
}
|
|
|
|
public static boolean validate(String salt, String password, String hash) {
|
|
System.out.println(salt + ", " + password);
|
|
var srcHash = hash(decode(salt), password.getBytes());
|
|
var targetHash = decode(hash);
|
|
for (int i = 0; i < srcHash.length; ++i) {
|
|
if (srcHash[i] != targetHash[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static byte[] hash(byte[] salt, byte[] password) {
|
|
try {
|
|
var concat = new byte[salt.length + password.length];
|
|
int i = 0;
|
|
for (; i < salt.length; ++i) {
|
|
concat[i] = salt[i];
|
|
}
|
|
for (int j = 0; j < password.length; ++j) {
|
|
concat[i + j] = password[j];
|
|
}
|
|
|
|
var md = MessageDigest.getInstance("SHA-256");
|
|
return md.digest(concat);
|
|
} catch (NoSuchAlgorithmException e) {
|
|
e.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static String encode(byte[] bytes) {
|
|
var chars = new char[bytes.length << 1];
|
|
for (int i = 0; i < bytes.length; ++i) {
|
|
chars[(i << 1) ] = toHex(bytes[i] >> 0);
|
|
chars[(i << 1) + 1] = toHex(bytes[i] >> 4);
|
|
}
|
|
return new String(chars);
|
|
}
|
|
|
|
private static byte[] decode(String data) {
|
|
var decoded = new byte[data.length() >> 1];
|
|
for (int i = 0; i < data.length(); i += 2) {
|
|
int currentByte =
|
|
(fromHex(data.charAt(i )) ) |
|
|
(fromHex(data.charAt(i + 1)) << 4);
|
|
decoded[i >> 1] = (byte) (currentByte & 0xFF);
|
|
}
|
|
return decoded;
|
|
}
|
|
|
|
private static char toHex(int halfByte) {
|
|
halfByte = halfByte & 0xF;
|
|
if (0 <= halfByte && halfByte <= 9 ) return (char) (halfByte + '0' );
|
|
if (10 <= halfByte && halfByte <= 15) return (char) (halfByte + 'a' - 10);
|
|
return '0';
|
|
}
|
|
|
|
private static int fromHex(char c) {
|
|
if ('0' <= c && c <= '9') return c - '0';
|
|
if ('A' <= c && c <= 'F') return c - 'A' + 10;
|
|
if ('a' <= c && c <= 'f') return c - 'a' + 10;
|
|
return 0;
|
|
}
|
|
}
|