• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 19155841408

07 Nov 2025 02:03AM UTC coverage: 66.675% (-0.04%) from 66.712%
19155841408

Pull #10352

github

web-flow
Merge e4313eba8 into 096ab65b1
Pull Request #10352: [WIP] chainrpc: return Unavailable while notifier starts

137328 of 205965 relevant lines covered (66.68%)

21333.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.82
/brontide/noise.go
1
package brontide
2

3
import (
4
        "crypto/cipher"
5
        "crypto/sha256"
6
        "encoding/binary"
7
        "errors"
8
        "fmt"
9
        "io"
10
        "math"
11
        "sync"
12
        "time"
13

14
        "github.com/btcsuite/btcd/btcec/v2"
15
        "github.com/lightningnetwork/lnd/keychain"
16
        "golang.org/x/crypto/chacha20poly1305"
17
        "golang.org/x/crypto/hkdf"
18
)
19

20
const (
21
        // protocolName is the precise instantiation of the Noise protocol
22
        // handshake at the center of Brontide. This value will be used as part
23
        // of the prologue. If the initiator and responder aren't using the
24
        // exact same string for this value, along with prologue of the Bitcoin
25
        // network, then the initial handshake will fail.
26
        protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"
27

28
        // macSize is the length in bytes of the tags generated by poly1305.
29
        macSize = 16
30

31
        // lengthHeaderSize is the number of bytes used to prefix encode the
32
        // length of a message payload.
33
        lengthHeaderSize = 2
34

35
        // encHeaderSize is the number of bytes required to hold an encrypted
36
        // header and it's MAC.
37
        encHeaderSize = lengthHeaderSize + macSize
38

39
        // maxMessageSize is the maximum size of an encrypted message including
40
        // the MAC. This is the max payload (65535) plus the MAC size (16).
41
        maxMessageSize = math.MaxUint16 + macSize
42

43
        // keyRotationInterval is the number of messages sent on a single
44
        // cipher stream before the keys are rotated forwards.
45
        keyRotationInterval = 1000
46

47
        // handshakeReadTimeout is a read timeout that will be enforced when
48
        // waiting for data payloads during the various acts of Brontide. If
49
        // the remote party fails to deliver the proper payload within this
50
        // time frame, then we'll fail the connection.
51
        handshakeReadTimeout = time.Second * 5
52
)
53

54
var (
55
        // ErrMaxMessageLengthExceeded is returned when a message to be written to
56
        // the cipher session exceeds the maximum allowed message payload.
57
        ErrMaxMessageLengthExceeded = errors.New("the generated payload exceeds " +
58
                "the max allowed message length of (2^16)-1")
59

60
        // ErrMessageNotFlushed signals that the connection cannot accept a new
61
        // message because the prior message has not been fully flushed.
62
        ErrMessageNotFlushed = errors.New("prior message not flushed")
63

64
        // lightningPrologue is the noise prologue that is used to initialize
65
        // the brontide noise handshake.
66
        lightningPrologue = []byte("lightning")
67

68
        // ephemeralGen is the default ephemeral key generator, used to derive a
69
        // unique ephemeral key for each brontide handshake.
70
        ephemeralGen = func() (*btcec.PrivateKey, error) {
9✔
71
                return btcec.NewPrivateKey()
9✔
72
        }
9✔
73

74
        // headerBufferPool is a pool for encrypted header buffers.
75
        headerBufferPool = &sync.Pool{
76
                New: func() interface{} {
13✔
77
                        b := make([]byte, 0, encHeaderSize)
13✔
78
                        return &b
13✔
79
                },
13✔
80
        }
81

82
        // bodyBufferPool is a pool for encrypted message body buffers.
83
        bodyBufferPool = &sync.Pool{
84
                New: func() interface{} {
13✔
85
                        // Allocate max size to avoid reallocation.
13✔
86
                        // maxMessageSize already includes the MAC.
13✔
87
                        b := make([]byte, 0, maxMessageSize)
13✔
88
                        return &b
13✔
89
                },
13✔
90
        }
91
)
92

93
// ecdh performs an ECDH operation between pub and priv. The returned value is
94
// the sha256 of the compressed shared point.
95
func ecdh(pub *btcec.PublicKey, priv keychain.SingleKeyECDH) ([]byte, error) {
1,980✔
96
        hash, err := priv.ECDH(pub)
1,980✔
97
        return hash[:], err
1,980✔
98
}
1,980✔
99

100
// cipherState encapsulates the state for the AEAD which will be used to
101
// encrypt+authenticate any payloads sent during the handshake, and messages
102
// sent once the handshake has completed.
103
type cipherState struct {
104
        // nonce is the nonce passed into the chacha20-poly1305 instance for
105
        // encryption+decryption. The nonce is incremented after each successful
106
        // encryption/decryption.
107
        //
108
        // TODO(roasbeef): this should actually be 96 bit
109
        nonce uint64
110

111
        // nonceBuffer is a reusable buffer for the nonce to avoid allocations.
112
        nonceBuffer [12]byte
113

114
        // secretKey is the shared symmetric key which will be used to
115
        // instantiate the cipher.
116
        //
117
        // TODO(roasbeef): m-lock??
118
        secretKey [32]byte
119

120
        // salt is an additional secret which is used during key rotation to
121
        // generate new keys.
122
        salt [32]byte
123

124
        // cipher is an instance of the ChaCha20-Poly1305 AEAD construction
125
        // created using the secretKey above.
126
        cipher cipher.AEAD
127
}
128

