Skip to content

Commit

Permalink
fix key agreement on lower android versions for SW keys
Browse files Browse the repository at this point in the history
  • Loading branch information
JesusMcCloud committed Jan 14, 2025
1 parent f77d295 commit b6a44a9
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ import at.asitplus.signum.supreme.sign.makeVerifier
import at.asitplus.signum.supreme.sign.verify
import at.asitplus.cryptotest.theme.AppTheme
import at.asitplus.cryptotest.theme.LocalThemeIsDark
import at.asitplus.signum.indispensable.CryptoPrivateKey
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.jsonEncoded
import at.asitplus.signum.supreme.SecretExposure
import at.asitplus.signum.supreme.agreement.keyAgreement
import at.asitplus.signum.supreme.asKmmResult
import at.asitplus.signum.supreme.os.PlatformSignerConfigurationBase
Expand Down Expand Up @@ -460,22 +462,37 @@ internal fun App() {
Napier.w { "input: $inputData" }
Napier.w { "signingKey: $currentKey" }
CoroutineScope(context).launch {
val alg= keyAlgorithm.algorithm as SignatureAlgorithm.ECDSA
val eph= Signer.Ephemeral {
ec {
curve = alg.requiredCurve
?: ECCurve.entries.find { it.nativeDigest == alg.digest }!!
digests = setOf(alg.digest)
val alg = keyAlgorithm.algorithm as SignatureAlgorithm.ECDSA
val eph = Signer.Ephemeral {
ec {
curve = alg.requiredCurve
?: ECCurve.entries.find { it.nativeDigest == alg.digest }!!
digests = setOf(alg.digest)

}
}.getOrThrow()
val pub = eph.publicKey as CryptoPublicKey.EC
Napier.i { "Got Pubkey: $pub" }
val agreed= pub.keyAgreement( currentSigner!!.getOrThrow() as Signer.ECDSA).getOrThrow()

val agreed3 =
(currentSigner!!.getOrThrow().publicKey as CryptoPublicKey.EC).keyAgreement(
@OptIn(SecretExposure::class)
eph.exportPrivateKey()
.getOrThrow() as CryptoPrivateKey.WithPublicKey<CryptoPublicKey.EC>
).getOrThrow()
Napier.i { "AGREED3: ${agreed3.encodeBase64()}" }


val agreed =
pub.keyAgreement(currentSigner!!.getOrThrow() as Signer.ECDSA)
.getOrThrow()
Napier.i { "AGREED1: ${agreed.encodeBase64()}" }
val agreed2 = ( currentSigner!!.getOrThrow() as Signer.ECDSA).keyAgreement(pub).getOrThrow()
val agreed2 =
(currentSigner!!.getOrThrow() as Signer.ECDSA).keyAgreement(pub)
.getOrThrow()
Napier.i { "AGREED2: ${agreed2.encodeBase64()}" }
}

}

},

Expand Down
7 changes: 6 additions & 1 deletion docs/docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ from certain (otherwise) hard requirements for Devices launched with later Andro
Hence, a device launched with Android&nbsp;10, and later updated to Android&nbsp;12 may still not support key agreement in
hardware.
The Supreme crypto provider will return a failure, in if key agreement is not supported in hardware.
TODO: will fail for auth on every use! Bug in Android; fix hidden behind a feature flag

In addition, all Android versions supporting key agreement contain a bug, which makes it impossible
to perform key agreement using an auth-on-every-use key. The bugfix is hidden behind a disabled-by-default
feature flag in the Android source code.
**Hence, either don't require biometric authentication for key you want to use for key agreement or
use a timeout of at leas one second!**

## Supported Algorithms

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ actual suspend fun Signer.ECDSA.performAgreement(
agreement.doPhase(publicKey.toJcaPublicKey().getOrThrow(), true)
agreement.generateSecret()
} else {
javax.crypto.KeyAgreement.getInstance("ECDH", "AndroidKeyStore").also {
javax.crypto.KeyAgreement.getInstance("ECDH").also {
@OptIn(HazardousMaterials::class)
it.init(jcaPrivateKey)
it.doPhase(publicKey.toJcaPublicKey().getOrThrow(), true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ suspend fun CryptoPublicKey.EC.keyAgreement(
* Elliptic-curve Diffie-Hellman key agreement.
* Curves of public key and signer need to match!
*/
suspend fun CryptoPrivateKey.WithPublicKey<CryptoPublicKey.EC>.keyAgreement(publicKey: CryptoPublicKey.EC) = catching {
(SignatureAlgorithm.ECDSA(this.publicKey.curve.nativeDigest, this.publicKey.curve).signerFor(this)
suspend fun CryptoPrivateKey.WithPublicKey<CryptoPublicKey.EC>.keyAgreement(publicKey: CryptoPublicKey.EC) =
(SignatureAlgorithm.ECDSA(this.publicKey.curve.nativeDigest, this.publicKey.curve)
.signerFor(this)
.getOrThrow() as Signer.ECDSA).keyAgreement(
publicKey
)
}

/**
* Elliptic-curve Diffie-Hellman key agreement.
Expand Down

0 comments on commit b6a44a9

Please sign in to comment.