summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Network/DatagramServer.hs4
-rw-r--r--src/Network/DatagramServer/Tox.hs70
2 files changed, 61 insertions, 13 deletions
diff --git a/src/Network/DatagramServer.hs b/src/Network/DatagramServer.hs
index 8c4ec928..bcf8b9af 100644
--- a/src/Network/DatagramServer.hs
+++ b/src/Network/DatagramServer.hs
@@ -569,8 +569,10 @@ listener mgr@Manager{..} hs p = do
569 (bs, addr) <- liftIO $ do 569 (bs, addr) <- liftIO $ do
570 handle exceptions $ BS.recvFrom sock (optMaxMsgSize options) 570 handle exceptions $ BS.recvFrom sock (optMaxMsgSize options)
571 case parsePacket (msgProxy p) bs >>= \r -> (,) r <$> decodeHeaders ctx r of 571 case parsePacket (msgProxy p) bs >>= \r -> (,) r <$> decodeHeaders ctx r of
572 Left e -> -- XXX: Send parse failure message? 572 Left e -> do
573 -- XXX: Send parse failure message?
573 -- liftIO \$ sendMessage sock addr $ encodeHeaders ctx (unknownMessage e) 574 -- liftIO \$ sendMessage sock addr $ encodeHeaders ctx (unknownMessage e)
575 logMsg 'W' "listener" (T.pack $ show e)
574 return () -- Without transaction id, error message isn't very useful. 576 return () -- Without transaction id, error message isn't very useful.
575 Right (raw,m) -> 577 Right (raw,m) ->
576 case envelopeClass m of 578 case envelopeClass m of
diff --git a/src/Network/DatagramServer/Tox.hs b/src/Network/DatagramServer/Tox.hs
index 85ee269c..5003f3a4 100644
--- a/src/Network/DatagramServer/Tox.hs
+++ b/src/Network/DatagramServer/Tox.hs
@@ -34,7 +34,9 @@ import qualified Network.DatagramServer.Types as Envelope (NodeId)
34import Crypto.PubKey.ECC.Types 34import Crypto.PubKey.ECC.Types
35import Crypto.PubKey.Curve25519 35import Crypto.PubKey.Curve25519
36import Crypto.ECC.Class 36import Crypto.ECC.Class
37import qualified Crypto.Cipher.XSalsa as Salsa20 37import qualified Crypto.Cipher.Salsa as Salsa
38import qualified Crypto.Cipher.XSalsa as XSalsa
39import qualified Crypto.MAC.Poly1305 as Poly1305
38import Data.LargeWord 40import Data.LargeWord
39import Foreign.Ptr 41import Foreign.Ptr
40import Foreign.Storable 42import Foreign.Storable
@@ -42,10 +44,13 @@ import Foreign.Marshal.Alloc
42import Data.Typeable 44import Data.Typeable
43import StaticAssert 45import StaticAssert
44import Crypto.Error.Types 46import Crypto.Error.Types
47import qualified Crypto.Error as Cryptonite
45import Data.Hashable 48import Data.Hashable
46import Text.PrettyPrint as PP hiding ((<>)) 49import Text.PrettyPrint as PP hiding ((<>))
47import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) 50import Text.PrettyPrint.HughesPJClass hiding (($$), (<>))
48import Data.ByteArray (convert) 51import qualified Data.ByteArray as BA
52import Data.ByteArray ( Bytes, convert )
53import Data.Monoid
49 54
50 55
51type Key32 = Word256 -- 32 byte key 56type Key32 = Word256 -- 32 byte key
@@ -224,26 +229,29 @@ data ToxCipherContext = ToxCipherContext
224 { dhtSecretKey :: SecretKey 229 { dhtSecretKey :: SecretKey
225 } 230 }
226 231
227newtype Ciphered = Ciphered { cipheredBytes :: ByteString } 232data Ciphered = Ciphered { cipheredMAC :: Poly1305.Auth
233 , cipheredBytes :: ByteString }
228 234
229getMessage :: Get (Message Ciphered) 235getMessage :: Get (Message Ciphered)
230getMessage = do 236getMessage = do
231 typ <- get 237 typ <- get
232 nid <- get 238 nid <- get
233 tid <- get 239 tid <- get
240 mac <- Poly1305.Auth . convert <$> getBytes 2
234 cnt <- remaining 241 cnt <- remaining
235 bs <- getBytes cnt 242 bs <- getBytes cnt
236 return Message { msgType = typ 243 return Message { msgType = typ
237 , msgClient = nid 244 , msgClient = nid
238 , msgNonce = tid 245 , msgNonce = tid
239 , msgPayload = Ciphered bs } 246 , msgPayload = Ciphered mac bs }
240 247
241putMessage :: Message Ciphered -> Put 248putMessage :: Message Ciphered -> Put
242putMessage (Message {..}) = do 249putMessage (Message {..}) = do
243 put msgType 250 put msgType
244 put msgClient 251 put msgClient
245 put msgNonce 252 put msgNonce
246 let Ciphered bs = msgPayload 253 let Ciphered (Poly1305.Auth mac) bs = msgPayload
254 putByteString (convert mac)
247 putByteString bs 255 putByteString bs
248 256
249id2key :: NodeId Message -> PublicKey 257id2key :: NodeId Message -> PublicKey
@@ -251,20 +259,58 @@ id2key recipient = case publicKey recipient of
251 CryptoPassed key -> key 259 CryptoPassed key -> key
252 CryptoFailed e -> error ("id2key: "++show e) 260 CryptoFailed e -> error ("id2key: "++show e)
253 261
254lookupSecret :: ToxCipherContext -> NodeId Message -> TransactionID Message -> Salsa20.State 262
255lookupSecret ctx recipient nonce = Salsa20.initialize 20 key nonce 263zeros32 :: Bytes
264zeros32 = BA.replicate 32 0
265
266zeros24 :: Bytes
267zeros24 = BA.take 24 zeros32
268
269hsalsa20 k n = a <> b
256 where 270 where
257 key = ecdh (Proxy :: Proxy Curve_X25519) (dhtSecretKey ctx) (id2key recipient) -- ByteArrayAccess b => b 271 Salsa.State st = XSalsa.initialize 20 k n
272 (_, as) = BA.splitAt 4 st
273 (a, xs) = BA.splitAt 16 as
274 (_, bs) = BA.splitAt 24 xs
275 (b, _ ) = BA.splitAt 16 bs
276
277lookupSecret :: ToxCipherContext -> NodeId Message -> TransactionID Message -> (Poly1305.State, XSalsa.State)
278lookupSecret ctx recipient nonce = (hash, crypt)
279 where
280 -- diffie helman
281 shared = ecdh (Proxy :: Proxy Curve_X25519) (dhtSecretKey ctx) (id2key recipient) -- ByteArrayAccess b => b
282 -- shared secret XSalsa key
283 k = hsalsa20 shared zeros24
284 -- cipher state
285 st0 = XSalsa.initialize 20 k nonce
286 -- Poly1305 key
287 (rs, crypt) = XSalsa.combine st0 zeros32
288 Cryptonite.CryptoPassed hash = Poly1305.initialize rs -- TODO: Pattern fail?
258 289
259decipher :: ToxCipherContext -> Message Ciphered -> Either String (Message ByteString) 290decipher :: ToxCipherContext -> Message Ciphered -> Either String (Message ByteString)
260decipher ctx ciphered = Right (fst . Salsa20.combine st . cipheredBytes <$> ciphered) 291decipher ctx ciphered = mapM (decipherAndAuth hash crypt) ciphered
261 where 292 where
262 st = lookupSecret ctx (msgClient ciphered) (msgNonce ciphered) 293 (hash, crypt) = lookupSecret ctx (msgClient ciphered) (msgNonce ciphered)
263 294
264encipher :: ToxCipherContext -> NodeId Message -> Message ByteString -> Message Ciphered 295encipher :: ToxCipherContext -> NodeId Message -> Message ByteString -> Message Ciphered
265encipher ctx recipient plain = Ciphered . fst . Salsa20.combine st <$> plain 296encipher ctx recipient plain = encipherAndHash hash crypt <$> plain
266 where 297 where
267 st = lookupSecret ctx recipient (msgNonce plain) 298 (hash, crypt) = lookupSecret ctx recipient (msgNonce plain)
299
300encipherAndHash :: Poly1305.State -> XSalsa.State -> ByteString -> Ciphered
301encipherAndHash hash crypt m = Ciphered a c
302 where
303 c = fst . XSalsa.combine crypt $ m
304 a = Poly1305.finalize . Poly1305.update hash $ c
305
306decipherAndAuth :: Poly1305.State -> XSalsa.State -> Ciphered -> Either String ByteString
307decipherAndAuth hash crypt (Ciphered mac c)
308 | (a == mac) = Right m
309 | otherwise = Left "decipherAndAuth: auth fail"
310 where
311 m = fst . XSalsa.combine crypt $ c
312 a = Poly1305.finalize . Poly1305.update hash $ c
313
268 314
269-- see rfc7748 315-- see rfc7748
270-- 316--