129
// Encrypt returns a ciphertext which is the encryption of the plainText
130
// observing the passed associatedData within the AEAD construction.
131
func (c *cipherState) Encrypt(associatedData, cipherText, plainText []byte) []byte {
3,790✔
132
        defer func() {
7,580✔
133
                c.nonce++
3,790✔
134

3,790✔
135
                if c.nonce == keyRotationInterval {
3,795✔
136
                        c.rotateKey()
5✔
137
                }
5✔
138
        }()
139

140
        // Write the nonce counter to the buffer (bytes 4-11).
141
        binary.LittleEndian.PutUint64(c.nonceBuffer[4:], c.nonce)
3,790✔
142

3,790✔
143
        return c.cipher.Seal(
3,790✔
144
                cipherText, c.nonceBuffer[:], plainText, associatedData,
3,790✔
145
        )
3,790✔
146
}
147

148
// Decrypt attempts to decrypt the passed ciphertext observing the specified
149
// associatedData within the AEAD construction. In the case that the final MAC
150
// check fails, then a non-nil error will be returned.
151
func (c *cipherState) Decrypt(associatedData, plainText, cipherText []byte) ([]byte, error) {
3,507✔
152
        defer func() {
7,014✔
153
                c.nonce++
3,507✔
154

3,507✔
155
                if c.nonce == keyRotationInterval {
3,512✔
156
                        c.rotateKey()
5✔
157
                }
5✔
158
        }()
159

160
        // Write the nonce counter to the buffer (bytes 4-11).
161
        binary.LittleEndian.PutUint64(c.nonceBuffer[4:], c.nonce)
3,507✔
162

3,507✔
163
        return c.cipher.Open(
3,507✔
164
                plainText, c.nonceBuffer[:], cipherText, associatedData,
3,507✔
165
        )
3,507✔
166
}
167

168
// InitializeKey initializes the secret key and AEAD cipher scheme based off of
169
// the passed key.
170
func (c *cipherState) InitializeKey(key [32]byte) {
4,039✔
171
        c.secretKey = key
4,039✔
172
        c.nonce = 0
4,039✔
173

4,039✔
174
        // Safe to ignore the error here as our key is properly sized
4,039✔
175
        // (32-bytes).
4,039✔
176
        c.cipher, _ = chacha20poly1305.New(c.secretKey[:])
4,039✔
177
}
4,039✔
178

179
// InitializeKeyWithSalt is identical to InitializeKey however it also sets the
180
// cipherState's salt field which is used for key rotation.
181
func (c *cipherState) InitializeKeyWithSalt(salt, key [32]byte) {
1,185✔
182
        c.salt = salt
1,185✔
183
        c.InitializeKey(key)
1,185✔
184
}
1,185✔
185

186
// rotateKey rotates the current encryption/decryption key for this cipherState
187
// instance. Key rotation is performed by ratcheting the current key forward
188
// using an HKDF invocation with the cipherState's salt as the salt, and the
189
// current key as the input.
190
func (c *cipherState) rotateKey() {
7✔
191
        var (
7✔
192
                info    []byte
7✔
193
                nextKey [32]byte
7✔
194
        )
7✔
195

7✔
196
        oldKey := c.secretKey
7✔
197
        h := hkdf.New(sha256.New, oldKey[:], c.salt[:], info)
7✔
198

7✔
199
        // hkdf(ck, k, zero)
7✔
200
        // |
7✔
201
        // | \
7✔
202
        // |  \
7✔
203
        // ck  k'
7✔
204
        h.Read(c.salt[:])
7✔
205
        h.Read(nextKey[:])
7✔
206

7✔
207
        c.InitializeKey(nextKey)
7✔
208
}
7✔
209

210
// symmetricState encapsulates a cipherState object and houses the ephemeral
211
// handshake digest state. This struct is used during the handshake to derive
212
// new shared secrets based off of the result of ECDH operations. Ultimately,
213
// the final key yielded by this struct is the result of an incremental
214
// Triple-DH operation.
215
type symmetricState struct {
216
        cipherState
217

218
        // chainingKey is used as the salt to the HKDF function to derive a new
219
        // chaining key as well as a new tempKey which is used for
220
        // encryption/decryption.
221
        chainingKey [32]byte
222

223
        // tempKey is the latter 32 bytes resulted from the latest HKDF
224
        // iteration. This key is used to encrypt/decrypt any handshake
225
        // messages or payloads sent until the next DH operation is executed.
226
        tempKey [32]byte
227

228
        // handshakeDigest is the cumulative hash digest of all handshake
229
        // messages sent from start to finish. This value is never transmitted
230
        // to the other side, but will be used as the AD when
231
        // encrypting/decrypting messages using our AEAD construction.
232
        handshakeDigest [32]byte
233
}
234

235
// mixKey implements a basic HKDF-based key ratchet. This method is called
236
// with the result of each DH output generated during the handshake process.
237
// The first 32 bytes extract from the HKDF reader is the next chaining key,
238
// then latter 32 bytes become the temp secret key using within any future AEAD
239
// operations until another DH operation is performed.
240
func (s *symmetricState) mixKey(input []byte) {
1,980✔
241
        var info []byte
1,980✔
242

1,980✔
243
        secret := input
1,980✔
244
        salt := s.chainingKey
1,980✔
245
        h := hkdf.New(sha256.New, secret, salt[:], info)
1,980✔
246

1,980✔
247
        // hkdf(ck, input, zero)
1,980✔
248
        // |
1,980✔
249
        // | \
1,980✔
250
        // |  \
1,980✔
251
        // ck  k
1,980✔
252
        h.Read(s.chainingKey[:])
1,980✔
253
        h.Read(s.tempKey[:])
1,980✔
254

1,980✔
255
        // cipher.k = temp_key
1,980✔
256
        s.InitializeKey(s.tempKey)
1,980✔
257
}
1,980✔
258

