Compare commits

...

8 Commits

25 changed files with 126 additions and 97 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ build/
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea
*.iws
*.iml
*.ipr

7
.idea/.gitignore generated vendored
View File

@ -1,10 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
/artifacts/crypto2_js_0_1_0_SNAPSHOT.xml
/artifacts/crypto2_jvm_0_1_0_SNAPSHOT.xml

View File

@ -1,6 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="crypto2-js-0.1.1-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="crypto2-js-0.1.1-SNAPSHOT.jar" />
</artifact>
</component>

View File

@ -1,8 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="crypto2-js-1.0-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="crypto2-js-1.0-SNAPSHOT.jar">
<element id="module-output" name="crypto2.jsMain" />
</root>
</artifact>
</component>

View File

@ -1,6 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="crypto2-jvm-0.1.1-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="crypto2-jvm-0.1.1-SNAPSHOT.jar" />
</artifact>
</component>

View File

@ -1,8 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="crypto2-jvm-1.0-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="crypto2-jvm-1.0-SNAPSHOT.jar">
<element id="module-output" name="crypto2.jvmMain" />
</root>
</artifact>
</component>

View File

@ -1,8 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="crypto2-wasm-js-0.1.1-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="crypto2-wasm-js-0.1.1-SNAPSHOT.jar">
<element id="module-output" name="crypto2.wasmJsMain" />
</root>
</artifact>
</component>

View File

@ -1,5 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>

2
.idea/gradle.xml generated
View File

@ -5,6 +5,7 @@
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/local/Cellar/gradle/7.6/libexec" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
@ -12,5 +13,6 @@
</option>
</GradleProjectSettings>
</option>
<option name="parallelModelFetch" value="true" />
</component>
</project>

View File

@ -1,7 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="ReplaceUntilWithRangeUntil" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="StructuralWrap" enabled="false" level="TYPO" enabled_by_default="false" />
</profile>
</component>

6
.idea/kotlinc.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.20" />
</component>
</project>

