Skip to content

Commit 970d169

Browse files
authored
Merge pull request #39 from a-sit-plus/release/2.2.0
* Dependency Updates * KmmResult 1.5.4 * Refactor `MultiBaseHelper` to only handle conversion * Change `JwsHeader.publicKey` from JsonWebKey to CryptoPublicKey * Remove `SignatureValueLength` parameters from JWS & COSE Algorithm Enum class * Remove deprecated functions * New `CryptoAlgorithm` class * New `CryptoSignature` class for easy Asn1 - RawByteArray conversion * Rename `Jws` classes * New `CryptoAlgorithm` class * New `CryptoSignature` class for easy Asn1 - RawByteArray conversion * Rename function in file `JcaExtensions.kt` from `.toPublicKey` to `.toJcaPublicKey` to reflect connection to JVMname function in file `JcaExtensions.kt` from `.toPublicKey` to `.toJcaPublicKey` to reflect connection to JVM * Remove VcLib-specific constants
2 parents 6b175c8 + 38398c4 commit 970d169

File tree

40 files changed

+794
-401
lines changed

40 files changed

+794
-401
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@
3232
* Add `xxxSafe()` functions to encapsulate endocing/decoding in `KmmResult`
3333
* Return `KmmResult` for conversions between different key representations ( i.e. `CryptoPublicKey`, `CoseKey` and `JsonWebKey`)
3434

35+
### 2.2.0
36+
* Dependency Updates
37+
* KmmResult 1.5.4
38+
* Refactor `MultiBaseHelper` to only handle conversion
39+
* Change `JwsHeader.publicKey` from JsonWebKey to CryptoPublicKey
40+
* Remove `SignatureValueLength` parameters from JWS & COSE Algorithm Enum class
41+
* Remove deprecated functions
42+
* New `CryptoAlgorithm` class
43+
* New `CryptoSignature` class for easy Asn1 - RawByteArray conversion
44+
* Rename `Jws` classes
45+
* New `CryptoAlgorithm` class
46+
* New `CryptoSignature` class for easy Asn1 - RawByteArray conversion
47+
* Rename function in file `JcaExtensions.kt` from `.toPublicKey` to `.toJcaPublicKey` to reflect connection to JVMname function in file `JcaExtensions.kt` from `.toPublicKey` to `.toJcaPublicKey` to reflect connection to JVM
48+
* Remove VcLib-specific constants

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import org.jetbrains.dokka.gradle.DokkaMultiModuleTask
22

33
plugins {
4-
id("at.asitplus.gradle.conventions") version "1.9.20+20231107" //version can be omitted for composite build
4+
id("at.asitplus.gradle.conventions") version "1.9.20+20231114" //version can be omitted for composite build
55
}
66
group = "at.asitplus.crypto"
77

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
object DatatypeVersions{
22
const val encoding= "1.2.3"
3-
const val kmmresult="1.5.3"
43
const val okio = "3.5.0"
54
}

datatypes-cose/build.gradle.kts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import DatatypeVersions.encoding
2-
import DatatypeVersions.kmmresult
32
import at.asitplus.gradle.*
43