259
// mixHash hashes the passed input data into the cumulative handshake digest.
260
// The running result of this value (h) is used as the associated data in all
261
// decryption/encryption operations.
262
func (s *symmetricState) mixHash(data []byte) {
5,648✔
263
        h := sha256.New()
5,648✔
264
        h.Write(s.handshakeDigest[:])
5,648✔
265
        h.Write(data)
5,648✔
266

5,648✔
267
        copy(s.handshakeDigest[:], h.Sum(nil))
5,648✔
268
}
5,648✔
269

270
// EncryptAndHash returns the authenticated encryption of the passed plaintext.
271
// When encrypting the handshake digest (h) is used as the associated data to
272
// the AEAD cipher.
273
func (s *symmetricState) EncryptAndHash(plaintext []byte) []byte {
1,304✔
274
        ciphertext := s.Encrypt(s.handshakeDigest[:], nil, plaintext)
1,304✔
275

1,304✔
276
        s.mixHash(ciphertext)
1,304✔
277

1,304✔
278
        return ciphertext
1,304✔
279
}
1,304✔
280

281
// DecryptAndHash returns the authenticated decryption of the passed
282
// ciphertext. When encrypting the handshake digest (h) is used as the
283
// associated data to the AEAD cipher.
284
func (s *symmetricState) DecryptAndHash(ciphertext []byte) ([]byte, error) {
1,267✔
285
        plaintext, err := s.Decrypt(s.handshakeDigest[:], nil, ciphertext)
1,267✔
286
        if err != nil {
1,324✔
287
                return nil, err
57✔
288
        }
57✔
289

290
        s.mixHash(ciphertext)
1,210✔
291

1,210✔
292
        return plaintext, nil
1,210✔
293
}
294

295
// InitializeSymmetric initializes the symmetric state by setting the handshake
296
// digest (h) and the chaining key (ck) to protocol name.
297
func (s *symmetricState) InitializeSymmetric(protocolName []byte) {
876✔
298
        var empty [32]byte
876✔
299

876✔
300
        s.handshakeDigest = sha256.Sum256(protocolName)
876✔
301
        s.chainingKey = s.handshakeDigest
876✔
302
        s.InitializeKey(empty)
876✔
303
}
876✔
304

305
// handshakeState encapsulates the symmetricState and keeps track of all the
306
// public keys (static and ephemeral) for both sides during the handshake
307
// transcript. If the handshake completes successfully, then two instances of a
308
// cipherState are emitted: one to encrypt messages from initiator to
309
// responder, and the other for the opposite direction.
310
type handshakeState struct {
311
        symmetricState
312

313
        initiator bool
314

315
        localStatic    keychain.SingleKeyECDH
316
        localEphemeral keychain.SingleKeyECDH // nolint (false positive)
317

318
        remoteStatic    *btcec.PublicKey
319
        remoteEphemeral *btcec.PublicKey
320
}
321

322
// newHandshakeState returns a new instance of the handshake state initialized
323
// with the prologue and protocol name. If this is the responder's handshake
324
// state, then the remotePub can be nil.
325
func newHandshakeState(initiator bool, prologue []byte,
326
        localKey keychain.SingleKeyECDH,
327
        remotePub *btcec.PublicKey) handshakeState {
876✔
328

876✔
329
        h := handshakeState{
876✔
330
                initiator:    initiator,
876✔
331
                localStatic:  localKey,
876✔
332
                remoteStatic: remotePub,
876✔
333
        }
876✔
334

876✔
335
        // Set the current chaining key and handshake digest to the hash of the
876✔
336
        // protocol name, and additionally mix in the prologue. If either sides
876✔
337
        // disagree about the prologue or protocol name, then the handshake
876✔
338
        // will fail.
876✔
339
        h.InitializeSymmetric([]byte(protocolName))
876✔
340
        h.mixHash(prologue)
876✔
341

876✔
342
        // In Noise_XK, the initiator should know the responder's static
876✔
343
        // public key, therefore we include the responder's static key in the
876✔
344
        // handshake digest. If the initiator gets this value wrong, then the
876✔
345
        // handshake will fail.
876✔
346
        if initiator {
1,313✔
347
                h.mixHash(remotePub.SerializeCompressed())
437✔
348
        } else {
879✔
349
                h.mixHash(localKey.PubKey().SerializeCompressed())
442✔
350
        }
442✔
351

352
        return h
876✔
353
}
354

355
// EphemeralGenerator is a functional option that allows callers to substitute
356
// a custom function for use when generating ephemeral keys for ActOne or
357
// ActTwo. The function closure returned by this function can be passed into
358
// NewBrontideMachine as a function option parameter.
359
func EphemeralGenerator(gen func() (*btcec.PrivateKey, error)) func(*Machine) {
396✔
360
        return func(m *Machine) {
1,258✔
361
                m.ephemeralGen = gen
862✔
362
        }
862✔
363
}
364