3
.idea/misc.xml generated
View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17 (5)" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -2,6 +2,16 @@
Kotlin Multiplatform cryptographic primitives using modern strong cryptography.
## v0.9.0 for kotlin 2.2.21, new kotlin time compatible
The primary goal was to fix kotlin-caused incompatibilities with kotlinx.datetime.Instant and Clock; the upgrade shoud be in-place
replacement providing calling code ises `kotlin.time.Instant` and
`kotlin.time.Clock` respectively. No other changes are needed.
Also we start to add small syntax sugar methods.
## v.0.8.4 is built for all platform, IOS and wasmJS included
Cryptographic API works exactly the same and compiles to any platform supported listed below with no change in source code.
All primitives meant to send over the network or store are `kotlinx.serialization` compatible, serializers included.
@ -21,7 +31,7 @@ repositories {
maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven")
}
dependencies {
import("net.sergeych:crypto2:0.7.1-SNAPSHOT")
import("net.sergeych:crypto2:0.8.4")
}
```

View File

@ -13,14 +13,14 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("multiplatform") version "2.0.21"
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.21"
kotlin("multiplatform") version "2.2.21"
id("org.jetbrains.kotlin.plugin.serialization") version "2.2.21"
id("org.jetbrains.dokka") version "1.9.20"
`maven-publish`
}
group = "net.sergeych"
version = "0.8.3-SNAPSHOT"
version = "0.9.0"
repositories {
mavenCentral()
@ -31,12 +31,8 @@ repositories {
}
kotlin {
jvm {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget = JvmTarget.JVM_11
}
}
jvmToolchain(21)
jvm()
js {
browser()
nodejs()
@ -44,12 +40,12 @@ kotlin {
linuxX64()
linuxArm64()
// macosX64()
// macosArm64()
// iosX64()
// iosArm64()
// iosSimulatorArm64()
// mingwX64()
macosX64()
macosArm64()
iosX64()
iosArm64()
iosSimulatorArm64()
mingwX64()
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
@ -60,26 +56,27 @@ kotlin {
languageSettings.optIn("kotlinx.serialization.ExperimentalSerializationApi")
languageSettings.optIn("kotlinx.coroutines.ExperimentalCoroutinesApi")
languageSettings.optIn("kotlin.ExperimentalUnsignedTypes")
languageSettings.optIn("kotlin.time.ExperimentalTime")
}
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
implementation("net.sergeych:multiplatform-crypto-libsodium-bindings:0.9.6")
implementation(project.dependencies.platform("org.kotlincrypto.hash:bom:0.5.1"))
implementation("org.kotlincrypto.hash:sha3")
api("com.ionspin.kotlin:bignum:0.3.9")
api("net.sergeych:mp_bintools:0.1.12-SNAPSHOT")
api("com.ionspin.kotlin:bignum:0.3.10")
api("net.sergeych:mp_bintools:0.3.2")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
implementation("org.slf4j:slf4j-simple:2.0.9")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.1")
}
}
val native by creating {
@ -115,6 +112,14 @@ publishing {
}
}
tasks.named<Test>("jvmTest") {
// Ignore Kotlin synthetic classes generated from files that look like tests
exclude("**/*TestKt.class")
exclude("**/*TestsKt.class")
exclude("**/*AssertThrowsKt.class")
exclude("**/*Test_toolsKt.class")
}
tasks.dokkaHtml.configure {
outputDirectory.set(buildDir.resolve("dokka"))
dokkaSourceSets {

View File

@ -9,3 +9,7 @@
#
kotlin.code.style=official
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8
org.gradle.configuration-cache=true
org.gradle.caching=true

View File

@ -10,6 +10,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -321,6 +321,27 @@ sealed class Container {
}.build()
}
/**
* Decrypt the container with a password. It scans all key ids for
* these with `KDP` params, e.g., derived from password, and try to
* derive keys from the password and decrypt the container. If there are
* no derivable keys, or all of them failed to decrypt, returns null.
* It could be long operation if there are multiple derivable keys with heavy
* KDF. See [PBKD] and [KDF] for more.
*
* @return decrypted data or null
*/
@Suppress("unused")
fun decryptWithPassword(password: String): UByteArray? {
for( id in this.keyIds ) {
id.kdp?.let { kdp ->
decryptWith(kdp.deriveKey(password))?.let { return it }
}
}
return null
}
companion object {
/**

View File

@ -60,6 +60,12 @@ sealed class Multikey {
*/
abstract fun check(keys: Iterable<VerifyingPublicKey>): Boolean
/**
* Step towards automated picking necessary keys.
* Return all the keys mentioned in this multikey condition.
*/
abstract fun mentionedKeys(): Set<VerifyingPublicKey>
/**
* Check that [verifyingKeys] satisfy the multikey condition
*/
@ -97,6 +103,10 @@ sealed class Multikey {
}
return false
}
override fun mentionedKeys(): Set<VerifyingPublicKey> {
return validKeys
}
}
/**
@ -119,6 +129,10 @@ sealed class Multikey {
}
return false
}
override fun mentionedKeys(): Set<VerifyingPublicKey> {
return validKeys.flatMap { it.mentionedKeys() }.toSet()
}
}
/**
@ -129,6 +143,7 @@ sealed class Multikey {
@Serializable
object AnyKey : Multikey() {
override fun check(keys: Iterable<VerifyingPublicKey>): Boolean = true
override fun mentionedKeys(): Set<VerifyingPublicKey> = emptySet()
}

View File

@ -10,7 +10,7 @@
package net.sergeych.crypto2
import kotlinx.datetime.Instant
import kotlin.time.Instant
import kotlinx.serialization.Serializable
import net.sergeych.bipack.BipackEncoder
import net.sergeych.bipack.decodeFromBipack

View File

@ -10,7 +10,7 @@
package net.sergeych.crypto2
import kotlinx.datetime.Instant
import kotlin.time.Instant
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.sergeych.bipack.BipackDecoder

View File

@ -10,7 +10,7 @@
package net.sergeych.crypto2
import kotlinx.datetime.Instant
import kotlin.time.Instant
interface SigningKey: KeyInstance {
val verifyingKey: VerifyingPublicKey

View File

@ -11,7 +11,7 @@
package net.sergeych.crypto2
import com.ionspin.kotlin.crypto.signature.Signature
import kotlinx.datetime.Instant
import kotlin.time.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

View File

@ -12,8 +12,8 @@
package net.sergeych.utools
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlin.time.Clock
import kotlin.time.Instant
fun now(): Instant = Clock.System.now()
fun nowToSeconds(): Instant = Clock.System.now().truncateToSeconds()

View File

@ -10,25 +10,17 @@
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Clock
import kotlin.time.Clock
import net.sergeych.crypto2.Hash
import net.sergeych.crypto2.initCrypto
import kotlin.random.Random
import kotlin.random.nextUBytes
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE")
suspend fun <T> sw(label: String, f: suspend () -> T): T {
val t1 = Clock.System.now()
val result = f()
val t2 = Clock.System.now()
// println("$label: ${t2 - t1}")
return result
}
class HashTest {
@Test
fun testEqualMethods() {
@ -77,3 +69,13 @@ class HashTest {
}
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE")
suspend fun <T> sw(label: String, f: suspend () -> T): T {
val t1 = Clock.System.now()
val result = f()
val t2 = Clock.System.now()
// println("$label: ${t2 - t1}")
return result
}

View File

@ -9,7 +9,7 @@
*/
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
import kotlin.time.Instant
import net.sergeych.crypto2.initCrypto
import net.sergeych.utools.nowToSeconds
import net.sergeych.utools.pack