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') } }