package com.infendro.kdf import com.infendro.bytes.bytearray.xorInto import com.infendro.bytes.int.copyInto import com.infendro.hash.HashFunction import com.infendro.kdf.util.ceilDiv import com.infendro.mac.HMAC class PBKDF2( override val bytes: Int, private val iterations: Int, function: HashFunction, ) : KDF { init { require(bytes > 0) require(iterations > 0) } private val hmac = HMAC(function) override fun hashInto(value: ByteArray, salt: ByteArray, destination: ByteArray, destinationOffset: Int) { for (iteration in 1..bytes.ceilDiv(hmac.bytes)) { val offset = (iteration - 1) * hmac.bytes val block = minOf(bytes - offset, hmac.bytes) val s = ByteArray(salt.size + 4) salt.copyInto(s) iteration.copyInto(s, salt.size) val buffer = hmac.hash(value, s) buffer.copyInto(destination, destinationOffset + offset, endIndex = block) repeat(iterations - 1) { hmac.hashInto(value, buffer, buffer) buffer.xorInto(destination, destinationOffset + offset, endIndex = block) } } } }