Skip to content

Commit 08b5cdc

Browse files
committed
PR review - guard authentication validity duration.
1 parent d084ee4 commit 08b5cdc

7 files changed

Lines changed: 119 additions & 30 deletions

File tree

forgerock-auth/src/main/java/org/forgerock/android/auth/callback/Binding.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -22,6 +22,8 @@ import kotlin.time.toDuration
2222

2323
private val TAG = Binding::class.java.simpleName
2424

25+
internal const val DEFAULT_AUTHENTICATION_VALIDITY_DURATION = 5
26+
2527
/**
2628
* Device Binding interface to provide utility method for [DeviceBindingCallback] and [DeviceSigningVerifierCallback]
2729
*/
@@ -83,6 +85,16 @@ interface Binding {
8385

8486
fun setClientError(clientError: String?)
8587

88+
/**
89+
* Validates that [authenticationValidityDuration] is greater than 0.
90+
* The Android Keystore treats 0 and -1 as special values that disable the time-based window
91+
* and require fresh user authentication on every single key use.
92+
* @throws IllegalArgumentException if [value] is not greater than 0
93+
*/
94+
fun validateAuthenticationValidityDuration(value: Int) {
95+
require(value > 0) { "authenticationValidityDuration must be greater than 0" }
96+
}
97+
8698
/**
8799
* Default function to identify [DeviceAuthenticator]
88100
*/

forgerock-auth/src/main/java/org/forgerock/android/auth/callback/DeviceBindingCallback.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -105,10 +105,24 @@ open class DeviceBindingCallback : AbstractCallback, Binding {
105105
private set
106106

107107
/**
108-
* The duration (in seconds) for which the generated key remains valid for user authentication.
109-
* Passed to [CryptoKey] during key generation. Defaults to 5 seconds.
108+
* The duration in seconds for which the generated key remains valid for user authentication
109+
* without requiring a fresh biometric/credential prompt. Only affects biometric-backed key
110+
* types ([DeviceBindingAuthenticationType.BIOMETRIC_ONLY] and
111+
* [DeviceBindingAuthenticationType.BIOMETRIC_ALLOW_FALLBACK]); ignored for [DeviceBindingAuthenticationType.NONE]
112+
* and [DeviceBindingAuthenticationType.APPLICATION_PIN].
113+
*
114+
* Must be greater than 0. The Android Keystore treats 0 and -1 as special values that disable
115+
* the time-based window and require fresh user authentication on every single key use — which
116+
* is very different from any positive duration. Setting this to 0 or -1 will throw
117+
* [IllegalArgumentException].
118+
*
119+
* Defaults to [DEFAULT_AUTHENTICATION_VALIDITY_DURATION] seconds.
110120
*/
111-
var authenticationValidityDuration: Int = 5
121+
var authenticationValidityDuration: Int = DEFAULT_AUTHENTICATION_VALIDITY_DURATION
122+
set(value) {
123+
validateAuthenticationValidityDuration(value)
124+
field = value
125+
}
112126

113127
init {
114128
//If attestation is not provided, default to NONE

forgerock-auth/src/main/java/org/forgerock/android/auth/callback/DeviceSigningVerifierCallback.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -115,10 +115,24 @@ open class DeviceSigningVerifierCallback : AbstractCallback, Binding {
115115
}
116116

117117
/**
118-
* The duration (in seconds) for which the generated key remains valid for user authentication.
119-
* Passed to the underlying crypto key during key generation. Defaults to 5 seconds.
118+
* The duration in seconds for which the generated key remains valid for user authentication
119+
* without requiring a fresh biometric/credential prompt. Only affects biometric-backed key
120+
* types ([DeviceBindingAuthenticationType.BIOMETRIC_ONLY] and
121+
* [DeviceBindingAuthenticationType.BIOMETRIC_ALLOW_FALLBACK]); ignored for [DeviceBindingAuthenticationType.NONE]
122+
* and [DeviceBindingAuthenticationType.APPLICATION_PIN].
123+
*
124+
* Must be greater than 0. The Android Keystore treats 0 and -1 as special values that disable
125+
* the time-based window and require fresh user authentication on every single key use — which
126+
* is very different from any positive duration. Setting this to 0 or -1 will throw
127+
* [IllegalArgumentException].
128+
*
129+
* Defaults to [DEFAULT_AUTHENTICATION_VALIDITY_DURATION] seconds.
120130
*/
121-
var authenticationValidityDuration: Int = 5
131+
var authenticationValidityDuration: Int = DEFAULT_AUTHENTICATION_VALIDITY_DURATION
132+
set(value) {
133+
validateAuthenticationValidityDuration(value)
134+
field = value
135+
}
122136

123137
/**
124138
* Sign the challenge with bounded device keys.

forgerock-auth/src/main/java/org/forgerock/android/auth/devicebind/DeviceBindAuthenticators.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -23,6 +23,7 @@ import kotlinx.parcelize.Parcelize
2323
import org.forgerock.android.auth.CryptoKey
2424
import org.forgerock.android.auth.Logger
2525
import org.forgerock.android.auth.callback.Attestation
26+
import org.forgerock.android.auth.callback.DEFAULT_AUTHENTICATION_VALIDITY_DURATION
2627
import org.forgerock.android.auth.callback.DeviceBindingAuthenticationType
2728
import java.security.PrivateKey
2829
import java.security.Signature
@@ -217,12 +218,12 @@ interface DeviceAuthenticator {
217218
* Initialize the DeviceAuthenticator with userId, authentication validity duration and prompt
218219
* @param userId The user ID for which the keys will be generated.
219220
* @param authenticationValidityDuration The duration (in seconds) for which the generated key remains valid
220-
* for user authentication. Passed to the underlying crypto key during key generation. Defaults to 5 seconds.
221+
* for user authentication. Passed to the underlying crypto key during key generation.
221222
* @param prompt The Prompt to modify the title, subtitle, description
222223
*
223224
* @return The initialized DeviceAuthenticator instance.
224225
*/
225-
fun DeviceAuthenticator.initialize(userId: String, authenticationValidityDuration: Int, prompt: Prompt): DeviceAuthenticator {
226+
fun DeviceAuthenticator.initialize(userId: String, authenticationValidityDuration: Int, prompt: Prompt): DeviceAuthenticator {
226227

227228
//Inject objects
228229
if (this is BiometricAuthenticator) {
@@ -244,7 +245,10 @@ fun DeviceAuthenticator.initialize(userId: String, authenticationValidityDuratio
244245
*
245246
* @return The initialized DeviceAuthenticator instance.
246247
*/
247-
fun DeviceAuthenticator.initialize(userId: String, authenticationValidityDuration: Int = 5): DeviceAuthenticator {
248+
fun DeviceAuthenticator.initialize(
249+
userId: String,
250+
authenticationValidityDuration: Int = DEFAULT_AUTHENTICATION_VALIDITY_DURATION,
251+
): DeviceAuthenticator {
248252
//Inject objects
249253
if (this is CryptoAware) {
250254
this.setKey(CryptoKey(userId, authenticationValidityDuration))

forgerock-auth/src/test/java/org/forgerock/android/auth/callback/DeviceBindingCallbackTest.kt

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ class DeviceBindingCallbackTest {
319319
verify(encryptedPref, times(0)).persist(any())
320320
}
321321

322+
@Test(expected = IllegalArgumentException::class)
323+
fun testAuthenticationValidityDurationRejectsZero() {
324+
val rawContent =
325+
"{\"type\":\"DeviceBindingCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"id=demo,ou=user,dc=openam,dc=forgerock,dc=org\"},{\"name\":\"username\",\"value\":\"demo\"},{\"name\":\"authenticationType\",\"value\":\"NONE\"},{\"name\":\"challenge\",\"value\":\"CS3+g40VkHXx+dN7rpnJKhrEAvwZaYgbaXoEcpO5twM=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":60},{\"name\":\"attestation\",\"value\":false}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1deviceName\",\"value\":\"\"},{\"name\":\"IDToken1deviceId\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
326+
DeviceBindingCallback(JSONObject(rawContent), 0).authenticationValidityDuration = 0
327+
}
328+
329+
@Test(expected = IllegalArgumentException::class)
330+
fun testAuthenticationValidityDurationRejectsNegative() {
331+
val rawContent =
332+
"{\"type\":\"DeviceBindingCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"id=demo,ou=user,dc=openam,dc=forgerock,dc=org\"},{\"name\":\"username\",\"value\":\"demo\"},{\"name\":\"authenticationType\",\"value\":\"NONE\"},{\"name\":\"challenge\",\"value\":\"CS3+g40VkHXx+dN7rpnJKhrEAvwZaYgbaXoEcpO5twM=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":60},{\"name\":\"attestation\",\"value\":false}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1deviceName\",\"value\":\"\"},{\"name\":\"IDToken1deviceId\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
333+
DeviceBindingCallback(JSONObject(rawContent), 0).authenticationValidityDuration = -1
334+
}
335+
322336
@Test
323337
fun testAuthenticationValidityDurationDefaultValue() {
324338
val rawContent =
@@ -329,23 +343,27 @@ class DeviceBindingCallbackTest {
329343

330344
@Test
331345
fun testAuthenticationValidityDurationCustomValuePassedToAuthenticator() = runBlocking {
346+
// Uses BIOMETRIC_ONLY because NONE and APPLICATION_PIN ignore authenticationValidityDuration —
347+
// CryptoKey.timeout is only consumed by biometric authenticators via
348+
// setUserAuthenticationValidityDurationSeconds / setUserAuthenticationParameters.
332349
val rawContent =
333-
"{\"type\":\"DeviceBindingCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"id=demo,ou=user,dc=openam,dc=forgerock,dc=org\"},{\"name\":\"username\",\"value\":\"demo\"},{\"name\":\"authenticationType\",\"value\":\"NONE\"},{\"name\":\"challenge\",\"value\":\"CS3+g40VkHXx+dN7rpnJKhrEAvwZaYgbaXoEcpO5twM=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":60},{\"name\":\"attestation\",\"value\":false}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1deviceName\",\"value\":\"\"},{\"name\":\"IDToken1deviceId\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
350+
"{\"type\":\"DeviceBindingCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"id=demo,ou=user,dc=openam,dc=forgerock,dc=org\"},{\"name\":\"username\",\"value\":\"demo\"},{\"name\":\"authenticationType\",\"value\":\"BIOMETRIC_ONLY\"},{\"name\":\"challenge\",\"value\":\"CS3+g40VkHXx+dN7rpnJKhrEAvwZaYgbaXoEcpO5twM=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":60},{\"name\":\"attestation\",\"value\":false}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1deviceName\",\"value\":\"\"},{\"name\":\"IDToken1deviceId\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
334351
val encryptedPref = mock<DeviceBindingRepository>()
335-
val deviceAuthenticator = mock<None>()
336-
whenever(deviceAuthenticator.isSupported(any(), any())).thenReturn(true)
337-
whenever(deviceAuthenticator.generateKeys(any(), any())).thenReturn(keyPair)
338-
whenever(deviceAuthenticator.authenticate(any())).thenReturn(Success(keyPair.privateKey))
352+
val biometricAuthenticator = mock<BiometricOnly>()
353+
whenever(biometricAuthenticator.type()).thenReturn(DeviceBindingAuthenticationType.BIOMETRIC_ONLY)
354+
whenever(biometricAuthenticator.isSupported(any(), any())).thenReturn(true)
355+
whenever(biometricAuthenticator.generateKeys(any(), any())).thenReturn(keyPair)
356+
whenever(biometricAuthenticator.authenticate(any())).thenReturn(Success(keyPair.privateKey))
339357

340358
val testObject = DeviceBindingCallbackMockTest(rawContent)
341359
testObject.authenticationValidityDuration = 30
342360
testObject.testExecute(context,
343-
deviceAuthenticator = deviceAuthenticator,
361+
deviceAuthenticator = biometricAuthenticator,
344362
encryptedPreference = encryptedPref,
345363
"device_id")
346364

347365
val captor: KArgumentCaptor<CryptoKey> = argumentCaptor()
348-
verify(deviceAuthenticator).setKey(captor.capture())
366+
verify(biometricAuthenticator).setKey(captor.capture())
349367
assertEquals(30, captor.firstValue.timeout)
350368
}
351369

forgerock-auth/src/test/java/org/forgerock/android/auth/callback/DeviceSigningVerifierCallbackTest.kt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ package org.forgerock.android.auth.callback
88

99
import android.content.Context
1010
import androidx.fragment.app.FragmentActivity
11+
import androidx.test.core.app.ActivityScenario
1112
import androidx.test.core.app.ApplicationProvider
1213
import androidx.test.ext.junit.runners.AndroidJUnit4
14+
import org.forgerock.android.auth.DummyActivity
15+
import org.forgerock.android.auth.InitProvider
1316
import kotlinx.coroutines.runBlocking
17+
import org.forgerock.android.auth.devicebind.BiometricOnly
1418
import org.forgerock.android.auth.devicebind.DeviceAuthenticator
1519
import org.forgerock.android.auth.devicebind.DeviceBindFragment
1620
import org.forgerock.android.auth.devicebind.None
@@ -166,6 +170,20 @@ class DeviceSigningVerifierCallbackTest {
166170
testObject.executeAllKey(context, userKeyService) { deviceAuthenticator }
167171
}
168172

173+
@Test(expected = IllegalArgumentException::class)
174+
fun testAuthenticationValidityDurationRejectsZero() {
175+
val rawContent =
176+
"{\"type\":\"DeviceSigningVerifierCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"\"},{\"name\":\"challenge\",\"value\":\"zYwKaKnqS2YzvhXSK+sFjC7FKBoprArqz6LpJ8qe9+g=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":5}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
177+
DeviceSigningVerifierCallback(JSONObject(rawContent), 0).authenticationValidityDuration = 0
178+
}
179+
180+
@Test(expected = IllegalArgumentException::class)
181+
fun testAuthenticationValidityDurationRejectsNegative() {
182+
val rawContent =
183+
"{\"type\":\"DeviceSigningVerifierCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"\"},{\"name\":\"challenge\",\"value\":\"zYwKaKnqS2YzvhXSK+sFjC7FKBoprArqz6LpJ8qe9+g=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":5}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
184+
DeviceSigningVerifierCallback(JSONObject(rawContent), 0).authenticationValidityDuration = -1
185+
}
186+
169187
@Test
170188
fun testAuthenticationValidityDurationDefaultValue() {
171189
val rawContent =
@@ -176,24 +194,31 @@ class DeviceSigningVerifierCallbackTest {
176194

177195
@Test
178196
fun testAuthenticationValidityDurationCustomValuePassedToAuthenticator() = runBlocking {
197+
// Uses BIOMETRIC_ONLY because NONE and APPLICATION_PIN ignore authenticationValidityDuration —
198+
// CryptoKey.timeout is only consumed by biometric authenticators via
199+
// setUserAuthenticationValidityDurationSeconds / setUserAuthenticationParameters.
179200
val rawContent =
180201
"{\"type\":\"DeviceSigningVerifierCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"jey\"},{\"name\":\"challenge\",\"value\":\"zYwKaKnqS2YzvhXSK+sFjC7FKBoprArqz6LpJ8qe9+g=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":20}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
181202
val userKey =
182-
UserKey("id1", "jey", "jey", "kid", DeviceBindingAuthenticationType.NONE, System.currentTimeMillis())
183-
val noneAuthenticator = mock<None>()
184-
whenever(noneAuthenticator.isSupported(context)).thenReturn(true)
185-
whenever(noneAuthenticator.validateCustomClaims(any())).thenReturn(true)
186-
whenever(noneAuthenticator.authenticate(any())).thenReturn(Success(keyPair.privateKey))
187-
whenever(noneAuthenticator.sign(
203+
UserKey("id1", "jey", "jey", "kid", DeviceBindingAuthenticationType.BIOMETRIC_ONLY, System.currentTimeMillis())
204+
val biometricAuthenticator = mock<BiometricOnly>()
205+
whenever(biometricAuthenticator.type()).thenReturn(DeviceBindingAuthenticationType.BIOMETRIC_ONLY)
206+
whenever(biometricAuthenticator.isSupported(context)).thenReturn(true)
207+
whenever(biometricAuthenticator.validateCustomClaims(any())).thenReturn(true)
208+
whenever(biometricAuthenticator.authenticate(any())).thenReturn(Success(keyPair.privateKey))
209+
whenever(biometricAuthenticator.sign(
188210
any<Context>(), any<UserKey>(), any<PrivateKey>(), any(), any<String>(), any<Date>(), any<Map<String, Any>>()
189211
)).thenReturn("jws")
190212

213+
val scenario: ActivityScenario<DummyActivity> = ActivityScenario.launch(DummyActivity::class.java)
214+
scenario.onActivity { InitProvider.setCurrentActivity(it) }
215+
191216
val testObject = DeviceSigningVerifierCallbackMock(rawContent)
192217
testObject.authenticationValidityDuration = 30
193-
testObject.executeAuthenticate(context, userKey, noneAuthenticator)
218+
testObject.executeAuthenticate(context, userKey, biometricAuthenticator)
194219

195220
val captor: KArgumentCaptor<org.forgerock.android.auth.CryptoKey> = argumentCaptor()
196-
verify(noneAuthenticator).setKey(captor.capture())
221+
verify(biometricAuthenticator).setKey(captor.capture())
197222
assertEquals(30, captor.firstValue.timeout)
198223
}
199224

@@ -203,6 +228,7 @@ class DeviceSigningVerifierCallbackTest {
203228
return date.time;
204229
}
205230

231+
@Test
206232
fun testSignForForValidClaims() = runBlocking {
207233
val rawContent =
208234
"{\"type\":\"DeviceSigningVerifierCallback\",\"output\":[{\"name\":\"userId\",\"value\":\"jey\"},{\"name\":\"challenge\",\"value\":\"zYwKaKnqS2YzvhXSK+sFjC7FKBoprArqz6LpJ8qe9+g=\"},{\"name\":\"title\",\"value\":\"Authentication required\"},{\"name\":\"subtitle\",\"value\":\"Cryptography device binding\"},{\"name\":\"description\",\"value\":\"Please complete with biometric to proceed\"},{\"name\":\"timeout\",\"value\":20}],\"input\":[{\"name\":\"IDToken1jws\",\"value\":\"\"},{\"name\":\"IDToken1clientError\",\"value\":\"\"}]}"
@@ -224,6 +250,7 @@ class DeviceSigningVerifierCallbackTest {
224250
}
225251

226252

253+
@Test
227254
fun testSignForForInvalidClaims() = runBlocking {
228255
val errorCode = -1
229256
val invalidCustomClaims = DeviceBindingErrorStatus.InvalidCustomClaims(code = errorCode)

forgerock-core/src/main/java/org/forgerock/android/auth/CryptoKey.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -25,7 +25,7 @@ import java.security.spec.AlgorithmParameterSpec
2525
/**
2626
* Helper class to generate and sign the keys
2727
*/
28-
class CryptoKey(private var keyId: String, val timeout: Int = 5) {
28+
class CryptoKey @JvmOverloads constructor(private var keyId: String, val timeout: Int = 5) {
2929

3030
//For hashing the keyId
3131
private val hashingAlgorithm = "SHA-256"

0 commit comments

Comments
 (0)