Coverage Summary for Class: HmacKt (it.unibo.tuprolog.argumentation.parallel.federation)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| HmacKt |
100%
(1/1)
|
100%
(3/3)
|
100%
(18/18)
|
100%
(124/124)
|
100%
(815/815)
|
package it.unibo.tuprolog.argumentation.parallel.federation
/**
* The HMAC-SHA-256 of [message] with [key] (RFC 2104, FIPS 180-4), in hexadecimal: written here, as the platforms
* share no synchronous one (the Web Crypto of browsers is asynchronous)
*/
internal fun hmac(
key: String,
message: String,
): String {
val keyBytes = key.encodeToByteArray().let { if (it.size > BLOCK) sha256(it) else it }.copyOf(BLOCK)
val inner = sha256(ByteArray(BLOCK) { (keyBytes[it].toInt() xor 0x36).toByte() } + message.encodeToByteArray())
val outer = sha256(ByteArray(BLOCK) { (keyBytes[it].toInt() xor 0x5c).toByte() } + inner)
return outer.joinToString("") { (it.toInt() and 0xff).toString(16).padStart(2, '0') }
}
// The bytes of a block of SHA-256
private const val BLOCK = 64
// The first 32 bits of the fractional parts of the cube roots of the first 64 primes
private val ROUNDS =
longArrayOf(
0x428a2f98,
0x71374491,
0xb5c0fbcf,
0xe9b5dba5,
0x3956c25b,
0x59f111f1,
0x923f82a4,
0xab1c5ed5,
0xd807aa98,
0x12835b01,
0x243185be,
0x550c7dc3,
0x72be5d74,
0x80deb1fe,
0x9bdc06a7,
0xc19bf174,
0xe49b69c1,
0xefbe4786,
0x0fc19dc6,
0x240ca1cc,
0x2de92c6f,
0x4a7484aa,
0x5cb0a9dc,
0x76f988da,
0x983e5152,
0xa831c66d,
0xb00327c8,
0xbf597fc7,
0xc6e00bf3,
0xd5a79147,
0x06ca6351,
0x14292967,
0x27b70a85,
0x2e1b2138,
0x4d2c6dfc,
0x53380d13,
0x650a7354,
0x766a0abb,
0x81c2c92e,
0x92722c85,
0xa2bfe8a1,
0xa81a664b,
0xc24b8b70,
0xc76c51a3,
0xd192e819,
0xd6990624,
0xf40e3585,
0x106aa070,
0x19a4c116,
0x1e376c08,
0x2748774c,
0x34b0bcb5,
0x391c0cb3,
0x4ed8aa4a,
0x5b9cca4f,
0x682e6ff3,
0x748f82ee,
0x78a5636f,
0x84c87814,
0x8cc70208,
0x90befffa,
0xa4506ceb,
0xbef9a3f7,
0xc67178f2,
).map { it.toInt() }.toIntArray()
// The SHA-256 digest of [data]
private fun sha256(data: ByteArray): ByteArray {
val hash =
longArrayOf(
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19,
).map { it.toInt() }.toIntArray()
// the data, a 1 bit, zeros, and its length in bits, to a whole number of blocks
val blocks = (data.size + 9 + BLOCK - 1) / BLOCK
val padded = data.copyOf(blocks * BLOCK)
padded[data.size] = 0x80.toByte()
val bits = data.size.toLong() * 8
for (i in 0 until 8) padded[padded.size - 1 - i] = (bits ushr (8 * i)).toByte()
val words = IntArray(64)
for (block in 0 until blocks) {
for (t in 0 until 16) {
val at = block * BLOCK + t * 4
words[t] =
((padded[at].toInt() and 0xff) shl 24) or ((padded[at + 1].toInt() and 0xff) shl 16) or
((padded[at + 2].toInt() and 0xff) shl 8) or (padded[at + 3].toInt() and 0xff)
}
for (t in 16 until 64) {
val s0 = words[t - 15].rotateRight(7) xor words[t - 15].rotateRight(18) xor (words[t - 15] ushr 3)
val s1 = words[t - 2].rotateRight(17) xor words[t - 2].rotateRight(19) xor (words[t - 2] ushr 10)
words[t] = words[t - 16] + s0 + words[t - 7] + s1
}
var a = hash[0]
var b = hash[1]
var c = hash[2]
var d = hash[3]
var e = hash[4]
var f = hash[5]
var g = hash[6]
var h = hash[7]
for (t in 0 until 64) {
val t1 =
h + (e.rotateRight(6) xor e.rotateRight(11) xor e.rotateRight(25)) + ((e and f) xor (e.inv() and g)) + ROUNDS[t] + words[t]
val t2 = (a.rotateRight(2) xor a.rotateRight(13) xor a.rotateRight(22)) + ((a and b) xor (a and c) xor (b and c))
h = g
g = f
f = e
e = d + t1
d = c
c = b
b = a
a = t1 + t2
}
hash[0] += a
hash[1] += b
hash[2] += c
hash[3] += d
hash[4] += e
hash[5] += f
hash[6] += g
hash[7] += h
}
return ByteArray(32) { (hash[it / 4] ushr (24 - 8 * (it % 4))).toByte() }
}