feat: added hash utils

This commit is contained in:
darwincereska
2025-12-17 10:04:59 -05:00
parent f818b38b3d
commit f46459b687

View File

@@ -0,0 +1,80 @@
package org.ccoin.utils
import java.security.MessageDigest
import java.security.SecureRandom
object HashUtils {
private val secureRandom = SecureRandom()
/** Computes SHA-256 hash of a byte array */
fun sha256(data: ByteArray): ByteArray = MessageDigest.getInstance("SHA-256").digest(data)
/** Computes SHA-256 hash of a string and returns hex string */
fun sha256Hex(input: String): String = sha256(input.toByteArray()).toHexString()
/** Computes double SHA-256 hash (like Bitcoin) */
fun doubleSha256(data: ByteArray): ByteArray = sha256(sha256(data))
/** Computes double SHA-256 hash and returns hex string */
fun doubleSha256Hex(input: String): String = doubleSha256(input.toByteArray()).toHexString()
/** Converts byte array to hex string */
fun ByteArray.toHexString(): String = joinToString("") { "%02x".format(it) }
/** Converts hex string to byte array */
fun String.hexToByteArray(): ByteArray {
require(length % 2 == 0) { "Hex string must have even length" }
return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
}
/** Validates if string is valid hex */
fun isValidHex(hex: String): Boolean = hex.all { it.isDigit() || it.lowercaseChar() in 'a'..'f' }
/** Generates a random hash for testing purposes */
fun generateRandomHash(): String {
val randomBytes = ByteArray(32)
secureRandom.nextBytes(randomBytes)
return randomBytes.toHexString()
}
/** Computes hash with salt for additional security */
fun hashWithSalt(input: String, salt: String): String = sha256Hex("$input:$salt")
/** Generates a random salt */
fun generateSalt(length: Int = 16): String {
val saltBytes = ByteArray(length)
secureRandom.nextBytes(saltBytes)
return saltBytes.toHexString()
}
/** Computes HMAC-SHA256 */
fun hmacSha256(key: String, message: String): String {
val keyBytes = key.toByteArray()
val messageBytes = message.toByteArray()
val blockSize = 64
val adjustedKey = when {
keyBytes.size > blockSize -> sha256(keyBytes)
keyBytes.size < blockSize -> keyBytes + ByteArray(blockSize - keyBytes.size)
else -> keyBytes
}
val outerPad = ByteArray(blockSize) { (adjustedKey[it].toInt() xor 0x5c).toByte() }
val innerPad = ByteArray(blockSize) { (adjustedKey[it].toInt() xor 0x36).toByte() }
val innerHash = sha256(innerPad + messageBytes)
val finalHash = sha256(outerPad + innerHash)
return finalHash.toHexString()
}
/** Validates hash format (64 character hex string for SHA-256) */
fun isValidSha256Hash(hash: String): Boolean = hash.length == 64 && isValidHex(hash)
/** Computes checksum for data integrity */
fun computeChecksum(data: String): String = sha256Hex(data).take(8)
/** Validates data against checksum */
fun validateChecksum(data: String, checksum: String): Boolean = computeChecksum(data) == checksum
}