refactoring signing keys
This commit is contained in:
parent
e619b45485
commit
7042e41d70
@ -82,7 +82,7 @@ kotlin {
|
||||
implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-websockets-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-netty:$ktor_version")
|
||||
implementation("io.ktor:ktor-client-netty:$ktor_version")
|
||||
implementation("io.ktor:ktor-client-cio:$ktor_version")
|
||||
}
|
||||
}
|
||||
val jvmTest by getting
|
||||
|
@ -1,4 +1,4 @@
|
||||
package net.sergeych.crypto
|
||||
package net.sergeych.crypto2
|
||||
|
||||
import com.ionspin.kotlin.crypto.LibsodiumInitializer
|
||||
import kotlinx.coroutines.sync.Mutex
|
@ -1,4 +1,4 @@
|
||||
package net.sergeych.crypto
|
||||
package net.sergeych.crypto2
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
@ -29,14 +29,14 @@ class SignedBox(
|
||||
* 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: Key.Signing): SignedBox =
|
||||
operator fun plus(key: SigningKey.Secret): SignedBox =
|
||||
if (key.verifying in this) this
|
||||
else SignedBox(message, seals + Seal.create(key, message), false)
|
||||
|
||||
/**
|
||||
* Check that it is signed with a specified key.
|
||||
*/
|
||||
operator fun contains(verifyingKey: Key.Verifying): Boolean {
|
||||
operator fun contains(verifyingKey: SigningKey.Public): Boolean {
|
||||
return seals.any { it.key == verifyingKey }
|
||||
}
|
||||
|
||||
@ -53,12 +53,12 @@ class SignedBox(
|
||||
* add seals.
|
||||
*/
|
||||
@Serializable
|
||||
data class Seal(val key: Key.Verifying, val signature: UByteArray) {
|
||||
data class Seal(val key: SigningKey.Public, val signature: UByteArray) {
|
||||
|
||||
fun verify(message: UByteArray): Boolean = key.verify(signature, message)
|
||||
|
||||
companion object {
|
||||
fun create(key: Key.Signing, message: UByteArray): Seal {
|
||||
fun create(key: SigningKey.Secret, message: UByteArray): Seal {
|
||||
return Seal(key.verifying, key.sign(message))
|
||||
}
|
||||
}
|
||||
@ -75,7 +75,7 @@ class SignedBox(
|
||||
* @param keys a list of keys to sign with, should be at least one key.
|
||||
* @throws IllegalArgumentException if keys are not specified.
|
||||
*/
|
||||
operator fun invoke(data: UByteArray, vararg keys: Key.Signing): SignedBox =
|
||||
operator fun invoke(data: UByteArray, vararg keys: SigningKey.Secret): SignedBox =
|
||||
SignedBox(data, keys.map { Seal.create(it, data) }, false)
|
||||
}
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
package net.sergeych.crypto
|
||||
package net.sergeych.crypto2
|
||||
|
||||
import com.ionspin.kotlin.crypto.signature.InvalidSignatureException
|
||||
import com.ionspin.kotlin.crypto.signature.Signature
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.sergeych.crypto.Key.Signing
|
||||
import net.sergeych.crypto2.SigningKey.Secret
|
||||
|
||||
/**
|
||||
* 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 [Signing.pair] to create new keys.
|
||||
* Use [Secret.pair] to create new keys.
|
||||
*/
|
||||
@Serializable
|
||||
sealed class Key {
|
||||
sealed class SigningKey {
|
||||
abstract val packed: UByteArray
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is Key && other.packed contentEquals packed
|
||||
return other is SigningKey && other.packed contentEquals packed
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
@ -31,8 +31,8 @@ sealed class Key {
|
||||
* Public key to verify signatures only
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("pvk")
|
||||
class Verifying(override val packed: UByteArray) : Key() {
|
||||
@SerialName("p")
|
||||
class Public(override val packed: UByteArray) : SigningKey() {
|
||||
/**
|
||||
* Verify the signature and return true if it is correct.
|
||||
*/
|
||||
@ -51,22 +51,22 @@ sealed class Key {
|
||||
* Secret key to sign only
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("ssk")
|
||||
class Signing(override val packed: UByteArray) : Key() {
|
||||
@SerialName("s")
|
||||
class Secret(override val packed: UByteArray) : SigningKey() {
|
||||
|
||||
val verifying: Verifying by lazy {
|
||||
Verifying(Signature.ed25519SkToPk(packed))
|
||||
val verifying: Public by lazy {
|
||||
Public(Signature.ed25519SkToPk(packed))
|
||||
}
|
||||
|
||||
fun sign(message: UByteArray): UByteArray = Signature.detached(message, packed)
|
||||
override fun toString(): String = "Sct:${super.toString()}"
|
||||
|
||||
companion object {
|
||||
data class Pair(val signing: Signing, val verifying: Verifying)
|
||||
data class Pair(val signing: Secret, val aPublic: Public)
|
||||
|
||||
fun pair(): Pair {
|
||||
val p = Signature.keypair()
|
||||
return Pair(Signing(p.secretKey), Verifying(p.publicKey))
|
||||
return Pair(Secret(p.secretKey), Public(p.publicKey))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.sergeych.crypto
|
||||
package net.sergeych.crypto2
|
||||
|
||||
import net.sergeych.bintools.CRC
|
||||
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.sergeych.crypto
|
||||
package net.sergeych.crypto2
|
||||
|
||||
import com.ionspin.kotlin.crypto.secretbox.SecretBox
|
||||
import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_NONCEBYTES
|
@ -1,4 +1,4 @@
|
||||
package net.sergeych.crypto
|
||||
package net.sergeych.crypto2
|
||||
|
||||
import net.sergeych.bintools.toDump
|
||||
import net.sergeych.mp_tools.encodeToBase64Url
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.isActive
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.Loggable
|
||||
import net.sergeych.mp_logger.debug
|
||||
@ -21,7 +21,7 @@ import net.sergeych.mp_tools.globalLaunch
|
||||
*/
|
||||
class KiloClient<S>(
|
||||
localInterface: KiloInterface<S>,
|
||||
secretKey: Key.Signing? = null,
|
||||
secretKey: SigningKey.Secret? = null,
|
||||
connectionDataFactory: ConnectionDataFactory<S>,
|
||||
) : RemoteInterface,
|
||||
Loggable by LogTag("CLIF") {
|
||||
@ -80,7 +80,7 @@ class KiloClient<S>(
|
||||
suspend fun token() = deferredClient.await().token()
|
||||
|
||||
/**
|
||||
* Remote party shared key ([Key.Verifying]]), could be used ti ensure server is what we expected and
|
||||
* Remote party shared key ([SigningKey.Public]]), 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
|
||||
@ -99,7 +99,7 @@ class KiloClient<S>(
|
||||
}
|
||||
private var connectionBuilder: (suspend () -> Transport.Device)? = null
|
||||
|
||||
var secretIdKey: Key.Signing? = null
|
||||
var secretIdKey: SigningKey.Secret? = null
|
||||
|
||||
/**
|
||||
* Build local command implementations (remotely callable ones), exception
|
||||
|
@ -2,7 +2,7 @@ package net.sergeych.kiloparsec
|
||||
|
||||
import com.ionspin.kotlin.crypto.keyexchange.KeyExchange
|
||||
import kotlinx.coroutines.*
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.Loggable
|
||||
import net.sergeych.mp_logger.debug
|
||||
@ -15,17 +15,17 @@ class KiloClientConnection<S>(
|
||||
private val clientInterface: KiloInterface<S>,
|
||||
private val device: Transport.Device,
|
||||
private val session: S,
|
||||
private val secretIdKey: Key.Signing? = null,
|
||||
private val secretIdKey: SigningKey.Secret? = null,
|
||||
) : RemoteInterface, Loggable by LogTag("KPC:${++clientIds}") {
|
||||
|
||||
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, secretIdKey: Key.Signing? = null)
|
||||
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, secretIdKey: SigningKey.Secret? = null)
|
||||
: this(localInterface, connection.device, connection.session, secretIdKey)
|
||||
|
||||
private val kiloRemoteInterface = CompletableDeferred<KiloRemoteInterface<S>>()
|
||||
|
||||
private val deferredParams = CompletableDeferred<KiloParams<S>>()
|
||||
|
||||
suspend fun remoteId(): Key.Verifying? = deferredParams.await().remoteIdentity
|
||||
suspend fun remoteId(): SigningKey.Public? = deferredParams.await().remoteIdentity
|
||||
|
||||
/**
|
||||
* Run the client, blocking until the device is closed, or some critical exception
|
||||
@ -59,7 +59,7 @@ class KiloClientConnection<S>(
|
||||
var params = KiloParams(false, transport, sk, session, null, this@KiloClientConnection)
|
||||
|
||||
// Check ID if any
|
||||
serverHe.serverSharedKey?.let { k ->
|
||||
serverHe.serverPublicKey?.let { k ->
|
||||
if (serverHe.signature == null)
|
||||
throw RemoteInterface.SecurityException("missing signature")
|
||||
if (!k.verify(serverHe.signature, params.token))
|
||||
|
@ -9,10 +9,10 @@ import kotlinx.serialization.Serializable
|
||||
import net.sergeych.bintools.toDataSource
|
||||
import net.sergeych.bipack.BipackDecoder
|
||||
import net.sergeych.bipack.BipackEncoder
|
||||
import net.sergeych.crypto.DecryptionFailedException
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto.randomBytes
|
||||
import net.sergeych.crypto.randomUInt
|
||||
import net.sergeych.crypto2.DecryptionFailedException
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.crypto2.randomBytes
|
||||
import net.sergeych.crypto2.randomUInt
|
||||
import net.sergeych.tools.ProtectedOp
|
||||
import net.sergeych.utools.pack
|
||||
import net.sergeych.utools.unpack
|
||||
@ -34,7 +34,7 @@ data class KiloParams<S>(
|
||||
val transport: RemoteInterface,
|
||||
val sessionKeyPair: KeyExchangeSessionKeyPair,
|
||||
val scopeSession: S,
|
||||
val remoteIdentity: Key.Verifying?,
|
||||
val remoteIdentity: SigningKey.Public?,
|
||||
val remoteTransport: RemoteInterface
|
||||
) {
|
||||
@Serializable
|
||||
@ -56,7 +56,7 @@ data class KiloParams<S>(
|
||||
override val session = scopeSession
|
||||
override val remote: RemoteInterface = remoteTransport
|
||||
override val sessionToken: UByteArray = token
|
||||
override val remoteIdentity: Key.Verifying? = this@KiloParams.remoteIdentity
|
||||
override val remoteIdentity: SigningKey.Public? = this@KiloParams.remoteIdentity
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.sergeych.kiloparsec
|
||||
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
|
||||
/**
|
||||
* Scope for Kiloparsec client/server commands execution, contain per-connection specific data. The scope
|
||||
@ -26,8 +26,8 @@ interface KiloScope<S> {
|
||||
val sessionToken: UByteArray
|
||||
|
||||
/**
|
||||
* If the remote part has provided a secret key, e.g., gave non-null [Key.Signing] on construction,
|
||||
* the kiloparsec checks it in the MITM-safe way and provides its [Key.Verifying] shared key here.
|
||||
* 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.
|
||||
* 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 +37,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: Key.Verifying?
|
||||
val remoteIdentity: SigningKey.Public?
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ package net.sergeych.kiloparsec
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.kiloparsec.adapter.InetTransportDevice
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.debug
|
||||
@ -17,7 +17,7 @@ private val instances = AtomicCounter()
|
||||
class KiloServer<S>(
|
||||
private val clientInterface: KiloInterface<S>,
|
||||
private val connections: Flow<InetTransportDevice>,
|
||||
private val serverSigningKey: Key.Signing? = null,
|
||||
private val serverSecretKey: SigningKey.Secret? = null,
|
||||
private val sessionBuilder: ()->S,
|
||||
): LogTag("KS:${instances.incrementAndGet()}") {
|
||||
|
||||
@ -26,7 +26,7 @@ class KiloServer<S>(
|
||||
launch {
|
||||
try {
|
||||
info { "connected ${device}" }
|
||||
KiloServerConnection(clientInterface, device, sessionBuilder(), serverSigningKey)
|
||||
KiloServerConnection(clientInterface, device, sessionBuilder(), serverSecretKey)
|
||||
.apply { debug { "server connection is ready" }}
|
||||
.run()
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package net.sergeych.kiloparsec
|
||||
|
||||
import com.ionspin.kotlin.crypto.keyexchange.KeyExchange
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.Loggable
|
||||
import net.sergeych.mp_logger.debug
|
||||
@ -23,15 +23,15 @@ class KiloServerConnection<S>(
|
||||
private val clientInterface: KiloInterface<S>,
|
||||
private val device: Transport.Device,
|
||||
private val session: S,
|
||||
private val serverSigningKey: Key.Signing? = null
|
||||
private val serverSigningKey: SigningKey.Secret? = null
|
||||
) : RemoteInterface, Loggable by LogTag("SRV${++serverIds}") {
|
||||
|
||||
/**
|
||||
* Shortcut to construct with [KiloConnectionData] intance
|
||||
*/
|
||||
@Suppress("unused")
|
||||
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, serverSigningKey: Key.Signing? = null)
|
||||
: this(localInterface, connection.device, connection.session, serverSigningKey)
|
||||
constructor(localInterface: KiloInterface<S>, connection: KiloConnectionData<S>, serverSecretKey: SigningKey.Secret? = null)
|
||||
: this(localInterface, connection.device, connection.session, serverSecretKey)
|
||||
|
||||
private val kiloRemoteInterface = CompletableDeferred<KiloRemoteInterface<S>>()
|
||||
|
||||
@ -60,13 +60,13 @@ class KiloServerConnection<S>(
|
||||
this@KiloServerConnection
|
||||
)
|
||||
|
||||
var verifying: Key.Verifying? = null
|
||||
var public: SigningKey.Public? = null
|
||||
var signature: UByteArray? = null
|
||||
if( serverSigningKey != null ) {
|
||||
verifying = serverSigningKey.verifying
|
||||
public = serverSigningKey.verifying
|
||||
signature = serverSigningKey.sign(params!!.token)
|
||||
}
|
||||
Handshake(1u, pair.publicKey, verifying, signature)
|
||||
Handshake(1u, pair.publicKey, public, signature)
|
||||
}
|
||||
on(L0ClientId) {
|
||||
var p = params ?: throw RemoteInterface.ClosedException("wrong handshake sequence")
|
||||
|
@ -13,7 +13,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.serializer
|
||||
import net.sergeych.crypto.toDump
|
||||
import net.sergeych.crypto2.toDump
|
||||
import net.sergeych.kiloparsec.Transport.Device
|
||||
import net.sergeych.mp_logger.*
|
||||
import net.sergeych.utools.pack
|
||||
|
@ -0,0 +1,76 @@
|
||||
package net.sergeych.kiloparsec.adapter
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.plugins.websocket.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.websocket.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.kiloparsec.KiloClient
|
||||
import net.sergeych.kiloparsec.KiloConnectionData
|
||||
import net.sergeych.kiloparsec.KiloInterface
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.exception
|
||||
import net.sergeych.mp_logger.info
|
||||
import net.sergeych.mp_logger.warning
|
||||
import net.sergeych.mp_tools.globalLaunch
|
||||
import net.sergeych.tools.AtomicCounter
|
||||
|
||||
private val counter = AtomicCounter()
|
||||
|
||||
fun <S>websocketClient(
|
||||
path: String,
|
||||
clientInterface: KiloInterface<S> = KiloInterface(),
|
||||
client: HttpClient = HttpClient { install(WebSockets) },
|
||||
secretKey: SigningKey.Secret? = null,
|
||||
sessionMaker: () -> S,
|
||||
): KiloClient<S> {
|
||||
var u = Url(path)
|
||||
if (u.encodedPath.length <= 1)
|
||||
u = URLBuilder(u).apply {
|
||||
encodedPath = "/kp"
|
||||
}.build()
|
||||
|
||||
return KiloClient(clientInterface, secretKey) {
|
||||
val input = Channel<UByteArray>()
|
||||
val output = Channel<UByteArray>()
|
||||
globalLaunch {
|
||||
val log = LogTag("KC:${counter.incrementAndGet()}:$u")
|
||||
client.webSocket({
|
||||
url.protocol = u.protocol
|
||||
url.host = u.host
|
||||
url.encodedPath = u.encodedPath
|
||||
url.parameters.appendAll(u.parameters)
|
||||
}) {
|
||||
try {
|
||||
log.info { "connected to server" }
|
||||
launch {
|
||||
for (block in output) {
|
||||
send(block.toByteArray())
|
||||
}
|
||||
log.info { "input is closed, closing the websocket" }
|
||||
cancel()
|
||||
}
|
||||
for (f in incoming) {
|
||||
if (f is Frame.Binary) {
|
||||
input.send(f.readBytes().toUByteArray())
|
||||
} else {
|
||||
log.warning { "ignoring unexpected frame of type ${f.frameType}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(_:CancellationException) {
|
||||
}
|
||||
catch(t: Throwable) {
|
||||
log.exception { "unexpected error" to t }
|
||||
}
|
||||
log.info { "closing connection" }
|
||||
}
|
||||
}
|
||||
val device = ProxyDevice(input,output) { input.close() }
|
||||
KiloConnectionData(device, sessionMaker())
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
package net.sergeych.kiloparsec
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
|
||||
// L0 commands - key exchange and check:
|
||||
@Serializable
|
||||
data class Handshake(val version: UInt, val publicKey: UByteArray,
|
||||
val serverSharedKey: Key.Verifying? = null,
|
||||
val serverPublicKey: SigningKey.Public? = null,
|
||||
val signature: UByteArray? = null)
|
||||
|
||||
@Serializable
|
||||
data class ClientIdentity(val clientIdKey: Key.Verifying?, val signature: UByteArray?)
|
||||
data class ClientIdentity(val clientIdKey: SigningKey.Public?, val signature: UByteArray?)
|
||||
|
||||
// Level 0 command: request key exchange
|
||||
internal val L0Request by command<Handshake, Handshake>()
|
||||
|
@ -2,7 +2,7 @@ import com.ionspin.kotlin.crypto.secretbox.SecretBox
|
||||
import com.ionspin.kotlin.crypto.util.decodeFromUByteArray
|
||||
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.crypto.*
|
||||
import net.sergeych.crypto2.*
|
||||
import net.sergeych.utools.pack
|
||||
import net.sergeych.utools.unpack
|
||||
import kotlin.test.*
|
||||
@ -11,11 +11,11 @@ class KeysTest {
|
||||
@Test
|
||||
fun testCreationAndMap() = runTest {
|
||||
initCrypto()
|
||||
val (stk,pbk) = Key.Signing.pair()
|
||||
val (stk,pbk) = SigningKey.Secret.pair()
|
||||
|
||||
val x = mapOf( stk to "STK!", pbk to "PBK!")
|
||||
assertEquals("STK!", x[stk])
|
||||
val s1 = Key.Signing(stk.packed)
|
||||
val s1 = SigningKey.Secret(stk.packed)
|
||||
assertEquals(stk, s1)
|
||||
assertEquals("STK!", x[s1])
|
||||
assertEquals("PBK!", x[pbk])
|
||||
@ -27,8 +27,8 @@ class KeysTest {
|
||||
|
||||
data1[0] = 0x01u
|
||||
assertFalse(s.verify(data1))
|
||||
val p2 = Key.Signing.pair()
|
||||
val p3 = Key.Signing.pair()
|
||||
val p2 = SigningKey.Secret.pair()
|
||||
val p3 = SigningKey.Secret.pair()
|
||||
|
||||
val ms = SignedBox(data, s1) + p2.signing
|
||||
|
||||
@ -36,8 +36,8 @@ class KeysTest {
|
||||
val ms1 = unpack<SignedBox>(pack(ms))
|
||||
assertContentEquals(data, ms1.message)
|
||||
assertTrue(pbk in ms1)
|
||||
assertTrue(p2.verifying in ms1)
|
||||
assertTrue(p3.verifying !in ms1)
|
||||
assertTrue(p2.aPublic in ms1)
|
||||
assertTrue(p3.aPublic !in ms1)
|
||||
|
||||
assertThrows<IllegalSignatureException> {
|
||||
unpack<SignedBox>(pack(ms).also { it[3] = 1u })
|
||||
|
@ -1,6 +1,6 @@
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.Instant
|
||||
import net.sergeych.crypto.initCrypto
|
||||
import net.sergeych.crypto2.initCrypto
|
||||
import net.sergeych.kiloparsec.Transport
|
||||
import net.sergeych.utools.nowToSeconds
|
||||
import net.sergeych.utools.pack
|
||||
|
@ -1,7 +1,7 @@
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.crypto.createContrail
|
||||
import net.sergeych.crypto.initCrypto
|
||||
import net.sergeych.crypto.isValidContrail
|
||||
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
|
||||
|
@ -4,8 +4,8 @@ import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.crypto.Key
|
||||
import net.sergeych.crypto.initCrypto
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.crypto2.initCrypto
|
||||
import net.sergeych.kiloparsec.*
|
||||
import net.sergeych.mp_logger.Log
|
||||
import kotlin.test.*
|
||||
@ -162,7 +162,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, Key.Verifying?>()
|
||||
val cmdGetClientId by command<Unit, SigningKey.Public?>()
|
||||
val cmdChainCallServer1 by command<String, String>()
|
||||
val cmdChainCallClient1 by command<String, String>()
|
||||
val cmdChainCallServer2 by command<String, String>()
|
||||
@ -171,8 +171,8 @@ class TransportTest {
|
||||
// Log.defaultLevel = Log.Level.DEBUG
|
||||
val (d1, d2) = createTestDevice()
|
||||
|
||||
val serverId = Key.Signing.pair()
|
||||
val clientId = Key.Signing.pair()
|
||||
val serverId = SigningKey.Secret.pair()
|
||||
val clientId = SigningKey.Secret.pair()
|
||||
|
||||
val serverInterface = KiloInterface<String>().apply {
|
||||
on(cmdPing) {
|
||||
|
@ -0,0 +1,64 @@
|
||||
package net.sergeych.kiloparsec.adapter
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.websocket.*
|
||||
import io.ktor.websocket.*
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import net.sergeych.crypto2.SigningKey
|
||||
import net.sergeych.kiloparsec.KiloInterface
|
||||
import net.sergeych.kiloparsec.KiloServerConnection
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.debug
|
||||
import net.sergeych.mp_logger.warning
|
||||
import net.sergeych.tools.AtomicCounter
|
||||
import java.time.Duration
|
||||
|
||||
fun <S> Application.setupWebsocketServer(
|
||||
localInterface: KiloInterface<S>,
|
||||
path: String = "/kp",
|
||||
serverKey: SigningKey.Secret? = null,
|
||||
createSession: () -> S,
|
||||
) {
|
||||
|
||||
install(Routing)
|
||||
install(WebSockets) {
|
||||
pingPeriod = Duration.ofSeconds(15)
|
||||
timeout = Duration.ofSeconds(15)
|
||||
maxFrameSize = Long.MAX_VALUE
|
||||
masking = false
|
||||
}
|
||||
val counter = AtomicCounter()
|
||||
routing {
|
||||
webSocket(path) {
|
||||
val log = LogTag("KWS:${counter.incrementAndGet()}")
|
||||
log.debug { "opening the connection" }
|
||||
val input = Channel<UByteArray>(256)
|
||||
val output = Channel<UByteArray>(256)
|
||||
launch {
|
||||
while (isActive) {
|
||||
send(output.receive().toByteArray())
|
||||
}
|
||||
}
|
||||
val server = KiloServerConnection(
|
||||
localInterface,
|
||||
ProxyDevice(input, output) { input.close() },
|
||||
createSession(),
|
||||
serverKey
|
||||
)
|
||||
launch { server.run() }
|
||||
for( f in incoming) {
|
||||
if (f is Frame.Binary)
|
||||
input.send(f.readBytes().toUByteArray())
|
||||
else
|
||||
log.warning { "unknown frame type ${f.frameType}, ignoring" }
|
||||
|
||||
}
|
||||
log.debug { "closing the server" }
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ClosedReceiveChannelException
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import net.sergeych.crypto.encodeVarUnsigned
|
||||
import net.sergeych.crypto.readVarUnsigned
|
||||
import net.sergeych.crypto2.encodeVarUnsigned
|
||||
import net.sergeych.crypto2.readVarUnsigned
|
||||
import net.sergeych.kiloparsec.Transport
|
||||
import net.sergeych.mp_logger.LogTag
|
||||
import net.sergeych.mp_logger.warning
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.sergeych.kiloparsec
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.crypto.initCrypto
|
||||
import net.sergeych.crypto2.initCrypto
|
||||
import net.sergeych.kiloparsec.adapter.acceptTcpDevice
|
||||
import net.sergeych.kiloparsec.adapter.connectTcpDevice
|
||||
import net.sergeych.mp_logger.Log
|
||||
@ -49,4 +49,9 @@ class ClientTest {
|
||||
// client.close()
|
||||
// Todo
|
||||
}
|
||||
|
||||
@Test
|
||||
fun webSocketTest() = runTest {
|
||||
// val server = setupWebsoketServer()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user