mirror of https://github.com/voidlizard/hbs2
196 lines
6.1 KiB
Haskell
196 lines
6.1 KiB
Haskell
{-# Language TemplateHaskell #-}
|
||
{-# Language UndecidableInstances #-}
|
||
|
||
module HBS2.Net.Proto.EncryptionHandshake where
|
||
|
||
import HBS2.Actors.Peer
|
||
import HBS2.Clock
|
||
import HBS2.Data.Types
|
||
import HBS2.Net.Auth.Credentials
|
||
import HBS2.Net.Proto
|
||
import HBS2.Net.Proto.Peer
|
||
import HBS2.Net.Proto.Sessions
|
||
import HBS2.Prelude.Plated
|
||
import HBS2.System.Logger.Simple
|
||
|
||
import Crypto.Saltine.Core.Box qualified as Encrypt
|
||
import Data.ByteString qualified as BS
|
||
import Data.Hashable hiding (Hashed)
|
||
import Data.String.Conversions (cs)
|
||
import Lens.Micro.Platform
|
||
|
||
instance
|
||
( Show (PubKey 'Encrypt (Encryption e))
|
||
, Show (PubKey 'Sign (Encryption e))
|
||
, Show (Nonce ())
|
||
)
|
||
=> Pretty (PeerData e) where
|
||
pretty = viaShow
|
||
|
||
data EncryptionHandshake e =
|
||
BeginEncryptionExchange (Signature (Encryption e)) (PubKey 'Encrypt (Encryption e))
|
||
| AckEncryptionExchange (Signature (Encryption e)) (PubKey 'Encrypt (Encryption e))
|
||
| ResetEncryptionKeys
|
||
deriving stock (Generic)
|
||
|
||
sendResetEncryptionKeys :: forall e s m .
|
||
( MonadIO m
|
||
, Request e (EncryptionHandshake e) m
|
||
, e ~ L4Proto
|
||
, s ~ Encryption e
|
||
)
|
||
=> Peer e
|
||
-> m ()
|
||
|
||
sendResetEncryptionKeys peer = do
|
||
request peer (ResetEncryptionKeys @e)
|
||
|
||
sendBeginEncryptionExchange :: forall e s m .
|
||
( MonadIO m
|
||
, Request e (EncryptionHandshake e) m
|
||
, Sessions e (EncryptionHandshake e) m
|
||
-- , HasCredentials s m
|
||
, Asymm s
|
||
, Signatures s
|
||
, Serialise (PubKey 'Encrypt s)
|
||
, Pretty (Peer e)
|
||
, HasProtocol e (EncryptionHandshake e)
|
||
, e ~ L4Proto
|
||
, s ~ Encryption e
|
||
)
|
||
=> PeerCredentials s
|
||
-> PubKey 'Encrypt (Encryption e)
|
||
-> Peer e
|
||
-> m ()
|
||
|
||
sendBeginEncryptionExchange creds ourpubkey peer = do
|
||
let sign = makeSign @s (view peerSignSk creds) ((cs . serialise) ourpubkey)
|
||
request peer (BeginEncryptionExchange @e sign ourpubkey)
|
||
|
||
data EncryptionHandshakeAdapter e m s = EncryptionHandshakeAdapter
|
||
{ encHandshake_considerPeerAsymmKey :: Peer e -> Maybe Encrypt.PublicKey -> m ()
|
||
|
||
, encAsymmetricKeyPair :: AsymmKeypair (Encryption e)
|
||
|
||
, encGetEncryptionKey :: EncryptionKeyIDKey e -> m (Maybe (CommonSecret (Encryption e)))
|
||
}
|
||
|
||
|
||
encryptionHandshakeProto :: forall e s m proto .
|
||
( MonadIO m
|
||
, Response e (EncryptionHandshake e) m
|
||
, Request e (EncryptionHandshake e) m
|
||
, Sessions e (KnownPeer e) m
|
||
, HasCredentials s m
|
||
, Asymm s
|
||
, Signatures s
|
||
, Sessions e (EncryptionHandshake e) m
|
||
, Serialise (PubKey 'Encrypt (Encryption e))
|
||
, s ~ Encryption e
|
||
, e ~ L4Proto
|
||
, PubKey 'Encrypt s ~ Encrypt.PublicKey
|
||
, Show (PubKey 'Sign s)
|
||
, Show (Nonce ())
|
||
, proto ~ EncryptionHandshake e
|
||
)
|
||
=> EncryptionHandshakeAdapter e m s
|
||
-> EncryptionHandshake e
|
||
-> m ()
|
||
|
||
encryptionHandshakeProto EncryptionHandshakeAdapter{..} = \case
|
||
|
||
ResetEncryptionKeys -> do
|
||
peer <- thatPeer @proto
|
||
mpeerData <- find (KnownPeerKey peer) id
|
||
-- TODO: check theirsign
|
||
trace $ "ENCRYPTION EHSP ResetEncryptionKeys from" <+> viaShow (peer, mpeerData)
|
||
|
||
-- сначала удалим у себя его прошлый ключ
|
||
encHandshake_considerPeerAsymmKey peer Nothing
|
||
|
||
creds <- getCredentials @s
|
||
ourpubkey <- pure $ pubKeyFromKeypair @s $ encAsymmetricKeyPair
|
||
sendBeginEncryptionExchange @e creds ourpubkey peer
|
||
|
||
BeginEncryptionExchange theirsign theirpubkey -> do
|
||
peer <- thatPeer @proto
|
||
mpeerData <- find (KnownPeerKey peer) id
|
||
-- TODO: check theirsign
|
||
|
||
trace $ "ENCRYPTION EHSP BeginEncryptionExchange from" <+> viaShow (peer, mpeerData)
|
||
|
||
-- взять свои ключи
|
||
creds <- getCredentials @s
|
||
|
||
ourpubkey <- pure $ pubKeyFromKeypair @s $ encAsymmetricKeyPair
|
||
|
||
-- подписать нонс
|
||
let sign = makeSign @s (view peerSignSk creds) ((cs . serialise) ourpubkey)
|
||
|
||
-- сначала удалим у себя его прошлый ключ
|
||
encHandshake_considerPeerAsymmKey peer Nothing
|
||
|
||
-- отправить обратно свой публичный ключ
|
||
-- отправится пока ещё в плоском виде
|
||
response (AckEncryptionExchange @e sign ourpubkey)
|
||
|
||
-- Только после этого прописываем его ключ у себя
|
||
encHandshake_considerPeerAsymmKey peer (Just theirpubkey)
|
||
|
||
AckEncryptionExchange theirsign theirpubkey -> do
|
||
peer <- thatPeer @proto
|
||
mpeerData <- find (KnownPeerKey peer) id
|
||
-- TODO: check theirsign
|
||
|
||
trace $ "ENCRYPTION EHSP AckEncryptionExchange from" <+> viaShow (peer, mpeerData)
|
||
|
||
-- Он уже прописал у себя наш публичный ключ и готов общаться шифрованными сообщениями
|
||
-- Прописываем его ключ у себя
|
||
encHandshake_considerPeerAsymmKey peer (Just theirpubkey)
|
||
|
||
where
|
||
proto = Proxy @(EncryptionHandshake e)
|
||
|
||
-----
|
||
|
||
data PeerAsymmInfo e = PeerAsymmInfo
|
||
|
||
data instance EventKey e (PeerAsymmInfo e) = PeerAsymmInfoKey
|
||
deriving stock (Generic)
|
||
|
||
deriving stock instance (Eq (Peer e)) => Eq (EventKey e (PeerAsymmInfo e))
|
||
instance (Hashable (Peer e)) => Hashable (EventKey e (PeerAsymmInfo e))
|
||
|
||
data instance Event e (PeerAsymmInfo e) =
|
||
PeerAsymmPubKey (Peer e) (AsymmPubKey (Encryption e))
|
||
deriving stock (Typeable)
|
||
|
||
instance Expires (EventKey e (PeerAsymmInfo e)) where
|
||
expiresIn _ = Nothing
|
||
|
||
instance
|
||
( Serialise (PubKey 'Sign (Encryption e))
|
||
, Serialise (PubKey 'Encrypt (Encryption e))
|
||
, Serialise (Signature (Encryption e))
|
||
)
|
||
=> Serialise (EncryptionHandshake e)
|
||
|
||
deriving instance
|
||
( Show (PubKey 'Encrypt (Encryption e))
|
||
, Show (Signature (Encryption e))
|
||
)
|
||
=> Show (EncryptionHandshake e)
|
||
|
||
type instance SessionData e (EncryptionHandshake e) = ()
|
||
|
||
newtype instance SessionKey e (EncryptionHandshake e) =
|
||
KnownPeerAsymmInfoKey (Peer e)
|
||
deriving stock (Generic, Typeable)
|
||
|
||
deriving instance Eq (Peer e) => Eq (SessionKey e (EncryptionHandshake e))
|
||
instance Hashable (Peer e) => Hashable (SessionKey e (EncryptionHandshake e))
|
||
|
||
data instance EventKey e (EncryptionHandshake e) =
|
||
AnyKnownPeerEncryptionHandshakeEventKey
|
||
deriving stock (Typeable, Eq,Generic)
|