diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/Multikey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Multikey.kt index 56f7b52..7e1aca1 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/Multikey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Multikey.kt @@ -2,6 +2,7 @@ package net.sergeych.crypto2 import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import net.sergeych.bipack.Unsigned import net.sergeych.crypto2.Multikey.Companion.allOf import net.sergeych.crypto2.Multikey.Companion.allOfMultikeys import net.sergeych.crypto2.Multikey.Companion.anyOf @@ -70,7 +71,11 @@ sealed class Multikey { */ @Serializable @SerialName("k") - class Keys internal constructor(val requiredMinimum: Int, val validKeys: Set) : Multikey() { + class Keys internal constructor( + @Unsigned + val requiredMinimum: Int, + val validKeys: Set + ) : Multikey() { override fun check(keys: Iterable): Boolean { var matches = 0 for( signer in keys ) { @@ -88,7 +93,11 @@ sealed class Multikey { */ @Serializable @SerialName("n") - class SomeOf internal constructor(val requiredMinimum: Int,val validKeys: List) : Multikey() { + class SomeOf internal constructor( + @Unsigned + val requiredMinimum: Int, + val validKeys: List + ) : Multikey() { override fun check(keys: Iterable): Boolean { var matches = 0 for( k in validKeys ) { diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt b/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt index 4a8f659..4841fec 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/SealedBox.kt @@ -6,6 +6,7 @@ import kotlinx.serialization.Transient import net.sergeych.bipack.BipackDecoder import net.sergeych.bipack.BipackEncoder import net.sergeych.bipack.decodeFromBipack +import net.sergeych.utools.pack /** * Multi-signed data box. Do not use the constructori directly, use [SealedBox.create] @@ -60,7 +61,7 @@ class SealedBox( * Add expiring seal, otherwise use [plus]. Overrides exising seal for [key] * if present: */ - fun addSeal(key: SigningKey, expiresAt: Instant): SealedBox { + fun addSeal(key: SigningKey, expiresAt: Instant?): SealedBox { val filtered = seals.filter { it.publicKey != key.verifyingKey } return SealedBox(message, filtered + key.seal(message, expiresAt), false) } @@ -78,6 +79,11 @@ class SealedBox( @Suppress("unused") fun isSealedBy(multikey: Multikey) = multikey.check(signedByKeys) + /** + * Unpack bipack-encoded payload + */ + inline fun unpack(): T = BipackDecoder.decode(message) + init { if (seals.isEmpty()) throw IllegalArgumentException("there should be at least one seal") if (checkOnInit) { @@ -102,6 +108,19 @@ class SealedBox( return SealedBox(data, keys.map { it.seal(data) }, false) } + /** + * Create a new instance serializing given data with Bipack and some + * keys. At least one key is required to disallow providing not-signed + * instances, e.g. [SealedBox] is guaranteed to be properly sealed when + * successfully instantiated. + * + * @param payload an object to serialize and sign + * @param keys a list of keys to sign with, should be at least one key. + * @throws IllegalArgumentException if keys are not specified. + */ + inline fun new(payload: T,vararg keys: SigningKey): SealedBox = + create(pack(payload), *keys) + inline fun encode(value: T, vararg keys: SigningKey): UByteArray = create(BipackEncoder.encode(value).toUByteArray(), *keys).encoded