From 134f6190373678cba144ac23a4eb9c42b04f3ea5 Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 19 Aug 2024 16:45:33 +0200 Subject: [PATCH] 0.5.3 incompatible but better asymmetric keys id (both encryption and signing) --- README.md | 6 ++++++ build.gradle.kts | 2 +- .../kotlin/net/sergeych/crypto2/KeyId.kt | 19 +++++++++++++++---- .../kotlin/net/sergeych/crypto2/PublicKey.kt | 2 ++ .../net/sergeych/crypto2/UniversalKey.kt | 2 +- .../sergeych/crypto2/VerifyingPublicKey.kt | 2 ++ src/commonTest/kotlin/KeysTest.kt | 11 +++++++++++ 7 files changed, 38 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dc92809..ad2795f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ Cryptographic API works exactly the same and compiles to any platform supported All primitives meant to send over the network or store are `kotlinx.serialization` compatible, serializers included. +# Important notes on upgrade + +Since version __0.5.*__ key identity calculation for asymmetric keys is updated +to make it more safe for theoretic future attack on blake2b hashing. Key.id values +are incompatible with older. Sorry for inconvenience. + # Usage ```kotlin diff --git a/build.gradle.kts b/build.gradle.kts index 9e6a0cc..3cc075d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "net.sergeych" -version = "0.4.3" +version = "0.5.3" repositories { mavenCentral() diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt b/src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt index 8d7fd63..25d2982 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/KeyId.kt @@ -23,7 +23,7 @@ import kotlinx.serialization.Serializable * password, see above. */ @Serializable -data class KeyId(val id: BinaryId, val kdp: PBKD.Params?=null ) { +data class KeyId(val id: BinaryId, val kdp: PBKD.Params? = null) { /** * Binary array representation of the [id], not including the [kdp]. Used in [SafeKeyExchange] @@ -31,7 +31,7 @@ data class KeyId(val id: BinaryId, val kdp: PBKD.Params?=null ) { */ val binaryTag: UByteArray by lazy { id.id } - val keymagic: KeysmagicNumber by lazy { KeysmagicNumber.entries[id.magic]} + val keymagic: KeysmagicNumber by lazy { KeysmagicNumber.entries[id.magic] } override fun equals(other: Any?): Boolean { if (this === other) return true @@ -45,6 +45,17 @@ data class KeyId(val id: BinaryId, val kdp: PBKD.Params?=null ) { override fun toString() = id.toString() - constructor(magicNumber: KeysmagicNumber, keyData: UByteArray, kdp: PBKD.Params?=null) - : this(BinaryId.createFromUBytes(magicNumber.ordinal, blake2b3l(keyData)), kdp) + constructor( + magicNumber: KeysmagicNumber, + keyData: UByteArray, + kdp: PBKD.Params? = null, + donNotHash: Boolean = false, + ) + : this( + BinaryId.createFromUBytes( + magicNumber.ordinal, + if (donNotHash) keyData else blake2b3l(keyData) + ), + kdp + ) } \ No newline at end of file diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/PublicKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/PublicKey.kt index 5a26299..6f51241 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/PublicKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/PublicKey.kt @@ -69,4 +69,6 @@ class PublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingK randomFill: IntRange? = null, ): Asymmetric.Message = Asymmetric.createMessage(senderKey, this, WithFill.encode(plainData, randomFill)) + + override val id by lazy { KeyId(magic, keyBytes, null, true) } } \ No newline at end of file diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt index ffa2c1d..b819475 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt @@ -13,7 +13,7 @@ sealed class UniversalKey: KeyInstance { open val magic: KeysmagicNumber = KeysmagicNumber.Unknown - override val id by lazy { KeyId(magic, keyBytes) } + override val id by lazy { KeyId(magic, keyBytes, null) } // Important: id can be overridden, so we use it, not magic: open val label by lazy { id.keymagic.label } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/VerifyingPublicKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/VerifyingPublicKey.kt index b024497..27adc15 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/VerifyingPublicKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/VerifyingPublicKey.kt @@ -24,4 +24,6 @@ class VerifyingPublicKey(override val keyBytes: UByteArray) : UniversalKey(), Ve @Transient override val magic: KeysmagicNumber = KeysmagicNumber.defaultVerifying + + override val id by lazy { KeyId(magic, keyBytes, null, true) } } \ No newline at end of file diff --git a/src/commonTest/kotlin/KeysTest.kt b/src/commonTest/kotlin/KeysTest.kt index 9450aee..1b9ee2a 100644 --- a/src/commonTest/kotlin/KeysTest.kt +++ b/src/commonTest/kotlin/KeysTest.kt @@ -159,6 +159,11 @@ class KeysTest { val x2 = pk1.encryptMessage(plain, sk1).encoded assertFalse { x1 contentEquals x2 } + + // public key ID should use key bytes instead + assertContentEquals(pk1.keyBytes, pk1.id.binaryTag.take(32).toUByteArray()) + assertContentEquals(pk1.keyBytes, sk1.id.binaryTag.take(32).toUByteArray()) + } @Test fun asymmetricKeySerializationTest() = runTest { @@ -261,5 +266,11 @@ class KeysTest { val dk2 = unpack(s2) assertEquals(k, dk1) assertEquals(k.verifyingKey, dk2) + + // id for public/shared keys should be of the key itself to increase safety. + // not hashed! + assertContentEquals(k.verifyingKey.keyBytes, dk2.id.binaryTag.take(32).toUByteArray()) + assertContentEquals(k.verifyingKey.keyBytes, dk1.id.binaryTag.take(32).toUByteArray()) + } } \ No newline at end of file