PinManager.java

 avatar
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