adopted crypto2 0.4.*

This commit is contained in:
Sergey Chernov 2024-06-25 10:39:00 +07:00
parent 38fbca955c
commit 5df6143c75
14 changed files with 46 additions and 57 deletions

View File

@ -44,6 +44,7 @@ kotlin {
// iosArm64()
// iosSimulatorArm64()
linuxX64()
linuxArm64()
// macosX64()
@ -66,7 +67,7 @@ kotlin {
// api("net.sergeych:mp_bintools:0.1.1")
// api("net.sergeych:mp_stools:1.4.7")
api("net.sergeych:crypto2:0.2.2-SNAPSHOT")
api("net.sergeych:crypto2:0.4.1-SNAPSHOT")
}
}
val commonTest by getting {

View File

@ -9,6 +9,7 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.sergeych.crypto2.SigningKey
import net.sergeych.crypto2.VerifyingPublicKey
import net.sergeych.mp_logger.LogTag
import net.sergeych.mp_logger.Loggable
import net.sergeych.mp_logger.debug
@ -23,7 +24,7 @@ import net.sergeych.mp_tools.globalLaunch
*/
class KiloClient<S>(
localInterface: KiloInterface<S>,
secretKey: SigningKey.Secret? = null,
secretKey: SigningKey? = null,
connectionDataFactory: ConnectionDataFactory<S>,
) : RemoteInterface,
Loggable by LogTag("CLIF") {
@ -101,14 +102,14 @@ class KiloClient<S>(
suspend fun token() = deferredClient.await().token()
/**
* Remote party shared key ([SigningKey.Public]]), could be used ti ensure server is what we expected and
* Remote party shared key ([VerifyingPublicKey]), could be used ti ensure server is what we expected and
* there is no active MITM attack.
*
* Non-null value means the key was successfully authenticated, null means remote party did not provide
* a key. Connection is established either with a properly authenticated key or no key at all.
*/
@Suppress("unused")
suspend fun remoteId() = deferredClient.await().remoteId()
suspend fun remoteId(): VerifyingPublicKey? = deferredClient.await().remoteId()
companion object {
class Builder<S>() {
@ -120,7 +121,7 @@ class KiloClient<S>(
}
private var connectionBuilder: (suspend () -> Transport.Device)? = null
var secretIdKey: SigningKey.Secret? = null
var secretIdKey: SigningKey? = null
/**
* Build local command implementations (remotely callable ones), exception

View File

@ -3,6 +3,7 @@ package net.sergeych.kiloparsec
import kotlinx.coroutines.*
import net.sergeych.crypto2.SafeKeyExchange
import net.sergeych.crypto2.SigningKey
import net.sergeych.crypto2.VerifyingPublicKey
import net.sergeych.mp_logger.LogTag
import net.sergeych.mp_logger.Loggable
import net.sergeych.mp_logger.debug
@ -15,17 +16,17 @@ class KiloClientConnection<S>(
private val clientInterface: KiloInterface<S>,
private val device: Transport.Device,
private val session: S,
private val secretIdKey: SigningKey.Secret? = null,
private val secretIdKey: SigningKey? = null,
) : RemoteInterface, Loggable by LogTag("KPC:${++clientIds}") {
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, secretIdKey: SigningKey.Secret? = null)
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, secretIdKey: SigningKey? = null)
: this(localInterface, connection.device, connection.session, secretIdKey)
private val kiloRemoteInterface = CompletableDeferred<KiloRemoteInterface<S>>()
private val deferredParams = CompletableDeferred<KiloParams<S>>()
suspend fun remoteId(): SigningKey.Public? = deferredParams.await().remoteIdentity
suspend fun remoteId(): VerifyingPublicKey? = deferredParams.await().remoteIdentity
/**
* Run the client, blocking until the device is closed, or some critical exception
@ -69,7 +70,7 @@ class KiloClientConnection<S>(
L0ClientId, params.encrypt(
pack(
ClientIdentity(
secretIdKey?.publicKey,
secretIdKey?.verifyingKey,
secretIdKey?.sign(params.token)
)
)

View File

@ -24,7 +24,7 @@ data class KiloParams<S>(
val transport: RemoteInterface,
val sessionKey: SafeKeyExchange.SessionKey,
val scopeSession: S,
val remoteIdentity: SigningKey.Public?,
val remoteIdentity: VerifyingPublicKey?,
val remoteTransport: RemoteInterface,
) {
@Serializable
@ -41,12 +41,12 @@ data class KiloParams<S>(
override val session = scopeSession
override val remote: RemoteInterface = remoteTransport
override val sessionToken: UByteArray = token
override val remoteIdentity: SigningKey.Public? = this@KiloParams.remoteIdentity
override val remoteIdentity: VerifyingPublicKey? = this@KiloParams.remoteIdentity
}
}
val token: UByteArray by lazy {
blake2b("token_".encodeToUByteArray() + sessionKey.sessionTag).sliceArray(0..<SymmetricKey.nonceByteLength)
blake2b("token_".encodeToUByteArray() + sessionKey.sessionTag).sliceArray(0..<SymmetricKey.nonceLength)
}
private val numericNonce = NumericNonce(token)

View File

@ -1,6 +1,7 @@
package net.sergeych.kiloparsec
import net.sergeych.crypto2.SigningKey
import net.sergeych.crypto2.VerifyingPublicKey
/**
* Scope for Kiloparsec client/server commands execution, contain per-connection specific data. The scope
@ -26,8 +27,8 @@ interface KiloScope<S> {
val sessionToken: UByteArray
/**
* If the remote part has provided a secret key, e.g., gave non-null [SigningKey.Secret] on construction,
* the kiloparsec checks it in the MITM-safe way and provides its [SigningKey.Public] shared key here.
* If the remote part has provided a secret key, e.g., gave non-null [SigningKey] on construction,
* the kiloparsec checks it in the MITM-safe way and provides its [VerifyingPublicKey] shared key here.
* Knowing a remote party shared key, it is possible to be sure that the connection is made directly
* to this party with no middle point intruders.
*
@ -37,6 +38,6 @@ interface KiloScope<S> {
* In spite of the above said, which means, non-null value in this field means the key is authorized, but
* It is up to the caller to ensure it is expected key of the remote party.
*/
val remoteIdentity: SigningKey.Public?
val remoteIdentity: VerifyingPublicKey?
}

View File

@ -17,7 +17,7 @@ private val instances = AtomicCounter()
class KiloServer<S>(
private val clientInterface: KiloInterface<S>,
private val connections: Flow<InetTransportDevice>,
private val serverSecretKey: SigningKey.Secret? = null,
private val serverSecretKey: SigningKey? = null,
private val sessionBuilder: ()->S,
): LogTag("KS:${instances.incrementAndGet()}") {

View File

@ -23,14 +23,14 @@ class KiloServerConnection<S>(
private val clientInterface: KiloInterface<S>,
private val device: Transport.Device,
private val session: S,
private val serverSigningKey: SigningKey.Secret? = null
private val serverSigningKey: SigningKey? = null
) : RemoteInterface, Loggable by LogTag("SRV${++serverIds}") {
/**
* Shortcut to construct with [KiloConnectionData] intance
*/
@Suppress("unused")
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, serverSecretKey: SigningKey.Secret? = null)
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, serverSecretKey: SigningKey? = null)
: this(localInterface, connection.device, connection.session, serverSecretKey)
private val kiloRemoteInterface = CompletableDeferred<KiloRemoteInterface<S>>()

View File

@ -28,7 +28,7 @@ fun <S> websocketClient(
path: String,
clientInterface: KiloInterface<S> = KiloInterface(),
client: HttpClient = HttpClient { install(WebSockets) },
secretKey: SigningKey.Secret? = null,
secretKey: SigningKey? = null,
sessionMaker: () -> S = {
@Suppress("UNCHECKED_CAST")
Unit as S

View File

@ -3,7 +3,7 @@ package net.sergeych.kiloparsec
import kotlinx.serialization.Serializable
import net.sergeych.crypto2.SafeKeyExchange
import net.sergeych.crypto2.Seal
import net.sergeych.crypto2.SigningKey
import net.sergeych.crypto2.VerifyingPublicKey
// L0 commands - key exchange and check:
@Serializable
@ -11,7 +11,7 @@ data class Handshake(val version: UInt, val publicKey: SafeKeyExchange.PublicKey
val signature: Seal? = null)
@Serializable
data class ClientIdentity(val clientIdKey: SigningKey.Public?, val signature: UByteArray?)
data class ClientIdentity(val clientIdKey: VerifyingPublicKey?, val signature: UByteArray?)
// Level 0 command: request key exchange
internal val L0Request by command<Handshake, Handshake>()

View File

@ -1,5 +1,8 @@
import kotlinx.coroutines.test.runTest
import net.sergeych.crypto2.*
import net.sergeych.crypto2.IllegalSignatureException
import net.sergeych.crypto2.SealedBox
import net.sergeych.crypto2.SigningSecretKey
import net.sergeych.crypto2.initCrypto
import net.sergeych.kiloparsec.encodeToUByteArray
import net.sergeych.utools.pack
import net.sergeych.utools.unpack
@ -9,11 +12,11 @@ class KeysTest {
@Test
fun testCreationAndMap() = runTest {
initCrypto()
val (stk,pbk) = SigningKey.pair()
val (stk,pbk) = SigningSecretKey.generatePair()
val x = mapOf( stk to "STK!", pbk to "PBK!")
assertEquals("STK!", x[stk])
val s1 = SigningKey.Secret(stk.packed)
val s1 = SigningSecretKey(stk.keyBytes)
assertEquals(stk, s1)
assertEquals("STK!", x[s1])
assertEquals("PBK!", x[pbk])
@ -25,8 +28,8 @@ class KeysTest {
data1[0] = 0x01u
assertFalse(s.isValid(data1))
val p2 = SigningKey.pair()
val p3 = SigningKey.pair()
val p2 = SigningSecretKey.generatePair()
val p3 = SigningSecretKey.generatePair()
val ms = SealedBox(data, s1) + p2.secretKey

View File

@ -1,23 +1,4 @@
import kotlinx.coroutines.test.runTest
import net.sergeych.crypto2.createContrail
import net.sergeych.crypto2.initCrypto
import net.sergeych.crypto2.isValidContrail
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class ToolsTest {
@Test
fun testContrails() = runTest {
initCrypto()
val c = createContrail(ubyteArrayOf(1u, 2u, 3u, 4u, 5u))
assertEquals(134u, c[0])
assertTrue { isValidContrail(c) }
c[2] = 11u
assertFalse { isValidContrail(c) }
}
// @Test
// fun testRemoceCmd() {
// assertEquals("lalala", removeCmd("lalala"))

View File

@ -3,7 +3,8 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.test.runTest
import net.sergeych.crypto2.SigningKey
import net.sergeych.crypto2.SigningSecretKey
import net.sergeych.crypto2.VerifyingPublicKey
import net.sergeych.crypto2.initCrypto
import net.sergeych.kiloparsec.*
import net.sergeych.mp_logger.Log
@ -167,7 +168,7 @@ class TransportTest {
val cmdPing by command<String, String>()
val cmdPush by command<String, String>()
val cmdGetToken by command<Unit, UByteArray>()
val cmdGetClientId by command<Unit, SigningKey.Public?>()
val cmdGetClientId by command<Unit, VerifyingPublicKey?>()
val cmdChainCallServer1 by command<String, String>()
val cmdChainCallClient1 by command<String, String>()
val cmdChainCallServer2 by command<String, String>()
@ -176,8 +177,8 @@ class TransportTest {
// Log.defaultLevel = Log.Level.DEBUG
val (d1, d2) = createTestDevice()
val serverId = SigningKey.pair()
val clientId = SigningKey.pair()
val serverId = SigningSecretKey.generatePair()
val clientId = SigningSecretKey.generatePair()
val cmdException by command<Unit, Unit>()
val cmdRemoteExceptionTest by command<Unit, String>()

View File

@ -21,7 +21,7 @@ import java.time.Duration
fun <S> Application.setupWebsocketServer(
localInterface: KiloInterface<S>,
path: String = "/kp",
serverKey: SigningKey.Secret? = null,
serverKey: SigningKey? = null,
createSession: () -> S,
) {

View File

@ -4,12 +4,12 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ClosedReceiveChannelException
import kotlinx.coroutines.flow.MutableStateFlow
import net.sergeych.crypto2.Contrail
import net.sergeych.crypto2.encodeVarUnsigned
import net.sergeych.crypto2.readVarUnsigned
import net.sergeych.kiloparsec.RemoteInterface
import net.sergeych.kiloparsec.Transport
import net.sergeych.mp_logger.LogTag
import net.sergeych.mp_logger.info
import net.sergeych.mp_logger.warning
import net.sergeych.mp_tools.globalLaunch
import net.sergeych.tools.waitFor
@ -25,7 +25,10 @@ private val log = LogTag("ASTD")
/**
* Prepend block with its size, varint-encoded
*/
private fun encode(block: UByteArray): ByteArray = (encodeVarUnsigned(block.size.toUInt()) + block).toByteArray()
private fun encode(block: UByteArray): ByteArray {
val c = Contrail.create(block)
return (encodeVarUnsigned(c.size.toUInt()) + c).toByteArray()
}
/**
* Convert asynchronous socket to a [Transport.Device] using non-blocking nio,
@ -122,7 +125,8 @@ suspend fun asyncSocketToDevice(socket: AsynchronousSocketChannel): InetTranspor
for (i in 0..<size.toInt()) {
block[i] = input.receive()
}
inputBlocks.send(block)
Contrail.unpack(block)?.let { inputBlocks.send(it) }
?: log.warning { "skipping bad block ${block.size} bytes" }
}
}
} catch (_: CancellationException) {
@ -135,17 +139,13 @@ suspend fun asyncSocketToDevice(socket: AsynchronousSocketChannel): InetTranspor
val addr = socket.remoteAddress as InetSocketAddress
deferredDevice.complete(
InetTransportDevice(inputBlocks, outputBlocks, JvmNetworkAddress(addr.address, addr.port), {
val log = LogTag("S:${addr.address}:${addr.port}")
log.info { "ASTD is waitig to close" }
yield()
// wait until all received data are parsed, but not too long
withTimeoutOrNull(500) {
receiving.waitFor { !it }
}
// then stop it
log.info { "ASTd is calling STOP" }
stop()
log.info { "STopped" }
})
)
}