1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
{-# LANGUAGE KindSignatures #-}
module Network.Tox.Crypto.Transport
( parseNetCrypto
, encodeNetCrypto
-- CryptoTransport
, NetCrypto(..)
, CryptoData(..)
, CryptoMessage(..)
, CryptoPacket(..)
, HandshakeData(..)
, Handshake(..)
) where
import Crypto.Tox
import Network.Tox.DHT.Transport (Cookie)
import Network.Socket
import Data.ByteString
import Data.Word
import Crypto.Hash
data NetCrypto
= NetHandshake (Handshake Encrypted)
| NetCrypto (CryptoPacket Encrypted)
parseNetCrypto :: ByteString -> SockAddr -> Either String (NetCrypto, SockAddr)
parseNetCrypto _ _ = Left "TODO: parseNetCrypto"
encodeNetCrypto :: NetCrypto -> SockAddr -> (ByteString, SockAddr)
encodeNetCrypto _ _ = _todo
data Handshake (f :: * -> *) = Handshake
{ handshakeCookie :: Cookie
, handshakeNonce :: Nonce24
, hadshakeData :: f HandshakeData
}
data HandshakeData = HandshakeData
{ baseNonce :: Nonce24
, sessionKey :: PublicKey
, cookieHash :: Digest SHA512
, otherCookie :: Cookie
}
data CryptoPacket (f :: * -> *) = CryptoPacket
{ pktNonce :: Word16
, pktData :: f CryptoData
}
data CryptoData = CryptoData
{ -- | [our recvbuffers buffer_start, (highest packet number handled + 1), (big endian)]
bufferStart :: Word32
-- | [ uint32_t packet number if lossless
-- , sendbuffer buffer_end if lossy , (big endian)]
, bufferEnd :: Word32
-- | [data]
, bufferData :: CryptoMessage
}
-- TODO: Flesh this out.
data CryptoMessage -- First byte indicates data
= Padding -- ^ 0 padding (skipped until we hit a non zero (data id) byte)
| PacketRequest -- ^ 1 packet request packet (lossy packet)
| KillPacket -- ^ 2 connection kill packet (lossy packet)
| UnspecifiedPacket -- ^ 3+ unspecified
| MessengerLossless -- ^ 16+ reserved for Messenger usage (lossless packets)
| MessengerLossy -- ^ 192+ reserved for Messenger usage (lossy packets)
| Messenger255 -- ^ 255 reserved for Messenger usage (lossless packet)
-- --> CookieRequest WithoutCookie
-- <-- CookieResponse CookieAddress
-- --> Handshake CookieAddress
-- <-- Handshake CookieAddress
-- Handshake packet:
-- [uint8_t 26] (0x1a)
-- [Cookie]
-- [nonce (24 bytes)]
-- [Encrypted message containing:
-- [24 bytes base nonce]
-- [session public key of the peer (32 bytes)]
-- [sha512 hash of the entire Cookie sitting outside the encrypted part]
-- [Other Cookie (used by the other to respond to the handshake packet)]
-- ]
-- cookie response packet (161 bytes):
--
-- [uint8_t 25]
-- [Random nonce (24 bytes)]
-- [Encrypted message containing:
-- [Cookie]
-- [uint64_t echo id (that was sent in the request)]
-- ]
--
-- Encrypted message is encrypted with the exact same symmetric key as the
-- cookie request packet it responds to but with a different nonce.
-- (Encrypted message is encrypted with reqesters's DHT private key,
-- responders's DHT public key and the nonce.)
--
-- Since we don't receive the public key, we will need to lookup the key by
-- the SockAddr... I don't understand why the CookieResponse message is
-- special this way. TODO: implement a multimap (SockAddr -> SharedSecret)
-- and wrap cookie queries with store/delete. TODO: Should the entire
-- SharedScret cache be keyed on only SockAddr ? Perhaps the secret cache
-- should be (NodeId -> Secret) and the cookie-request map should be
-- (SockAddr -> NodeId)
-- Encrypted packets:
--
-- Length Contents
-- :---------:--------------------------------------------------------------
-- `1` `uint8_t` (0x1b)
-- `2` `uint16_t` The last 2 bytes of the nonce used to encrypt this
-- variable Payload
--
-- The payload is encrypted with the session key and 'base nonce' set by the
-- receiver in their handshake + packet number (starting at 0, big endian math).
|