Compare commits

...

2 Commits

Author SHA1 Message Date
49acfddde7 bump version to 1.2.0
Some checks failed
/ publish (push) Failing after 59s
2025-12-13 01:45:23 +01:00
498a5b5826 update dependencies, use common plugin 2025-12-13 01:45:23 +01:00
6 changed files with 59 additions and 84 deletions

View File

@@ -1,12 +1,11 @@
group = "com.infendro"
version = "1.1.1"
import com.infendro.plugin.infendro
import com.infendro.plugin.token
repositories {
maven("https://git.infendro.com/api/packages/Infendro/maven")
mavenCentral()
}
group = "com.infendro"
version = "1.2.0"
plugins {
alias(libs.plugins.infendro)
alias(libs.plugins.multiplatform)
id("maven-publish")
}
@@ -18,9 +17,14 @@ kotlin {
}
linuxX64()
repositories {
infendro()
mavenCentral()
}
sourceSets {
commonMain.dependencies {
implementation(libs.random)
implementation(libs.prng)
implementation(libs.mac)
implementation(libs.hash)
implementation(libs.bytearray)
@@ -28,35 +32,11 @@ kotlin {
}
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalUnsignedTypes")
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
}
}
publishing {
repositories {
maven {
url = uri("https://git.infendro.com/api/packages/Infendro/maven")
authentication.create("header", HttpHeaderAuthentication::class)
credentials(HttpHeaderCredentials::class) {
val token = secret("git.token") ?: throw GradleException()
name = "Authorization"
value = "token $token"
}
}
}
}
fun secret(
key: String,
): String? {
val property = key
val environment = key
.uppercase()
.replace(".", "__")
val prop = properties[property] as String?
val env = System.getenv(environment)
return prop ?: env
publishing.repositories {
infendro(token)
}

View File

@@ -1,15 +1,17 @@
[versions]
kotlin = "2.1.20"
random = "1.0.0"
mac = "1.1.2"
hash = "1.2.2"
bytearray = "1.1.1"
infendro = "1.0.0"
kotlin = "2.2.21"
prng = "1.2.0"
mac = "1.2.0"
hash = "1.3.2"
bytearray = "1.2.4"
[plugins]
infendro = { id = "com.infendro.plugin", version.ref = "infendro" }
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
[libraries]
random = { module = "com.infendro:random", version.ref = "random" }
prng = { module = "com.infendro:prng", version.ref = "prng" }
mac = { module = "com.infendro:mac", version.ref = "mac" }
hash = { module = "com.infendro:hash", version.ref = "hash" }
bytearray = { module = "com.infendro:bytearray", version.ref = "bytearray" }

View File

@@ -1 +1,6 @@
rootProject.name = "otp"
pluginManagement.repositories {
maven("https://git.infendro.com/api/packages/Infendro/maven")
mavenCentral()
}

View File

@@ -1,19 +1,20 @@
package com.infendro.otp
import com.infendro.bytearray.toByteArray
import com.infendro.bytearray.toInt
import com.infendro.bytearray.toUByteArray
import com.infendro.hash.HashFunction
import com.infendro.hash.SHA1
import com.infendro.hash.sha1.SHA1
import com.infendro.mac.HMAC
import kotlin.experimental.and
import kotlin.math.pow
class HOTP(
val function: HashFunction = SHA1,
val length: Int = 6,
) {
private val hmac = HMAC(function)
fun verify(
secret: ByteArray,
secret: UByteArray,
counter: Long,
otp: String,
): Boolean {
@@ -21,33 +22,31 @@ class HOTP(
}
fun generate(
secret: ByteArray,
secret: UByteArray,
counter: Long,
): String {
if (counter < 0) throw Exception()
if (counter < 0)
throw IllegalArgumentException()
val hash = generateHash(
secret,
counter.toByteArray()
)
val hash = generateHash(secret, counter.toUByteArray())
return otp(hash)
}
private fun generateHash(
secret: ByteArray,
value: ByteArray,
): ByteArray {
return HMAC(function).hash(secret, value)
secret: UByteArray,
value: UByteArray,
): UByteArray {
return hmac.hash(secret, value)
}
private fun otp(
hash: ByteArray,
hash: UByteArray,
): String {
val offset = (hash.last() and 0xF).toInt()
val offset = (hash.last() and 0xFU).toInt()
var truncatedHash = hash
.drop(offset)
.take(4)
.drop(offset).take(4)
.toUByteArray()
.toInt() and 0x7FFFFFFF
truncatedHash %= 10.0.pow(length).toInt()

View File

@@ -1,22 +1,14 @@
package com.infendro.otp
import com.infendro.hash.*
import com.infendro.random.PRNG
import com.infendro.hash.HashFunction
import com.infendro.random.csprng.CSPRNG
object SecretGenerator {
private val random = PRNG.HMAC
class SecretGenerator(
val function: HashFunction,
) {
private val random = CSPRNG.HMAC(function)
fun generate(
algorithm: HashFunction = SHA1,
): ByteArray {
val bytes = when (algorithm) {
MD5 -> 16
SHA1 -> 20
SHA224 -> 28
SHA256 -> 32
SHA384 -> 48
SHA512 -> 64
}
return random.nextBytes(bytes)
fun generate(): ByteArray {
return random.nextBytes(function.bytes)
}
}

View File

@@ -1,20 +1,20 @@
package com.infendro.otp
import com.infendro.hash.HashFunction
import com.infendro.hash.SHA1
import com.infendro.hash.sha1.SHA1
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Instant
class TOTP(
function: HashFunction = SHA1,
length: Int = 6,
val function: HashFunction = SHA1,
val length: Int = 6,
val period: Duration = 30.seconds,
) {
val hotp = HOTP(function, length)
private val hotp = HOTP(function, length)
fun verify(
secret: ByteArray,
secret: UByteArray,
instant: Instant,
otp: String,
): Boolean {
@@ -22,13 +22,10 @@ class TOTP(
}
fun generate(
secret: ByteArray,
secret: UByteArray,
instant: Instant,
): String {
return hotp.generate(
secret,
counter(instant)
)
return hotp.generate(secret, counter(instant))
}
private fun counter(