0.7.4-SNAPSHOT back to no wasm; public/secret key renamed with compatibility aliases and deprecation warnings
This commit is contained in:
parent
d180da309b
commit
e2d4fb07ad
@ -9,7 +9,6 @@
|
||||
*/
|
||||
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
@ -20,13 +19,13 @@ plugins {
|
||||
}
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.8.1"
|
||||
version = "0.7.4-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://maven.universablockchain.com/")
|
||||
maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
|
||||
maven("https://gitea.sergeych.net/api/packages/YoungBlood/maven")
|
||||
// maven("https://gitea.sergeych.net/api/packages/YoungBlood/maven")
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@ -50,10 +49,10 @@ kotlin {
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
mingwX64()
|
||||
@OptIn(ExperimentalWasmDsl::class)
|
||||
wasmJs {
|
||||
browser()
|
||||
}
|
||||
// @OptIn(ExperimentalWasmDsl::class)
|
||||
// wasmJs {
|
||||
// browser()
|
||||
// }
|
||||
val ktor_version = "2.3.6"
|
||||
|
||||
sourceSets {
|
||||
@ -97,18 +96,18 @@ kotlin {
|
||||
for (platform in listOf(linuxX64Main, linuxArm64Main, macosX64Main, macosArm64Main, iosX64Main, iosArm64Main, iosSimulatorArm64Main, mingwX64Main))
|
||||
platform { dependsOn(native) }
|
||||
|
||||
val wasmJsMain by getting {
|
||||
val wasmJsTargetRegex = Regex(pattern = "wasmJs.*")
|
||||
configurations.all {
|
||||
if (wasmJsTargetRegex.containsMatchIn(input = this.name)) {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute(module("com.ionspin.kotlin:multiplatform-crypto-libsodium-bindings:0.9.2"))
|
||||
.using(module("net.sergeych:multiplatform-crypto-libsodium-bindings:0.9.4-SNAPSHOT"))
|
||||
.withoutClassifier()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// val wasmJsMain by getting {
|
||||
// val wasmJsTargetRegex = Regex(pattern = "wasmJs.*")
|
||||
// configurations.all {
|
||||
// if (wasmJsTargetRegex.containsMatchIn(input = this.name)) {
|
||||
// resolutionStrategy.dependencySubstitution {
|
||||
// substitute(module("com.ionspin.kotlin:multiplatform-crypto-libsodium-bindings:0.9.2"))
|
||||
// .using(module("net.sergeych:multiplatform-crypto-libsodium-bindings:0.9.4-SNAPSHOT"))
|
||||
// .withoutClassifier()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,10 @@ import net.sergeych.crypto2.Asymmetric.generateKeys
|
||||
*
|
||||
* ## How to
|
||||
*
|
||||
* - [SecretKey.new] to create a secret key that includes [SecretKey.publicKey].
|
||||
* - [DecryptingSecretKey.new] to create a secret key that includes [DecryptingSecretKey.publicKey].
|
||||
* [generateKeys] also makes the pair.
|
||||
* - [PublicKey] provides encryption, anonymous or authenticated.
|
||||
* - [SecretKey] provides authenticated decryption of what [PublicKey] was encrypted with.
|
||||
* - [EncryptingPublicKey] provides encryption, anonymous or authenticated.
|
||||
* - [DecryptingSecretKey] provides authenticated decryption of what [EncryptingPublicKey] was encrypted with.
|
||||
* - [Message] is a serializable container with all necessary data to decrypt public-key encrypted data it.
|
||||
*
|
||||
* __Algorithms:__
|
||||
@ -41,8 +41,8 @@ object Asymmetric {
|
||||
/**
|
||||
* Encrypted message holder.
|
||||
*
|
||||
* 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].
|
||||
* Do not instantiate it directly, use [EncryptingPublicKey.encryptMessage], [EncryptingPublicKey.encryptAnonymousMessage], etc.
|
||||
* instead. Also [DecryptingSecretKey.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.
|
||||
* This class carries all this information; serialize and pass it to the recipient.
|
||||
@ -51,12 +51,12 @@ object Asymmetric {
|
||||
class Message(
|
||||
private val nonce: UByteArray,
|
||||
private val encryptedMessage: UByteArray,
|
||||
val senderPublicKey: PublicKey,
|
||||
val senderPublicKey: EncryptingPublicKey,
|
||||
) {
|
||||
/**
|
||||
* Decrypt the message, same as [SecretKey.decrypt]
|
||||
* Decrypt the message, same as [DecryptingSecretKey.decrypt]
|
||||
*/
|
||||
fun decrypt(recipientKey: SecretKey): UByteArray {
|
||||
fun decrypt(recipientKey: DecryptingSecretKey): UByteArray {
|
||||
return decryptWithSenderKey(senderPublicKey, recipientKey)
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ object Asymmetric {
|
||||
* Decrypt a message which is not include sender's public key (which should somehow be
|
||||
* known to the recipient). Use it if [senderPublicKey] is null.
|
||||
*/
|
||||
fun decryptWithSenderKey(senderKey: PublicKey, recipientKey: SecretKey): UByteArray {
|
||||
fun decryptWithSenderKey(senderKey: EncryptingPublicKey, recipientKey: DecryptingSecretKey): UByteArray {
|
||||
return try {
|
||||
WithFill.decode(
|
||||
Box.openEasy(encryptedMessage, nonce, senderKey.keyBytes, recipientKey.keyBytes)
|
||||
@ -89,19 +89,19 @@ object Asymmetric {
|
||||
|
||||
/**
|
||||
* Encrypt the [plainData] using [from] sender for [recipient] public key. Note that to decrypt it
|
||||
* the [SecretKey] that corresponds to the [recipient] public key is needed, Sender can't decrypt the message!
|
||||
* the [DecryptingSecretKey] that corresponds to the [recipient] public key is needed, Sender can't decrypt the message!
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* When it is important not to provide senders' key, use [PublicKey.encryptAnonymousMessage].
|
||||
* When it is important not to provide senders' key, use [EncryptingPublicKey.encryptAnonymousMessage].
|
||||
*
|
||||
* @param from the senders' secret key.
|
||||
* @param recipient the recipients' public key.
|
||||
* @param plainData data to encrypt
|
||||
*/
|
||||
internal fun createMessage(
|
||||
from: SecretKey, recipient: PublicKey, plainData: UByteArray,
|
||||
from: DecryptingSecretKey, recipient: EncryptingPublicKey, plainData: UByteArray,
|
||||
nonce: UByteArray = randomNonce(),
|
||||
): Message {
|
||||
return Message(
|
||||
@ -114,8 +114,8 @@ object Asymmetric {
|
||||
|
||||
private fun randomNonce(): UByteArray = randomUBytes(crypto_box_NONCEBYTES)
|
||||
|
||||
fun generateKeys() = SecretKey.generateKeys()
|
||||
fun newSecretKey() = SecretKey.new()
|
||||
fun generateKeys() = DecryptingSecretKey.generateKeys()
|
||||
fun newSecretKey() = DecryptingSecretKey.new()
|
||||
|
||||
val nonceBytesLength = crypto_box_NONCEBYTES
|
||||
|
||||
@ -125,4 +125,4 @@ object Asymmetric {
|
||||
* Shortcut type: a pair of sender secret key and recipient private key could be used so
|
||||
* simplify such interfaces
|
||||
*/
|
||||
typealias AsymmetricEncryptionPair = Pair<SecretKey?, PublicKey>
|
||||
typealias AsymmetricEncryptionPair = Pair<DecryptingSecretKey?, EncryptingPublicKey>
|
||||
|
@ -58,7 +58,7 @@ open class BinaryId(
|
||||
/**
|
||||
* Bad format (crc does not match)
|
||||
*/
|
||||
class InvalidException(text: String,reason: Throwable?=null) : IllegalArgumentException(text,reason)
|
||||
class InvalidException(text: String, reason: Throwable? = null) : IllegalArgumentException(text, reason)
|
||||
|
||||
/**
|
||||
* Attempt to compare binary ids with different magic. In this case only [equals]
|
||||
@ -80,32 +80,32 @@ open class BinaryId(
|
||||
rest.last().toInt()
|
||||
}
|
||||
|
||||
private val innerData: UByteArray by lazy { id.sliceArray( 1..< id.size-1 ) }
|
||||
private val innerData: UByteArray by lazy { id.sliceArray(1..<id.size - 1) }
|
||||
|
||||
/**
|
||||
* The ID body: all the bytes except check and magic. ID bytes could carry useful information.
|
||||
*
|
||||
* - `id.size` is [body] size + 2 (see [BinaryId] inner structure)
|
||||
*/
|
||||
val body: UByteArray by lazy { id.sliceArray( 0 until id.size-2 ) }
|
||||
val body: UByteArray by lazy { id.sliceArray(0 until id.size - 2) }
|
||||
|
||||
val asVerifyingKey: VerifyingKey by lazy {
|
||||
if( magic != KeysmagicNumber.defaultVerifying.ordinal)
|
||||
if (magic != KeysmagicNumber.defaultVerifying.ordinal)
|
||||
throw InvalidException("It is not a veryfing key: magic=$magic, required ${KeysmagicNumber.defaultVerifying.ordinal}")
|
||||
check(body.size == 32)
|
||||
VerifyingPublicKey(body)
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to recnstruct a [PublicKey] from [id] bytes. For such keys, [PublicKey.id] and [SecretKey.id]
|
||||
* Try to recnstruct a [EncryptingPublicKey] from [id] bytes. For such keys, [EncryptingPublicKey.id] and [DecryptingSecretKey.id]
|
||||
* are made from public key bytes so it could be restored from such an ID
|
||||
*
|
||||
*/
|
||||
val asPublicKey: PublicKey by lazy {
|
||||
if( magic != KeysmagicNumber.defaultAssymmetric.ordinal)
|
||||
val asPublicKey: EncryptingPublicKey by lazy {
|
||||
if (magic != KeysmagicNumber.defaultAssymmetric.ordinal)
|
||||
throw InvalidException("It is not a veryfing key: magic=$magic, required ${KeysmagicNumber.defaultAssymmetric.ordinal}")
|
||||
check(body.size == 32)
|
||||
PublicKey(body)
|
||||
EncryptingPublicKey(body)
|
||||
}
|
||||
|
||||
override fun toString(): String = id.encodeToBase64Url()
|
||||
@ -167,8 +167,8 @@ open class BinaryId(
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun createRandom(magicNumber: Int, size: Int=16) =
|
||||
createFromBytes(magicNumber, Random.Default.nextBytes(size-2))
|
||||
fun createRandom(magicNumber: Int, size: Int = 16) =
|
||||
createFromBytes(magicNumber, Random.Default.nextBytes(size - 2))
|
||||
|
||||
/**
|
||||
* Encode a string as UTF and create a binaryId from its bytes and provided magic.
|
||||
|
@ -34,8 +34,8 @@ import net.sergeych.crypto2.Container.Companion.createWith
|
||||
*
|
||||
* Some rules:
|
||||
*
|
||||
* When adding public key recipient, it is faster to use your known [SecretKey], but you
|
||||
* can stay anonymous by just adding [PublicKey] only.
|
||||
* When adding public key recipient, it is faster to use your known [DecryptingSecretKey], but you
|
||||
* can stay anonymous by just adding [EncryptingPublicKey] only.
|
||||
*
|
||||
* Put your data in [SealedBox] if you need to authenticate message origin and timestamp, then put
|
||||
* the sealed box in the [Container], this will conceal signers from attack. In the case you need to
|
||||
@ -117,7 +117,7 @@ sealed class Container {
|
||||
* Add e key to the __decrypted__ container. The new container is also decrypted so you can add
|
||||
* more keys, etc.
|
||||
*/
|
||||
operator fun plus(recipient: PublicKey) = addRecipients { key(recipient) }
|
||||
operator fun plus(recipient: EncryptingPublicKey) = addRecipients { key(recipient) }
|
||||
|
||||
/**
|
||||
* Add e key to the __decrypted__ container. The new container is also decrypted so you can add
|
||||
@ -129,7 +129,7 @@ sealed class Container {
|
||||
* Add e key to the __decrypted__ container. The new container is also decrypted so you can add
|
||||
* more keys, etc.
|
||||
*/
|
||||
operator fun plus(pair: Pair<SecretKey, PublicKey>) = addRecipients { key(pair) }
|
||||
operator fun plus(pair: Pair<DecryptingSecretKey, EncryptingPublicKey>) = addRecipients { key(pair) }
|
||||
|
||||
/**
|
||||
* Update the data in the decrypted container. It keeps the same set of keys and update
|
||||
@ -155,14 +155,14 @@ sealed class Container {
|
||||
abstract val decryptedWithKeyId: KeyId?
|
||||
|
||||
/**
|
||||
* If the container _is decrypted by the [PublicKey]_, e.g., using secret key encryption,
|
||||
* contains the [PublicKey] that corresponds the [SecretKey] used while encrypting, this
|
||||
* If the container _is decrypted by the [EncryptingPublicKey]_, e.g., using secret key encryption,
|
||||
* contains the [EncryptingPublicKey] that corresponds the [DecryptingSecretKey] used while encrypting, this
|
||||
* authenticating the sender party cryptographically. This key could be used to encrypt
|
||||
* the response to be visible to the sender only; the sender, providing it kept his secret key,
|
||||
* could decrypt it.
|
||||
*/
|
||||
@Transient
|
||||
var authorisedByKey: PublicKey? = null
|
||||
var authorisedByKey: EncryptingPublicKey? = null
|
||||
protected set
|
||||
|
||||
/**
|
||||
@ -203,7 +203,7 @@ sealed class Container {
|
||||
kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let {
|
||||
decryptedData = it
|
||||
decryptedWithKey = k
|
||||
if( k is SecretKey) {
|
||||
if(k is DecryptingSecretKey) {
|
||||
authorisedByKey = Asymmetric.Message.decode(encryptedMessage).senderPublicKey
|
||||
}
|
||||
return it
|
||||
@ -226,7 +226,7 @@ sealed class Container {
|
||||
// otherwise, we don't know the encryption key and will try to derive it
|
||||
// from the decryption key:
|
||||
when (val k = decryptedWithKey!!) {
|
||||
is SecretKey -> {
|
||||
is DecryptingSecretKey -> {
|
||||
key(k.publicKey)
|
||||
}
|
||||
|
||||
@ -269,12 +269,12 @@ sealed class Container {
|
||||
constructor(key: EncryptingKey, encodeMainKey: UByteArray) :
|
||||
this(key.id, key.encrypt(encodeMainKey))
|
||||
|
||||
constructor(sender: SecretKey?, recipient: PublicKey, encodeMainKey: UByteArray) :
|
||||
constructor(sender: DecryptingSecretKey?, recipient: EncryptingPublicKey, encodeMainKey: UByteArray) :
|
||||
this(
|
||||
recipient.id,
|
||||
recipient.encryptMessage(
|
||||
encodeMainKey,
|
||||
senderKey = sender ?: SecretKey.new(),
|
||||
senderKey = sender ?: DecryptingSecretKey.new(),
|
||||
).encoded
|
||||
)
|
||||
}
|
||||
@ -304,7 +304,7 @@ sealed class Container {
|
||||
throw InvalidContainerException()
|
||||
decryptedWithKeyId = key.id
|
||||
mainKey = k
|
||||
if( key is SecretKey) {
|
||||
if(key is DecryptingSecretKey) {
|
||||
authorisedByKey = Asymmetric.Message.decode(encryptedKey.cipherData).senderPublicKey
|
||||
}
|
||||
}
|
||||
@ -368,8 +368,8 @@ sealed class Container {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one or more [SecretKey] as sender authority coupled with [PublicKey] as
|
||||
* a recipient. This is faster than anonymous usage of [PublicKey] only
|
||||
* Add one or more [DecryptingSecretKey] as sender authority coupled with [EncryptingPublicKey] as
|
||||
* a recipient. This is faster than anonymous usage of [EncryptingPublicKey] only
|
||||
*/
|
||||
fun key(vararg pairs: AsymmetricEncryptionPair) {
|
||||
keyPairs.addAll(pairs)
|
||||
@ -378,7 +378,7 @@ sealed class Container {
|
||||
/**
|
||||
* Add one or more public keys as recipients. This is slower than using pairs of sender -> recipient.
|
||||
*/
|
||||
fun key(vararg publicKeys: PublicKey) {
|
||||
fun key(vararg publicKeys: EncryptingPublicKey) {
|
||||
keyPairs.addAll(publicKeys.map { null to it })
|
||||
}
|
||||
|
||||
@ -439,7 +439,7 @@ sealed class Container {
|
||||
Single(
|
||||
pk.id, pk.encryptMessage(
|
||||
plainData,
|
||||
senderKey = sk ?: SecretKey.new(),
|
||||
senderKey = sk ?: DecryptingSecretKey.new(),
|
||||
randomFill = fillRange
|
||||
).encoded,
|
||||
plainData,
|
||||
|
@ -18,7 +18,7 @@ import net.sergeych.crypto2.SymmetricKey.WithNonce
|
||||
/**
|
||||
* Some key able to perform decrypting. It is not serializable by purpose, as not all such
|
||||
* keys are wise to transfer/save. Concrete implementations are, like [SymmetricKey] or
|
||||
* [SecretKey].
|
||||
* [DecryptingSecretKey].
|
||||
*/
|
||||
interface DecryptingKey : NonceBased, KeyInstance {
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@ import kotlinx.serialization.Serializable
|
||||
* Important. `KeyId` of matching keys are the same, so you can use it to identify
|
||||
* and find matching keys in the [UniversalRing], etc. For example:
|
||||
*
|
||||
* - [SecretKey] and [PublicKey] from the same pair have the same `KeyId`, thus the former
|
||||
* - [DecryptingSecretKey] and [EncryptingPublicKey] from the same pair have the same `KeyId`, thus the former
|
||||
* can decrypt what was encrypted with the latter.
|
||||
*
|
||||
* - [SigningSecretKey] and corresponding [VerifyingKey] have the same `KeyId`. Use it to pick a proper key for
|
||||
@ -28,7 +28,7 @@ import kotlinx.serialization.Serializable
|
||||
*
|
||||
* See [PBKD.Params.deriveKey] for deriving keys from id.
|
||||
*
|
||||
* See [id], and [BinaryId] class for more. Note that for [PublicKey] and [VerifyingPublicKey] [BinaryId.asPublicKey]
|
||||
* See [id], and [BinaryId] class for more. Note that for [EncryptingPublicKey] and [VerifyingPublicKey] [BinaryId.asPublicKey]
|
||||
* and [BinaryId.asVerifyingKey] restore actual keys, providing [BinaryId.magic] has proper value, see [KeysmagicNumber]]
|
||||
*
|
||||
* @param id actual id used in equality test amd hash code generation. `Id` of the matching keys is the same.
|
||||
|
@ -17,20 +17,22 @@ import net.sergeych.bipack.decodeFromBipack
|
||||
import net.sergeych.crypto2.VerifyingPublicKey.Companion.toString
|
||||
import net.sergeych.mp_tools.decodeBase64Url
|
||||
|
||||
@Deprecated("Use EncryptingPublicKey",ReplaceWith("EncryptingPublicKey"))
|
||||
typealias PublicKey = EncryptingPublicKey
|
||||
/**
|
||||
* The public for public-key encryption. It encrypts messages that can only be decrypted with corresponding
|
||||
* [SecretKey].
|
||||
* [DecryptingSecretKey].
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("encp")
|
||||
class PublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingKey {
|
||||
class EncryptingPublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingKey {
|
||||
|
||||
override val magic: KeysmagicNumber = KeysmagicNumber.defaultAssymmetric
|
||||
@Transient
|
||||
override val label: String = "pub"
|
||||
|
||||
/**
|
||||
* 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 [DecryptingSecretKey] that corresponds this.
|
||||
* Anonymous message uses one-time secret key, the public part of which is included into the
|
||||
* [Asymmetric.Message], so the sender could not be identified.
|
||||
*
|
||||
@ -67,18 +69,18 @@ class PublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingK
|
||||
fun encryptMessage(
|
||||
plainData: UByteArray,
|
||||
nonce: UByteArray = randomNonce(),
|
||||
senderKey: SecretKey = newSecretKey(),
|
||||
senderKey: DecryptingSecretKey = newSecretKey(),
|
||||
randomFill: IntRange? = null,
|
||||
) = Asymmetric.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]
|
||||
* [DecryptingSecretKey] 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,
|
||||
senderKey: DecryptingSecretKey,
|
||||
randomFill: IntRange? = null,
|
||||
): Asymmetric.Message =
|
||||
Asymmetric.createMessage(senderKey, this, WithFill.encode(plainData, randomFill))
|
||||
@ -91,12 +93,12 @@ class PublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingK
|
||||
* possible)
|
||||
* @throws IllegalArgumentException the public key isn't recognized
|
||||
*/
|
||||
fun parse(text: String): PublicKey {
|
||||
fun parse(text: String): EncryptingPublicKey {
|
||||
val s = text.trim()
|
||||
|
||||
fun parseId(t: String): PublicKey{
|
||||
fun parseId(t: String): EncryptingPublicKey {
|
||||
val id = BinaryId.restoreFromString(t)
|
||||
if( id.magic != KeysmagicNumber.defaultAssymmetric.ordinal)
|
||||
if (id.magic != KeysmagicNumber.defaultAssymmetric.ordinal)
|
||||
throw IllegalArgumentException("invalid magick ${id.magic} for PublicKey")
|
||||
return id.asPublicKey
|
||||
}
|
||||
@ -110,10 +112,10 @@ class PublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingK
|
||||
// consider it is serialized key in base64 format
|
||||
val data = s.decodeBase64Url().asUByteArray()
|
||||
if (data.size == 32)
|
||||
PublicKey(data)
|
||||
EncryptingPublicKey(data)
|
||||
else {
|
||||
runCatching { data.decodeFromBipack<PublicKey>() }.getOrNull()
|
||||
?: kotlin.runCatching { data.decodeFromBipack<UniversalKey>() as PublicKey }
|
||||
runCatching { data.decodeFromBipack<EncryptingPublicKey>() }.getOrNull()
|
||||
?: kotlin.runCatching { data.decodeFromBipack<UniversalKey>() as EncryptingPublicKey }
|
||||
.getOrElse { throw IllegalArgumentException("can't parse verifying key") }
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import net.sergeych.crypto2.SafeKeyExchange.SessionKey
|
||||
* Usage:
|
||||
*
|
||||
* 1. Create [SafeKeyExchange] on both server and client sides
|
||||
* 2. Exchange [publicKey] instances
|
||||
* 2. Exchange [EncryptingPublicKey] instances
|
||||
* 3. Create [serverSessionKey] and [clientSessionKey] respectively
|
||||
* 4. Use [SessionKey.sendingKey] and [SessionKey.receivingKey] to send and receive encrypted data.
|
||||
*
|
||||
@ -30,7 +30,7 @@ import net.sergeych.crypto2.SafeKeyExchange.SessionKey
|
||||
* instances as often as performance considerations allow.
|
||||
* - while it is possible to generate several keys "ahead", the care should be taken when storing them,
|
||||
* encrypt it with some other key to maintain safety.
|
||||
* - do not use [publicKey] for anything but creating session keys.
|
||||
* - do not use [EncryptingPublicKey] for anything but creating session keys.
|
||||
*/
|
||||
class SafeKeyExchange {
|
||||
private val pair = KeyExchange.keypair()
|
||||
|
@ -109,7 +109,7 @@ class Seal(
|
||||
* to check the authenticity of the arbitrary [message] using a public key, [VerifyingPublicKey]
|
||||
* instance, using public-key signing algorithms.
|
||||
*
|
||||
* Unlike a regular binary signature, Seal contains the signer's [publicKey], and also
|
||||
* Unlike a regular binary signature, Seal contains the signer's [EncryptingPublicKey], and also
|
||||
* [createdAt] and [expiresAt] fields which are also signed and are guaranteed to be non-tampered
|
||||
* if the [isValid] returns true (or [verify] does not throw). See [isExpired].
|
||||
*
|
||||
|
@ -16,24 +16,28 @@ import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
|
||||
@Deprecated("Use DecryptingSecretKey instead",ReplaceWith("DecryptingSecretKey"))
|
||||
typealias SecretKey = DecryptingSecretKey
|
||||
|
||||
/**
|
||||
* The secret key used in public-key encryption; it is used to _decrypt_ data encrypted with its
|
||||
* public counterpart, see [publicKey].
|
||||
* public counterpart, see [EncryptingPublicKey].
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("encs")
|
||||
class SecretKey(
|
||||
class DecryptingSecretKey(
|
||||
override val keyBytes: UByteArray,
|
||||
@Transient
|
||||
val _cachedPublicKey: PublicKey? = null,
|
||||
val _cachedPublicKey: EncryptingPublicKey? = null,
|
||||
) : DecryptingKey, UniversalKey() {
|
||||
|
||||
@Transient
|
||||
override val label: String = "sec"
|
||||
|
||||
/**
|
||||
* Decrypt with authentication checks the message which must have [Asymmetric.Message.senderPublicKey] set.
|
||||
* Use [decryptWithSenderKey] otherwise. Note that the authenticated encryption is always use, even if
|
||||
* the [PublicKey.encryptAnonymousMessage] was used to create a message, if it is successfully decrypted,
|
||||
* the [EncryptingPublicKey.encryptAnonymousMessage] was used to create a message, if it is successfully decrypted,
|
||||
* 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,
|
||||
@ -45,20 +49,20 @@ class SecretKey(
|
||||
* Decrypt using [senderPublicKey] as a sender key (overriding the [Asymmetric.Message.senderPublicKey] if set).
|
||||
* See [decrypt] for more.
|
||||
*/
|
||||
fun decryptWithSenderKey(message: Asymmetric.Message, senderPublicKey: PublicKey): UByteArray =
|
||||
fun decryptWithSenderKey(message: Asymmetric.Message, senderPublicKey: EncryptingPublicKey): UByteArray =
|
||||
message.decryptWithSenderKey(senderPublicKey, this)
|
||||
|
||||
@Transient
|
||||
private var cachedPublicKey: PublicKey? = _cachedPublicKey
|
||||
private var cachedPublicKey: EncryptingPublicKey? = _cachedPublicKey
|
||||
|
||||
/**
|
||||
* The corresponding public key
|
||||
*/
|
||||
val publicKey: PublicKey by lazy {
|
||||
val publicKey: EncryptingPublicKey by lazy {
|
||||
if (cachedPublicKey != null)
|
||||
cachedPublicKey!!
|
||||
else
|
||||
PublicKey(ScalarMultiplication.scalarMultiplicationBase(keyBytes))
|
||||
EncryptingPublicKey(ScalarMultiplication.scalarMultiplicationBase(keyBytes))
|
||||
.also { cachedPublicKey = it }
|
||||
}
|
||||
|
||||
@ -81,18 +85,18 @@ class SecretKey(
|
||||
get() = 0
|
||||
|
||||
companion object {
|
||||
data class KeyPair(val secretKey: SecretKey, val publicKey: PublicKey)
|
||||
data class KeyPair(val secretKey: DecryptingSecretKey, val publicKey: EncryptingPublicKey)
|
||||
|
||||
/**
|
||||
* Generate a new random pair of public and secret keys.
|
||||
*/
|
||||
fun generateKeys(): KeyPair {
|
||||
val p = Box.keypair()
|
||||
val pk = PublicKey(p.publicKey)
|
||||
return KeyPair(SecretKey(p.secretKey, pk), pk)
|
||||
val pk = EncryptingPublicKey(p.publicKey)
|
||||
return KeyPair(DecryptingSecretKey(p.secretKey, pk), pk)
|
||||
}
|
||||
|
||||
fun new(): SecretKey = generateKeys().secretKey
|
||||
fun new(): DecryptingSecretKey = generateKeys().secretKey
|
||||
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ sealed class UniversalKey : KeyInstance {
|
||||
|
||||
/**
|
||||
* Key ID positively identify key from the point of view of _decrypting or verifying_. So matching [VerifyingKey]
|
||||
* and [SigningKey] will have the same id, same as matching [PublicKey] and [SecretKey].
|
||||
* and [SigningKey] will have the same id, same as matching [EncryptingPublicKey] and [DecryptingSecretKey].
|
||||
*
|
||||
* KeyId is based on [BinaryId] which includes checksum (crc8) and magick number for additional security,
|
||||
* see [KeysmagicNumber].
|
||||
@ -53,7 +53,7 @@ sealed class UniversalKey : KeyInstance {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newSecretKey() = SecretKey.new()
|
||||
fun newSecretKey() = DecryptingSecretKey.new()
|
||||
fun newSigningKey() = SigningSecretKey.new()
|
||||
|
||||
@Suppress("unused")
|
||||
@ -67,7 +67,7 @@ sealed class UniversalKey : KeyInstance {
|
||||
val s = text.trim()
|
||||
return when {
|
||||
s.startsWith("\uD83D\uDDDDpub#") || s.startsWith("pub#") ->
|
||||
PublicKey.parse(s)
|
||||
EncryptingPublicKey.parse(s)
|
||||
s.startsWith("\uD83D\uDDDDver#") || s.startsWith("ver#") ->
|
||||
VerifyingPublicKey.parse(s)
|
||||
else -> {
|
||||
|
@ -24,7 +24,7 @@ import kotlinx.serialization.Transient
|
||||
@SerialName("uprv")
|
||||
class UniversalPrivateKey(
|
||||
val signingKey: SigningSecretKey,
|
||||
val decryptingKey: SecretKey
|
||||
val decryptingKey: DecryptingSecretKey
|
||||
) : UniversalKey(), DecryptingKey by decryptingKey, SigningKey by signingKey {
|
||||
|
||||
override val keyBytes by lazy { signingKey.keyBytes + decryptingKey.keyBytes }
|
||||
@ -52,6 +52,6 @@ class UniversalPrivateKey(
|
||||
* Generate 2 new random keys (4 key pairs under the hood) to securely signd and
|
||||
* decrypt data.
|
||||
*/
|
||||
fun new() = UniversalPrivateKey(SigningSecretKey.new(), SecretKey.new())
|
||||
fun new() = UniversalPrivateKey(SigningSecretKey.new(), DecryptingSecretKey.new())
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ import kotlinx.serialization.Transient
|
||||
@SerialName("upub")
|
||||
class UniversalPublicKey(
|
||||
val verifyingKey: VerifyingPublicKey,
|
||||
val encryptingKey: PublicKey
|
||||
val encryptingKey: EncryptingPublicKey
|
||||
): UniversalKey(), VerifyingKey by verifyingKey, EncryptingKey by encryptingKey{
|
||||
|
||||
override val keyBytes by lazy { verifyingKey.keyBytes + encryptingKey.keyBytes }
|
||||
|
@ -48,7 +48,7 @@ class UniversalRing(
|
||||
|
||||
/**
|
||||
* Find a key of the specified type that matches the id. In general, you require key implementations like
|
||||
* [SecretKey], [PublicKey], [VerifyingPublicKey], [SigningSecretKey] and [SymmetricKey],
|
||||
* [DecryptingSecretKey], [EncryptingPublicKey], [VerifyingPublicKey], [SigningSecretKey] and [SymmetricKey],
|
||||
* or just key interfaces: [EncryptingKey], [DecryptingKey], [SigningKey] and [VerifyingKey].
|
||||
*
|
||||
* Note that key interfaces are not serializable as for now, you should try to cast to a serializable
|
||||
|
@ -187,7 +187,7 @@ class KeysTest {
|
||||
// println(sk0.publicKey)
|
||||
val j = Json { prettyPrint = true }
|
||||
|
||||
val sk1 = j.decodeFromString<SecretKey>(j.encodeToString(sk0))
|
||||
val sk1 = j.decodeFromString<DecryptingSecretKey>(j.encodeToString(sk0))
|
||||
assertEquals(sk0, sk1)
|
||||
assertEquals(pk0, sk1.publicKey)
|
||||
// println(j.encodeToString(sk1))
|
||||
@ -216,9 +216,9 @@ class KeysTest {
|
||||
assertEquals(usy2, usy1)
|
||||
assertFalse { usy1 == usy3 }
|
||||
|
||||
val sk1 = SecretKey.new()
|
||||
val sk2 = SecretKey(sk1.keyBytes)
|
||||
val sk3 = SecretKey.new()
|
||||
val sk1 = DecryptingSecretKey.new()
|
||||
val sk2 = DecryptingSecretKey(sk1.keyBytes)
|
||||
val sk3 = DecryptingSecretKey.new()
|
||||
|
||||
assertEquals(sk1, sk2)
|
||||
assertEquals(sk2, sk1)
|
||||
@ -418,13 +418,13 @@ class KeysTest {
|
||||
@Test
|
||||
fun testEncodedSizes2() = runTest {
|
||||
initCrypto()
|
||||
val x = SecretKey.new()
|
||||
val x = DecryptingSecretKey.new()
|
||||
// println("key bytes: ${x.keyBytes.size}:\n${x.keyBytes.toDump()}")
|
||||
val y = BipackEncoder.encode(x)
|
||||
// println("packed: ${y.size}: ${y.toDump()}")
|
||||
assertTrue { x.keyBytes.size + 5 > y.size }
|
||||
assertEquals(x, BipackDecoder.decode<SecretKey>(y))
|
||||
assertContentEquals(x.keyBytes, BipackDecoder.decode<SecretKey>(y).keyBytes)
|
||||
assertEquals(x, BipackDecoder.decode<DecryptingSecretKey>(y))
|
||||
assertContentEquals(x.keyBytes, BipackDecoder.decode<DecryptingSecretKey>(y).keyBytes)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -432,7 +432,7 @@ class KeysTest {
|
||||
initCrypto()
|
||||
val k1 = SigningSecretKey.new()
|
||||
val k2 = k1.verifyingKey
|
||||
val k3 = SecretKey.new()
|
||||
val k3 = DecryptingSecretKey.new()
|
||||
val k4 = k3.publicKey
|
||||
|
||||
val k5 = UniversalPrivateKey.new()
|
||||
|
@ -27,7 +27,7 @@ class RingTest {
|
||||
assertEquals(y1, y2)
|
||||
|
||||
val e1 = Asymmetric.newSecretKey()
|
||||
val e2: SecretKey = BipackDecoder.decode(BipackEncoder.encode(e1))
|
||||
val e2: DecryptingSecretKey = BipackDecoder.decode(BipackEncoder.encode(e1))
|
||||
assertEquals(e1, e2)
|
||||
|
||||
val k1 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()) as UniversalKey
|
||||
@ -164,14 +164,14 @@ class RingTest {
|
||||
|
||||
var r1 = ra + rb + rc + rd
|
||||
|
||||
assertEquals(a, r1.findKey<SecretKey>(a.id))
|
||||
assertEquals(a, r1.findKey<DecryptingSecretKey>(a.id))
|
||||
assertEquals(a, r1.keyByTag<UniversalKey>("foo_a"))
|
||||
assertEquals(b, r1.findKey<SigningKey>(b.id))
|
||||
assertEquals(c, r1.findById(c.id).first())
|
||||
|
||||
r1 = UniversalRing.join(listOf(ra, rb, rc, rd))
|
||||
|
||||
assertEquals(a, r1.findKey<SecretKey>(a.id))
|
||||
assertEquals(a, r1.findKey<DecryptingSecretKey>(a.id))
|
||||
assertEquals(a, r1.keyByTag<UniversalKey>("foo_a"))
|
||||
assertEquals(b, r1.findKey<SigningKey>(b.id))
|
||||
assertEquals(c, r1.findById(c.id).first())
|
||||
|
Loading…
x
Reference in New Issue
Block a user