105 lines
2.7 KiB
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
|