Skip to content

Instantly share code, notes, and snippets.

@iseki0
Last active April 7, 2023 06:15
Show Gist options
  • Save iseki0/493f7a7ab5f49e829d578f2baa3e1f40 to your computer and use it in GitHub Desktop.
Save iseki0/493f7a7ab5f49e829d578f2baa3e1f40 to your computer and use it in GitHub Desktop.
@file:Suppress("DuplicatedCode", "MemberVisibilityCanBePrivate", "DataClassPrivateConstructor")
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.serialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.io.File
import java.io.InputStream
import java.security.MessageDigest
import java.util.HexFormat
private fun decodeInt(a: ByteArray, off: Int): Int = (a[off * 4].toInt() shl 24) or
(a[off * 4 + 1].toInt() and 0xff shl 16) or
(a[off * 4 + 2].toInt() and 0xff shl 8) or
(a[off * 4 + 3].toInt() and 0xff)
private fun encodeInt(a: ByteArray, off: Int, i: Int) {
a[off * 4] = (i shr 24).toByte()
a[off * 4 + 1] = (i shr 16).toByte()
a[off * 4 + 2] = (i shr 8).toByte()
a[off * 4 + 3] = i.toByte()
}
private fun encodeHex(a: ByteArray) = HexFormat.of().formatHex(a)!!
private fun decodeHex(s: String) = HexFormat.of().parseHex(s)!!
//fun generateTypes(len: Int, name: String): String {
// val blen = len * 4
// val fields = (0 until len).joinToString(separator = "\n") { "private val i$it: Int," }
// val decodes = (1 until len).joinToString(separator = "\n") { "decodeInt(a, $it)," }
// val encodes = (0 until len).joinToString(separator = "\n") { "encodeInt(it, $it, i$it)" }
//
// return """
// @JvmRecord
// @Serializable($name.Serializer::class)
// data class $name private constructor(
// $fields
// ) {
// fun toBytes() = ByteArray($blen).also {
// $encodes
// }
//
// override fun toString(): String = encodeHex(toBytes())
//
// constructor(a: ByteArray) : this(
// decodeInt(a, 0).also { require(a.size == $blen) },
// $decodes
// )
//
// constructor(a: String) : this(decodeHex(a))
//
// internal object Serializer : KSerializer<$name> {
// override val descriptor: SerialDescriptor = serialDescriptor<String>()
//
// override fun deserialize(decoder: Decoder): $name = $name(decoder.decodeString())
//
// override fun serialize(encoder: Encoder, value: $name) {
// encoder.encodeString(value.toString())
// }
//
// }
// }
//
// """.trimIndent()
//}
//
//fun main() {
// generateTypes(4, "MD5").also(::println)
// generateTypes(5, "Sha1").also(::println)
// generateTypes(7, "Sha224").also(::println)
// generateTypes(8, "Sha256").also(::println)
// generateTypes(12, "Sha384").also(::println)
// generateTypes(16, "Sha512").also(::println)
//}
@JvmRecord
@Serializable(MD5.Serializer::class)
data class MD5 private constructor(
private val i0: Int,
private val i1: Int,
private val i2: Int,
private val i3: Int,
) {
fun toBytes() = ByteArray(16).also {
encodeInt(it, 0, i0)
encodeInt(it, 1, i1)
encodeInt(it, 2, i2)
encodeInt(it, 3, i3)
}
override fun toString(): String = encodeHex(toBytes())
constructor(a: ByteArray) : this(
decodeInt(a, 0).also { require(a.size == 16) },
decodeInt(a, 1),
decodeInt(a, 2),
decodeInt(a, 3),
)
constructor(a: String) : this(decodeHex(a))
internal object Serializer : KSerializer<MD5> {
override val descriptor: SerialDescriptor = serialDescriptor<String>()
override fun deserialize(decoder: Decoder): MD5 = MD5(decoder.decodeString())
override fun serialize(encoder: Encoder, value: MD5) {
encoder.encodeString(value.toString())
}
}
}
@JvmRecord
@Serializable(Sha1.Serializer::class)
data class Sha1 private constructor(
private val i0: Int,
private val i1: Int,
private val i2: Int,
private val i3: Int,
private val i4: Int,
) {
fun toBytes() = ByteArray(20).also {
encodeInt(it, 0, i0)
encodeInt(it, 1, i1)
encodeInt(it, 2, i2)
encodeInt(it, 3, i3)
encodeInt(it, 4, i4)
}
override fun toString(): String = encodeHex(toBytes())
constructor(a: ByteArray) : this(
decodeInt(a, 0).also { require(a.size == 20) },
decodeInt(a, 1),
decodeInt(a, 2),
decodeInt(a, 3),
decodeInt(a, 4),
)
constructor(a: String) : this(decodeHex(a))
internal object Serializer : KSerializer<Sha1> {
override val descriptor: SerialDescriptor = serialDescriptor<String>()
override fun deserialize(decoder: Decoder): Sha1 = Sha1(decoder.decodeString())
override fun serialize(encoder: Encoder, value: Sha1) {
encoder.encodeString(value.toString())
}
}
}
@JvmRecord
@Serializable(Sha224.Serializer::class)
data class Sha224 private constructor(
private val i0: Int,
private val i1: Int,
private val i2: Int,
private val i3: Int,
private val i4: Int,
private val i5: Int,
private val i6: Int,
) {
fun toBytes() = ByteArray(28).also {
encodeInt(it, 0, i0)
encodeInt(it, 1, i1)
encodeInt(it, 2, i2)
encodeInt(it, 3, i3)
encodeInt(it, 4, i4)
encodeInt(it, 5, i5)
encodeInt(it, 6, i6)
}
override fun toString(): String = encodeHex(toBytes())
constructor(a: ByteArray) : this(
decodeInt(a, 0).also { require(a.size == 28) },
decodeInt(a, 1),
decodeInt(a, 2),
decodeInt(a, 3),
decodeInt(a, 4),
decodeInt(a, 5),
decodeInt(a, 6),
)
constructor(a: String) : this(decodeHex(a))
internal object Serializer : KSerializer<Sha224> {
override val descriptor: SerialDescriptor = serialDescriptor<String>()
override fun deserialize(decoder: Decoder): Sha224 = Sha224(decoder.decodeString())
override fun serialize(encoder: Encoder, value: Sha224) {
encoder.encodeString(value.toString())
}
}
}
@JvmRecord
@Serializable(Sha256.Serializer::class)
data class Sha256 private constructor(
private val i0: Int,
private val i1: Int,
private val i2: Int,
private val i3: Int,
private val i4: Int,
private val i5: Int,
private val i6: Int,
private val i7: Int,
) {
fun toBytes() = ByteArray(32).also {
encodeInt(it, 0, i0)
encodeInt(it, 1, i1)
encodeInt(it, 2, i2)
encodeInt(it, 3, i3)
encodeInt(it, 4, i4)
encodeInt(it, 5, i5)
encodeInt(it, 6, i6)
encodeInt(it, 7, i7)
}
override fun toString(): String = encodeHex(toBytes())
constructor(a: ByteArray) : this(
decodeInt(a, 0).also { require(a.size == 32) },
decodeInt(a, 1),
decodeInt(a, 2),
decodeInt(a, 3),
decodeInt(a, 4),
decodeInt(a, 5),
decodeInt(a, 6),
decodeInt(a, 7),
)
constructor(a: String) : this(decodeHex(a))
internal object Serializer : KSerializer<Sha256> {
override val descriptor: SerialDescriptor = serialDescriptor<String>()
override fun deserialize(decoder: Decoder): Sha256 = Sha256(decoder.decodeString())
override fun serialize(encoder: Encoder, value: Sha256) {
encoder.encodeString(value.toString())
}
}
}
@JvmRecord
@Serializable(Sha384.Serializer::class)
data class Sha384 private constructor(
private val i0: Int,
private val i1: Int,
private val i2: Int,
private val i3: Int,
private val i4: Int,
private val i5: Int,
private val i6: Int,
private val i7: Int,
private val i8: Int,
private val i9: Int,
private val i10: Int,
private val i11: Int,
) {
fun toBytes() = ByteArray(48).also {
encodeInt(it, 0, i0)
encodeInt(it, 1, i1)
encodeInt(it, 2, i2)
encodeInt(it, 3, i3)
encodeInt(it, 4, i4)
encodeInt(it, 5, i5)
encodeInt(it, 6, i6)
encodeInt(it, 7, i7)
encodeInt(it, 8, i8)
encodeInt(it, 9, i9)
encodeInt(it, 10, i10)
encodeInt(it, 11, i11)
}
override fun toString(): String = encodeHex(toBytes())
constructor(a: ByteArray) : this(
decodeInt(a, 0).also { require(a.size == 48) },
decodeInt(a, 1),
decodeInt(a, 2),
decodeInt(a, 3),
decodeInt(a, 4),
decodeInt(a, 5),
decodeInt(a, 6),
decodeInt(a, 7),
decodeInt(a, 8),
decodeInt(a, 9),
decodeInt(a, 10),
decodeInt(a, 11),
)
constructor(a: String) : this(decodeHex(a))
internal object Serializer : KSerializer<Sha384> {
override val descriptor: SerialDescriptor = serialDescriptor<String>()
override fun deserialize(decoder: Decoder): Sha384 = Sha384(decoder.decodeString())
override fun serialize(encoder: Encoder, value: Sha384) {
encoder.encodeString(value.toString())
}
}
}
@JvmRecord
@Serializable(Sha512.Serializer::class)
data class Sha512 private constructor(
private val i0: Int,
private val i1: Int,
private val i2: Int,
private val i3: Int,
private val i4: Int,
private val i5: Int,
private val i6: Int,
private val i7: Int,
private val i8: Int,
private val i9: Int,
private val i10: Int,
private val i11: Int,
private val i12: Int,
private val i13: Int,
private val i14: Int,
private val i15: Int,
) {
fun toBytes() = ByteArray(64).also {
encodeInt(it, 0, i0)
encodeInt(it, 1, i1)
encodeInt(it, 2, i2)
encodeInt(it, 3, i3)
encodeInt(it, 4, i4)
encodeInt(it, 5, i5)
encodeInt(it, 6, i6)
encodeInt(it, 7, i7)
encodeInt(it, 8, i8)
encodeInt(it, 9, i9)
encodeInt(it, 10, i10)
encodeInt(it, 11, i11)
encodeInt(it, 12, i12)
encodeInt(it, 13, i13)
encodeInt(it, 14, i14)
encodeInt(it, 15, i15)
}
override fun toString(): String = encodeHex(toBytes())
constructor(a: ByteArray) : this(
decodeInt(a, 0).also { require(a.size == 64) },
decodeInt(a, 1),
decodeInt(a, 2),
decodeInt(a, 3),
decodeInt(a, 4),
decodeInt(a, 5),
decodeInt(a, 6),
decodeInt(a, 7),
decodeInt(a, 8),
decodeInt(a, 9),
decodeInt(a, 10),
decodeInt(a, 11),
decodeInt(a, 12),
decodeInt(a, 13),
decodeInt(a, 14),
decodeInt(a, 15),
)
constructor(a: String) : this(decodeHex(a))
internal object Serializer : KSerializer<Sha512> {
override val descriptor: SerialDescriptor = serialDescriptor<String>()
override fun deserialize(decoder: Decoder): Sha512 = Sha512(decoder.decodeString())
override fun serialize(encoder: Encoder, value: Sha512) {
encoder.encodeString(value.toString())
}
}
}
internal fun MessageDigest.hashStream(inputStream: InputStream): ByteArray {
val buffer = ByteArray(4 * 1024)
var read: Int
while (inputStream.read(buffer).also { read = it } > -1) {
update(buffer, 0, read)
}
return digest()
}
private fun getSha256() = MessageDigest.getInstance("SHA-256")!!
fun InputStream.sha256() = getSha256().hashStream(this).let(::Sha256)
fun File.sha256() = inputStream().use { it.sha256() }
fun ByteArray.sha256() = getSha256().digest(this).let(::Sha1)
private fun getSha1() = MessageDigest.getInstance("SHA-1")!!
fun InputStream.sha1() = getSha1().hashStream(this).let(::Sha1)
fun File.sha1() = inputStream().use { it.sha1() }
fun ByteArray.sha1() = getSha1().digest(this).let(::Sha1)
private fun getMD5() = MessageDigest.getInstance("MD5")!!
fun InputStream.md5() = getMD5().hashStream(this).let(::MD5)
fun File.md5() = inputStream().use { it.md5() }
fun ByteArray.md5() = getMD5().digest(this).let(::MD5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment