bolt8

Encrypted and authenticated transport, per BOLT #8 (docs.ppad.tech/bolt8).
git clone git://git.ppad.tech/bolt8.git
Log | Files | Refs | README | LICENSE

BOLT8.hs (25366B)


      1 {-# OPTIONS_HADDOCK prune #-}
      2 {-# LANGUAGE BangPatterns #-}
      3 {-# LANGUAGE DeriveGeneric #-}
      4 {-# LANGUAGE OverloadedStrings #-}
      5 
      6 -- |
      7 -- Module: Lightning.Protocol.BOLT8
      8 -- Copyright: (c) 2025 Jared Tobin
      9 -- License: MIT
     10 -- Maintainer: Jared Tobin <jared@ppad.tech>
     11 --
     12 -- Encrypted and authenticated transport for the Lightning Network, per
     13 -- [BOLT #8](https://github.com/lightning/bolts/blob/master/08-transport.md):
     14 -- the @Noise_XK_secp256k1_ChaChaPoly_SHA256@ handshake, followed by
     15 -- length-prefixed, authenticated encryption of messages.
     16 --
     17 -- The library is pure; reading from and writing to the network is up
     18 -- to the caller.
     19 --
     20 -- = Handshake
     21 --
     22 -- The /initiator/ knows the responder's static public key in advance.
     23 -- It sends act one ('act1'), receives act two, and replies with act
     24 -- three ('act3'). The /responder/ receives act one, replies with act two
     25 -- ('act2'), and receives act three ('finalize'), which authenticates
     26 -- the initiator's static key. Both sides end up with a t'Handshake'.
     27 --
     28 -- >>> :set -XOverloadedStrings
     29 -- >>> import qualified Data.ByteString as BS
     30 -- >>> let Just i = keypair (BS.replicate 32 0x11)
     31 -- >>> let Just r = keypair (BS.replicate 32 0x21)
     32 -- >>> -- initiator, knowing r's public key; entropy must be random!
     33 -- >>> let Right (msg1, i_hs) = act1 i (keypair_pub r) (BS.replicate 32 0x12)
     34 -- >>> -- responder
     35 -- >>> let Right (msg2, r_hs) = act2 r (BS.replicate 32 0x22) msg1
     36 -- >>> -- initiator
     37 -- >>> let Right (msg3, i_res) = act3 i_hs msg2
     38 -- >>> -- responder
     39 -- >>> let Right r_res = finalize r_hs msg3
     40 -- >>> handshake_remote_static r_res == keypair_pub i
     41 -- True
     42 --
     43 -- = Transport
     44 --
     45 -- A t'Handshake' carries a t'Sender' for outgoing messages and a
     46 -- t'Receiver' for incoming ones. They are independent, so a writer
     47 -- thread can own the t'Sender' and a reader thread the t'Receiver'.
     48 --
     49 -- >>> let Right (ct, i_snd) = encrypt (handshake_sender i_res) "hello"
     50 -- >>> fmap fst (decrypt (handshake_receiver r_res) ct)
     51 -- Right "hello"
     52 --
     53 -- On a byte stream, read exactly 18 bytes and pass them to
     54 -- 'decrypt_header', which returns the number of bytes to read next;
     55 -- then read exactly that many bytes and pass them to 'decrypt_body'.
     56 -- 'decrypt' does both for a buffer holding exactly one frame.
     57 --
     58 -- Keys rotate every 1000 nonces, i.e. every 500 messages in each
     59 -- direction; this is handled internally. Messages are at most 65535
     60 -- bytes.
     61 --
     62 -- = Security
     63 --
     64 -- * __Use each state exactly once.__ Every function that takes an
     65 --   t'Initiator', t'Responder', t'Sender', t'Receiver' or t'Pending'
     66 --   returns the next state, and the caller must continue with that.
     67 --   States are ordinary immutable values, so nothing stops an old one
     68 --   from being used again, and doing so is catastrophic: encrypting
     69 --   twice with the same t'Sender' reuses a nonce, which reveals the XOR
     70 --   of the two plaintexts and allows forgeries, and decrypting with an
     71 --   old t'Receiver' accepts replayed frames.
     72 --
     73 -- * __Ephemeral entropy must be fresh.__ The 32 bytes passed to 'act1'
     74 --   and 'act2' are used directly as the ephemeral secret key. They
     75 --   must come from a cryptographically secure random source, be
     76 --   uniformly random, and never be reused.
     77 --
     78 -- * __Any error is fatal.__ BOLT #8 requires terminating the
     79 --   connection on any handshake or transport failure. Don't retry with
     80 --   the previous state. The one exception is 'encrypt' rejecting an
     81 --   oversized message, which advances nothing.
     82 
     83 module Lightning.Protocol.BOLT8 (
     84     -- * Keys
     85     Keypair
     86   , keypair
     87   , keypair_pub
     88   , Pub
     89   , parse_pub
     90   , serialize_pub
     91 
     92     -- * Handshake
     93   , Handshake
     94   , handshake_sender
     95   , handshake_receiver
     96   , handshake_remote_static
     97 
     98     -- ** Initiator
     99   , Initiator
    100   , act1
    101   , act3
    102 
    103     -- ** Responder
    104   , Responder
    105   , act2
    106   , finalize
    107 
    108     -- * Transport
    109   , Sender
    110   , encrypt
    111   , Receiver
    112   , decrypt
    113   , Pending
    114   , decrypt_header
    115   , decrypt_body
    116 
    117     -- * Errors
    118   , Error(..)
    119   ) where
    120 
    121 import Control.DeepSeq (NFData(..))
    122 import Control.Monad (guard, unless)
    123 import qualified Crypto.AEAD.ChaCha20Poly1305 as AEAD
    124 import qualified Crypto.Curve.Secp256k1 as Secp256k1
    125 import qualified Crypto.Hash.SHA256 as SHA256
    126 import qualified Crypto.KDF.HMAC as HKDF
    127 import Data.Bits (unsafeShiftR, (.&.))
    128 import qualified Data.ByteString as BS
    129 import qualified Data.ByteString.Unsafe as BU
    130 import Data.Word (Word8, Word16, Word64)
    131 import GHC.Generics (Generic)
    132 
    133 -- keys -----------------------------------------------------------------------
    134 
    135 -- A secret key: 32 bytes encoding a valid secp256k1 scalar.
    136 newtype Sec = Sec BS.ByteString
    137 
    138 -- | A secp256k1 public key.
    139 --
    140 --   'Show' renders the 33-byte compressed encoding in hex.
    141 newtype Pub = Pub Secp256k1.Projective
    142 
    143 instance Eq Pub where
    144   Pub a == Pub b =
    145     Secp256k1.serialize_point a == Secp256k1.serialize_point b
    146 
    147 instance Show Pub where
    148   showsPrec d p = showParen (d > 10) $
    149     showString "Pub " . shows (hex (serialize_pub p))
    150 
    151 instance NFData Pub where
    152   rnf (Pub p) = p `seq` ()
    153 
    154 -- | A secp256k1 keypair: a secret key and its public key.
    155 --
    156 --   Has no 'Show' or 'Eq' instance, as it contains secret material.
    157 data Keypair = Keypair !Sec !Pub
    158 
    159 instance NFData Keypair where
    160   rnf (Keypair (Sec s) p) = s `seq` rnf p
    161 
    162 -- | Construct a keypair from a 32-byte secret key.
    163 --
    164 --   The bytes are used directly as the secret key, so they must be
    165 --   uniformly random and kept secret. Returns 'Nothing' if the input
    166 --   is not 32 bytes, or is not a valid secp256k1 secret key (zero, or
    167 --   not less than the curve order).
    168 --
    169 --   >>> import Data.Maybe (isJust)
    170 --   >>> isJust (keypair (BS.replicate 32 0x11))
    171 --   True
    172 --   >>> isJust (keypair (BS.replicate 32 0x00))
    173 --   False
    174 keypair :: BS.ByteString -> Maybe Keypair
    175 keypair sec = do
    176   guard (BS.length sec == 32)
    177   k <- Secp256k1.parse_int256 sec
    178   p <- Secp256k1.derive_pub k
    179   pure $! Keypair (Sec sec) (Pub p)
    180 
    181 -- | The public key of a keypair.
    182 --
    183 --   >>> let Just r = keypair (BS.replicate 32 0x21)
    184 --   >>> keypair_pub r
    185 --   Pub "028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7"
    186 keypair_pub :: Keypair -> Pub
    187 keypair_pub (Keypair _ p) = p
    188 
    189 -- | Parse a 33-byte compressed public key.
    190 --
    191 --   >>> let Just r = keypair (BS.replicate 32 0x21)
    192 --   >>> parse_pub (serialize_pub (keypair_pub r)) == Just (keypair_pub r)
    193 --   True
    194 --   >>> parse_pub (BS.replicate 33 0x04)
    195 --   Nothing
    196 parse_pub :: BS.ByteString -> Maybe Pub
    197 parse_pub bs = do
    198   guard (BS.length bs == 33)
    199   p <- Secp256k1.parse_point bs
    200   pure (Pub p)
    201 
    202 -- | Serialize a public key in 33-byte compressed form.
    203 --
    204 --   >>> let Just r = keypair (BS.replicate 32 0x21)
    205 --   >>> BS.length (serialize_pub (keypair_pub r))
    206 --   33
    207 serialize_pub :: Pub -> BS.ByteString
    208 serialize_pub (Pub p) = Secp256k1.serialize_point p
    209 
    210 -- handshake state ------------------------------------------------------------
    211 
    212 -- | The initiator's handshake state between acts one and three.
    213 --
    214 --   Produced by 'act1' and consumed by 'act3'. Contains secret
    215 --   material; use it once.
    216 data Initiator = Initiator
    217   {-# UNPACK #-} !BS.ByteString -- handshake hash
    218   {-# UNPACK #-} !BS.ByteString -- chaining key
    219   !Sec                          -- ephemeral secret
    220   !Keypair                      -- local static keypair
    221   !Pub                          -- remote static public key
    222 
    223 instance NFData Initiator where
    224   rnf (Initiator h ck (Sec e) s rs) =
    225     h `seq` ck `seq` e `seq` rnf s `seq` rnf rs
    226 
    227 -- | The responder's handshake state between acts two and three.
    228 --
    229 --   Produced by 'act2' and consumed by 'finalize'. Contains secret
    230 --   material; use it once.
    231 data Responder = Responder
    232   {-# UNPACK #-} !BS.ByteString -- handshake hash
    233   {-# UNPACK #-} !BS.ByteString -- chaining key
    234   {-# UNPACK #-} !BS.ByteString -- temp_k2
    235   !Sec                          -- ephemeral secret
    236 
    237 instance NFData Responder where
    238   rnf (Responder h ck k (Sec e)) = h `seq` ck `seq` k `seq` e `seq` ()
    239 
    240 -- | The result of a successful handshake: the initial transport
    241 --   states and the remote party's authenticated static public key.
    242 --
    243 --   Take the t'Sender' and t'Receiver' out once, right after the
    244 --   handshake, and don't keep the t'Handshake' around: it always yields
    245 --   the /initial/ states, and encrypting with the initial t'Sender'
    246 --   a second time reuses a nonce.
    247 data Handshake = Handshake !Sender !Receiver !Pub
    248 
    249 instance NFData Handshake where
    250   rnf (Handshake s r p) = rnf s `seq` rnf r `seq` rnf p
    251 
    252 -- | The initial t'Sender', for encrypting outgoing messages.
    253 --
    254 --   Call this once per handshake. Every call returns the same initial
    255 --   state, so encrypting with the result of a second call reuses a
    256 --   nonce.
    257 handshake_sender :: Handshake -> Sender
    258 handshake_sender (Handshake s _ _) = s
    259 
    260 -- | The initial t'Receiver', for decrypting incoming messages.
    261 --
    262 --   Call this once per handshake. Every call returns the same initial
    263 --   state, so decrypting with the result of a second call accepts
    264 --   replayed frames.
    265 handshake_receiver :: Handshake -> Receiver
    266 handshake_receiver (Handshake _ r _) = r
    267 
    268 -- | The remote party's static public key, authenticated by the
    269 --   handshake. For the initiator, this is the key passed to 'act1'.
    270 handshake_remote_static :: Handshake -> Pub
    271 handshake_remote_static (Handshake _ _ p) = p
    272 
    273 -- transport state ------------------------------------------------------------
    274 
    275 -- One direction's cipher state.
    276 data Cipher = Cipher
    277   {-# UNPACK #-} !BS.ByteString -- key
    278   {-# UNPACK #-} !Word64        -- nonce, always < 1000
    279   {-# UNPACK #-} !BS.ByteString -- chaining key
    280 
    281 instance NFData Cipher where
    282   rnf (Cipher k n ck) = k `seq` n `seq` ck `seq` ()
    283 
    284 -- | State for encrypting outgoing messages.
    285 --
    286 --   Each 'encrypt' returns the next t'Sender'. Never use a t'Sender'
    287 --   twice: doing so reuses a nonce.
    288 newtype Sender = Sender Cipher
    289 
    290 instance NFData Sender where
    291   rnf (Sender c) = rnf c
    292 
    293 -- | State for decrypting incoming messages.
    294 --
    295 --   Each 'decrypt' or 'decrypt_header' consumes the t'Receiver'.
    296 --   Never use a t'Receiver' twice: doing so accepts replayed frames.
    297 newtype Receiver = Receiver Cipher
    298 
    299 instance NFData Receiver where
    300   rnf (Receiver c) = rnf c
    301 
    302 -- | A t'Receiver' that has decrypted a frame header and awaits the
    303 --   frame body.
    304 --
    305 --   Produced by 'decrypt_header' and consumed by 'decrypt_body'. Use
    306 --   it once.
    307 data Pending = Pending {-# UNPACK #-} !Int !Cipher
    308 
    309 instance NFData Pending where
    310   rnf (Pending n c) = n `seq` rnf c
    311 
    312 -- errors ---------------------------------------------------------------------
    313 
    314 -- | Handshake and transport errors.
    315 --
    316 --   Any error is fatal for the connection.
    317 data Error =
    318     InvalidEntropy
    319     -- ^ ephemeral entropy is not a valid secret key
    320   | InvalidLength
    321     -- ^ input of the wrong length, or a payload over 65535 bytes
    322   | InvalidVersion
    323     -- ^ unknown handshake version
    324   | InvalidPub
    325     -- ^ invalid public key in a handshake message
    326   | InvalidMAC
    327     -- ^ authentication failed
    328   deriving (Eq, Show, Generic)
    329 
    330 instance NFData Error
    331 
    332 -- protocol constants ---------------------------------------------------------
    333 
    334 _PROTOCOL_NAME :: BS.ByteString
    335 _PROTOCOL_NAME = "Noise_XK_secp256k1_ChaChaPoly_SHA256"
    336 
    337 _PROLOGUE :: BS.ByteString
    338 _PROLOGUE = "lightning"
    339 
    340 -- cryptographic primitives ---------------------------------------------------
    341 
    342 -- ECDH as specified by BOLT #8: SHA256 of the compressed shared point.
    343 --
    344 -- 'Nothing' is unreachable for a valid secret key and a parsed point.
    345 ecdh :: Sec -> Pub -> Maybe BS.ByteString
    346 ecdh (Sec sec) (Pub pub) = do
    347   k <- Secp256k1.parse_int256 sec
    348   pt <- Secp256k1.mul pub k
    349   pure (SHA256.hash (Secp256k1.serialize_point pt))
    350 
    351 -- h' = SHA256(h || dat)
    352 mix_hash :: BS.ByteString -> BS.ByteString -> BS.ByteString
    353 mix_hash h dat = SHA256.hash (h <> dat)
    354 
    355 -- (ck', k) = HKDF(ck, ikm), with ck as salt and empty info.
    356 --
    357 -- HKDF limits output to 255 * hashlen bytes (8160 for SHA256), so
    358 -- 'Nothing' is impossible for the 64 bytes requested here.
    359 mix_key
    360   :: BS.ByteString
    361   -> BS.ByteString
    362   -> (BS.ByteString, BS.ByteString)
    363 mix_key ck ikm =
    364   case HKDF.derive hmac ck mempty 64 ikm of
    365     Nothing ->
    366       error "ppad-bolt8: internal error, please report a bug!"
    367     Just output -> BS.splitAt 32 output
    368   where
    369     hmac k b = case SHA256.hmac k b of
    370       SHA256.MAC mac -> mac
    371 
    372 -- ChaCha20-Poly1305 encryption, returning ciphertext || MAC.
    373 --
    374 -- Keys are always 32 bytes (halves of HKDF output), nonces always 12
    375 -- bytes, and plaintexts at most 65535 bytes (far below the ChaCha20
    376 -- counter limit), so encryption cannot fail.
    377 encrypt_with_ad
    378   :: BS.ByteString -- ^ key (32 bytes)
    379   -> Word64        -- ^ nonce
    380   -> BS.ByteString -- ^ associated data
    381   -> BS.ByteString -- ^ plaintext
    382   -> BS.ByteString
    383 encrypt_with_ad key n ad pt =
    384   case AEAD.encrypt ad key (encode_nonce n) pt of
    385     Left _ ->
    386       error "ppad-bolt8: internal error, please report a bug!"
    387     Right (ct, mac) -> ct <> mac
    388 
    389 -- ChaCha20-Poly1305 decryption of ciphertext || MAC.
    390 decrypt_with_ad
    391   :: BS.ByteString       -- ^ key (32 bytes)
    392   -> Word64              -- ^ nonce
    393   -> BS.ByteString       -- ^ associated data
    394   -> BS.ByteString       -- ^ ciphertext || mac
    395   -> Maybe BS.ByteString -- ^ plaintext
    396 decrypt_with_ad key n ad ctmac
    397   | BS.length ctmac < 16 = Nothing
    398   | otherwise =
    399       let (ct, mac) = BS.splitAt (BS.length ctmac - 16) ctmac
    400       in  case AEAD.decrypt ad key (encode_nonce n) (ct, mac) of
    401             Left _   -> Nothing
    402             Right pt -> Just pt
    403 
    404 -- 96-bit nonce: 4 zero bytes followed by the 64-bit nonce, little-endian
    405 encode_nonce :: Word64 -> BS.ByteString
    406 encode_nonce n = BS.replicate 4 0x00 <> BS.pack [
    407     fi n
    408   , fi (unsafeShiftR n 8)
    409   , fi (unsafeShiftR n 16)
    410   , fi (unsafeShiftR n 24)
    411   , fi (unsafeShiftR n 32)
    412   , fi (unsafeShiftR n 40)
    413   , fi (unsafeShiftR n 48)
    414   , fi (unsafeShiftR n 56)
    415   ]
    416 
    417 -- big-endian 16-bit encoding
    418 encode_be16 :: Word16 -> BS.ByteString
    419 encode_be16 n = BS.pack [fi (unsafeShiftR n 8), fi n]
    420 
    421 -- big-endian 16-bit decoding of exactly two bytes
    422 decode_be16 :: BS.ByteString -> Maybe Word16
    423 decode_be16 bs
    424   | BS.length bs /= 2 = Nothing
    425   | otherwise =
    426       let !b0 = BU.unsafeIndex bs 0
    427           !b1 = BU.unsafeIndex bs 1
    428       in  Just (fi b0 * 0x100 + fi b1)
    429 
    430 -- handshake ------------------------------------------------------------------
    431 
    432 -- Initial (h, ck), given the responder's static public key:
    433 --
    434 --   h = SHA256(protocol_name); ck = h
    435 --   h = SHA256(h || prologue)
    436 --   h = SHA256(h || rs.pub)
    437 initial_state :: Pub -> (BS.ByteString, BS.ByteString)
    438 initial_state rs =
    439   let !h0 = SHA256.hash _PROTOCOL_NAME
    440       !h1 = mix_hash h0 _PROLOGUE
    441       !h2 = mix_hash h1 (serialize_pub rs)
    442   in  (h2, h0)
    443 
    444 -- Split a 50-byte act one or act two message into its ephemeral public
    445 -- key and MAC, checking length and version.
    446 parse_act :: BS.ByteString -> Either Error (BS.ByteString, BS.ByteString)
    447 parse_act msg = do
    448   require (BS.length msg == 50) InvalidLength
    449   require (BU.unsafeHead msg == 0x00) InvalidVersion
    450   let !(e, c) = BS.splitAt 33 (BU.unsafeTail msg)
    451   pure (e, c)
    452 
    453 -- | Initiator: produce act one (50 bytes).
    454 --
    455 --   Takes the local static keypair, the responder's static public key,
    456 --   and 32 bytes of entropy for the ephemeral key. Returns act one and
    457 --   the state for 'act3'.
    458 --
    459 --   The entropy is used directly as the ephemeral secret key. It must
    460 --   be fresh, uniformly random output of a cryptographically secure
    461 --   random source, and must never be reused. Fails with
    462 --   'InvalidEntropy' if it is not a valid secret key.
    463 --
    464 --   >>> let Just i = keypair (BS.replicate 32 0x11)
    465 --   >>> let Just r = keypair (BS.replicate 32 0x21)
    466 --   >>> let ent = BS.replicate 32 0x12 -- use random bytes in practice
    467 --   >>> fmap (BS.length . fst) (act1 i (keypair_pub r) ent)
    468 --   Right 50
    469 act1
    470   :: Keypair       -- ^ local static keypair
    471   -> Pub           -- ^ responder's static public key
    472   -> BS.ByteString -- ^ 32 bytes of fresh entropy
    473   -> Either Error (BS.ByteString, Initiator)
    474 act1 s rs ent = do
    475   Keypair e_sec e_pub <- note InvalidEntropy (keypair ent)
    476   let !(h0, ck0) = initial_state rs
    477       !e_bytes = serialize_pub e_pub
    478       !h1 = mix_hash h0 e_bytes
    479   es <- note InvalidPub (ecdh e_sec rs)
    480   let !(ck1, temp_k1) = mix_key ck0 es
    481       !c = encrypt_with_ad temp_k1 0 h1 BS.empty
    482       !h2 = mix_hash h1 c
    483       !msg = BS.cons 0x00 (e_bytes <> c)
    484   pure (msg, Initiator h2 ck1 e_sec s rs)
    485 
    486 -- | Responder: process act one and produce act two (50 bytes).
    487 --
    488 --   Takes the local static keypair, 32 bytes of entropy for the
    489 --   ephemeral key, and act one. Returns act two and the state for
    490 --   'finalize'.
    491 --
    492 --   The entropy is used directly as the ephemeral secret key. It must
    493 --   be fresh, uniformly random output of a cryptographically secure
    494 --   random source, and must never be reused. Fails with
    495 --   'InvalidEntropy' if it is not a valid secret key.
    496 --
    497 --   Any error means the connection must be terminated.
    498 --
    499 --   >>> let Just i = keypair (BS.replicate 32 0x11)
    500 --   >>> let Just r = keypair (BS.replicate 32 0x21)
    501 --   >>> let Right (msg1, _) = act1 i (keypair_pub r) (BS.replicate 32 0x12)
    502 --   >>> fmap (BS.length . fst) (act2 r (BS.replicate 32 0x22) msg1)
    503 --   Right 50
    504 --   >>> fmap fst (act2 r (BS.replicate 32 0x22) (BS.take 49 msg1))
    505 --   Left InvalidLength
    506 act2
    507   :: Keypair       -- ^ local static keypair
    508   -> BS.ByteString -- ^ 32 bytes of fresh entropy
    509   -> BS.ByteString -- ^ act one
    510   -> Either Error (BS.ByteString, Responder)
    511 act2 (Keypair s_sec s_pub) ent msg1 = do
    512   (re_bytes, c) <- parse_act msg1
    513   re <- note InvalidPub (parse_pub re_bytes)
    514   Keypair e_sec e_pub <- note InvalidEntropy (keypair ent)
    515   let !(h0, ck0) = initial_state s_pub
    516       !h1 = mix_hash h0 re_bytes
    517   es <- note InvalidPub (ecdh s_sec re)
    518   let !(ck1, temp_k1) = mix_key ck0 es
    519   _ <- note InvalidMAC (decrypt_with_ad temp_k1 0 h1 c)
    520   let !h2 = mix_hash h1 c
    521       !e_bytes = serialize_pub e_pub
    522       !h3 = mix_hash h2 e_bytes
    523   ee <- note InvalidPub (ecdh e_sec re)
    524   let !(ck2, temp_k2) = mix_key ck1 ee
    525       !c2 = encrypt_with_ad temp_k2 0 h3 BS.empty
    526       !h4 = mix_hash h3 c2
    527       !msg = BS.cons 0x00 (e_bytes <> c2)
    528   pure (msg, Responder h4 ck2 temp_k2 e_sec)
    529 
    530 -- | Initiator: process act two and produce act three (66 bytes),
    531 --   completing the handshake.
    532 --
    533 --   Any error means the connection must be terminated.
    534 --
    535 --   Continuing the module-level example:
    536 --
    537 --   >>> fmap (BS.length . fst) (act3 i_hs msg2)
    538 --   Right 66
    539 act3
    540   :: Initiator     -- ^ state from 'act1'
    541   -> BS.ByteString -- ^ act two
    542   -> Either Error (BS.ByteString, Handshake)
    543 act3 (Initiator h ck e_sec (Keypair s_sec s_pub) rs) msg2 = do
    544   (re_bytes, c) <- parse_act msg2
    545   re <- note InvalidPub (parse_pub re_bytes)
    546   let !h1 = mix_hash h re_bytes
    547   ee <- note InvalidPub (ecdh e_sec re)
    548   let !(ck1, temp_k2) = mix_key ck ee
    549   _ <- note InvalidMAC (decrypt_with_ad temp_k2 0 h1 c)
    550   let !h2 = mix_hash h1 c
    551       !c3 = encrypt_with_ad temp_k2 1 h2 (serialize_pub s_pub)
    552       !h3 = mix_hash h2 c3
    553   se <- note InvalidPub (ecdh s_sec re)
    554   let !(ck2, temp_k3) = mix_key ck1 se
    555       !t = encrypt_with_ad temp_k3 0 h3 BS.empty
    556       !(sk, rk) = mix_key ck2 BS.empty
    557       !msg = BS.cons 0x00 (c3 <> t)
    558       !hs = Handshake (Sender (Cipher sk 0 ck2))
    559                       (Receiver (Cipher rk 0 ck2)) rs
    560   pure (msg, hs)
    561 
    562 -- | Responder: process act three, completing the handshake and
    563 --   authenticating the initiator's static public key.
    564 --
    565 --   Any error means the connection must be terminated.
    566 --
    567 --   Continuing the module-level example:
    568 --
    569 --   >>> let Right r_res' = finalize r_hs msg3
    570 --   >>> handshake_remote_static r_res' == keypair_pub i
    571 --   True
    572 finalize
    573   :: Responder     -- ^ state from 'act2'
    574   -> BS.ByteString -- ^ act three
    575   -> Either Error Handshake
    576 finalize (Responder h ck temp_k2 e_sec) msg3 = do
    577   require (BS.length msg3 == 66) InvalidLength
    578   require (BU.unsafeHead msg3 == 0x00) InvalidVersion
    579   let !(c, t) = BS.splitAt 49 (BU.unsafeTail msg3)
    580   rs_bytes <- note InvalidMAC (decrypt_with_ad temp_k2 1 h c)
    581   rs <- note InvalidPub (parse_pub rs_bytes)
    582   let !h1 = mix_hash h c
    583   se <- note InvalidPub (ecdh e_sec rs)
    584   let !(ck1, temp_k3) = mix_key ck se
    585   _ <- note InvalidMAC (decrypt_with_ad temp_k3 0 h1 t)
    586   let !(rk, sk) = mix_key ck1 BS.empty
    587   pure (Handshake (Sender (Cipher sk 0 ck1)) (Receiver (Cipher rk 0 ck1)) rs)
    588 
    589 -- transport ------------------------------------------------------------------
    590 
    591 -- Encrypt under the current key and nonce, then advance.
    592 seal :: Cipher -> BS.ByteString -> (BS.ByteString, Cipher)
    593 seal c@(Cipher k n _) pt =
    594   let !ct = encrypt_with_ad k n BS.empty pt
    595   in  (ct, step c)
    596 
    597 -- Decrypt under the current key and nonce, then advance.
    598 open :: Cipher -> BS.ByteString -> Maybe (BS.ByteString, Cipher)
    599 open c@(Cipher k n _) ct = do
    600   pt <- decrypt_with_ad k n BS.empty ct
    601   pure (pt, step c)
    602 
    603 -- Increment the nonce, rotating the key once it reaches 1000:
    604 --
    605 --   (ck', k') = HKDF(ck, k), n' = 0
    606 step :: Cipher -> Cipher
    607 step (Cipher k n ck)
    608   | n' >= 1000 =
    609       let !(ck', k') = mix_key ck k
    610       in  Cipher k' 0 ck'
    611   | otherwise = Cipher k n' ck
    612   where
    613     !n' = n + 1
    614 
    615 -- | Encrypt a message of at most 65535 bytes.
    616 --
    617 --   Returns the frame to send (the message length plus 34 bytes) and
    618 --   the next t'Sender', which must be used for the following message.
    619 --   Encrypting with the same t'Sender' twice reuses a nonce and breaks
    620 --   confidentiality and authenticity.
    621 --
    622 --   Fails only with 'InvalidLength', for an oversized message. Nothing
    623 --   is encrypted in that case, so the given t'Sender' remains the
    624 --   current one and the connection can continue.
    625 --
    626 --   Continuing the module-level example:
    627 --
    628 --   >>> fmap (BS.length . fst) (encrypt i_snd "hello")
    629 --   Right 39
    630 --   >>> fmap fst (encrypt i_snd (BS.replicate 65536 0x00))
    631 --   Left InvalidLength
    632 encrypt
    633   :: Sender        -- ^ current state
    634   -> BS.ByteString -- ^ message
    635   -> Either Error (BS.ByteString, Sender)
    636 encrypt (Sender c0) m = do
    637   let !len = BS.length m
    638   require (len <= 65535) InvalidLength
    639   let !(lc, c1) = seal c0 (encode_be16 (fi len))
    640       !(bc, c2) = seal c1 m
    641   pure (lc <> bc, Sender c2)
    642 
    643 -- | Decrypt a buffer holding exactly one frame.
    644 --
    645 --   Returns the message and the next t'Receiver'. Fails with
    646 --   'InvalidLength' if the buffer is not exactly one frame, and with
    647 --   'InvalidMAC' if authentication fails. Any error means the
    648 --   connection must be terminated.
    649 --
    650 --   Continuing the module-level example:
    651 --
    652 --   >>> fmap fst (decrypt (handshake_receiver r_res) ct)
    653 --   Right "hello"
    654 --   >>> fmap fst (decrypt (handshake_receiver r_res) (BS.take 38 ct))
    655 --   Left InvalidLength
    656 decrypt
    657   :: Receiver      -- ^ current state
    658   -> BS.ByteString -- ^ one frame
    659   -> Either Error (BS.ByteString, Receiver)
    660 decrypt r frame = do
    661   let !(lc, c) = BS.splitAt 18 frame
    662   (_, p) <- decrypt_header r lc
    663   decrypt_body p c
    664 
    665 -- | Decrypt the 18-byte header (encrypted length and its MAC) at the
    666 --   start of a frame.
    667 --
    668 --   Returns the number of bytes in the rest of the frame (the message
    669 --   length plus a 16-byte MAC), which the caller should read exactly,
    670 --   and the state for 'decrypt_body'. Fails with 'InvalidLength' if
    671 --   the input is not 18 bytes, and with 'InvalidMAC' if
    672 --   authentication fails. Any error means the connection must be
    673 --   terminated.
    674 --
    675 --   Continuing the module-level example:
    676 --
    677 --   >>> fmap fst (decrypt_header (handshake_receiver r_res) (BS.take 18 ct))
    678 --   Right 21
    679 decrypt_header
    680   :: Receiver      -- ^ current state
    681   -> BS.ByteString -- ^ 18-byte header
    682   -> Either Error (Int, Pending)
    683 decrypt_header (Receiver c0) lc = do
    684   require (BS.length lc == 18) InvalidLength
    685   (l, c1) <- note InvalidMAC (open c0 lc)
    686   len <- note InvalidLength (decode_be16 l)
    687   let !body = fi len + 16
    688   pure (body, Pending body c1)
    689 
    690 -- | Decrypt the rest of a frame, following 'decrypt_header'.
    691 --
    692 --   The input must be exactly as long as 'decrypt_header' reported.
    693 --   Returns the message and the next t'Receiver'. Fails with
    694 --   'InvalidLength' on a length mismatch, and with 'InvalidMAC' if
    695 --   authentication fails. Any error means the connection must be
    696 --   terminated.
    697 --
    698 --   Continuing the module-level example:
    699 --
    700 --   >>> let (hdr, rest) = BS.splitAt 18 ct
    701 --   >>> let Right (n, p) = decrypt_header (handshake_receiver r_res) hdr
    702 --   >>> fmap fst (decrypt_body p (BS.take n rest))
    703 --   Right "hello"
    704 decrypt_body
    705   :: Pending       -- ^ state from 'decrypt_header'
    706   -> BS.ByteString -- ^ the rest of the frame
    707   -> Either Error (BS.ByteString, Receiver)
    708 decrypt_body (Pending body c1) c = do
    709   require (BS.length c == body) InvalidLength
    710   (m, c2) <- note InvalidMAC (open c1 c)
    711   pure (m, Receiver c2)
    712 
    713 -- utilities ------------------------------------------------------------------
    714 
    715 -- lowercase hex encoding
    716 hex :: BS.ByteString -> String
    717 hex = BS.foldr (\w acc -> nibble (unsafeShiftR w 4) : nibble (w .&. 15) : acc)
    718   []
    719   where
    720     nibble :: Word8 -> Char
    721     nibble n
    722       | n < 10    = toEnum (fi n + 0x30)
    723       | otherwise = toEnum (fi n + 0x57)
    724 
    725 note :: e -> Maybe a -> Either e a
    726 note e = maybe (Left e) Right
    727 {-# INLINE note #-}
    728 
    729 require :: Bool -> e -> Either e ()
    730 require cond e = unless cond (Left e)
    731 {-# INLINE require #-}
    732 
    733 fi :: (Integral a, Num b) => a -> b
    734 fi = fromIntegral
    735 {-# INLINE fi #-}