Container started

This commit is contained in:
Sergey Chernov 2024-06-19 16:46:32 +07:00
parent e4e3b5ba8b
commit e2916d0fe2
12 changed files with 360 additions and 76 deletions

View File

@ -7,6 +7,7 @@ import com.ionspin.kotlin.crypto.scalarmult.ScalarMultiplication
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import net.sergeych.bipack.BipackDecoder import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder
import net.sergeych.crypto2.Asymmetric.Message import net.sergeych.crypto2.Asymmetric.Message
import net.sergeych.crypto2.Asymmetric.PublicKey import net.sergeych.crypto2.Asymmetric.PublicKey
import net.sergeych.crypto2.Asymmetric.SecretKey import net.sergeych.crypto2.Asymmetric.SecretKey
@ -32,7 +33,7 @@ object Asymmetric {
/** /**
* Encrypted message holder. * Encrypted message holder.
* *
* Do not instantiate it directly, use [SecretKey.encrypt], [PublicKey.encryptAnonymously] or [createMessage] * Do not instantiate it directly, use [PublicKey.encryptMessage], [PublicKey.encryptAnonymousMessage], etc.
* instead. Also [SecretKey.decrypt] can be used to decrypt it same as [decrypt] or [decryptWithSenderKey]. * instead. Also [SecretKey.decrypt] can be used to decrypt it same as [decrypt] or [decryptWithSenderKey].
* *
* To successfully decrypt the message, it is necessary to know a sender public key, and non-secret nonce. * To successfully decrypt the message, it is necessary to know a sender public key, and non-secret nonce.
@ -42,13 +43,12 @@ object Asymmetric {
class Message( class Message(
private val nonce: UByteArray, private val nonce: UByteArray,
private val encryptedMessage: UByteArray, private val encryptedMessage: UByteArray,
val senderPublicKey: PublicKey? = null, val senderPublicKey: PublicKey,
) { ) {
/** /**
* Decrypt the message, same as [SecretKey.decrypt] * Decrypt the message, same as [SecretKey.decrypt]
*/ */
fun decrypt(recipientKey: SecretKey): UByteArray { fun decrypt(recipientKey: SecretKey): UByteArray {
check(senderPublicKey != null)
return decryptWithSenderKey(senderPublicKey, recipientKey) return decryptWithSenderKey(senderPublicKey, recipientKey)
} }
@ -58,11 +58,15 @@ object Asymmetric {
*/ */
fun decryptWithSenderKey(senderKey: PublicKey, recipientKey: SecretKey): UByteArray { fun decryptWithSenderKey(senderKey: PublicKey, recipientKey: SecretKey): UByteArray {
return try { return try {
WithFill.decode(
Box.openEasy(encryptedMessage, nonce, senderKey.keyBytes, recipientKey.keyBytes) Box.openEasy(encryptedMessage, nonce, senderKey.keyBytes, recipientKey.keyBytes)
)
} catch (_: BoxCorruptedOrTamperedDataException) { } catch (_: BoxCorruptedOrTamperedDataException) {
throw DecryptionFailedException() throw DecryptionFailedException()
} }
} }
val encoded: UByteArray by lazy { BipackEncoder.encode(this).toUByteArray() }
} }
/** /**
@ -72,30 +76,27 @@ object Asymmetric {
* The authenticated encryption is used, is the message _is successfully decrypted_, it also means that * The authenticated encryption is used, is the message _is successfully decrypted_, it also means that
* it was signed by the sender, whose public key is known at the decryption time. * it was signed by the sender, whose public key is known at the decryption time.
* *
* When it is important not to provide senders' key, use [PublicKey.encryptAnonymously]. * When it is important not to provide senders' key, use [PublicKey.encryptAnonymousMessage].
* *
* @param from the senders' secret key. * @param from the senders' secret key.
* @param recipient the recipients' public key. * @param recipient the recipients' public key.
* @param plainData data to encrypt * @param plainData data to encrypt
* @param excludeSenderKey if set to true, senders' public key will not be included in the message.
* In this case, the recipient must know it from other sources to be able to decrypt the message.
*/ */
fun createMessage( private fun createMessage(
from: SecretKey, recipient: PublicKey, plainData: UByteArray, from: SecretKey, recipient: PublicKey, plainData: UByteArray,
excludeSenderKey: Boolean = false, nonce: UByteArray = randomNonce(),
): Message { ): Message {
val nonce = randomNonce()
return Message( return Message(
nonce, nonce,
Box.easy(plainData, nonce, recipient.keyBytes, from.keyBytes), Box.easy(plainData, nonce, recipient.keyBytes, from.keyBytes),
if (excludeSenderKey) null else from.publicKey from.publicKey
) )
} }
/** /**
* The generated key pair. See [generateKeys] * The generated key pair. See [generateKeys]
*/ */
data class KeyPair(val secretKey: SecretKey, val senderKey: PublicKey) data class KeyPair(val secretKey: SecretKey, val publicKey: PublicKey)
/** /**
* Generate a new random pair of public and secret keys. * Generate a new random pair of public and secret keys.
@ -114,11 +115,18 @@ object Asymmetric {
val nonceBytesLength = crypto_box_NONCEBYTES val nonceBytesLength = crypto_box_NONCEBYTES
/** /**
* The public key used as the recipient for [Message] (see [SecretKey.encrypt], etc.). It also * The public key: [encryptMessage] so only a secret key owner can read it. Allows
* could be used to encrypt anonymous messages with [encryptAnonymously] * anonymous [encryptAnonymousMessage] and signed [encryptMessage] encryption.
*
* Anonymous encryption is very slow in comparison.
*/ */
@Serializable @Serializable
class PublicKey(val keyBytes: UByteArray) { class PublicKey(val keyBytes: UByteArray) {
val tag: KeyTag by lazy {
KeyTag(KeysMagickNumbers.defaultAssymmetric, blake2b(keyBytes))
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is PublicKey) return false if (other !is PublicKey) return false
@ -126,19 +134,57 @@ object Asymmetric {
return keyBytes contentEquals other.keyBytes return keyBytes contentEquals other.keyBytes
} }
override fun hashCode(): Int {
return keyBytes.hashCode()
}
/** /**
* Create an anonymous message that could be decrypted only with the [SecretKey] that corresponds this. * Create an anonymous message that could be decrypted only with the [SecretKey] that corresponds this.
* Anonymous message uses one-time secret key, the public part of which is included into the * Anonymous message uses one-time secret key, the public part of which is included into the
* [Message], so the sender could not be identified. * [Message], so the sender could not be identified.
*
* __Anonymous encryption is much slower__ as it generates new keys every time, use [encryptMessage]
* when possible
*
* The authentication is used despite the anonymity, and the fact of the successful decryption * The authentication is used despite the anonymity, and the fact of the successful decryption
* proves that the message was not altered after creation. * proves that the message was not altered after creation.
*/ */
fun encryptAnonymously(plainData: UByteArray): Message = fun encryptAnonymousMessage(plainData: UByteArray, randomFill: IntRange? = null): Message =
createMessage(generateKeys().secretKey, this, plainData) encryptMessage(plainData,randomFill=randomFill)
/**
* Anonymous encryption, see [encryptAnonymousMessage], to binary data. Sender could not be identified.
*/
@Suppress("unused")
fun encrypt(plainData: UByteArray, randomFill: IntRange? = null): UByteArray =
encryptMessage(plainData, randomFill = randomFill).encoded
/**
* Universal public-key encryption. Note that message authenticity is guaranteed if the decryption is successful
* whether [senderKey] is provider, the latter only allow to positively identify the sender.
*
* @param plainData data to encrypt
* @param nonce allows specifying exact nonce, default to random (safe)
* @param senderKey key to authenticate sending party. It is safe and much faster to specify it,
* otherwise an anonymous key will be created for each encryption, also safe and anonymous, but slow.
*/
fun encryptMessage(
plainData: UByteArray,
nonce: UByteArray = randomNonce(),
senderKey: SecretKey = randomSecretKey(),
randomFill: IntRange? = null,
) = createMessage(senderKey, this, WithFill.encode(plainData, randomFill), nonce)
/**
* Encrypt message using the specified secret key as sender authentication. Recipient, the party having
* [SecretKey] corresponding to this one, will be able to decrypt the message and be sure that [senderKey]
* was the author and the message was not altered.
*/
fun encryptMessage(plainData: UByteArray,
senderKey: SecretKey,
randomFill: IntRange? = null): Message =
createMessage(senderKey, this, WithFill.encode(plainData, randomFill))
override fun hashCode(): Int {
return keyBytes.hashCode()
}
} }
/** /**
@ -151,19 +197,10 @@ object Asymmetric {
val _cachedPublicKey: PublicKey? = null, val _cachedPublicKey: PublicKey? = null,
) : DecryptingKey { ) : DecryptingKey {
/**
* Encrypt the message for [recipient]. The [Message] will include the our [publicKey]
* and thus ready to be decrypted.
*
* The message is authenticated by this secret key.
*/
fun encrypt(plainData: UByteArray, recipient: PublicKey): Message =
createMessage(this, recipient, plainData)
/** /**
* Decrypt with authentication checks the message which must have [Message.senderPublicKey] set. * Decrypt with authentication checks the message which must have [Message.senderPublicKey] set.
* Use [decryptWithSenderKey] otherwise. Note that the authenticated encryption is always use, even if * Use [decryptWithSenderKey] otherwise. Note that the authenticated encryption is always use, even if
* the [PublicKey.encryptAnonymously] was used to create a message, if it is successfully decrypted, * the [PublicKey.encryptAnonymousMessage] was used to create a message, if it is successfully decrypted,
* it is guaranteed that the message was not altered after creation. * it is guaranteed that the message was not altered after creation.
* *
* @throws DecryptionFailedException If the message is tampered (changed after creation) or was not intended for us, * @throws DecryptionFailedException If the message is tampered (changed after creation) or was not intended for us,
@ -213,9 +250,7 @@ object Asymmetric {
return message.decrypt(this) return message.decrypt(this)
} }
override val decryptingTag: KeyTag by lazy { override val tag: KeyTag by lazy { publicKey.tag }
KeyTag(KeysMagickNumbers.defaultAssymmetric, blake2b(publicKey.keyBytes))
}
override val nonceBytesLength: Int override val nonceBytesLength: Int
get() = 0 get() = 0

View File

@ -1,9 +1,148 @@
//package net.sergeych.crypto2 package net.sergeych.crypto2
//
//import kotlinx.serialization.Serializable import kotlinx.serialization.SerialName
// import kotlinx.serialization.Serializable
//@Serializable import kotlinx.serialization.Transient
//sealed class Container { import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder
/*
The problem with container is the following. When we encrypt it with asymmetric key,
we provide public key as the recipient. But public key alone is not effective
as it is restricted to anonymous encryption which is very slow.
We might need an alternative to specify the (sender key,recipient key) pair also. We need a good
solution for it.
*/
@Serializable
sealed class Container {
class InvalidContainerException : Crypto2Exception("the container is invalid")
abstract fun decryptWith(keyRing: UniversalRing): UByteArray?
fun decryptWith(vararg decryptingKeys: DecryptingKey): UByteArray? =
decryptWith(UniversalRing(*decryptingKeys))
@Transient
var decryptedData: UByteArray? = null
val isDecrypted: Boolean get() = decryptedData != null
@Serializable
@SerialName("1")
class Single(val keyTag: KeyTag, val encryptedMessage: UByteArray) : Container() {
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
decryptedData?.let { return it }
for (k in keyRing) {
if (k.tag == keyTag) {
kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let {
decryptedData = it
return it
}
}
}
return null
}
}
@Serializable
@SerialName("*")
class Multi(val encryptedKeys: List<EncryptedKey>, val encryptedMessage: UByteArray) : Container() {
@Serializable
class EncryptedKey(val tag: KeyTag, val cipherData: UByteArray)
private var mainKey: SymmetricKey? = null
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
decryptedData?.let { return it }
for (key in keyRing) {
val tag = key.tag
for (encryptedKey in encryptedKeys) {
if (tag == encryptedKey.tag) {
kotlin.runCatching {
BipackDecoder.decode<SymmetricKey>(
key.decrypt(encryptedKey.cipherData).toByteArray()
)
}.getOrNull()?.let { k ->
if (kotlin.runCatching { decryptedData = k.decrypt(encryptedKey.cipherData) }.isFailure)
throw InvalidContainerException()
mainKey = k
}
if (decryptedData != null) return decryptedData
}
}
}
return null
}
}
val encoded: UByteArray by lazy {
BipackEncoder.encode(this).toUByteArray()
}
companion object {
class Builder internal constructor(private val plainData: UByteArray) {
private val plainKeys = mutableListOf<EncryptingKey>()
private val keyPairs = mutableListOf<Pair<Asymmetric.SecretKey?,Asymmetric.PublicKey>>()
private var fillRange: IntRange? = null
fun key(vararg keys: EncryptingKey) { plainKeys.addAll(keys) }
fun key(vararg pairs: Pair<Asymmetric.SecretKey,Asymmetric.PublicKey>) {
keyPairs.addAll(pairs)
}
fun key(vararg publicKeys: Asymmetric.PublicKey) {
keyPairs.addAll(publicKeys.map { null to it })
}
@Suppress("unused")
fun fill(range: IntRange) {
require(range.first >= 0 ) { "range must be positive"}
fillRange = range
}
fun build(): Container {
return when( plainKeys.size + keyPairs.size ) {
0 -> throw IllegalArgumentException("Container needs at least one key")
1 -> {
plainKeys.firstOrNull()?.let {
Single(it.tag, it.encrypt(plainData, fillRange))
} ?: run {
val (sk, pk) = keyPairs.first()
Single(pk.tag, pk.encryptMessage(plainData,
senderKey = sk ?: Asymmetric.randomSecretKey(),
randomFill = fillRange).encoded)
}
}
else -> {
TODO("multikey")
}
}
}
}
fun create(plainData: UByteArray,builder: Builder.()->Unit) =
Builder(plainData).also { it.builder() }.build()
fun create(plainData: UByteArray, vararg keys: EncryptingKey): Container =
create(plainData) { key(*keys) }
fun create(plainData: UByteArray, vararg keys: Pair<Asymmetric.SecretKey,Asymmetric.PublicKey>) =
create(plainData) { key(*keys) }
fun decode(encoded: UByteArray): Container {
return BipackDecoder.decode(encoded.toByteArray())
}
}
}
// //
// //
// /** // /**

