Compare commits
2 Commits
c14269e0c6
...
e3619a2df1
| Author | SHA1 | Date | |
|---|---|---|---|
|
e3619a2df1
|
|||
|
88d673922a
|
@@ -23,6 +23,10 @@ kotlin {
|
|||||||
implementation(libs.bytearray)
|
implementation(libs.bytearray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalUnsignedTypes")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash
|
||||||
|
|
||||||
sealed class HashFunction {
|
abstract class HashFunction {
|
||||||
abstract val bytes: Int
|
abstract val bytes: Int
|
||||||
|
@Suppress("UNUSED")
|
||||||
val bits: Int
|
val bits: Int
|
||||||
get() = bytes * 8
|
get() = bytes * 8
|
||||||
|
|
||||||
|
|||||||
113
src/commonMain/kotlin/com/infendro/hash/keccak/Keccak.kt
Normal file
113
src/commonMain/kotlin/com/infendro/hash/keccak/Keccak.kt
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package com.infendro.hash.keccak
|
||||||
|
|
||||||
|
import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN
|
||||||
|
import com.infendro.bytearray.addAll
|
||||||
|
import com.infendro.bytearray.toByteArray
|
||||||
|
import com.infendro.bytearray.toULongArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
open class Keccak internal constructor(
|
||||||
|
override val bytes: Int,
|
||||||
|
private val rate: Int,
|
||||||
|
private val domain: Byte,
|
||||||
|
) : HashFunction() {
|
||||||
|
init {
|
||||||
|
if (rate % 8 != 0) {
|
||||||
|
throw IllegalArgumentException("rate must be divisible by 8")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val rc = ulongArrayOf(
|
||||||
|
0x0000000000000001UL, 0x0000000000008082UL, 0x800000000000808aUL, 0x8000000080008000UL,
|
||||||
|
0x000000000000808bUL, 0x0000000080000001UL, 0x8000000080008081UL, 0x8000000000008009UL,
|
||||||
|
0x000000000000008aUL, 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000aUL,
|
||||||
|
0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL,
|
||||||
|
0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL,
|
||||||
|
0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL
|
||||||
|
)
|
||||||
|
|
||||||
|
private val rotation = arrayOf(
|
||||||
|
intArrayOf(0, 36, 3, 41, 18),
|
||||||
|
intArrayOf(1, 44, 10, 45, 2),
|
||||||
|
intArrayOf(62, 6, 43, 15, 61),
|
||||||
|
intArrayOf(28, 55, 25, 21, 56),
|
||||||
|
intArrayOf(27, 20, 39, 8, 14),
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun hash(
|
||||||
|
value: ByteArray,
|
||||||
|
): ByteArray {
|
||||||
|
val paddedValue = buildList {
|
||||||
|
addAll(value)
|
||||||
|
add(domain)
|
||||||
|
while ((size % rate) != (rate - 1)) {
|
||||||
|
add(0x00.toByte())
|
||||||
|
}
|
||||||
|
add(0x80.toByte())
|
||||||
|
}
|
||||||
|
|
||||||
|
val state = ULongArray(25)
|
||||||
|
|
||||||
|
// absorb
|
||||||
|
val chunks = paddedValue
|
||||||
|
.chunked(rate)
|
||||||
|
for (chunk in chunks) {
|
||||||
|
val numbers = chunk.toULongArray(LITTLE_ENDIAN)
|
||||||
|
for ((i, number) in numbers.withIndex()) {
|
||||||
|
state[i] = state[i] xor number
|
||||||
|
}
|
||||||
|
permute(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// squeeze
|
||||||
|
return buildList(bytes) {
|
||||||
|
var i = 0
|
||||||
|
while (size < bytes) {
|
||||||
|
if (i == rate / 8) {
|
||||||
|
permute(state)
|
||||||
|
i = 0
|
||||||
|
}
|
||||||
|
addAll(
|
||||||
|
state[i++].toByteArray(LITTLE_ENDIAN)
|
||||||
|
.take(min(bytes - size, 8))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.toByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun permute(
|
||||||
|
a: ULongArray,
|
||||||
|
) {
|
||||||
|
val b = ULongArray(25)
|
||||||
|
val c = ULongArray(5)
|
||||||
|
val d = ULongArray(5)
|
||||||
|
|
||||||
|
repeat(24) { round ->
|
||||||
|
// θ
|
||||||
|
for (x in 0..4) {
|
||||||
|
c[x] = a[x] xor a[x + 5] xor a[x + 10] xor a[x + 15] xor a[x + 20]
|
||||||
|
}
|
||||||
|
for (x in 0..4) {
|
||||||
|
d[x] = c[(x + 4) % 5] xor c[(x + 1) % 5].rotateLeft(1)
|
||||||
|
}
|
||||||
|
for (x in 0..4) for (y in 0..4) {
|
||||||
|
a[x + 5 * y] = a[x + 5 * y] xor d[x]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ρ and π
|
||||||
|
for (x in 0..4) for (y in 0..4) {
|
||||||
|
b[y + 5 * ((2 * x + 3 * y) % 5)] = a[x + 5 * y].rotateLeft(rotation[x][y])
|
||||||
|
}
|
||||||
|
|
||||||
|
// χ
|
||||||
|
for (x in 0..4) for (y in 0..4) {
|
||||||
|
a[x + 5 * y] = b[x + 5 * y] xor ((b[((x + 1) % 5) + 5 * y].inv()) and b[((x + 2) % 5) + 5 * y])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ι
|
||||||
|
a[0] = a[0] xor rc[round]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.infendro.hash.keccak.sha3
|
||||||
|
|
||||||
|
import com.infendro.hash.keccak.Keccak
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
object `SHA3-224` : Keccak(28, 144, 0x06)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.infendro.hash.keccak.sha3
|
||||||
|
|
||||||
|
import com.infendro.hash.keccak.Keccak
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
object `SHA3-256` : Keccak(32, 136, 0x06)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.infendro.hash.keccak.sha3
|
||||||
|
|
||||||
|
import com.infendro.hash.keccak.Keccak
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
object `SHA3-384` : Keccak(48, 104, 0x06)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.infendro.hash.keccak.sha3
|
||||||
|
|
||||||
|
import com.infendro.hash.keccak.Keccak
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
object `SHA3-512` : Keccak(64, 72, 0x06)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.infendro.hash.keccak.shake
|
||||||
|
|
||||||
|
import com.infendro.hash.keccak.Keccak
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
class SHAKE128(bytes: Int) : Keccak(bytes, 168, 0x1F)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.infendro.hash.keccak.shake
|
||||||
|
|
||||||
|
import com.infendro.hash.keccak.Keccak
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
|
class SHAKE256(bytes: Int) : Keccak(bytes, 136, 0x1F)
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash.md
|
||||||
|
|
||||||
import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN
|
import com.infendro.bytearray.ByteOrder
|
||||||
import com.infendro.bytearray.addAll
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.bytearray.toByteArray
|
import com.infendro.bytearray.toByteArray
|
||||||
import com.infendro.bytearray.toUIntArray
|
import com.infendro.bytearray.toUIntArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
object MD5 : HashFunction() {
|
object MD5 : HashFunction() {
|
||||||
override val bytes: Int
|
override val bytes: Int
|
||||||
get() = 16
|
get() = 16
|
||||||
@@ -62,14 +64,14 @@ object MD5 : HashFunction() {
|
|||||||
while (size % 64 != 56) {
|
while (size % 64 != 56) {
|
||||||
add(0x00.toByte())
|
add(0x00.toByte())
|
||||||
}
|
}
|
||||||
addAll(ml.toByteArray(LITTLE_ENDIAN))
|
addAll(ml.toByteArray(ByteOrder.LITTLE_ENDIAN))
|
||||||
}
|
}
|
||||||
|
|
||||||
val chunks = paddedValue
|
val chunks = paddedValue
|
||||||
.chunked(64)
|
.chunked(64)
|
||||||
for (chunk in chunks) {
|
for (chunk in chunks) {
|
||||||
val w = buildList {
|
val w = buildList {
|
||||||
addAll(chunk.toUIntArray(LITTLE_ENDIAN))
|
addAll(chunk.toUIntArray(ByteOrder.LITTLE_ENDIAN))
|
||||||
}
|
}
|
||||||
|
|
||||||
var a = a0
|
var a = a0
|
||||||
@@ -103,10 +105,10 @@ object MD5 : HashFunction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return byteArrayOf(
|
return byteArrayOf(
|
||||||
*a0.toByteArray(LITTLE_ENDIAN),
|
*a0.toByteArray(ByteOrder.LITTLE_ENDIAN),
|
||||||
*b0.toByteArray(LITTLE_ENDIAN),
|
*b0.toByteArray(ByteOrder.LITTLE_ENDIAN),
|
||||||
*c0.toByteArray(LITTLE_ENDIAN),
|
*c0.toByteArray(ByteOrder.LITTLE_ENDIAN),
|
||||||
*d0.toByteArray(LITTLE_ENDIAN),
|
*d0.toByteArray(ByteOrder.LITTLE_ENDIAN),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash.sha1
|
||||||
|
|
||||||
import com.infendro.bytearray.addAll
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.bytearray.toByteArray
|
import com.infendro.bytearray.toByteArray
|
||||||
import com.infendro.bytearray.toUIntArray
|
import com.infendro.bytearray.toUIntArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
object SHA1 : HashFunction() {
|
object SHA1 : HashFunction() {
|
||||||
override val bytes: Int
|
override val bytes: Int
|
||||||
get() = 20
|
get() = 20
|
||||||
@@ -80,4 +82,4 @@ object SHA1 : HashFunction() {
|
|||||||
*h4.toByteArray(),
|
*h4.toByteArray(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash.sha2
|
||||||
|
|
||||||
import com.infendro.bytearray.addAll
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.bytearray.toByteArray
|
import com.infendro.bytearray.toByteArray
|
||||||
import com.infendro.bytearray.toUIntArray
|
import com.infendro.bytearray.toUIntArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
|
||||||
object SHA224 : HashFunction() {
|
@Suppress("UNUSED")
|
||||||
|
object `SHA-224` : HashFunction() {
|
||||||
override val bytes: Int
|
override val bytes: Int
|
||||||
get() = 28
|
get() = 28
|
||||||
|
|
||||||
@@ -63,10 +65,10 @@ object SHA224 : HashFunction() {
|
|||||||
var h = h7
|
var h = h7
|
||||||
|
|
||||||
for (i in 0..<64) {
|
for (i in 0..<64) {
|
||||||
|
val s0 = a.rotateRight(2) xor a.rotateRight(13) xor a.rotateRight(22)
|
||||||
val s1 = e.rotateRight(6) xor e.rotateRight(11) xor e.rotateRight(25)
|
val s1 = e.rotateRight(6) xor e.rotateRight(11) xor e.rotateRight(25)
|
||||||
val ch = (e and f) xor (e.inv() and g)
|
val ch = (e and f) xor (e.inv() and g)
|
||||||
val temp1 = h + s1 + ch + k[i] + w[i]
|
val temp1 = h + s1 + ch + k[i] + w[i]
|
||||||
val s0 = a.rotateRight(2) xor a.rotateRight(13) xor a.rotateRight(22)
|
|
||||||
val maj = (a and b) xor (a and c) xor (b and c)
|
val maj = (a and b) xor (a and c) xor (b and c)
|
||||||
val temp2 = s0 + maj
|
val temp2 = s0 + maj
|
||||||
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash.sha2
|
||||||
|
|
||||||
import com.infendro.bytearray.addAll
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.bytearray.toByteArray
|
import com.infendro.bytearray.toByteArray
|
||||||
import com.infendro.bytearray.toUIntArray
|
import com.infendro.bytearray.toUIntArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
|
||||||
object SHA256 : HashFunction() {
|
@Suppress("UNUSED")
|
||||||
|
object `SHA-256` : HashFunction() {
|
||||||
override val bytes: Int
|
override val bytes: Int
|
||||||
get() = 32
|
get() = 32
|
||||||
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash.sha2
|
||||||
|
|
||||||
import com.infendro.bytearray.addAll
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.bytearray.toByteArray
|
import com.infendro.bytearray.toByteArray
|
||||||
import com.infendro.bytearray.toULongArray
|
import com.infendro.bytearray.toULongArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
|
||||||
object SHA384 : HashFunction() {
|
@Suppress("UNUSED")
|
||||||
|
object `SHA-384` : HashFunction() {
|
||||||
override val bytes: Int
|
override val bytes: Int
|
||||||
get() = 48
|
get() = 48
|
||||||
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.infendro.hash
|
package com.infendro.hash.sha2
|
||||||
|
|
||||||
import com.infendro.bytearray.addAll
|
import com.infendro.bytearray.addAll
|
||||||
import com.infendro.bytearray.toByteArray
|
import com.infendro.bytearray.toByteArray
|
||||||
import com.infendro.bytearray.toULongArray
|
import com.infendro.bytearray.toULongArray
|
||||||
|
import com.infendro.hash.HashFunction
|
||||||
|
|
||||||
object SHA512 : HashFunction() {
|
@Suppress("UNUSED")
|
||||||
|
object `SHA-512` : HashFunction() {
|
||||||
override val bytes: Int
|
override val bytes: Int
|
||||||
get() = 64
|
get() = 64
|
||||||
|
|
||||||
Reference in New Issue
Block a user