Files
otp.kt/src/commonMain/kotlin/com/infendro/otp/HOTP.kt
2026-03-12 11:25:47 +01:00

33 lines
959 B
Kotlin

package com.infendro.otp
import com.infendro.bytes.bytearray.toInt
import com.infendro.bytes.long.toByteArray
import com.infendro.hash.HashFunction
import com.infendro.hash.sha1.SHA1
import com.infendro.mac.HMAC
import com.infendro.otp.util.pow
import kotlin.experimental.and
class HOTP(
val function: HashFunction = SHA1(),
val length: Int = 6,
) {
private val hmac = HMAC(function)
fun generate(secret: ByteArray, counter: Long): String {
require(counter >= 0)
return otp(secret, counter)
}
fun verify(secret: ByteArray, counter: Long, otp: String): Boolean {
return generate(secret, counter) == otp
}
private fun otp(secret: ByteArray, counter: Long): String {
val hash = hmac.hash(secret, counter.toByteArray())
val offset = (hash.last() and 0xF).toInt()
val otp = (hash.toInt(offset) and 0x7FFFFFFF) % 10.pow(length)
return "$otp".padStart(length, '0')
}
}