View File

@ -28,7 +28,7 @@ interface DecryptingKey : NonceBased {
fun decryptString(cipherData: UByteArray): String = decrypt(cipherData).decodeFromUByteArray() fun decryptString(cipherData: UByteArray): String = decrypt(cipherData).decodeFromUByteArray()
val decryptingTag: KeyTag val tag: KeyTag
} }

View File

@ -27,7 +27,7 @@ interface EncryptingKey : NonceBased {
fun encrypt(plainText: String,randomFill: IntRange? = null): UByteArray = fun encrypt(plainText: String,randomFill: IntRange? = null): UByteArray =
encrypt(plainText.encodeToUByteArray(),randomFill) encrypt(plainText.encodeToUByteArray(),randomFill)
val encryptingTag: KeyTag val tag: KeyTag
fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange? = null): UByteArray fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange? = null): UByteArray
} }

View File

@ -47,11 +47,14 @@ class SafeKeyExchange {
@Suppress("unused") @Suppress("unused")
val sessionTag: UByteArray by lazy { val sessionTag: UByteArray by lazy {
if (!isClient) if (!isClient)
blake2b(decryptingTag.tag + encryptingTag.tag) blake2b(tag.tag + tag.tag)
else else
blake2b(encryptingTag.tag + decryptingTag.tag) blake2b(tag.tag + tag.tag)
} }
override val tag: KeyTag
get() = if( isClient ) sendingKey.tag else receivingKey.tag
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is SessionKey) return false if (other !is SessionKey) return false

