gs-std/src/main/scala/gs/std/v0/MD5.scala

105 lines
2.7 KiB
Scala

package gs.std.v0
import java.security.MessageDigest
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
/**
* Opaque type representing a MD5 hash.
*/
opaque type MD5 = Array[Byte]
/**
* Opaque type representing a MD5 hash.
*/
object MD5:
/**
* MD5 hashes are exactly 16 bytes.
*/
final val NumberOfBytes: ByteCount = ByteCount(16)
/**
* The algorithm name is "MD5".
*/
final val Algorithm: String = "MD5"
/**
* Instantiate a [[MD5]] from the given byte array. This function does not
* know whether the array is actually a calculated hash.
*
* Typically used for loading pre-validated hashes (e.g. from a database).
*
* @param bytes The bytes - must contain exactly 16 bytes.
* @return The new [[MD5]] instance.
*/
def fromBytes(bytes: Array[Byte]): MD5 =
if NumberOfBytes.equal(bytes.length) then
bytes
else
throw IllegalArgumentException(s"MD5 values must be exactly $NumberOfBytes bytes.")
/**
* Calculate the MD5 hash for the given byte array.
*
* @param data The byte array.
* @return The calculated [[MD5]].
*/
def calculate(data: Array[Byte]): MD5 =
MessageDigest.getInstance(Algorithm).digest(data)
/*
* Calculate the MD5 hash for the given string.
*
* @param data The string data.
* @param charset The character set of the string. Defaults to UTF-8.
* @return The calculated [[MD5]].
*/
def calculate(data: String, charset: Charset = StandardCharsets.UTF_8): MD5 =
calculate(data.getBytes(charset))
extension (md5: MD5)
/**
* @return The underlying byte array.
*/
def unwrap(): Array[Byte] = md5
/**
* @return The underlying byte array.
*/
def toBytes(): Array[Byte] = md5
/**
* Get the byte at the given index (0 to 15).
*
* Throws an exception if an out-of-bound index is given.
*
* @param index The byte index (0 to 15).
* @return The byte at the specified index.
*/
def getByte(index: Int): Byte =
if index < 0 || index >= NumberOfBytes.unwrap() then
throw IndexOutOfBoundsException(s"Index $index out of MD5 bound of $NumberOfBytes bytes.")
else
md5.apply(index)
/**
* Determine if this hash is the same as some other hash. Compares each byte
* in order.
*
* @param other The [[MD5]] to compare against.
* @return True if the hashes are identical, false otherwise.
*/
def isSame(other: MD5): Boolean = md5.sameElements(other)
/**
* @return This hash encoded to a Base64 string.
*/
def base64(): EncodedString = Base64Encoder.encode(md5)
/**
* @return This hash encoded to a Hexadecimal string.
*/
def hex(): EncodedString = HexEncoder.encode(md5)
end MD5