{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}
module Lightning.Protocol.BOLT8 (
Sec
, Pub
, keypair
, parse_pub
, serialize_pub
, act1
, act3
, act2
, finalize
, Session
, HandshakeState
, Handshake(..)
, encrypt
, decrypt
, decrypt_frame
, decrypt_frame_partial
, FrameResult(..)
, Error(..)
) where
import Control.Monad (guard, unless)
import qualified Crypto.AEAD.ChaCha20Poly1305 as AEAD
import qualified Crypto.Curve.Secp256k1 as Secp256k1
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Crypto.KDF.HMAC as HKDF
import Data.Bits (unsafeShiftR, (.&.))
import qualified Data.ByteString as BS
import Data.Word (Word16, Word64)
import GHC.Generics (Generic)
newtype Sec = Sec BS.ByteString
deriving (Sec -> Sec -> Bool
(Sec -> Sec -> Bool) -> (Sec -> Sec -> Bool) -> Eq Sec
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Sec -> Sec -> Bool
== :: Sec -> Sec -> Bool
$c/= :: Sec -> Sec -> Bool
/= :: Sec -> Sec -> Bool
Eq, (forall x. Sec -> Rep Sec x)
-> (forall x. Rep Sec x -> Sec) -> Generic Sec
forall x. Rep Sec x -> Sec
forall x. Sec -> Rep Sec x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Sec -> Rep Sec x
from :: forall x. Sec -> Rep Sec x
$cto :: forall x. Rep Sec x -> Sec
to :: forall x. Rep Sec x -> Sec
Generic)
newtype Pub = Pub Secp256k1.Projective
instance Eq Pub where
(Pub Projective
a) == :: Pub -> Pub -> Bool
== (Pub Projective
b) =
Projective -> ByteString
Secp256k1.serialize_point Projective
a ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== Projective -> ByteString
Secp256k1.serialize_point Projective
b
instance Show Pub where
show :: Pub -> String
show (Pub Projective
p) = String
"Pub " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
forall a. Show a => a -> String
show (Projective -> ByteString
Secp256k1.serialize_point Projective
p)
data Error =
InvalidKey
| InvalidPub
| InvalidMAC
| InvalidVersion
| InvalidLength
| DecryptionFailed
deriving (Error -> Error -> Bool
(Error -> Error -> Bool) -> (Error -> Error -> Bool) -> Eq Error
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Error -> Error -> Bool
== :: Error -> Error -> Bool
$c/= :: Error -> Error -> Bool
/= :: Error -> Error -> Bool
Eq, Int -> Error -> ShowS
[Error] -> ShowS
Error -> String
(Int -> Error -> ShowS)
-> (Error -> String) -> ([Error] -> ShowS) -> Show Error
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Error -> ShowS
showsPrec :: Int -> Error -> ShowS
$cshow :: Error -> String
show :: Error -> String
$cshowList :: [Error] -> ShowS
showList :: [Error] -> ShowS
Show, (forall x. Error -> Rep Error x)
-> (forall x. Rep Error x -> Error) -> Generic Error
forall x. Rep Error x -> Error
forall x. Error -> Rep Error x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Error -> Rep Error x
from :: forall x. Error -> Rep Error x
$cto :: forall x. Rep Error x -> Error
to :: forall x. Rep Error x -> Error
Generic)
data FrameResult =
NeedMore {-# UNPACK #-} !Int
| FrameOk !BS.ByteString !BS.ByteString !Session
| FrameError !Error
deriving (forall x. FrameResult -> Rep FrameResult x)
-> (forall x. Rep FrameResult x -> FrameResult)
-> Generic FrameResult
forall x. Rep FrameResult x -> FrameResult
forall x. FrameResult -> Rep FrameResult x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FrameResult -> Rep FrameResult x
from :: forall x. FrameResult -> Rep FrameResult x
$cto :: forall x. Rep FrameResult x -> FrameResult
to :: forall x. Rep FrameResult x -> FrameResult
Generic
data Session = Session {
Session -> ByteString
sess_sk :: {-# UNPACK #-} !BS.ByteString
, Session -> Word64
sess_sn :: {-# UNPACK #-} !Word64
, Session -> ByteString
sess_sck :: {-# UNPACK #-} !BS.ByteString
, Session -> ByteString
sess_rk :: {-# UNPACK #-} !BS.ByteString
, Session -> Word64
sess_rn :: {-# UNPACK #-} !Word64
, Session -> ByteString
sess_rck :: {-# UNPACK #-} !BS.ByteString
}
deriving (forall x. Session -> Rep Session x)
-> (forall x. Rep Session x -> Session) -> Generic Session
forall x. Rep Session x -> Session
forall x. Session -> Rep Session x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Session -> Rep Session x
from :: forall x. Session -> Rep Session x
$cto :: forall x. Rep Session x -> Session
to :: forall x. Rep Session x -> Session
Generic
data Handshake = Handshake {
Handshake -> Session
session :: !Session
, Handshake -> Pub
remote_static :: !Pub
}
deriving (forall x. Handshake -> Rep Handshake x)
-> (forall x. Rep Handshake x -> Handshake) -> Generic Handshake
forall x. Rep Handshake x -> Handshake
forall x. Handshake -> Rep Handshake x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Handshake -> Rep Handshake x
from :: forall x. Handshake -> Rep Handshake x
$cto :: forall x. Rep Handshake x -> Handshake
to :: forall x. Rep Handshake x -> Handshake
Generic
data HandshakeState = HandshakeState {
HandshakeState -> ByteString
hs_h :: {-# UNPACK #-} !BS.ByteString
, HandshakeState -> ByteString
hs_ck :: {-# UNPACK #-} !BS.ByteString
, HandshakeState -> ByteString
hs_temp_k :: {-# UNPACK #-} !BS.ByteString
, HandshakeState -> Sec
hs_e_sec :: !Sec
, HandshakeState -> Pub
hs_e_pub :: !Pub
, HandshakeState -> Sec
hs_s_sec :: !Sec
, HandshakeState -> Pub
hs_s_pub :: !Pub
, HandshakeState -> Maybe Pub
hs_re :: !(Maybe Pub)
, HandshakeState -> Maybe Pub
hs_rs :: !(Maybe Pub)
}
deriving (forall x. HandshakeState -> Rep HandshakeState x)
-> (forall x. Rep HandshakeState x -> HandshakeState)
-> Generic HandshakeState
forall x. Rep HandshakeState x -> HandshakeState
forall x. HandshakeState -> Rep HandshakeState x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. HandshakeState -> Rep HandshakeState x
from :: forall x. HandshakeState -> Rep HandshakeState x
$cto :: forall x. Rep HandshakeState x -> HandshakeState
to :: forall x. Rep HandshakeState x -> HandshakeState
Generic
_PROTOCOL_NAME :: BS.ByteString
_PROTOCOL_NAME :: ByteString
_PROTOCOL_NAME = ByteString
"Noise_XK_secp256k1_ChaChaPoly_SHA256"
_PROLOGUE :: BS.ByteString
_PROLOGUE :: ByteString
_PROLOGUE = ByteString
"lightning"
keypair :: BS.ByteString -> Maybe (Sec, Pub)
keypair :: ByteString -> Maybe (Sec, Pub)
keypair ByteString
ent = do
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (ByteString -> Int
BS.length ByteString
ent Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
32)
k <- ByteString -> Maybe Wider
Secp256k1.parse_int256 ByteString
ent
p <- Secp256k1.derive_pub k
pure (Sec ent, Pub p)
parse_pub :: BS.ByteString -> Maybe Pub
parse_pub :: ByteString -> Maybe Pub
parse_pub ByteString
bs = do
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
33)
p <- ByteString -> Maybe Projective
Secp256k1.parse_point ByteString
bs
pure (Pub p)
serialize_pub :: Pub -> BS.ByteString
serialize_pub :: Pub -> ByteString
serialize_pub (Pub Projective
p) = Projective -> ByteString
Secp256k1.serialize_point Projective
p
ecdh :: Sec -> Pub -> Maybe BS.ByteString
ecdh :: Sec -> Pub -> Maybe ByteString
ecdh (Sec ByteString
sec) (Pub Projective
pub) = do
k <- ByteString -> Maybe Wider
Secp256k1.parse_int256 ByteString
sec
pt <- Secp256k1.mul pub k
let compressed = Projective -> ByteString
Secp256k1.serialize_point Projective
pt
pure (SHA256.hash compressed)
mix_hash :: BS.ByteString -> BS.ByteString -> BS.ByteString
mix_hash :: ByteString -> ByteString -> ByteString
mix_hash ByteString
h ByteString
dat = ByteString -> ByteString
SHA256.hash (ByteString
h ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
dat)
mix_key :: BS.ByteString -> BS.ByteString -> (BS.ByteString, BS.ByteString)
mix_key :: ByteString -> ByteString -> (ByteString, ByteString)
mix_key ByteString
ck ByteString
ikm = case (ByteString -> ByteString -> ByteString)
-> ByteString
-> ByteString
-> Word64
-> ByteString
-> Maybe ByteString
HKDF.derive ByteString -> ByteString -> ByteString
hmac ByteString
ck ByteString
forall a. Monoid a => a
mempty Word64
64 ByteString
ikm of
Maybe ByteString
Nothing -> String -> (ByteString, ByteString)
forall a. HasCallStack => String -> a
error String
"ppad-bolt8: internal error, please report a bug!"
Just ByteString
output -> Int -> ByteString -> (ByteString, ByteString)
BS.splitAt Int
32 ByteString
output
where
hmac :: ByteString -> ByteString -> ByteString
hmac ByteString
k ByteString
b = case ByteString -> ByteString -> MAC
SHA256.hmac ByteString
k ByteString
b of
SHA256.MAC ByteString
mac -> ByteString
mac
encrypt_with_ad
:: BS.ByteString
-> Word64
-> BS.ByteString
-> BS.ByteString
-> Maybe BS.ByteString
encrypt_with_ad :: ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
encrypt_with_ad ByteString
key Word64
n ByteString
ad ByteString
pt =
case ByteString
-> ByteString
-> ByteString
-> ByteString
-> Either Error (ByteString, ByteString)
AEAD.encrypt ByteString
ad ByteString
key (Word64 -> ByteString
encode_nonce Word64
n) ByteString
pt of
Left Error
_ -> Maybe ByteString
forall a. Maybe a
Nothing
Right (ByteString
ct, ByteString
mac) -> ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString
ct ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
mac)
decrypt_with_ad
:: BS.ByteString
-> Word64
-> BS.ByteString
-> BS.ByteString
-> Maybe BS.ByteString
decrypt_with_ad :: ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
decrypt_with_ad ByteString
key Word64
n ByteString
ad ByteString
ctmac
| ByteString -> Int
BS.length ByteString
ctmac Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
16 = Maybe ByteString
forall a. Maybe a
Nothing
| Bool
otherwise =
let (ByteString
ct, ByteString
mac) = Int -> ByteString -> (ByteString, ByteString)
BS.splitAt (ByteString -> Int
BS.length ByteString
ctmac Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
16) ByteString
ctmac
in case ByteString
-> ByteString
-> ByteString
-> (ByteString, ByteString)
-> Either Error ByteString
AEAD.decrypt ByteString
ad ByteString
key (Word64 -> ByteString
encode_nonce Word64
n) (ByteString
ct, ByteString
mac) of
Left Error
_ -> Maybe ByteString
forall a. Maybe a
Nothing
Right ByteString
pt -> ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
pt
encode_nonce :: Word64 -> BS.ByteString
encode_nonce :: Word64 -> ByteString
encode_nonce Word64
n = Int -> Word8 -> ByteString
BS.replicate Int
4 Word8
0x00 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word64 -> ByteString
encode_le64 Word64
n
encode_le64 :: Word64 -> BS.ByteString
encode_le64 :: Word64 -> ByteString
encode_le64 Word64
n = [Word8] -> ByteString
BS.pack [
Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64
n Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
8 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
16 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
24 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
32 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
40 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
48 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
, Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
56 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xff)
]
encode_be16 :: Word16 -> BS.ByteString
encode_be16 :: Word16 -> ByteString
encode_be16 Word16
n = [Word8] -> ByteString
BS.pack [Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
unsafeShiftR Word16
n Int
8), Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fi (Word16
n Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.&. Word16
0xff)]
decode_be16 :: BS.ByteString -> Maybe Word16
decode_be16 :: ByteString -> Maybe Word16
decode_be16 ByteString
bs
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
2 = Maybe Word16
forall a. Maybe a
Nothing
| Bool
otherwise =
let !b0 :: Word8
b0 = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
0
!b1 :: Word8
b1 = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
bs Int
1
in Word16 -> Maybe Word16
forall a. a -> Maybe a
Just (Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
b0 Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
* Word16
0x100 Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
+ Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Word8
b1)
init_handshake
:: Sec
-> Pub
-> Sec
-> Pub
-> Maybe Pub
-> Bool
-> HandshakeState
init_handshake :: Sec -> Pub -> Sec -> Pub -> Maybe Pub -> Bool -> HandshakeState
init_handshake Sec
s_sec Pub
s_pub Sec
e_sec Pub
e_pub Maybe Pub
m_rs Bool
is_initiator =
let !h0 :: ByteString
h0 = ByteString -> ByteString
SHA256.hash ByteString
_PROTOCOL_NAME
!ck :: ByteString
ck = ByteString
h0
!h1 :: ByteString
h1 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h0 ByteString
_PROLOGUE
!h2 :: ByteString
h2 = case (Bool
is_initiator, Maybe Pub
m_rs) of
(Bool
True, Just Pub
rs) -> ByteString -> ByteString -> ByteString
mix_hash ByteString
h1 (Pub -> ByteString
serialize_pub Pub
rs)
(Bool
False, Maybe Pub
Nothing) -> ByteString -> ByteString -> ByteString
mix_hash ByteString
h1 (Pub -> ByteString
serialize_pub Pub
s_pub)
(Bool, Maybe Pub)
_ -> ByteString
h1
in HandshakeState {
hs_h :: ByteString
hs_h = ByteString
h2
, hs_ck :: ByteString
hs_ck = ByteString
ck
, hs_temp_k :: ByteString
hs_temp_k = Int -> Word8 -> ByteString
BS.replicate Int
32 Word8
0x00
, hs_e_sec :: Sec
hs_e_sec = Sec
e_sec
, hs_e_pub :: Pub
hs_e_pub = Pub
e_pub
, hs_s_sec :: Sec
hs_s_sec = Sec
s_sec
, hs_s_pub :: Pub
hs_s_pub = Pub
s_pub
, hs_re :: Maybe Pub
hs_re = Maybe Pub
forall a. Maybe a
Nothing
, hs_rs :: Maybe Pub
hs_rs = Maybe Pub
m_rs
}
act1
:: Sec
-> Pub
-> Pub
-> BS.ByteString
-> Either Error (BS.ByteString, HandshakeState)
act1 :: Sec
-> Pub
-> Pub
-> ByteString
-> Either Error (ByteString, HandshakeState)
act1 Sec
s_sec Pub
s_pub Pub
rs ByteString
ent = do
(e_sec, e_pub) <- Error -> Maybe (Sec, Pub) -> Either Error (Sec, Pub)
forall e a. e -> Maybe a -> Either e a
note Error
InvalidKey (ByteString -> Maybe (Sec, Pub)
keypair ByteString
ent)
let !hs0 = Sec -> Pub -> Sec -> Pub -> Maybe Pub -> Bool -> HandshakeState
init_handshake Sec
s_sec Pub
s_pub Sec
e_sec Pub
e_pub (Pub -> Maybe Pub
forall a. a -> Maybe a
Just Pub
rs) Bool
True
!e_pub_bytes = Pub -> ByteString
serialize_pub Pub
e_pub
!h1 = ByteString -> ByteString -> ByteString
mix_hash (HandshakeState -> ByteString
hs_h HandshakeState
hs0) ByteString
e_pub_bytes
es <- note InvalidKey (ecdh e_sec rs)
let !(ck1, temp_k1) = mix_key (hs_ck hs0) es
c <- note InvalidMAC (encrypt_with_ad temp_k1 0 h1 BS.empty)
let !h2 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h1 ByteString
c
!msg = Word8 -> ByteString
BS.singleton Word8
0x00 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
e_pub_bytes ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
c
!hs1 = HandshakeState
hs0 {
hs_h = h2
, hs_ck = ck1
, hs_temp_k = temp_k1
}
pure (msg, hs1)
act2
:: Sec
-> Pub
-> BS.ByteString
-> BS.ByteString
-> Either Error (BS.ByteString, HandshakeState)
act2 :: Sec
-> Pub
-> ByteString
-> ByteString
-> Either Error (ByteString, HandshakeState)
act2 Sec
s_sec Pub
s_pub ByteString
ent ByteString
msg1 = do
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (ByteString -> Int
BS.length ByteString
msg1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
50) Error
InvalidLength
let !version :: Word8
version = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
msg1 Int
0
!re_bytes :: ByteString
re_bytes = Int -> ByteString -> ByteString
BS.take Int
33 (Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
msg1)
!c :: ByteString
c = Int -> ByteString -> ByteString
BS.drop Int
34 ByteString
msg1
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (Word8
version Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x00) Error
InvalidVersion
re <- Error -> Maybe Pub -> Either Error Pub
forall e a. e -> Maybe a -> Either e a
note Error
InvalidPub (ByteString -> Maybe Pub
parse_pub ByteString
re_bytes)
(e_sec, e_pub) <- note InvalidKey (keypair ent)
let !hs0 = Sec -> Pub -> Sec -> Pub -> Maybe Pub -> Bool -> HandshakeState
init_handshake Sec
s_sec Pub
s_pub Sec
e_sec Pub
e_pub Maybe Pub
forall a. Maybe a
Nothing Bool
False
!h1 = ByteString -> ByteString -> ByteString
mix_hash (HandshakeState -> ByteString
hs_h HandshakeState
hs0) ByteString
re_bytes
es <- note InvalidKey (ecdh s_sec re)
let !(ck1, temp_k1) = mix_key (hs_ck hs0) es
_ <- note InvalidMAC (decrypt_with_ad temp_k1 0 h1 c)
let !h2 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h1 ByteString
c
!e_pub_bytes = Pub -> ByteString
serialize_pub Pub
e_pub
!h3 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h2 ByteString
e_pub_bytes
ee <- note InvalidKey (ecdh e_sec re)
let !(ck2, temp_k2) = mix_key ck1 ee
c2 <- note InvalidMAC (encrypt_with_ad temp_k2 0 h3 BS.empty)
let !h4 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h3 ByteString
c2
!msg = Word8 -> ByteString
BS.singleton Word8
0x00 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
e_pub_bytes ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
c2
!hs1 = HandshakeState
hs0 {
hs_h = h4
, hs_ck = ck2
, hs_temp_k = temp_k2
, hs_re = Just re
}
pure (msg, hs1)
act3
:: HandshakeState
-> BS.ByteString
-> Either Error (BS.ByteString, Handshake)
act3 :: HandshakeState
-> ByteString -> Either Error (ByteString, Handshake)
act3 HandshakeState
hs ByteString
msg2 = do
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (ByteString -> Int
BS.length ByteString
msg2 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
50) Error
InvalidLength
let !version :: Word8
version = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
msg2 Int
0
!re_bytes :: ByteString
re_bytes = Int -> ByteString -> ByteString
BS.take Int
33 (Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
msg2)
!c :: ByteString
c = Int -> ByteString -> ByteString
BS.drop Int
34 ByteString
msg2
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (Word8
version Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x00) Error
InvalidVersion
re <- Error -> Maybe Pub -> Either Error Pub
forall e a. e -> Maybe a -> Either e a
note Error
InvalidPub (ByteString -> Maybe Pub
parse_pub ByteString
re_bytes)
let !h1 = ByteString -> ByteString -> ByteString
mix_hash (HandshakeState -> ByteString
hs_h HandshakeState
hs) ByteString
re_bytes
ee <- note InvalidKey (ecdh (hs_e_sec hs) re)
let !(ck1, temp_k2) = mix_key (hs_ck hs) ee
_ <- note InvalidMAC (decrypt_with_ad temp_k2 0 h1 c)
let !h2 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h1 ByteString
c
!s_pub_bytes = Pub -> ByteString
serialize_pub (HandshakeState -> Pub
hs_s_pub HandshakeState
hs)
c3 <- note InvalidMAC (encrypt_with_ad temp_k2 1 h2 s_pub_bytes)
let !h3 = ByteString -> ByteString -> ByteString
mix_hash ByteString
h2 ByteString
c3
se <- note InvalidKey (ecdh (hs_s_sec hs) re)
let !(ck2, temp_k3) = mix_key ck1 se
t <- note InvalidMAC (encrypt_with_ad temp_k3 0 h3 BS.empty)
let !(sk, rk) = mix_key ck2 BS.empty
!msg = Word8 -> ByteString
BS.singleton Word8
0x00 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
c3 ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
t
!sess = Session {
sess_sk :: ByteString
sess_sk = ByteString
sk
, sess_sn :: Word64
sess_sn = Word64
0
, sess_sck :: ByteString
sess_sck = ByteString
ck2
, sess_rk :: ByteString
sess_rk = ByteString
rk
, sess_rn :: Word64
sess_rn = Word64
0
, sess_rck :: ByteString
sess_rck = ByteString
ck2
}
rs <- note InvalidPub (hs_rs hs)
let !result = Handshake {
session :: Session
session = Session
sess
, remote_static :: Pub
remote_static = Pub
rs
}
pure (msg, result)
finalize
:: HandshakeState
-> BS.ByteString
-> Either Error Handshake
finalize :: HandshakeState -> ByteString -> Either Error Handshake
finalize HandshakeState
hs ByteString
msg3 = do
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (ByteString -> Int
BS.length ByteString
msg3 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
66) Error
InvalidLength
let !version :: Word8
version = HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
BS.index ByteString
msg3 Int
0
!c :: ByteString
c = Int -> ByteString -> ByteString
BS.take Int
49 (Int -> ByteString -> ByteString
BS.drop Int
1 ByteString
msg3)
!t :: ByteString
t = Int -> ByteString -> ByteString
BS.drop Int
50 ByteString
msg3
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (Word8
version Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x00) Error
InvalidVersion
rs_bytes <- Error -> Maybe ByteString -> Either Error ByteString
forall e a. e -> Maybe a -> Either e a
note Error
InvalidMAC (ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
decrypt_with_ad (HandshakeState -> ByteString
hs_temp_k HandshakeState
hs) Word64
1 (HandshakeState -> ByteString
hs_h HandshakeState
hs) ByteString
c)
rs <- note InvalidPub (parse_pub rs_bytes)
let !h1 = ByteString -> ByteString -> ByteString
mix_hash (HandshakeState -> ByteString
hs_h HandshakeState
hs) ByteString
c
se <- note InvalidKey (ecdh (hs_e_sec hs) rs)
let !(ck1, temp_k3) = mix_key (hs_ck hs) se
_ <- note InvalidMAC (decrypt_with_ad temp_k3 0 h1 t)
let !(rk, sk) = mix_key ck1 BS.empty
!sess = Session {
sess_sk :: ByteString
sess_sk = ByteString
sk
, sess_sn :: Word64
sess_sn = Word64
0
, sess_sck :: ByteString
sess_sck = ByteString
ck1
, sess_rk :: ByteString
sess_rk = ByteString
rk
, sess_rn :: Word64
sess_rn = Word64
0
, sess_rck :: ByteString
sess_rck = ByteString
ck1
}
!result = Handshake {
session :: Session
session = Session
sess
, remote_static :: Pub
remote_static = Pub
rs
}
pure result
encrypt
:: Session
-> BS.ByteString
-> Either Error (BS.ByteString, Session)
encrypt :: Session -> ByteString -> Either Error (ByteString, Session)
encrypt Session
sess ByteString
pt = do
let !len :: Int
len = ByteString -> Int
BS.length ByteString
pt
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
65535) Error
InvalidLength
let !len_bytes :: ByteString
len_bytes = Word16 -> ByteString
encode_be16 (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fi Int
len)
lc <- Error -> Maybe ByteString -> Either Error ByteString
forall e a. e -> Maybe a -> Either e a
note Error
InvalidMAC (ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
encrypt_with_ad (Session -> ByteString
sess_sk Session
sess) (Session -> Word64
sess_sn Session
sess)
ByteString
BS.empty ByteString
len_bytes)
let !(sn1, sck1, sk1) = step_nonce (sess_sn sess) (sess_sck sess) (sess_sk sess)
bc <- note InvalidMAC (encrypt_with_ad sk1 sn1 BS.empty pt)
let !(sn2, sck2, sk2) = step_nonce sn1 sck1 sk1
!packet = ByteString
lc ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
bc
!sess' = Session
sess {
sess_sk = sk2
, sess_sn = sn2
, sess_sck = sck2
}
pure (packet, sess')
decrypt
:: Session
-> BS.ByteString
-> Either Error (BS.ByteString, Session)
decrypt :: Session -> ByteString -> Either Error (ByteString, Session)
decrypt Session
sess ByteString
packet = do
(pt, remainder, sess') <- Session
-> ByteString -> Either Error (ByteString, ByteString, Session)
decrypt_frame Session
sess ByteString
packet
require (BS.null remainder) InvalidLength
pure (pt, sess')
decrypt_frame
:: Session
-> BS.ByteString
-> Either Error (BS.ByteString, BS.ByteString, Session)
decrypt_frame :: Session
-> ByteString -> Either Error (ByteString, ByteString, Session)
decrypt_frame Session
sess ByteString
packet = do
Bool -> Error -> Either Error ()
forall e. Bool -> e -> Either e ()
require (ByteString -> Int
BS.length ByteString
packet Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
34) Error
InvalidLength
let !lc :: ByteString
lc = Int -> ByteString -> ByteString
BS.take Int
18 ByteString
packet
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
18 ByteString
packet
len_bytes <- Error -> Maybe ByteString -> Either Error ByteString
forall e a. e -> Maybe a -> Either e a
note Error
InvalidMAC (ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
decrypt_with_ad (Session -> ByteString
sess_rk Session
sess) (Session -> Word64
sess_rn Session
sess)
ByteString
BS.empty ByteString
lc)
len <- note InvalidLength (decode_be16 len_bytes)
let !(rn1, rck1, rk1) = step_nonce (sess_rn sess) (sess_rck sess) (sess_rk sess)
!body_len = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fi Word16
len Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16
require (BS.length rest >= body_len) InvalidLength
let !bc = Int -> ByteString -> ByteString
BS.take Int
body_len ByteString
rest
!remainder = Int -> ByteString -> ByteString
BS.drop Int
body_len ByteString
rest
pt <- note InvalidMAC (decrypt_with_ad rk1 rn1 BS.empty bc)
let !(rn2, rck2, rk2) = step_nonce rn1 rck1 rk1
!sess' = Session
sess {
sess_rk = rk2
, sess_rn = rn2
, sess_rck = rck2
}
pure (pt, remainder, sess')
decrypt_frame_partial
:: Session
-> BS.ByteString
-> FrameResult
decrypt_frame_partial :: Session -> ByteString -> FrameResult
decrypt_frame_partial Session
sess ByteString
buf
| Int
buflen Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
18 = Int -> FrameResult
NeedMore (Int
18 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
buflen)
| Bool
otherwise =
let !lc :: ByteString
lc = Int -> ByteString -> ByteString
BS.take Int
18 ByteString
buf
!rest :: ByteString
rest = Int -> ByteString -> ByteString
BS.drop Int
18 ByteString
buf
in case ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
decrypt_with_ad (Session -> ByteString
sess_rk Session
sess) (Session -> Word64
sess_rn Session
sess) ByteString
BS.empty ByteString
lc of
Maybe ByteString
Nothing -> Error -> FrameResult
FrameError Error
InvalidMAC
Just ByteString
len_bytes -> case ByteString -> Maybe Word16
decode_be16 ByteString
len_bytes of
Maybe Word16
Nothing -> Error -> FrameResult
FrameError Error
InvalidLength
Just Word16
len ->
let !body_len :: Int
body_len = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fi Word16
len Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
16
!(Word64
rn1, ByteString
rck1, ByteString
rk1) = Word64
-> ByteString -> ByteString -> (Word64, ByteString, ByteString)
step_nonce (Session -> Word64
sess_rn Session
sess)
(Session -> ByteString
sess_rck Session
sess) (Session -> ByteString
sess_rk Session
sess)
in if ByteString -> Int
BS.length ByteString
rest Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
body_len
then Int -> FrameResult
NeedMore (Int
body_len Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
BS.length ByteString
rest)
else
let !bc :: ByteString
bc = Int -> ByteString -> ByteString
BS.take Int
body_len ByteString
rest
!remainder :: ByteString
remainder = Int -> ByteString -> ByteString
BS.drop Int
body_len ByteString
rest
in case ByteString
-> Word64 -> ByteString -> ByteString -> Maybe ByteString
decrypt_with_ad ByteString
rk1 Word64
rn1 ByteString
BS.empty ByteString
bc of
Maybe ByteString
Nothing -> Error -> FrameResult
FrameError Error
InvalidMAC
Just ByteString
pt ->
let !(Word64
rn2, ByteString
rck2, ByteString
rk2) = Word64
-> ByteString -> ByteString -> (Word64, ByteString, ByteString)
step_nonce Word64
rn1 ByteString
rck1 ByteString
rk1
!sess' :: Session
sess' = Session
sess {
sess_rk = rk2
, sess_rn = rn2
, sess_rck = rck2
}
in ByteString -> ByteString -> Session -> FrameResult
FrameOk ByteString
pt ByteString
remainder Session
sess'
where
!buflen :: Int
buflen = ByteString -> Int
BS.length ByteString
buf
step_nonce
:: Word64
-> BS.ByteString
-> BS.ByteString
-> (Word64, BS.ByteString, BS.ByteString)
step_nonce :: Word64
-> ByteString -> ByteString -> (Word64, ByteString, ByteString)
step_nonce Word64
n ByteString
ck ByteString
k
| Word64
n Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1 Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
1000 =
let !(ByteString
ck', ByteString
k') = ByteString -> ByteString -> (ByteString, ByteString)
mix_key ByteString
ck ByteString
k
in (Word64
0, ByteString
ck', ByteString
k')
| Bool
otherwise = (Word64
n Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1, ByteString
ck, ByteString
k)
note :: e -> Maybe a -> Either e a
note :: forall e a. e -> Maybe a -> Either e a
note e
e = Either e a -> (a -> Either e a) -> Maybe a -> Either e a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (e -> Either e a
forall a b. a -> Either a b
Left e
e) a -> Either e a
forall a b. b -> Either a b
Right
{-# INLINE note #-}
require :: Bool -> e -> Either e ()
require :: forall e. Bool -> e -> Either e ()
require Bool
cond e
e = Bool -> Either e () -> Either e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
cond (e -> Either e ()
forall a b. a -> Either a b
Left e
e)
{-# INLINE require #-}
fi :: (Integral a, Num b) => a -> b
fi :: forall a b. (Integral a, Num b) => a -> b
fi = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE fi #-}