365
// Machine is a state-machine which implements Brontide: an
366
// Authenticated-key Exchange in Three Acts. Brontide is derived from the Noise
367
// framework, specifically implementing the Noise_XK handshake. Once the
368
// initial 3-act handshake has completed all messages are encrypted with a
369
// chacha20 AEAD cipher. On the wire, all messages are prefixed with an
370
// authenticated+encrypted length field. Additionally, the encrypted+auth'd
371
// length prefix is used as the AD when encrypting+decryption messages. This
372
// construction provides confidentiality of packet length, avoids introducing
373
// a padding-oracle, and binds the encrypted packet length to the packet
374
// itself.
375
//
376
// The acts proceeds the following order (initiator on the left):
377
//
378
//        GenActOne()   ->
379
//                          RecvActOne()
380
//                      <-  GenActTwo()
381
//        RecvActTwo()
382
//        GenActThree() ->
383
//                          RecvActThree()
384
//
385
// This exchange corresponds to the following Noise handshake:
386
//
387
//        <- s
388
//        ...
389
//        -> e, es
390
//        <- e, ee
391
//        -> s, se
392
type Machine struct {
393
        sendCipher cipherState
394
        recvCipher cipherState
395

396
        ephemeralGen func() (*btcec.PrivateKey, error)
397

398
        handshakeState
399

400
        // nextCipherHeader is a static buffer that we'll use to read in the
401
        // next ciphertext header from the wire. The header is a 2 byte length
402
        // (of the next ciphertext), followed by a 16 byte MAC.
403
        nextCipherHeader [encHeaderSize]byte
404

405
        // pktLenBuffer is a reusable buffer for encoding the packet length.
406
        pktLenBuffer [lengthHeaderSize]byte
407

408
        // nextHeaderSend holds a reference to the remaining header bytes to
409
        // write out for a pending message. This allows us to tolerate timeout
410
        // errors that cause partial writes.
411
        nextHeaderSend []byte
412

413
        // nextBodySend holds a reference to the remaining body bytes to write
414
        // out for a pending message. This allows us to tolerate timeout errors
415
        // that cause partial writes.
416
        nextBodySend []byte
417

418
        // pooledHeaderBuf is the pooled buffer used for the header, which we
419
        // need to track so we can return it to the pool when done.
420
        pooledHeaderBuf *[]byte
421

422
        // pooledBodyBuf is the pooled buffer used for the body, which we need
423
        // to track so we can return it to the pool when done.
424
        pooledBodyBuf *[]byte
425
}
426

427
// NewBrontideMachine creates a new instance of the brontide state-machine. If
428
// the responder (listener) is creating the object, then the remotePub should
429
// be nil. The handshake state within brontide is initialized using the ascii
430
// string "lightning" as the prologue. The last parameter is a set of variadic
431
// arguments for adding additional options to the brontide Machine
432
// initialization.
433
func NewBrontideMachine(initiator bool, localKey keychain.SingleKeyECDH,
434
        remotePub *btcec.PublicKey, options ...func(*Machine)) *Machine {
876✔
435

876✔
436
        handshake := newHandshakeState(
876✔
437
                initiator, lightningPrologue, localKey, remotePub,
876✔
438
        )
876✔
439

876✔
440
        m := &Machine{
876✔
441
                handshakeState: handshake,
876✔
442
                ephemeralGen:   ephemeralGen,
876✔
443
        }
876✔
444

876✔
445
        // With the default options established, we'll now process all the
876✔
446
        // options passed in as parameters.
876✔
447
        for _, option := range options {
1,738✔
448
                option(m)
862✔
449
        }
862✔
450

451
        return m
876✔
452
}
453

454
const (
455
        // HandshakeVersion is the expected version of the brontide handshake.
456
        // Any messages that carry a different version will cause the handshake
457
        // to abort immediately.
458
        HandshakeVersion = byte(0)
459

460
        // ActOneSize is the size of the packet sent from initiator to
461
        // responder in ActOne. The packet consists of a handshake version, an
462
        // ephemeral key in compressed format, and a 16-byte poly1305 tag.
463
        //
464
        // 1 + 33 + 16
465
        ActOneSize = 50
466

467
        // ActTwoSize is the size the packet sent from responder to initiator
468
        // in ActTwo. The packet consists of a handshake version, an ephemeral
469
        // key in compressed format and a 16-byte poly1305 tag.
470
        //
471
        // 1 + 33 + 16
472
        ActTwoSize = 50
473

474
        // ActThreeSize is the size of the packet sent from initiator to
475
        // responder in ActThree. The packet consists of a handshake version,
476
        // the initiators static key encrypted with strong forward secrecy and
477
        // a 16-byte poly1035 tag.
478
        //
479
        // 1 + 33 + 16 + 16
480
        ActThreeSize = 66
481
)
482

483
// GenActOne generates the initial packet (act one) to be sent from initiator
484
// to responder. During act one the initiator generates a fresh ephemeral key,
485
// hashes it into the handshake digest, and performs an ECDH between this key
486
// and the responder's static key. Future payloads are encrypted with a key
487
// derived from this result.
488
//
489
//        -> e, es
490
func (b *Machine) GenActOne() ([ActOneSize]byte, error) {
390✔
491
        var actOne [ActOneSize]byte
390✔
492

390✔
493
        // e
390✔
494
        localEphemeral, err := b.ephemeralGen()
390✔
495
        if err != nil {
390✔
496
                return actOne, err
×
497
        }
×
498
        b.localEphemeral = &keychain.PrivKeyECDH{
390✔
499
                PrivKey: localEphemeral,
390✔
500
        }
390✔
501

390✔
502
        ephemeral := localEphemeral.PubKey().SerializeCompressed()
390✔
503
        b.mixHash(ephemeral)
390✔
504

390✔
505
        // es
390✔
506
        s, err := ecdh(b.remoteStatic, b.localEphemeral)
390✔
507
        if err != nil {
390✔
508
                return actOne, err
×
509
        }
×
510
        b.mixKey(s[:])
390✔
511

390✔
512
        authPayload := b.EncryptAndHash([]byte{})
390✔
513

390✔
514
        actOne[0] = HandshakeVersion
390✔
515
        copy(actOne[1:34], ephemeral)
390✔
516
        copy(actOne[34:], authPayload)
390✔
517

390✔
518
        return actOne, nil
390✔
519
}
520

