PinManager.java
unknown
java
10 months ago
2.7 kB
20
Indexable
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
public class PinManager {
private static final Path PIN_BASE = Paths.get(System.getProperty("user.home"), ".geldboerse", "pins");
private static final SecureRandom RNG = new SecureRandom();
static {
try {
Files.createDirectories(PIN_BASE);
} catch (IOException e) {
throw new RuntimeException("Konnte PIN-Ordner nicht anlegen: " + PIN_BASE + " -> " + e.getMessage(), e);
}
}
private static Path fileForUser(String username) {
String safe = username.trim().replaceAll("[^a-zA-Z0-9._-]", "_");
return PIN_BASE.resolve(safe + ".pin");
}
public static boolean hasPin(String username) {
return Files.exists(fileForUser(username));
}
public static void setPin(String username, String pin) throws Exception {
byte[] salt = new byte[16];
RNG.nextBytes(salt);
byte[] hash = hashPin(salt, pin);
String payload = Base64.getEncoder().encodeToString(salt) + ":" +
Base64.getEncoder().encodeToString(hash);
Files.writeString(fileForUser(username), payload, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
public static boolean verify(String username, String pin) throws Exception {
Path p = fileForUser(username);
if (!Files.exists(p)) return false;
String payload = Files.readString(p, StandardCharsets.UTF_8).trim();
String[] parts = payload.split(":");
if (parts.length != 2) return false;
byte[] salt = Base64.getDecoder().decode(parts[0]);
byte[] expected = Base64.getDecoder().decode(parts[1]);
byte[] actual = hashPin(salt, pin);
return slowEquals(expected, actual);
}
private static byte[] hashPin(byte[] salt, String pin) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
md.update(pin.getBytes(StandardCharsets.UTF_8));
return md.digest();
}
private static boolean slowEquals(byte[] a, byte[] b) {
if (a == null || b == null || a.length != b.length) return false;
int diff = 0;
for (int i = 0; i < a.length; i++) diff |= (a[i] ^ b[i]);
return diff == 0;
}
public static boolean isValidFourDigit(String pin) {
return pin != null && pin.matches("\\d{4}");
}
}
Editor is loading...
Leave a Comment