Refactored using IntelliJ

This commit is contained in:
UnlegitDqrk
2026-02-06 18:03:32 +01:00
parent 6c513c9436
commit 8829737d30
16 changed files with 880 additions and 823 deletions

View File

@@ -7,7 +7,8 @@ import java.nio.charset.StandardCharsets;
*/
public final class Html {
private Html() {}
private Html() {
}
/**
* Escapes text for HTML.
@@ -37,7 +38,7 @@ public final class Html {
* Simple page wrapper.
*
* @param title title
* @param body body html
* @param body body html
* @return full html
*/
public static String page(String title, String body) {

View File

@@ -88,7 +88,7 @@ public final class RequestParams {
* Returns SHA-256 hex of a header value.
*
* @param hasher hasher
* @param key header key
* @param key header key
* @return sha256 hex (or null if missing)
*/
public String getSha256Hex(WebHasher hasher, String key) {

View File

@@ -26,8 +26,8 @@ public final class WebHasher {
* Creates a hasher.
*
* @param pbkdf2Iterations iterations (recommended >= 100k)
* @param pbkdf2SaltBytes salt bytes
* @param pbkdf2KeyBytes derived key bytes
* @param pbkdf2SaltBytes salt bytes
* @param pbkdf2KeyBytes derived key bytes
*/
public WebHasher(int pbkdf2Iterations, int pbkdf2SaltBytes, int pbkdf2KeyBytes) {
if (pbkdf2Iterations < 10_000) throw new IllegalArgumentException("pbkdf2Iterations too low");
@@ -38,6 +38,35 @@ public final class WebHasher {
this.pbkdf2KeyBytes = pbkdf2KeyBytes;
}
private static byte[] derive(char[] password, byte[] salt, int iterations, int keyBytes) {
try {
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyBytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
return skf.generateSecret(spec).getEncoded();
} catch (Exception e) {
throw new IllegalStateException("PBKDF2 not available", e);
}
}
private static boolean constantTimeEquals(byte[] a, byte[] b) {
if (a == null || b == null) return false;
if (a.length != b.length) return false;
int r = 0;
for (int i = 0; i < a.length; i++) r |= (a[i] ^ b[i]);
return r == 0;
}
private static String toHexLower(byte[] data) {
final char[] hex = "0123456789abcdef".toCharArray();
char[] out = new char[data.length * 2];
int i = 0;
for (byte b : data) {
out[i++] = hex[(b >>> 4) & 0x0F];
out[i++] = hex[b & 0x0F];
}
return new String(out);
}
/**
* SHA-256 hashes text (lowercase hex).
*
@@ -77,7 +106,7 @@ public final class WebHasher {
* Verifies a raw password against a stored PBKDF2 string.
*
* @param password raw password
* @param stored stored format
* @param stored stored format
* @return true if valid
*/
public boolean pbkdf2Verify(String password, String stored) {
@@ -107,33 +136,4 @@ public final class WebHasher {
byte[] actual = derive(password.toCharArray(), salt, it, expected.length);
return constantTimeEquals(expected, actual);
}
private static byte[] derive(char[] password, byte[] salt, int iterations, int keyBytes) {
try {
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyBytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
return skf.generateSecret(spec).getEncoded();
} catch (Exception e) {
throw new IllegalStateException("PBKDF2 not available", e);
}
}
private static boolean constantTimeEquals(byte[] a, byte[] b) {
if (a == null || b == null) return false;
if (a.length != b.length) return false;
int r = 0;
for (int i = 0; i < a.length; i++) r |= (a[i] ^ b[i]);
return r == 0;
}
private static String toHexLower(byte[] data) {
final char[] hex = "0123456789abcdef".toCharArray();
char[] out = new char[data.length * 2];
int i = 0;
for (byte b : data) {
out[i++] = hex[(b >>> 4) & 0x0F];
out[i++] = hex[b & 0x0F];
}
return new String(out);
}
}