521
// RecvActOne processes the act one packet sent by the initiator. The responder
522
// executes the mirrored actions to that of the initiator extending the
523
// handshake digest and deriving a new shared secret based on an ECDH with the
524
// initiator's ephemeral key and responder's static key.
525
func (b *Machine) RecvActOne(actOne [ActOneSize]byte) error {
378✔
526
        var (
378✔
527
                err error
378✔
528
                e   [33]byte
378✔
529
                p   [16]byte
378✔
530
        )
378✔
531

378✔
532
        // If the handshake version is unknown, then the handshake fails
378✔
533
        // immediately.
378✔
534
        if actOne[0] != HandshakeVersion {
388✔
535
                return fmt.Errorf("act one: invalid handshake version: %v, "+
10✔
536
                        "only %v is valid, msg=%x", actOne[0], HandshakeVersion,
10✔
537
                        actOne[:])
10✔
538
        }
10✔
539

540
        copy(e[:], actOne[1:34])
368✔
541
        copy(p[:], actOne[34:])
368✔
542

368✔
543
        // e
368✔
544
        b.remoteEphemeral, err = btcec.ParsePubKey(e[:])
368✔
545
        if err != nil {
374✔
546
                return err
6✔
547
        }
6✔
548
        b.mixHash(b.remoteEphemeral.SerializeCompressed())
362✔
549

362✔
550
        // es
362✔
551
        s, err := ecdh(b.remoteEphemeral, b.localStatic)
362✔
552
        if err != nil {
362✔
553
                return err
×
554
        }
×
555
        b.mixKey(s)
362✔
556

362✔
557
        // If the initiator doesn't know our static key, then this operation
362✔
558
        // will fail.
362✔
559
        _, err = b.DecryptAndHash(p[:])
362✔
560
        return err
362✔
561
}
562

563
// GenActTwo generates the second packet (act two) to be sent from the
564
// responder to the initiator. The packet for act two is identical to that of
565
// act one, but then results in a different ECDH operation between the
566
// initiator's and responder's ephemeral keys.
567
//
568
//        <- e, ee
569
func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) {
331✔
570
        var actTwo [ActTwoSize]byte
331✔
571

331✔
572
        // e
331✔
573
        localEphemeral, err := b.ephemeralGen()
331✔
574
        if err != nil {
331✔
575
                return actTwo, err
×
576
        }
×
577
        b.localEphemeral = &keychain.PrivKeyECDH{
331✔
578
                PrivKey: localEphemeral,
331✔
579
        }
331✔
580

331✔
581
        ephemeral := localEphemeral.PubKey().SerializeCompressed()
331✔
582
        b.mixHash(localEphemeral.PubKey().SerializeCompressed())
331✔
583

331✔
584
        // ee
331✔
585
        s, err := ecdh(b.remoteEphemeral, b.localEphemeral)
331✔
586
        if err != nil {
331✔
587
                return actTwo, err
×
588
        }
×
589
        b.mixKey(s)
331✔
590

331✔
591
        authPayload := b.EncryptAndHash([]byte{})
331✔
592

331✔
593
        actTwo[0] = HandshakeVersion
331✔
594
        copy(actTwo[1:34], ephemeral)
331✔
595
        copy(actTwo[34:], authPayload)
331✔
596

331✔
597
        return actTwo, nil
331✔
598
}
599

600
// RecvActTwo processes the second packet (act two) sent from the responder to
601
// the initiator. A successful processing of this packet authenticates the
602
// initiator to the responder.
603
func (b *Machine) RecvActTwo(actTwo [ActTwoSize]byte) error {
355✔
604
        var (
355✔
605
                err error
355✔
606
                e   [33]byte
355✔
607
                p   [16]byte
355✔
608
        )
355✔
609

355✔
610
        // If the handshake version is unknown, then the handshake fails
355✔
611
        // immediately.
355✔
612
        if actTwo[0] != HandshakeVersion {
385✔
613
                return fmt.Errorf("act two: invalid handshake version: %v, "+
30✔
614
                        "only %v is valid, msg=%x", actTwo[0], HandshakeVersion,
30✔
615
                        actTwo[:])
30✔
616
        }
30✔
617

618
        copy(e[:], actTwo[1:34])
325✔
619
        copy(p[:], actTwo[34:])
325✔
620

325✔
621
        // e
325✔
622
        b.remoteEphemeral, err = btcec.ParsePubKey(e[:])
325✔
623
        if err != nil {
330✔
624
                return err
5✔
625
        }
5✔
626
        b.mixHash(b.remoteEphemeral.SerializeCompressed())
320✔
627

320✔
628
        // ee
320✔
629
        s, err := ecdh(b.remoteEphemeral, b.localEphemeral)
320✔
630
        if err != nil {
320✔
631
                return err
×
632
        }
×
633
        b.mixKey(s)
320✔
634

320✔
635
        _, err = b.DecryptAndHash(p[:])
320✔
636
        return err
320✔
637
}
638

