agent: xrcp implementation for connection via link (no multicast) (#884)

* WIP: start working on connection invites

startSession/OOB is broken now - the port isn't coming from the actualy assigned one.

* Add invite types

* clean old invite-related types

* apply renames

* Move SessionKeys from Invitation

* Stub host-side keys and handle

* move keys and handles to Types

* add Simplex.RemoteControl.Client

* more keys

* progress

* crypto for sessions

* progress to multicast

* multicast crypto

* add RC TLS server

* agent api for remote control

* WIP: tls client

* fix test

* update encoding to include nonce

* add TODO

* update

* Use network-info to find TransportHost

* request and submit tls client certificate

* WIP: add missing bits for testing RC client

* RCEncryptedHello encoding

* add block encoding

* refactor

* validate known host certificate

* remove some spaghetti

* functional API to host/ctrl clients

* refactor connectRCCtrl_

* refactor connectRCHost

* question

* add type

* fix RC session

* update doc

* update doc 2

* add block on confirmation

* remove unused parameter

* export CtrlSessKeys

* export

* fix parsing

* move test of xrcp handshake

* move KEM to HELLO step

* fix JSON

* type

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
Alexander BondarenkoandEvgeny Poberezkin authored and GitHub committed 2023-11-07 13:05:18 +00:00
1 parent 1a0c4b73de
commit 1a8dfb4cbe
22 files changed
+1181 -316

No files matched your search

+23 -7
View File
@@ -1,5 +1,6 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
module Simplex.Messaging.Crypto.SNTRUP761 where
@@ -8,21 +9,36 @@ import Data.ByteArray (ScrubbedBytes)
import qualified Data.ByteArray as BA
import Data.ByteString (ByteString)
import Simplex.Messaging.Crypto
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.SNTRUP761.Bindings
-- Hybrid shared secret for crypto_box is defined as SHA256(DHSecret || KEMSharedKey),
-- similar to https://datatracker.ietf.org/doc/draft-josefsson-ntruprime-hybrid/
class KEMSharedSecret kem where kemSecretBytes :: kem -> ScrubbedBytes
newtype KEMHybridSecret = KEMHybridSecret ScrubbedBytes
newtype KEMHybridOrDHSecret = KEMHybridOrDHSecret ScrubbedBytes
instance KEMSharedSecret KEMHybridSecret where kemSecretBytes (KEMHybridSecret secret) = secret
instance KEMSharedSecret KEMHybridOrDHSecret where kemSecretBytes (KEMHybridOrDHSecret secret) = secret
-- | NaCl @crypto_box@ decrypt with a shared hybrid DH + KEM secret and 192-bit nonce.
kcbDecrypt :: KEMHybridSecret -> CbNonce -> ByteString -> Either CryptoError ByteString
kcbDecrypt (KEMHybridSecret secret) = sbDecrypt_ secret
kcbDecrypt :: KEMSharedSecret kem => kem -> CbNonce -> ByteString -> Either CryptoError ByteString
kcbDecrypt = sbDecrypt_ . kemSecretBytes
-- | NaCl @crypto_box@ encrypt with a shared hybrid DH + KEM secret and 192-bit nonce.
kcbEncrypt :: KEMHybridSecret -> CbNonce -> ByteString -> Int -> Either CryptoError ByteString
kcbEncrypt (KEMHybridSecret secret) = sbEncrypt_ secret
kcbEncrypt :: KEMSharedSecret kem => kem -> CbNonce -> ByteString -> Int -> Either CryptoError ByteString
kcbEncrypt = sbEncrypt_ . kemSecretBytes
kemHybridSecret :: DhSecret 'X25519 -> KEMSharedKey -> KEMHybridSecret
kemHybridSecret (DhSecretX25519 k1) (KEMSharedKey k2) =
KEMHybridSecret $ BA.convert (hash $ BA.convert k1 <> k2 :: Digest SHA256)
kemHybridSecret :: PublicKeyX25519 -> PrivateKeyX25519 -> KEMSharedKey -> KEMHybridSecret
kemHybridSecret k pk (KEMSharedKey kem) =
let DhSecretX25519 dh = C.dh' k pk
in KEMHybridSecret $ BA.convert (hash $ BA.convert dh <> kem :: Digest SHA256)
kemHybridOrDHSecret :: PublicKeyX25519 -> PrivateKeyX25519 -> Maybe KEMSharedKey -> KEMHybridOrDHSecret
kemHybridOrDHSecret k pk = \case
Just kem -> KEMHybridOrDHSecret $ kemSecretBytes $ kemHybridSecret k pk kem
Nothing -> let DhSecretX25519 dh = C.dh' k pk in KEMHybridOrDHSecret $ BA.convert dh
@@ -4,6 +4,7 @@ module Simplex.Messaging.Crypto.SNTRUP761.Bindings where
import Control.Concurrent.STM
import Crypto.Random (ChaChaDRG)
import Data.Aeson (FromJSON (..), ToJSON (..))
import Data.Bifunctor (bimap)
import Data.ByteArray (ScrubbedBytes)
import qualified Data.ByteArray as BA
@@ -16,14 +17,20 @@ import Simplex.Messaging.Encoding
import Simplex.Messaging.Encoding.String
newtype KEMPublicKey = KEMPublicKey ByteString
deriving (Show)
newtype KEMSecretKey = KEMSecretKey ScrubbedBytes
deriving (Show)
newtype KEMCiphertext = KEMCiphertext ByteString
deriving (Show)
newtype KEMSharedKey = KEMSharedKey ScrubbedBytes
deriving (Show)
sntrup761Keypair :: TVar ChaChaDRG -> IO (KEMPublicKey, KEMSecretKey)
type KEMKeyPair = (KEMPublicKey, KEMSecretKey)
sntrup761Keypair :: TVar ChaChaDRG -> IO KEMKeyPair
sntrup761Keypair drg =
bimap KEMPublicKey KEMSecretKey
<$> BA.allocRet
@@ -51,14 +58,17 @@ sntrup761Dec (KEMCiphertext c) (KEMSecretKey sk) =
KEMSharedKey
<$> BA.alloc c_SNTRUP761_SIZE (\kPtr -> c_sntrup761_dec kPtr cPtr skPtr)
instance Encoding KEMPublicKey where
smpEncode (KEMPublicKey pk) = smpEncode (BA.convert pk :: ByteString)
smpP = KEMPublicKey . BA.convert <$> smpP @ByteString
instance StrEncoding KEMPublicKey where
strEncode (KEMPublicKey pk) = strEncode (BA.convert pk :: ByteString)
strP = KEMPublicKey . BA.convert <$> strP @ByteString
instance Encoding KEMCiphertext where
smpEncode (KEMCiphertext c) = smpEncode (BA.convert c :: ByteString)
smpP = KEMCiphertext . BA.convert <$> smpP @ByteString
smpEncode (KEMCiphertext c) = smpEncode . Large $ BA.convert c
smpP = KEMCiphertext . BA.convert . unLarge <$> smpP
instance ToJSON KEMPublicKey where
toJSON = strToJSON
toEncoding = strToJEncoding
instance FromJSON KEMPublicKey where
parseJSON = strParseJSON "KEMPublicKey"