54
plugins {
@@ -9,7 +8,7 @@ plugins {
98
id("at.asitplus.gradle.conventions")
109
}
1110

12-
version = "2.1.0"
11+
version = "2.2.0"
1312

1413
kotlin {
1514
jvm()
@@ -39,7 +38,7 @@ exportIosFramework(
3938
"KmpCryptoCose",
4039
serialization("cbor"),
4140
datetime(),
42-
"at.asitplus:kmmresult:${kmmresult}",
41+
kmmresult(),
4342
project(":datatypes")
4443
)
4544

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package at.asitplus.crypto.datatypes.cose
22

3-
import at.asitplus.crypto.datatypes.JwsAlgorithm
3+
import at.asitplus.crypto.datatypes.CryptoAlgorithm
44
import kotlinx.serialization.KSerializer
55
import kotlinx.serialization.Serializable
66
import kotlinx.serialization.descriptors.PrimitiveKind
@@ -10,12 +10,12 @@ import kotlinx.serialization.encoding.Decoder
1010
import kotlinx.serialization.encoding.Encoder
1111

1212
@Serializable(with = CoseAlgorithmSerializer::class)
13-
enum class CoseAlgorithm(val value: Int) {
13+
enum class CoseAlgorithm(val value: Int, val isEC: Boolean = false) {
1414

1515
// ECDSA with SHA-size
16-
ES256(-7),
17-
ES384(-35),
18-
ES512(-36),
16+
ES256(-7, true),
17+
ES384(-35, true),
18+
ES512(-36, true),
1919

2020
// HMAC-size with SHA-size
2121
HS256(5),
@@ -30,38 +30,32 @@ enum class CoseAlgorithm(val value: Int) {
3030
// RSASSA-PKCS1-v1_5 with SHA-size
3131
RS256(-257),
3232
RS384(-258),
33-
RS512(-259);
33+
RS512(-259),
3434

35-
fun toJwsAlgorithm() = when(this) {
36-
ES256 -> JwsAlgorithm.ES256
37-
ES384 -> JwsAlgorithm.ES384
38-
ES512 -> JwsAlgorithm.ES512
35+
// RSASSA-PKCS1-v1_5 using SHA-1
36+
RS1(-65535);
3937

40-
HS256 -> JwsAlgorithm.HS256
41-
HS384 -> JwsAlgorithm.HS384
42-
HS512 -> JwsAlgorithm.HS512
4338

44-
PS256 -> JwsAlgorithm.PS256
45-
PS384 -> JwsAlgorithm.PS384
46-
PS512 -> JwsAlgorithm.PS512
39+
fun toCryptoAlgorithm() = when(this) {
40+
ES256 -> CryptoAlgorithm.ES256
41+
ES384 -> CryptoAlgorithm.ES384
42+
ES512 -> CryptoAlgorithm.ES512
4743

48-
RS256 -> JwsAlgorithm.RS256
49-
RS384 -> JwsAlgorithm.RS384
50-
RS512 -> JwsAlgorithm.RS512
51-
}
44+
HS256 -> CryptoAlgorithm.HS256
45+
HS384 -> CryptoAlgorithm.HS384
46+
HS512 -> CryptoAlgorithm.HS512
5247

53-
val signatureValueLength
54-
get() = when (this) {
55-
ES256 -> 256 / 8 * 2
56-
ES384 -> 384 / 8 * 2
57-
ES512 -> 512 / 8 * 2
58-
HS256 -> 256 / 8
59-
HS384 -> 384 / 8
60-
HS512 -> 512 / 8
61-
else -> -1 // RSA signatures do not have a fixed size
62-
}
63-
}
48+
PS256 -> CryptoAlgorithm.PS256
49+
PS384 -> CryptoAlgorithm.PS384
50+
PS512 -> CryptoAlgorithm.PS512
51+
52+
RS256 -> CryptoAlgorithm.RS256
53+
RS384 -> CryptoAlgorithm.RS384
54+
RS512 -> CryptoAlgorithm.RS512
6455

56+
RS1 -> CryptoAlgorithm.RS1
57+
}
58+
}
6559

6660
object CoseAlgorithmSerializer : KSerializer<CoseAlgorithm> {
6761

@@ -74,7 +68,27 @@ object CoseAlgorithmSerializer : KSerializer<CoseAlgorithm> {
7468

7569
override fun deserialize(decoder: Decoder): CoseAlgorithm {
7670
val decoded = decoder.decodeInt()
77-
return CoseAlgorithm.values().first { it.value == decoded }
71+
return CoseAlgorithm.entries.first { it.value == decoded }
7872
}
7973

74+
}
75+
76+
fun CryptoAlgorithm.toCoseAlgorithm() = when(this) {
77+
CryptoAlgorithm.ES256 -> CoseAlgorithm.ES256
78+
CryptoAlgorithm.ES384 -> CoseAlgorithm.ES384
79+
CryptoAlgorithm.ES512 -> CoseAlgorithm.ES512
80+
81+
CryptoAlgorithm.HS256 -> CoseAlgorithm.HS256
82+
CryptoAlgorithm.HS384 -> CoseAlgorithm.HS384
83+
CryptoAlgorithm.HS512 -> CoseAlgorithm.HS512
84+
85+
CryptoAlgorithm.PS256 -> CoseAlgorithm.PS256
86+
CryptoAlgorithm.PS384 -> CoseAlgorithm.PS384
87+
CryptoAlgorithm.PS512 -> CoseAlgorithm.PS512
88+
89+
CryptoAlgorithm.RS256 -> CoseAlgorithm.RS256
90+
CryptoAlgorithm.RS384 -> CoseAlgorithm.RS384
91+
CryptoAlgorithm.RS512 -> CoseAlgorithm.RS512
92+
93+
CryptoAlgorithm.RS1 -> CoseAlgorithm.RS1
8094
}

datatypes-cose/src/commonMain/kotlin/at/asitplus/crypto/datatypes/cose/CoseHeader.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@ import at.asitplus.crypto.datatypes.cose.io.cborSerializer
44
import io.github.aakira.napier.Napier
55
import io.matthewnelson.encoding.base16.Base16
66
import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString
7-
import kotlinx.serialization.ExperimentalSerializationApi
8-
import kotlinx.serialization.SerialName
9-
import kotlinx.serialization.Serializable
7+
import kotlinx.serialization.*
108
import kotlinx.serialization.cbor.ByteString
119
import kotlinx.serialization.cbor.SerialLabel
12-
import kotlinx.serialization.decodeFromByteArray
13-
import kotlinx.serialization.encodeToByteArray
1410

1511
/**
1612
* Protected header of a [CoseSigned].

datatypes-cose/src/commonMain/kotlin/at/asitplus/crypto/datatypes/cose/CoseKey.kt

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ data class CoseKey(
8282
* or the first error. More details in either [CoseKeyParams.RsaParams.toCryptoPublicKey] or [CoseKeyParams.EcYByteArrayParams.toCryptoPublicKey]
8383
*/
8484
fun toCryptoPublicKey(): KmmResult<CryptoPublicKey> =
85-
keyParams?.toCryptoPublicKey() ?: KmmResult.failure(IllegalArgumentException("No public key parameters!"))
85+
keyParams?.toCryptoPublicKey() ?: failure(IllegalArgumentException("No public key parameters!"))
8686

8787
fun serialize() = cborSerializer.encodeToByteArray(this)
8888

@@ -218,7 +218,11 @@ object CoseKeySerializer : KSerializer<CoseKey> {
218218
@SerialLabel(-4)
219219
@SerialName("d")
220220
@ByteString
221-
val d: ByteArray? = null
221+
val d: ByteArray? = null,
222+
@SerialLabel(-1)
223+
@SerialName("k")
224+
@ByteString
225+
val k: ByteArray? = null
222226
) {
223227
constructor(src: CoseKey) : this(
224228
src.type,
@@ -237,6 +241,10 @@ object CoseKeySerializer : KSerializer<CoseKey> {
237241
is CoseKeyParams.RsaParams -> params.e
238242
else -> null
239243
},
244+
when (val params = src.keyParams) {
245+
is CoseKeyParams.SymmKeyParams -> params.k
246+
else -> null
247+
},
240248
when (val params = src.keyParams) {
241249
is CoseKeyParams.RsaParams -> params.d
242250
is CoseKeyParams.EcYByteArrayParams -> params.d
@@ -334,6 +342,39 @@ object CoseKeySerializer : KSerializer<CoseKey> {
334342
override fun toCoseKey() = CoseKey(type, keyId, algorithm, operations, baseIv, CoseKeyParams.RsaParams(n, e, d))
335343
}
336344

345+
@Serializable
346+
private class CoseSymmKeySerialContainer(
347+
@SerialLabel(1)
348+
@SerialName("kty")
349+
val type: CoseKeyType,
350+
@SerialLabel(2)
351+
@SerialName("kid")
352+
@ByteString
353+
val keyId: ByteArray? = null,
354+
@SerialLabel(3)
355+
@SerialName("alg")
356+
val algorithm: CoseAlgorithm? = null,
357+
@SerialLabel(4)
358+
@SerialName("key_ops")
359+
val operations: Array<CoseKeyOperation>? = null,
360+
@SerialLabel(5)
361+
@SerialName("Base IV")
362+
@ByteString
363+
val baseIv: ByteArray? = null,
364+
@SerialLabel(-1)
365+
@SerialName("k")
366+
val k: ByteArray? = null,
367+
) : SerialContainer {
368+
init {
369+
if (type != CoseKeyType.SYMMETRIC) throw IllegalArgumentException("Not a symmetric key!")
370+
if (k == null) throw IllegalArgumentException("Parameter k not optional for symmetric keys")
371+
}
372+
373+
override fun toCoseKey() =
374+
CoseKey(type, keyId, algorithm, operations, baseIv, CoseKeyParams.SymmKeyParams(k!!))
375+
376+
}
377+
337378
override val descriptor: SerialDescriptor
338379
get() = CoseKeySerialContainer.serializer().descriptor
339380

@@ -344,7 +385,7 @@ object CoseKeySerializer : KSerializer<CoseKey> {
344385
"alg" to 3,
345386
"key_ops" to 4,
346387
"Base IV" to 5,
347-
"n/crv" to -1,
388+
"k/n/crv" to -1,
348389
"x/e" to -2,
349390
"y" to -3,
350391
"d" to 4
@@ -360,6 +401,7 @@ object CoseKeySerializer : KSerializer<CoseKey> {
360401
var xOrE: ByteArray? = null
361402
var y: ByteArray? = null
362403
var d: ByteArray? = null
404+
var k: ByteArray? = null
363405

364406
decoder.decodeStructure(descriptor) {
365407
while (true) {
@@ -391,7 +433,7 @@ object CoseKeySerializer : KSerializer<CoseKey> {
391433
ArraySerializer(CoseKeyOperationSerializer)
392434
)
393435

394-
labels["n/crv"] -> {
436+
labels["k/n/crv"] -> {
395437
when (type) {
396438
CoseKeyType.EC2 -> {
397439
val deser = CoseEllipticCurveSerializer
@@ -403,7 +445,10 @@ object CoseKeySerializer : KSerializer<CoseKey> {
403445
n = decodeNullableSerializableElement(deser.descriptor, index, deser)
404446
}
405447

406-
CoseKeyType.SYMMETRIC -> {}
448+
CoseKeyType.SYMMETRIC -> {
449+
val deser = ByteArraySerializer()
450+
k = decodeNullableSerializableElement(deser.descriptor, index, deser)
451+
}
407452
}
408453

409454
}
@@ -444,7 +489,9 @@ object CoseKeySerializer : KSerializer<CoseKey> {
444489
CoseRsaKeySerialContainer(type, keyId, alg, keyOps, baseIv, n, xOrE, d).toCoseKey()
445490
}
446491

447-
CoseKeyType.SYMMETRIC -> CoseKey(type, keyId, alg, keyOps, keyParams = null)
492+
CoseKeyType.SYMMETRIC -> {
493+
CoseSymmKeySerialContainer(type,keyId,alg,keyOps,baseIv, k).toCoseKey()
494+
}
448495
}
449496
}
450497

datatypes-cose/src/commonMain/kotlin/at/asitplus/crypto/datatypes/cose/CoseKeyParams.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package at.asitplus.crypto.datatypes.cose
22

33
import at.asitplus.KmmResult
4+
import at.asitplus.KmmResult.Companion.failure
45
import at.asitplus.KmmResult.Companion.wrap
56
import at.asitplus.crypto.datatypes.CryptoPublicKey
67
import at.asitplus.crypto.datatypes.asn1.decodeFromDer
@@ -153,4 +154,10 @@ sealed class CoseKeyParams {
153154
}.wrap()
154155
}
155156
}
157+
158+
data class SymmKeyParams(
159+
val k: ByteArray
160+
): CoseKeyParams() {
161+
override fun toCryptoPublicKey(): KmmResult<CryptoPublicKey> = failure(IllegalArgumentException("Symmetric keys do not have public component"))
162+
}
156163
}

datatypes-cose/src/commonMain/kotlin/at/asitplus/crypto/datatypes/cose/CoseKeyType.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object CoseKeyTypeSerializer : KSerializer<CoseKeyType> {
2626

2727
override fun deserialize(decoder: Decoder): CoseKeyType {
2828
val decoded = decoder.decodeInt()
29-
return CoseKeyType.values().firstOrNull { it.value == decoded }
29+
return CoseKeyType.entries.firstOrNull { it.value == decoded }
3030
?: throw IllegalArgumentException("Not known: $decoded")
3131
}
3232
}

0 commit comments

Comments
 (0)