639
// GenActThree creates the final (act three) packet of the handshake. Act three
640
// is to be sent from the initiator to the responder. The purpose of act three
641
// is to transmit the initiator's public key under strong forward secrecy to
642
// the responder. This act also includes the final ECDH operation which yields
643
// the final session.
644
//
645
//        -> s, se
646
func (b *Machine) GenActThree() ([ActThreeSize]byte, error) {
296✔
647
        var actThree [ActThreeSize]byte
296✔
648

296✔
649
        ourPubkey := b.localStatic.PubKey().SerializeCompressed()
296✔
650
        ciphertext := b.EncryptAndHash(ourPubkey)
296✔
651

296✔
652
        s, err := ecdh(b.remoteEphemeral, b.localStatic)
296✔
653
        if err != nil {
296✔
654
                return actThree, err
×
655
        }
×
656
        b.mixKey(s)
296✔
657

296✔
658
        authPayload := b.EncryptAndHash([]byte{})
296✔
659

296✔
660
        actThree[0] = HandshakeVersion
296✔
661
        copy(actThree[1:50], ciphertext)
296✔
662
        copy(actThree[50:], authPayload)
296✔
663

296✔
664
        // With the final ECDH operation complete, derive the session sending
296✔
665
        // and receiving keys.
296✔
666
        b.split()
296✔
667

296✔
668
        return actThree, nil
296✔
669
}
670

671
// RecvActThree processes the final act (act three) sent from the initiator to
672
// the responder. After processing this act, the responder learns of the
673
// initiator's static public key. Decryption of the static key serves to
674
// authenticate the initiator to the responder.
675
func (b *Machine) RecvActThree(actThree [ActThreeSize]byte) error {
331✔
676
        var (
331✔
677
                err error
331✔
678
                s   [33 + 16]byte
331✔
679
                p   [16]byte
331✔
680
        )
331✔
681

331✔
682
        // If the handshake version is unknown, then the handshake fails
331✔
683
        // immediately.
331✔
684
        if actThree[0] != HandshakeVersion {
364✔
685
                return fmt.Errorf("act three: invalid handshake version: %v, "+
33✔
686
                        "only %v is valid, msg=%x", actThree[0], HandshakeVersion,
33✔
687
                        actThree[:])
33✔
688
        }
33✔
689

690
        copy(s[:], actThree[1:33+16+1])
298✔
691
        copy(p[:], actThree[33+16+1:])
298✔
692

298✔
693
        // s
298✔
694
        remotePub, err := b.DecryptAndHash(s[:])
298✔
695
        if err != nil {
300✔
696
                return err
2✔
697
        }
2✔
698
        b.remoteStatic, err = btcec.ParsePubKey(remotePub)
296✔
699
        if err != nil {
296✔
700
                return err
×
701
        }
×
702

703
        // se
704
        se, err := ecdh(b.remoteStatic, b.localEphemeral)
296✔
705
        if err != nil {
296✔
706
                return err
×
707
        }
×
708
        b.mixKey(se)
296✔
709

296✔
710
        if _, err := b.DecryptAndHash(p[:]); err != nil {
296✔
711
                return err
×
712
        }
×
713

714
        // With the final ECDH operation complete, derive the session sending
715
        // and receiving keys.
716
        b.split()
296✔
717

296✔
718
        return nil
296✔
719
}
720

721
// split is the final wrap-up act to be executed at the end of a successful
722
// three act handshake. This function creates two internal cipherState
723
// instances: one which is used to encrypt messages from the initiator to the
724
// responder, and another which is used to encrypt message for the opposite
725
// direction.
726
func (b *Machine) split() {
594✔
727
        var (
594✔
728
                empty   []byte
594✔
729
                sendKey [32]byte
594✔
730
                recvKey [32]byte
594✔
731
        )
594✔
732

594✔
733
        h := hkdf.New(sha256.New, empty, b.chainingKey[:], empty)
594✔
734

594✔
735
        // If we're the initiator the first 32 bytes are used to encrypt our
594✔
736
        // messages and the second 32-bytes to decrypt their messages. For the
594✔
737
        // responder the opposite is true.
594✔
738
        if b.initiator {
890✔
739
                h.Read(sendKey[:])
296✔
740
                b.sendCipher = cipherState{}
296✔
741
                b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
296✔
742

296✔
743
                h.Read(recvKey[:])
296✔
744
                b.recvCipher = cipherState{}
296✔
745
                b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
296✔
746
        } else {
597✔
747
                h.Read(recvKey[:])
301✔
748
                b.recvCipher = cipherState{}
301✔
749
                b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
301✔
750

301✔
751
                h.Read(sendKey[:])
301✔
752
                b.sendCipher = cipherState{}
301✔
753
                b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
301✔
754
        }
301✔
755
}
756

