Skip to content

Instantly share code, notes, and snippets.

@arleighdickerson
Created July 13, 2025 17:04
Show Gist options
  • Save arleighdickerson/5d4549cd2a7647a91fbe30d0b151bf24 to your computer and use it in GitHub Desktop.
Save arleighdickerson/5d4549cd2a7647a91fbe30d0b151bf24 to your computer and use it in GitHub Desktop.
import lombok.NonNull;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base32;
import org.springframework.lang.Nullable;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Locale;
import java.util.regex.Pattern;
public final class HashUtil {
public static final String HASH_REGEX = "^[a-z0-9]{128}$";
private static final Pattern HASH_PATTERN = Pattern.compile(HASH_REGEX);
public static boolean isValidHash(@Nullable String hash) {
return hash == null || HASH_PATTERN.matcher(hash).matches();
}
private HashUtil() {
}
public static String createHash(@NonNull String plainText) {
return createHash(plainText, null);
}
/**
* @param plainText the input text to hash
* @param salt a salt for the hash
*
* @return the encoded value of the hash, containing only lowercase alphanumeric characters
*/
@SneakyThrows
public static String createHash(@NonNull String plainText, @Nullable byte[] salt) {
MessageDigest md = MessageDigest.getInstance("SHA-512");
if (salt != null && salt.length > 0) {
// add salt if one is provided
md.update(salt);
}
byte[] hash = md.digest(plainText.getBytes(StandardCharsets.UTF_8));
// encode with base32 for case-insensitivity
return new Base32(false)
// pad the hash before encoding to ensure url safety (no trailing '=' chars)
.encodeToString(addPadding(hash))
// use [a-z] instead of [A-Z]
.toLowerCase(Locale.ROOT);
}
public static byte[] addPadding(byte[] input) {
int res = 16 - input.length % 16;
byte[] result = new byte[res];
Arrays.fill(result, (byte) res);
return merge(input, result);
}
private static byte[] merge(byte[] arr1, byte[] arr2) {
byte[] results = new byte[arr1.length + arr2.length];
int i = 0;
for (; i < arr1.length; i += 1) {
results[i] = arr1[i];
}
for (int j = i; j - i < arr2.length; j += 1) {
results[j] = arr2[j - i];
}
return results;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment