refactored keys, unversal keys and ring

This commit is contained in:
Sergey Chernov 2024-06-22 18:18:14 +07:00
parent 7eeb780bdb
commit ede55650f4
16 changed files with 274 additions and 241 deletions

View File

@ -109,7 +109,7 @@ object Asymmetric {
private fun randomNonce(): UByteArray = randomUBytes(crypto_box_NONCEBYTES)
fun randomSecretKey(): SecretKey = generateKeys().secretKey
fun new(): SecretKey = generateKeys().secretKey
@Suppress("unused")
val nonceBytesLength = crypto_box_NONCEBYTES
@ -121,22 +121,9 @@ object Asymmetric {
* Anonymous encryption is very slow in comparison.
*/
@Serializable
class PublicKey(val keyBytes: UByteArray) {
class PublicKey(override val keyBytes: UByteArray) : BinaryKeyBase() {
val tag: KeyId by lazy {
KeyId(KeysMagickNumbers.defaultAssymmetric, blake2b(keyBytes))
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is PublicKey) return false
return keyBytes contentEquals other.keyBytes
}
override fun hashCode(): Int {
return keyBytes.contentHashCode()
}
override val magick: KeysMagickNumber = KeysMagickNumber.defaultAssymmetric
/**
* Create an anonymous message that could be decrypted only with the [SecretKey] that corresponds this.
@ -171,7 +158,7 @@ object Asymmetric {
fun encryptMessage(
plainData: UByteArray,
nonce: UByteArray = randomNonce(),
senderKey: SecretKey = randomSecretKey(),
senderKey: SecretKey = new(),
randomFill: IntRange? = null,
) = createMessage(senderKey, this, WithFill.encode(plainData, randomFill), nonce)
@ -192,10 +179,10 @@ object Asymmetric {
*/
@Serializable
class SecretKey(
val keyBytes: UByteArray,
override val keyBytes: UByteArray,
@Transient
val _cachedPublicKey: PublicKey? = null,
) : DecryptingKey {
) : DecryptingKey, BinaryKeyBase() {
/**
* Decrypt with authentication checks the message which must have [Message.senderPublicKey] set.
@ -226,17 +213,6 @@ object Asymmetric {
.also { cachedPublicKey = it }
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is SecretKey) return false
return keyBytes contentEquals other.keyBytes
}
override fun hashCode(): Int {
return keyBytes.contentHashCode()
}
/**
* Nonce-based decryption is impossible, it is already included in message
*/
@ -250,7 +226,8 @@ object Asymmetric {
return message.decrypt(this)
}
override val id: KeyId by lazy { publicKey.tag }
override val magick: KeysMagickNumber = KeysMagickNumber.defaultAssymmetric
override val id: KeyId by lazy { publicKey.id }
override val nonceBytesLength: Int
get() = 0

View File

@ -0,0 +1,47 @@
package net.sergeych.crypto2
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
interface VerifyingKey {
val id: KeyId
/**
* Verify the signature and return true if it is correct.
*/
fun verify(signature: UByteArray, message: UByteArray): Boolean
}
interface SigningKey {
val verifyingKey: SigningPublicKey
fun sign(message: UByteArray): UByteArray
fun seal(message: UByteArray, expiresAt: Instant? = null): Seal
}
@Serializable
abstract class BinaryKeyBase() {
abstract val keyBytes: UByteArray
abstract val magick: KeysMagickNumber
open val id by lazy { KeyId(magick, keyBytes) }
override fun equals(other: Any?): Boolean {
return other is BinaryKeyBase && other.keyBytes contentEquals keyBytes
}
override fun hashCode(): Int {
return keyBytes.contentHashCode()
}
override fun toString(): String = keyBytes.encodeToBase64Url()
companion object {
}
}
open class IllegalSignatureException(text: String = "signed data is tampered or signature is corrupted") :
IllegalStateException(text)
class ExpiredSignatureException(text: String) : IllegalSignatureException(text)

View File

@ -232,10 +232,10 @@ sealed class Container {
constructor(sender: Asymmetric.SecretKey?, recipient: Asymmetric.PublicKey, encodeMainKey: UByteArray) :
this(
recipient.tag,
recipient.id,
recipient.encryptMessage(
encodeMainKey,
senderKey = sender ?: Asymmetric.randomSecretKey(),
senderKey = sender ?: Asymmetric.new(),
).encoded
)
}
@ -375,7 +375,7 @@ sealed class Container {
mainKey = p.mainKey ?: throw IllegalStateException("parent container must be decrypted")
} else {
eks = mutableListOf<Multi.EncryptedKey>()
mainKey = SymmetricKey.random()
mainKey = SymmetricKey.new()
}
val encodedMainKey = BipackEncoder.encode(mainKey).toUByteArray()
createMulti(eks, encodedMainKey, mainKey)
@ -389,9 +389,9 @@ sealed class Container {
val pair = keyPairs.first()
val (sk, pk) = pair
Single(
pk.tag, pk.encryptMessage(
pk.id, pk.encryptMessage(
plainData,
senderKey = sk ?: Asymmetric.randomSecretKey(),
senderKey = sk ?: Asymmetric.new(),
randomFill = fillRange
).encoded,
plainData,

View File

@ -23,6 +23,6 @@ data class KeyId(val id: BinaryId, val kdp: KeyDerivationParams?=null ) {
override fun toString() = id.toString()
constructor(magickNumber: KeysMagickNumbers, data: UByteArray,kdp: KeyDerivationParams?=null)
constructor(magickNumber: KeysMagickNumber, data: UByteArray, kdp: KeyDerivationParams?=null)
: this(BinaryId.createFromUBytes(magickNumber.number, data), kdp)
}

View File

@ -1,10 +1,11 @@
package net.sergeych.crypto2
enum class KeysMagickNumbers(val number: Int) {
enum class KeysMagickNumber(val number: Int) {
defaultAssymmetric(0),
defaultSymmetric(1),
defaultSession(2),
defaultSigning(3),
defaultVerifying(4),
;
companion object {
@ -12,6 +13,6 @@ enum class KeysMagickNumbers(val number: Int) {
val forNumber = entries.map { it.number to it }.toMap()
@Suppress("unused")
fun findFor(binaryId: BinaryId): KeysMagickNumbers? = forNumber[binaryId.magick]
fun findFor(binaryId: BinaryId): KeysMagickNumber? = forNumber[binaryId.magick]
}
}

View File

@ -23,7 +23,7 @@ import net.sergeych.utools.now
*/
@Serializable
class Seal(
val publicKey: Signing.PublicKey,
val publicKey: SigningPublicKey,
val signature: UByteArray,
val nonce: UByteArray?,
val createdAt: Instant,
@ -95,7 +95,7 @@ class Seal(
* Seal [message] with a [key].
*
* Seals are kotlinx-serializable and can be used
* to check the authenticity of the arbitrary [message] using a public key, [Signing.PublicKey]
* to check the authenticity of the arbitrary [message] using a public key, [SigningPublicKey]
* instance, using public-key signing algorithms.
*
* Unlike a regular binary signature, Seal contains the signer's [publicKey], and also
@ -130,7 +130,7 @@ class Seal(
* rare case so default os false.
*/
fun create(
key: Signing.SecretKey,
key: SigningSecretKey,
message: UByteArray,
createdAt: Instant = now(),
expiresAt: Instant? = null,
@ -138,7 +138,7 @@ class Seal(
): Seal {
val nonce = if( nonDeterministic ) randomUBytes(32) else null
val data = BipackEncoder.encode(SealedData(message, nonce, createdAt, expiresAt)).toUByteArray()
return Seal(key.publicKey, key.sign(data), nonce, createdAt, expiresAt)
return Seal(key.verifyingKey, key.sign(data), nonce, createdAt, expiresAt)
}
/**

View File

@ -30,7 +30,7 @@ class SealedBox(
) {
@Suppress("unused")
constructor(message: UByteArray, vararg keys: Signing.SecretKey) :
constructor(message: UByteArray, vararg keys: SigningSecretKey) :
this(message, keys.map { it.seal(message) } )
/**
@ -38,23 +38,23 @@ class SealedBox(
* key, or return unchanged (same) object if it is already signed by this key; you
* _can't assume it always returns a copied object!_
*/
operator fun plus(key: Signing.SecretKey): SealedBox =
if (key.publicKey in this) this
operator fun plus(key: SigningSecretKey): SealedBox =
if (key.verifyingKey in this) this
else SealedBox(message, seals + key.seal(message),false)
/**
* Add expiring seal, otherwise use [plus]. Overrides exising seal for [key]
* if present:
*/
fun addSeal(key: Signing.SecretKey, expresAt: Instant): SealedBox {
val filtered = seals.filter { it.publicKey != key.publicKey }
fun addSeal(key: SigningSecretKey, expresAt: Instant): SealedBox {
val filtered = seals.filter { it.publicKey != key.verifyingKey }
return SealedBox(message, filtered + key.seal(message, expresAt), false)
}
/**
* Check that it is signed with a specified key.
*/
operator fun contains(publicKey: Signing.PublicKey): Boolean {
operator fun contains(publicKey: SigningPublicKey): Boolean {
return seals.any { it.publicKey == publicKey }
}
@ -77,7 +77,7 @@ class SealedBox(
* @param keys a list of keys to sign with, should be at least one key.
* @throws IllegalArgumentException if keys are not specified.
*/
fun create(data: UByteArray, vararg keys: Signing.SecretKey): SealedBox {
fun create(data: UByteArray, vararg keys: SigningSecretKey): SealedBox {
return SealedBox(data, keys.map { it.seal(data) }, false)
}
}

View File

@ -1,107 +0,0 @@
package net.sergeych.crypto2
import com.ionspin.kotlin.crypto.signature.InvalidSignatureException
import com.ionspin.kotlin.crypto.signature.Signature
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import net.sergeych.crypto2.Signing.Companion.pair
import net.sergeych.utools.now
interface VerifyingKey {
val id: KeyId
/**
* Verify the signature and return true if it is correct.
*/
fun verify(signature: UByteArray, message: UByteArray): Boolean
}
interface SigningKey {
val publicKey: Signing.PublicKey
fun sign(message: UByteArray): UByteArray
fun seal(message: UByteArray, expiresAt: Instant? = null): Seal
}
/**
* Keys in general: public, secret and later symmetric too.
* Keys could be compared to each other for equality and used
* as a Map keys (not sure about js).
*
* Use [pair] to create new keys.
*/
@Serializable
sealed class Signing {
abstract val id: KeyId
abstract val packed: UByteArray
override fun equals(other: Any?): Boolean {
return other is Signing && other.packed contentEquals packed
}
override fun hashCode(): Int {
return packed.contentHashCode()
}
override fun toString(): String = packed.encodeToBase64Url()
/**
* Public key to verify signatures only
*/
@Serializable
@SerialName("p")
class PublicKey(override val packed: UByteArray) : Signing(), VerifyingKey {
/**
* Verify the signature and return true if it is correct.
*/
override fun verify(signature: UByteArray, message: UByteArray): Boolean = try {
Signature.verifyDetached(signature, message, packed)
true
} catch (_: InvalidSignatureException) {
false
}
override fun toString(): String = "Pub:${super.toString()}"
override val id: KeyId by lazy {
KeyId(KeysMagickNumbers.defaultSigning, packed)
}
}
/**
* Secret key to sign only
*/
@Serializable
@SerialName("s")
class SecretKey(override val packed: UByteArray) : Signing(), SigningKey {
override val publicKey: PublicKey by lazy {
PublicKey(Signature.ed25519SkToPk(packed))
}
override fun sign(message: UByteArray): UByteArray = Signature.detached(message, packed)
override fun seal(message: UByteArray, expiresAt: Instant?): Seal =
Seal.create(this, message, now(), expiresAt)
override fun toString(): String = "Sct:${super.toString()}"
override val id: KeyId
get() = publicKey.id
}
companion object {
data class Pair(val secretKey: SecretKey, val publicKey: PublicKey)
fun pair(): Pair {
val p = Signature.keypair()
return Pair(SecretKey(p.secretKey), PublicKey(p.publicKey))
}
}
}
open class IllegalSignatureException(text: String="signed data is tampered or signature is corrupted")
: IllegalStateException(text)
class ExpiredSignatureException(text: String): IllegalSignatureException(text)

View File

@ -0,0 +1,27 @@
package net.sergeych.crypto2
import com.ionspin.kotlin.crypto.signature.InvalidSignatureException
import com.ionspin.kotlin.crypto.signature.Signature
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
/**
* Public key to verify signatures only
*/
@Serializable
class SigningPublicKey(override val keyBytes: UByteArray) : BinaryKeyBase(), VerifyingKey {
/**
* Verify the signature and return true if it is correct.
*/
override fun verify(signature: UByteArray, message: UByteArray): Boolean = try {
Signature.verifyDetached(signature, message, keyBytes)
true
} catch (_: InvalidSignatureException) {
false
}
override fun toString(): String = "Pub:${super.toString()}"
@Transient
override val magick: KeysMagickNumber = KeysMagickNumber.defaultVerifying
}

View File

@ -0,0 +1,47 @@
package net.sergeych.crypto2
import com.ionspin.kotlin.crypto.signature.Signature
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.sergeych.utools.now
/**
* Secret key to sign only
*/
@Serializable
class SigningSecretKey(
override val keyBytes: UByteArray,
@Transient
private var cachedPublicKey: SigningPublicKey?=null
) : BinaryKeyBase(), SigningKey {
override val verifyingKey: SigningPublicKey by lazy {
cachedPublicKey ?:
SigningPublicKey(Signature.ed25519SkToPk(keyBytes)).also { cachedPublicKey = it }
}
override fun sign(message: UByteArray): UByteArray = Signature.detached(message, keyBytes)
override fun seal(message: UByteArray, expiresAt: Instant?): Seal =
Seal.create(this, message, now(), expiresAt)
override fun toString(): String = "Sct:${super.toString()}"
@Transient
override val magick = KeysMagickNumber.defaultSigning
companion object {
data class SigningKeyPair(val secretKey: SigningSecretKey, val publicKey: SigningPublicKey)
fun generatePair(): SigningKeyPair {
val p = Signature.keypair()
val publicKey = SigningPublicKey(p.publicKey)
return SigningKeyPair(SigningSecretKey(p.secretKey, publicKey), publicKey)
}
fun new(): SigningSecretKey = generatePair().secretKey
}
}

View File

@ -37,7 +37,7 @@ class SymmetricKey(
override val nonceBytesLength: Int = nonceByteLength
override val id by lazy { KeyId(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) }
override val id by lazy { KeyId(KeysMagickNumber.defaultSymmetric,blake2b3l(keyBytes)) }
override fun decryptWithNonce(cipherData: UByteArray, nonce: UByteArray): UByteArray =
protectDecryption {
@ -60,7 +60,7 @@ class SymmetricKey(
/**
* Create a secure random symmetric key.
*/
fun random() = SymmetricKey(SecretBox.keygen())
fun new() = SymmetricKey(SecretBox.keygen())
val nonceByteLength = crypto_secretbox_NONCEBYTES
}

View File

@ -7,14 +7,6 @@ import kotlinx.serialization.Transient
@Serializable
sealed class UniversalKey {
abstract val id: KeyId
@Transient
open val canEncrypt = false
@Transient
open val canDecrypt = false
@Transient
open val canSign = false
@Transient
open val canVerify = false
@Serializable
@SerialName("sym")
@ -26,11 +18,6 @@ sealed class UniversalKey {
override val nonceBytesLength: Int = key.nonceBytesLength
override fun toString() = "U.Sym:$id"
@Transient
override val canDecrypt: Boolean = true
@Transient
override val canEncrypt: Boolean = true
}
@Serializable
@ -41,37 +28,55 @@ sealed class UniversalKey {
override val id: KeyId = key.id
@Transient
override val nonceBytesLength: Int = key.nonceBytesLength
@Transient
override val canDecrypt: Boolean = true
@Transient
override val canEncrypt: Boolean = true
}
@Serializable
@SerialName("sec")
data class Secret(val key: Asymmetric.SecretKey) : UniversalKey(), DecryptingKey by key {
@Transient
val publicKey: Public = Public(key.publicKey)
override val id: KeyId by lazy { key.id }
override fun toString() = "U.Sec:$id"
@Transient
override val canDecrypt: Boolean = true
}
@Serializable
@SerialName("pub")
data class Public(val key: Asymmetric.PublicKey) : UniversalKey(), EncryptingKey {
override val id: KeyId by lazy { key.id }
override fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange?): UByteArray =
key.encryptMessage(plainData, nonce, randomFill= randomFill).encoded
override fun encrypt(plainData: UByteArray, randomFill: IntRange?): UByteArray =
key.encryptMessage(plainData, randomFill=randomFill).encoded
override val nonceBytesLength: Int
get() = Asymmetric.nonceBytesLength
override fun toString() = "U.Sec:$id"
}
@Serializable
@SerialName("sig")
data class Signing(val key: net.sergeych.crypto2.Signing.SecretKey) : UniversalKey() {
data class Signing(val key: SigningSecretKey) : UniversalKey(), SigningKey by key {
override val id: KeyId by lazy { key.id }
override fun toString() = "U.Sig:$id"
@Transient
override val canDecrypt: Boolean = true
/**
* [Verifying] key, e.g. [verifyingKey] wrapped in the [UniversalKey] variant.
*/
val publicKey by lazy { Verifying(verifyingKey) }
}
@Serializable
@SerialName("ver")
data class Verifying(val key: net.sergeych.crypto2.Signing.PublicKey) : UniversalKey() {
data class Verifying(val key: SigningPublicKey) : UniversalKey(), VerifyingKey by key {
override val id: KeyId by lazy { key.id }
override fun toString() = "U.Sig:$id"
@Transient
override val canDecrypt: Boolean = true
}
@ -85,6 +90,14 @@ sealed class UniversalKey {
is SafeKeyExchange.SessionKey -> Session(key)
else -> throw UnsupportedOperationException("can't create universal key from ${key::class.simpleName}")
}
fun newSecretKey(): Secret =
Secret(Asymmetric.new())
fun newSigningKey(): Signing =
Signing(SigningSecretKey.new())
@Suppress("unused")
fun newSymmetricKey(): Symmetric =
Symmetric(SymmetricKey.new())
}
}

View File

@ -4,27 +4,37 @@ import kotlinx.serialization.Serializable
@Serializable
class UniversalRing(
private val keyWithTags: Map<UniversalKey,Set<String>>
val keyWithTags: Map<UniversalKey,Set<String>>
) {
val decryptingKeys: Set<DecryptingKey> by lazy {
keyWithTags.keys.mapNotNull { it as? DecryptingKey }.toSet()
}
constructor(vararg keys: UniversalKey) : this(keys.associateWith { setOf() })
constructor(vararg keys: DecryptingKey) : this(keys.associate { UniversalKey.from(it) to setOf<String>() })
constructor(vararg keyTags: Pair<UniversalKey, String>)
: this(keyTags.associate { it.first to setOf(it.second) })
private val byId by lazy { keyWithTags.keys.associateBy { it.id } }
private val byIdWithTags by lazy { keyWithTags.entries.associate { it.key.id to (it.key to it.value) } }
val decryptingKeys: Set<DecryptingKey> by lazy { keys<DecryptingKey>() }
operator fun get(keyId: KeyId): UniversalKey? = byId[keyId]
inline fun <reified T>keys(): Set<T> =
keyWithTags.keys.mapNotNull { it as? T }.toSet()
inline fun <reified T>findKey(id: KeyId): UniversalKey? =
keyWithTags.keys.find { it is T && it.id == id }
fun allByAnyOfTags(vararg tags: String) = sequence {
for( e in keyWithTags.entries) {
if( tags.any { it in e.value }) yield(e.key)
}
}
inline fun <reified T>keyByTag(tag: String) = allByAnyOfTags(tag).first { it is T }
@Suppress("unused")
inline fun <reified T>keyByAnyTag(vararg tags: String) = allByAnyOfTags(*tags).first { it is T }
operator fun get(keyId: KeyId): Collection<UniversalKey> = keyWithTags.keys.filter { it.id == keyId }
fun getTags(key: UniversalKey): Set<String>? = keyWithTags[key]
fun keyWithTags(keyId: KeyId?): Pair<UniversalKey,Set<String>>? = byIdWithTags[keyId]
operator fun contains(element: UniversalKey): Boolean = byId.containsKey(element.id)
operator fun contains(element: UniversalKey): Boolean = element in keyWithTags
operator fun plus(key: UniversalKey): UniversalRing =
if( key in this ) this else UniversalRing(keyWithTags + (key to setOf()) )
@ -56,9 +66,6 @@ class UniversalRing(
operator fun minus(key: UniversalKey): UniversalRing =
if( key in this ) UniversalRing(keyWithTags.filter { it.key != key }) else this
operator fun minus(keyId: KeyId): UniversalRing =
if( keyId in byId ) UniversalRing(keyWithTags.filter { it.key.id != keyId }) else this
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is UniversalRing) return false

View File

@ -9,8 +9,8 @@ class ContainerTest {
@Test
fun testSingle() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val syk1 = SymmetricKey.new()
val syk2 = SymmetricKey.new()
val data = "sergeych, ohm many.".encodeToUByteArray()
val c = Container.createWith(data, syk1)
@ -87,9 +87,9 @@ class ContainerTest {
@Test
fun testMultipleSymmetric() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val syk3 = SymmetricKey.random()
val syk1 = SymmetricKey.new()
val syk2 = SymmetricKey.new()
val syk3 = SymmetricKey.new()
val p1 = Asymmetric.generateKeys()
val p2 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()
@ -131,9 +131,9 @@ class ContainerTest {
@Test
fun testSingleGrowSymmetric() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val syk3 = SymmetricKey.random()
val syk1 = SymmetricKey.new()
val syk2 = SymmetricKey.new()
val syk3 = SymmetricKey.new()
val p1 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()
val p4 = Asymmetric.generateKeys()
@ -193,8 +193,8 @@ class ContainerTest {
@Test
fun testSingleGrowAsymmetric() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val syk1 = SymmetricKey.new()
val syk2 = SymmetricKey.new()
val p1 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()
val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'"
@ -226,9 +226,9 @@ class ContainerTest {
@Test
fun testMixedOps1() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val syk3 = SymmetricKey.random()
val syk1 = SymmetricKey.new()
val syk2 = SymmetricKey.new()
val syk3 = SymmetricKey.new()
val p1 = Asymmetric.generateKeys()
val p2 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()
@ -263,9 +263,9 @@ class ContainerTest {
@Test
fun testMixedOps2() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val syk3 = SymmetricKey.random()
val syk1 = SymmetricKey.new()
val syk2 = SymmetricKey.new()
val syk3 = SymmetricKey.new()
val p1 = Asymmetric.generateKeys()
val p2 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()

View File

@ -13,11 +13,11 @@ class KeysTest {
@Test
fun testSigningCreationAndMap() = runTest {
initCrypto()
val (stk,pbk) = Signing.pair()
val (stk,pbk) = SigningSecretKey.generatePair()
val x = mapOf( stk to "STK!", pbk to "PBK!")
assertEquals("STK!", x[stk])
val s1 = Signing.SecretKey(stk.packed)
val s1 = SigningSecretKey(stk.keyBytes)
assertEquals(stk, s1)
assertEquals("STK!", x[s1])
assertEquals("PBK!", x[pbk])
@ -29,8 +29,8 @@ class KeysTest {
data1[0] = 0x01u
assertFalse(s.isValid(data1))
val p2 = Signing.pair()
val p3 = Signing.pair()
val p2 = SigningSecretKey.generatePair()
val p3 = SigningSecretKey.generatePair()
val ms = SealedBox.create(data, s1) + p2.secretKey
@ -49,8 +49,8 @@ class KeysTest {
@Test
fun testNonDeterministicSeals() = runTest {
initCrypto()
val data = "Welcome to the Miami, bitch!".encodeToUByteArray()
val (sk,_) = Signing.pair()
val data = "Welcome to the crazy new world!".encodeToUByteArray()
val (sk,_) = SigningSecretKey.generatePair()
val t = now()
val s1 = Seal.create(sk, data, createdAt = t)
val s2 = Seal.create(sk, data, createdAt = t)
@ -72,8 +72,8 @@ class KeysTest {
@Test
fun secretEncryptTest() = runTest {
initCrypto()
val key = SymmetricKey.random()
val key1 = SymmetricKey.random()
val key = SymmetricKey.new()
val key1 = SymmetricKey.new()
assertEquals("hello", key.decrypt(key.encrypt("hello".encodeToUByteArray())).decodeFromUByteArray())
assertEquals("hello", key.decryptString(key.encrypt("hello")))
assertEquals("hello", key.decryptObject(key.encryptObject("hello")))
@ -88,7 +88,7 @@ class KeysTest {
@Test
fun symmetricKeyTest() = runTest {
initCrypto()
val k1 = SymmetricKey.random()
val k1 = SymmetricKey.new()
val src = "Buena Vista".encodeToUByteArray()
val nonce = k1.randomNonce()
@ -176,9 +176,9 @@ class KeysTest {
@Test
fun testUniKeys() = runTest {
initCrypto()
val sy1 = SymmetricKey.random()
val sy1 = SymmetricKey.new()
val sy2 = SymmetricKey(sy1.keyBytes)
val sy3 = SymmetricKey.random()
val sy3 = SymmetricKey.new()
assertEquals(sy1, sy2)
assertEquals(sy2, sy1)
@ -195,9 +195,9 @@ class KeysTest {
assertEquals(usy2, usy1)
assertFalse { usy1 == usy3 }
val sk1 = Asymmetric.randomSecretKey()
val sk1 = Asymmetric.new()
val sk2 = Asymmetric.SecretKey(sk1.keyBytes)
val sk3 = Asymmetric.randomSecretKey()
val sk3 = Asymmetric.new()
assertEquals(sk1, sk2)
assertEquals(sk2, sk1)

View File

@ -16,7 +16,7 @@ class RingTest {
val y2 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray())
assertEquals(y1, y2)
val e1 = Asymmetric.randomSecretKey()
val e1 = Asymmetric.new()
val e2: Asymmetric.SecretKey = BipackDecoder.decode(BipackEncoder.encode(e1))
assertEquals(e1, e2)
@ -26,8 +26,8 @@ class RingTest {
assertEquals(k1, k11)
val k2 = UniversalKey.from(Asymmetric.randomSecretKey())
val k3 = UniversalKey.from(Asymmetric.randomSecretKey())
val k2 = UniversalKey.from(Asymmetric.new())
val k3 = UniversalKey.from(Asymmetric.new())
//
val r = UniversalRing(k1, k2)
// val r = UniversalRing(k1)
@ -35,8 +35,8 @@ class RingTest {
assertTrue(k1 in r)
assertFalse { k3 in r }
println(Asymmetric.randomSecretKey().keyBytes.size)
println(BipackEncoder.encode(Asymmetric.randomSecretKey()).size)
println(Asymmetric.new().keyBytes.size)
println(BipackEncoder.encode(Asymmetric.new()).size)
val encoded = BipackEncoder.encode(r)
println(encoded.toDump())
println(encoded.size)
@ -60,16 +60,8 @@ class RingTest {
fun testTags() = runTest {
initCrypto()
val y1 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray())
val y2 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray())
val e1 = Asymmetric.randomSecretKey()
val e2: Asymmetric.SecretKey = BipackDecoder.decode(BipackEncoder.encode(e1))
val k1 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()))
val k11 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()))
val k2 = UniversalKey.from(Asymmetric.randomSecretKey())
val k3 = UniversalKey.from(Asymmetric.randomSecretKey())
val k2 = UniversalKey.from(Asymmetric.new())
val r1 = UniversalRing(k1, k2)
var r2 = UniversalRing(deepCopy(k1), deepCopy(k2))
@ -91,6 +83,35 @@ class RingTest {
assertEquals(r2, r3)
}
@Test
fun testAsymmetricEncryption() = runTest {
initCrypto()
val sk1 = UniversalKey.newSecretKey()
val sk2 = UniversalKey.newSecretKey()
val sk3 = UniversalKey.newSecretKey()
// val sk4 = UniversalKey.newSecretKey()
val sik1 = UniversalKey.newSigningKey()
// val sik2 = UniversalKey.newSigningKey()
val sik3 = UniversalKey.newSigningKey()
val data = "Mendeleev' table".encodeToUByteArray()
val r = UniversalRing(sk2, sk3, sk1.publicKey, sk3.publicKey, sik3.publicKey, sik1)
r.addTags(sik1, "SECRET_SIGN")
val box = deepCopy(Container.create(data) { key(sk3.publicKey) })
assertContentEquals(data, box.decryptWith(r))
assertEquals(sk3.publicKey, r.findKey<EncryptingKey>(sk3.id))
assertTrue { sik3.publicKey in r }
assertEquals(sik1, r.findKey<EncryptingKey>(sik1.publicKey.id))
assertEquals(sik1, r.keyByTag<SigningKey>("SECRET_SIGN"))
}
@Test
fun testSize() = runTest {
// val sy1 = SymmetricKey.random().toUniversal()