757
// WriteMessage encrypts and buffers the next message p. The ciphertext of the
758
// message is prepended with an encrypt+auth'd length which must be used as the
759
// AD to the AEAD construction when being decrypted by the other side.
760
//
761
// NOTE: This DOES NOT write the message to the wire, it should be followed by a
762
// call to Flush to ensure the message is written.
763
func (b *Machine) WriteMessage(p []byte) error {
1,248✔
764
        // The total length of each message payload including the MAC size
1,248✔
765
        // payload exceed the largest number encodable within a 16-bit unsigned
1,248✔
766
        // integer.
1,248✔
767
        if len(p) > math.MaxUint16 {
1,250✔
768
                return ErrMaxMessageLengthExceeded
2✔
769
        }
2✔
770

771
        // If a prior message was written but it hasn't been fully flushed,
772
        // return an error as we only support buffering of one message at a
773
        // time.
774
        if len(b.nextHeaderSend) > 0 || len(b.nextBodySend) > 0 {
1,246✔
775
                return ErrMessageNotFlushed
×
776
        }
×
777

778
        // The full length of the packet is only the packet length, and does
779
        // NOT include the MAC.
780
        fullLength := uint16(len(p))
1,246✔
781

1,246✔
782
        binary.BigEndian.PutUint16(b.pktLenBuffer[:], fullLength)
1,246✔
783

1,246✔
784
        headerBufInterface := headerBufferPool.Get()
1,246✔
785
        headerBuf, ok := headerBufInterface.(*[]byte)
1,246✔
786
        if !ok {
1,246✔
787
                b.releaseBuffers()
×
788
                return fmt.Errorf("headerBufferPool returned unexpected "+
×
789
                        "type: %T", headerBufInterface)
×
790
        }
×
791
        b.pooledHeaderBuf = headerBuf
1,246✔
792

1,246✔
793
        bodyBufInterface := bodyBufferPool.Get()
1,246✔
794
        bodyBuf, ok := bodyBufInterface.(*[]byte)
1,246✔
795
        if !ok {
1,246✔
796
                b.releaseBuffers()
×
797
                return fmt.Errorf("bodyBufferPool returned unexpected "+
×
798
                        "type: %T", bodyBufInterface)
×
799
        }
×
800
        b.pooledBodyBuf = bodyBuf
1,246✔
801

1,246✔
802
        // First, generate the encrypted+MAC'd length prefix for the packet. We
1,246✔
803
        // pass our pooled buffer as the cipherText (dst) parameter.
1,246✔
804
        b.nextHeaderSend = b.sendCipher.Encrypt(
1,246✔
805
                nil, *b.pooledHeaderBuf, b.pktLenBuffer[:],
1,246✔
806
        )
1,246✔
807

1,246✔
808
        // Finally, generate the encrypted packet itself. We pass our pooled
1,246✔
809
        // buffer as the cipherText (dst) parameter.
1,246✔
810
        b.nextBodySend = b.sendCipher.Encrypt(nil, *b.pooledBodyBuf, p)
1,246✔
811

1,246✔
812
        return nil
1,246✔
813
}
814

815
// Flush attempts to write a message buffered using WriteMessage to the provided
816
// io.Writer. If no buffered message exists, this will result in a NOP.
817
// Otherwise, it will continue to write the remaining bytes, picking up where
818
// the byte stream left off in the event of a partial write. The number of bytes
819
// returned reflects the number of plaintext bytes in the payload, and does not
820
// account for the overhead of the header or MACs.
821
//
822
// NOTE: It is safe to call this method again iff a timeout error is returned.
823
func (b *Machine) Flush(w io.Writer) (int, error) {
1,263✔
824
        // First, write out the pending header bytes, if any exist. Any header
1,263✔
825
        // bytes written will not count towards the total amount flushed.
1,263✔
826
        if len(b.nextHeaderSend) > 0 {
2,510✔
827
                // Write any remaining header bytes and shift the slice to point
1,247✔
828
                // to the next segment of unwritten bytes. If an error is
1,247✔
829
                // encountered, we can continue to write the header from where
1,247✔
830
                // we left off on a subsequent call to Flush.
1,247✔
831
                n, err := w.Write(b.nextHeaderSend)
1,247✔
832
                b.nextHeaderSend = b.nextHeaderSend[n:]
1,247✔
833
                if err != nil {
1,251✔
834
                        return 0, err
4✔
835
                }
4✔
836
        }
837

838
        // Next, write the pending body bytes, if any exist. Only the number of
839
        // bytes written that correspond to the ciphertext will be included in
840
        // the total bytes written, bytes written as part of the MAC will not be
841
        // counted.
842
        var nn int
1,259✔
843
        if len(b.nextBodySend) > 0 {
2,512✔
844
                // Write out all bytes excluding the mac and shift the body
1,253✔
845
                // slice depending on the number of actual bytes written.
1,253✔
846
                n, err := w.Write(b.nextBodySend)
1,253✔
847
                b.nextBodySend = b.nextBodySend[n:]
1,253✔
848

1,253✔
849
                // If we partially or fully wrote any of the body's MAC, we'll
1,253✔
850
                // subtract that contribution from the total amount flushed to
1,253✔
851
                // preserve the abstraction of returning the number of plaintext
1,253✔
852
                // bytes written by the connection.
1,253✔
853
                //
1,253✔
854
                // There are three possible scenarios we must handle to ensure
1,253✔
855
                // the returned value is correct. In the first case, the write
1,253✔
856
                // straddles both payload and MAC bytes, and we must subtract
1,253✔
857
                // the number of MAC bytes written from n. In the second, only
1,253✔
858
                // payload bytes are written, thus we can return n unmodified.
1,253✔
859
                // The final scenario pertains to the case where only MAC bytes
1,253✔
860
                // are written, none of which count towards the total.
1,253✔
861
                //
1,253✔
862
                //                 |-----------Payload------------|----MAC----|
1,253✔
863
                // Straddle:       S---------------------------------E--------0
1,253✔
864
                // Payload-only:   S------------------------E-----------------0
1,253✔
865
                // MAC-only:                                        S-------E-0
1,253✔
866
                start, end := n+len(b.nextBodySend), len(b.nextBodySend)
1,253✔
867
                switch {
1,253✔
868

869
                // Straddles payload and MAC bytes, subtract number of MAC bytes
870
                // written from the actual number written.
871
                case start > macSize && end <= macSize:
1,199✔
872
                        nn = n - (macSize - end)
1,199✔
873

874
                // Only payload bytes are written, return n directly.
875
                case start > macSize && end > macSize:
5✔
876
                        nn = n
5✔
877

878
                // Only MAC bytes are written, return 0 bytes written.
879
                default:
52✔
880
                }
881

882
                if err != nil {
1,264✔
883
                        return nn, err
11✔
884
                }
11✔
885
        }
886

887
        // If both header and body have been fully flushed, release the pooled
888
        // buffers back to their pools.
889
        if len(b.nextHeaderSend) == 0 && len(b.nextBodySend) == 0 {
2,502✔
890
                b.releaseBuffers()
1,251✔
891
        }
1,251✔
892

893
        return nn, nil
1,251✔
894
}
895

