diff --git a/server/src/main/kotlin/org/ccoin/utils/HashUtils.kt b/server/src/main/kotlin/org/ccoin/utils/HashUtils.kt index e69de29..9f6964d 100644 --- a/server/src/main/kotlin/org/ccoin/utils/HashUtils.kt +++ b/server/src/main/kotlin/org/ccoin/utils/HashUtils.kt @@ -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 +} +