View File

@ -3,8 +3,6 @@ package net.sergeych.crypto2
import com.ionspin.kotlin.crypto.secretbox.SecretBox import com.ionspin.kotlin.crypto.secretbox.SecretBox
import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_NONCEBYTES import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_NONCEBYTES
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder
/** /**
* Symmetric key implements authenticated encrypting with random nonce and optional fill. * Symmetric key implements authenticated encrypting with random nonce and optional fill.
@ -32,36 +30,18 @@ class SymmetricKey(
val nonce: UByteArray, val nonce: UByteArray,
) )
/**
* @suppress
* add some random data to the end of the plain message
*/
@Serializable
data class WithFill(
val data: UByteArray,
val safetyFill: UByteArray? = null,
)
override fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange?): UByteArray { override fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange?): UByteArray {
require(nonce.size == nonceByteLength) require(nonce.size == nonceByteLength)
return SecretBox.easy(WithFill.encode(plainData, randomFill), nonce, keyBytes)
val fill = randomFill?.let {
require(it.start >= 0)
randomUBytes(randomInt(it))
}
val filled = BipackEncoder.encode(WithFill(plainData, fill))
return SecretBox.easy(filled.toUByteArray(), nonce, keyBytes)
} }
override val nonceBytesLength: Int = nonceByteLength override val nonceBytesLength: Int = nonceByteLength
override val encryptingTag by lazy { KeyTag(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) } override val tag by lazy { KeyTag(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) }
override val decryptingTag get() = encryptingTag
override fun decryptWithNonce(cipherData: UByteArray, nonce: UByteArray): UByteArray = override fun decryptWithNonce(cipherData: UByteArray, nonce: UByteArray): UByteArray =
protectDecryption { protectDecryption {
BipackDecoder.decode<WithFill>(SecretBox.openEasy(cipherData, nonce, keyBytes).toByteArray()) WithFill.decode(SecretBox.openEasy(cipherData, nonce, keyBytes))
.data
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {

View File

@ -7,7 +7,7 @@ import kotlinx.serialization.Transient
@Serializable @Serializable
sealed class UniversalKey : DecryptingKey { sealed class UniversalKey : DecryptingKey {
abstract val tag: KeyTag // abstract val tag: KeyTag
@ -15,7 +15,7 @@ sealed class UniversalKey : DecryptingKey {
@SerialName("sy") @SerialName("sy")
data class Symmetric(val key: SymmetricKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key { data class Symmetric(val key: SymmetricKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key {
@Transient @Transient
override val tag: KeyTag = key.encryptingTag override val tag: KeyTag = key.tag
@Transient @Transient
override val nonceBytesLength: Int = key.nonceBytesLength override val nonceBytesLength: Int = key.nonceBytesLength
@ -28,7 +28,7 @@ sealed class UniversalKey : DecryptingKey {
data class Session(val key: SafeKeyExchange.SessionKey) : UniversalKey(), EncryptingKey by key, data class Session(val key: SafeKeyExchange.SessionKey) : UniversalKey(), EncryptingKey by key,
DecryptingKey by key { DecryptingKey by key {
@Transient @Transient
override val tag: KeyTag = key.encryptingTag override val tag: KeyTag = key.tag
@Transient @Transient
override val nonceBytesLength: Int = key.nonceBytesLength override val nonceBytesLength: Int = key.nonceBytesLength
} }
@ -36,7 +36,7 @@ sealed class UniversalKey : DecryptingKey {
@Serializable @Serializable
@SerialName("se") @SerialName("se")
data class Secret(val key: Asymmetric.SecretKey) : UniversalKey(), DecryptingKey by key { data class Secret(val key: Asymmetric.SecretKey) : UniversalKey(), DecryptingKey by key {
override val tag: KeyTag by lazy { key.decryptingTag } override val tag: KeyTag by lazy { key.tag }
override fun toString() = "U.Sec:$tag" override fun toString() = "U.Sec:$tag"
} }

View File

@ -8,6 +8,7 @@ class UniversalRing(
private val keys: Collection<UniversalKey> private val keys: Collection<UniversalKey>
): Collection<UniversalKey> by keys { ): Collection<UniversalKey> by keys {
constructor(vararg keys: UniversalKey) : this(keys.toSet()) constructor(vararg keys: UniversalKey) : this(keys.toSet())
constructor(vararg keys: DecryptingKey) : this(keys.map { UniversalKey.from(it) }.toSet())
@Transient @Transient
val keySet = if( keys is Set<UniversalKey> ) keys else keys.toSet() val keySet = if( keys is Set<UniversalKey> ) keys else keys.toSet()

View File

@ -0,0 +1,37 @@
package net.sergeych.crypto2
import kotlinx.serialization.Serializable
import net.sergeych.bipack.BipackDecoder
import net.sergeych.bipack.BipackEncoder
import net.sergeych.crypto2.WithFill.Companion.decode
import net.sergeych.crypto2.WithFill.Companion.encode
/**
* Utility class to optionally extend a message with random bytes added _before the message bytes_ that
* reduces chances to effective cryptanalysis from the first block. Use
* [encode] and [decode] to process filled data.
*/
@Serializable
class WithFill private constructor(
@Suppress("unused")
val safetyFill: UByteArray = ubyteArrayOf(),
val data: UByteArray,
) {
companion object {
/**
* Create binary data with specified fill
*/
fun encode(data: UByteArray,range: IntRange? = null) =
BipackEncoder.encode(WithFill(range?.let {
require(range.first >= 0) { "range should not be negative" }
randomUBytes(randomInt(it))
} ?: ubyteArrayOf(), data)).toUByteArray()
/**
* extract binary data from filled
*/
fun decode(data: UByteArray): UByteArray =
BipackDecoder.decode<WithFill>(data.toByteArray()).data
}
}

View File

@ -0,0 +1,86 @@
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import kotlinx.coroutines.test.runTest
import net.sergeych.crypto2.Asymmetric
import net.sergeych.crypto2.Container
import net.sergeych.crypto2.SymmetricKey
import net.sergeych.crypto2.initCrypto
import kotlin.test.*
class ContainerTest {
@Test
fun testSingle() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
val data = "sergeych, ohm many.".encodeToUByteArray()
val c = Container.create(data, syk1)
assertFalse { c.isDecrypted }
val c1 = Container.decode(c.encoded)
assertFalse { c.isDecrypted }
assertIs<Container.Single>(c)
assertNull(c1.decryptWith(syk2))
val d = c1.decryptWith(syk2, syk1)
assertNotNull(d)
assertContentEquals(data, d)
assertTrue { c1.isDecrypted }
}
@Test
fun testSinglePair() = runTest {
initCrypto()
val p1 = Asymmetric.generateKeys()
val p2 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()
val data = "sergeych, ohm many.".encodeToUByteArray()
val c = Container.create(data, p1.secretKey to p2.publicKey)
assertFalse { c.isDecrypted }
val c1 = Container.decode(c.encoded)
assertFalse { c.isDecrypted }
assertIs<Container.Single>(c)
assertNull(c1.decryptWith(p3.secretKey))
val d = c1.decryptWith(p3.secretKey, p2.secretKey)
assertNotNull(d)
assertContentEquals(data, d)
assertTrue { c1.isDecrypted }
}
@Test
fun testSingleAsymmetric() = runTest {
initCrypto()
// val p1 = Asymmetric.generateKeys()
val p2 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys()
val data = "sergeych, ohm many.".encodeToUByteArray()
val c = Container.create(data) { key(p2.publicKey) }
assertFalse { c.isDecrypted }
val c1 = Container.decode(c.encoded)
assertFalse { c.isDecrypted }
assertIs<Container.Single>(c)
assertNull(c1.decryptWith(p3.secretKey))
val d = c1.decryptWith(p3.secretKey, p2.secretKey)
assertNotNull(d)
assertContentEquals(data, d)
assertTrue { c1.isDecrypted }
}
@Test
fun testMultipleSymmetric() = runTest {
initCrypto()
val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random()
// val syk3 = SymmetricKey.random()
val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'"
.encodeToUByteArray()
val c = Container.create(data, syk1, syk2)
assertFalse { c.isDecrypted }
val c1 = Container.decode(c.encoded)
assertFalse { c1.isDecrypted }
}
}

View File

@ -3,7 +3,6 @@ import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import net.sergeych.bipack.BipackEncoder
import net.sergeych.crypto2.* import net.sergeych.crypto2.*
import net.sergeych.utools.now import net.sergeych.utools.now
import net.sergeych.utools.pack import net.sergeych.utools.pack
@ -140,25 +139,24 @@ class KeysTest {
val plain = "The fake vaccine kills".encodeToUByteArray() val plain = "The fake vaccine kills".encodeToUByteArray()
var m = Asymmetric.createMessage(sk0, pk1, plain) var m = pk1.encryptMessage(plain, sk1)
assertContentEquals(plain, m.decrypt(sk1)) assertContentEquals(plain, m.decrypt(sk1))
assertThrows<DecryptionFailedException> { assertThrows<DecryptionFailedException> {
assertContentEquals(plain, m.decrypt(sk2)) assertContentEquals(plain, m.decrypt(sk2))
} }
m = pk2.encryptAnonymously(plain) m = pk2.encryptAnonymousMessage(plain)
assertContentEquals(plain, m.decrypt(sk2)) assertContentEquals(plain, m.decrypt(sk2))
assertContentEquals(plain, sk2.decrypt(m)) assertContentEquals(plain, sk2.decrypt(m))
assertContentEquals(plain, sk2.decrypt(sk1.encrypt(plain, pk2))) // assertContentEquals(plain, sk2.decrypt(sk1.encrypt(plain, pk2)))
assertThrows<DecryptionFailedException> { assertThrows<DecryptionFailedException> {
assertContentEquals(plain, m.decrypt(sk1)) assertContentEquals(plain, m.decrypt(sk1))
} }
val x1 = BipackEncoder.encode(Asymmetric.createMessage(sk0, pk1, plain)) val x1 = pk1.encryptMessage(plain, sk1).encoded
val x2 = BipackEncoder.encode(Asymmetric.createMessage(sk0, pk1, plain)) val x2 = pk1.encryptMessage(plain, sk1).encoded
assertFalse { x1 contentEquals x2 } assertFalse { x1 contentEquals x2 }
} }
@Test @Test
fun asymmetricKeySerializationTest() = runTest { fun asymmetricKeySerializationTest() = runTest {

View File

@ -52,4 +52,9 @@ class RingTest {
assertEquals(r, r2) assertEquals(r, r2)
} }
@Test
@Ignore
fun testKeysWithSameTags() {
// it should be able to keep keys with same tags
}
} }