896
// releaseBuffers returns the pooled buffers back to their respective pools
897
// and clears the references.
898
func (b *Machine) releaseBuffers() {
1,251✔
899
        if b.pooledHeaderBuf != nil {
2,496✔
900
                *b.pooledHeaderBuf = (*b.pooledHeaderBuf)[:0]
1,245✔
901
                headerBufferPool.Put(b.pooledHeaderBuf)
1,245✔
902
                b.pooledHeaderBuf = nil
1,245✔
903
        }
1,245✔
904

905
        if b.pooledBodyBuf != nil {
2,496✔
906
                *b.pooledBodyBuf = (*b.pooledBodyBuf)[:0]
1,245✔
907
                bodyBufferPool.Put(b.pooledBodyBuf)
1,245✔
908
                b.pooledBodyBuf = nil
1,245✔
909
        }
1,245✔
910

911
        b.nextHeaderSend = nil
1,251✔
912
        b.nextBodySend = nil
1,251✔
913
}
914

915
// ReadMessage attempts to read the next message from the passed io.Reader. In
916
// the case of an authentication error, a non-nil error is returned.
917
func (b *Machine) ReadMessage(r io.Reader) ([]byte, error) {
1,196✔
918
        pktLen, err := b.ReadHeader(r)
1,196✔
919
        if err != nil {
1,271✔
920
                return nil, err
75✔
921
        }
75✔
922

923
        buf := make([]byte, pktLen)
1,121✔
924
        return b.ReadBody(r, buf)
1,121✔
925
}
926

927
// ReadHeader attempts to read the next message header from the passed
928
// io.Reader. The header contains the length of the next body including
929
// additional overhead of the MAC. In the case of an authentication error, a
930
// non-nil error is returned.
931
//
932
// NOTE: This method SHOULD NOT be used in the case that the io.Reader may be
933
// adversarial and induce long delays. If the caller needs to set read deadlines
934
// appropriately, it is preferred that they use the split ReadHeader and
935
// ReadBody methods so that the deadlines can be set appropriately on each.
936
func (b *Machine) ReadHeader(r io.Reader) (uint32, error) {
1,196✔
937
        _, err := io.ReadFull(r, b.nextCipherHeader[:])
1,196✔
938
        if err != nil {
1,270✔
939
                return 0, err
74✔
940
        }
74✔
941

942
        // Attempt to decrypt+auth the packet length present in the stream.
943
        //
944
        // By passing in `nextCipherHeader` as the destination, we avoid making
945
        // the library allocate a new buffer to decode the plaintext.
946
        pktLenBytes, err := b.recvCipher.Decrypt(
1,125✔
947
                nil, b.nextCipherHeader[:0], b.nextCipherHeader[:],
1,125✔
948
        )
1,125✔
949
        if err != nil {
1,129✔
950
                return 0, err
4✔
951
        }
4✔
952

953
        // Compute the packet length that we will need to read off the wire.
954
        pktLen := uint32(binary.BigEndian.Uint16(pktLenBytes)) + macSize
1,121✔
955

1,121✔
956
        return pktLen, nil
1,121✔
957
}
958

959
// ReadBody attempts to ready the next message body from the passed io.Reader.
960
// The provided buffer MUST be the length indicated by the packet length
961
// returned by the preceding call to ReadHeader. In the case of an
962
// authentication error, a non-nil error is returned.
963
func (b *Machine) ReadBody(r io.Reader, buf []byte) ([]byte, error) {
1,121✔
964
        // Next, using the length read from the packet header, read the
1,121✔
965
        // encrypted packet itself into the buffer allocated by the read
1,121✔
966
        // pool.
1,121✔
967
        _, err := io.ReadFull(r, buf)
1,121✔
968
        if err != nil {
1,121✔
969
                return nil, err
×
970
        }
×
971

972
        // Finally, decrypt the message held in the buffer, and return a new
973
        // byte slice containing the plaintext.
974
        //
975
        // By passing in the buf (the ciphertext) as the first argument, we end
976
        // up re-using it as we don't force the library to allocate a new
977
        // buffer to decode the plaintext.
978
        return b.recvCipher.Decrypt(nil, buf[:0], buf)
1,121✔
979
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc