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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

94.88
/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
        "time"
12

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

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

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

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

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

38
        // keyRotationInterval is the number of messages sent on a single
39
        // cipher stream before the keys are rotated forwards.
40
        keyRotationInterval = 1000
41

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

49
var (
50
        // ErrMaxMessageLengthExceeded is returned when a message to be written to
51
        // the cipher session exceeds the maximum allowed message payload.
52
        ErrMaxMessageLengthExceeded = errors.New("the generated payload exceeds " +
53
                "the max allowed message length of (2^16)-1")
54

55
        // ErrMessageNotFlushed signals that the connection cannot accept a new
56
        // message because the prior message has not been fully flushed.
57
        ErrMessageNotFlushed = errors.New("prior message not flushed")
58

59
        // lightningPrologue is the noise prologue that is used to initialize
60
        // the brontide noise handshake.
61
        lightningPrologue = []byte("lightning")
62

63
        // ephemeralGen is the default ephemeral key generator, used to derive a
64
        // unique ephemeral key for each brontide handshake.
65
        ephemeralGen = func() (*btcec.PrivateKey, error) {
6✔
66
                return btcec.NewPrivateKey()
6✔
67
        }
6✔
68
)
69

70
// TODO(roasbeef): free buffer pool?
71

72
// ecdh performs an ECDH operation between pub and priv. The returned value is
73
// the sha256 of the compressed shared point.
74
func ecdh(pub *btcec.PublicKey, priv keychain.SingleKeyECDH) ([]byte, error) {
1,977✔
75
        hash, err := priv.ECDH(pub)
1,977✔
76
        return hash[:], err
1,977✔
77
}
1,977✔
78

79
// cipherState encapsulates the state for the AEAD which will be used to
80
// encrypt+authenticate any payloads sent during the handshake, and messages
81
// sent once the handshake has completed.
82
type cipherState struct {
83
        // nonce is the nonce passed into the chacha20-poly1305 instance for
84
        // encryption+decryption. The nonce is incremented after each successful
85
        // encryption/decryption.
86
        //
87
        // TODO(roasbeef): this should actually be 96 bit
88
        nonce uint64
89

90
        // secretKey is the shared symmetric key which will be used to
91
        // instantiate the cipher.
92
        //
93
        // TODO(roasbeef): m-lock??
94
        secretKey [32]byte
95

96
        // salt is an additional secret which is used during key rotation to
97
        // generate new keys.
98
        salt [32]byte
99

100
        // cipher is an instance of the ChaCha20-Poly1305 AEAD construction
101
        // created using the secretKey above.
102
        cipher cipher.AEAD
103
}
104

105
// Encrypt returns a ciphertext which is the encryption of the plainText
106
// observing the passed associatedData within the AEAD construction.
107
func (c *cipherState) Encrypt(associatedData, cipherText, plainText []byte) []byte {
3,787✔
108
        defer func() {
7,574✔
109
                c.nonce++
3,787✔
110

3,787✔
111
                if c.nonce == keyRotationInterval {
3,789✔
112
                        c.rotateKey()
2✔
113
                }
2✔
114
        }()
115

116
        var nonce [12]byte
3,787✔
117
        binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
3,787✔
118

3,787✔
119
        return c.cipher.Seal(cipherText, nonce[:], plainText, associatedData)
3,787✔
120
}
121

122
// Decrypt attempts to decrypt the passed ciphertext observing the specified
123
// associatedData within the AEAD construction. In the case that the final MAC
124
// check fails, then a non-nil error will be returned.
125
func (c *cipherState) Decrypt(associatedData, plainText, cipherText []byte) ([]byte, error) {
3,504✔
126
        defer func() {
7,008✔
127
                c.nonce++
3,504✔
128

3,504✔
129
                if c.nonce == keyRotationInterval {
3,506✔
130
                        c.rotateKey()
2✔
131
                }
2✔
132
        }()
133

134
        var nonce [12]byte
3,504✔
135
        binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
3,504✔
136

3,504✔
137
        return c.cipher.Open(plainText, nonce[:], cipherText, associatedData)
3,504✔
138
}
139

140
// InitializeKey initializes the secret key and AEAD cipher scheme based off of
141
// the passed key.
142
func (c *cipherState) InitializeKey(key [32]byte) {
4,036✔
143
        c.secretKey = key
4,036✔
144
        c.nonce = 0
4,036✔
145

4,036✔
146
        // Safe to ignore the error here as our key is properly sized
4,036✔
147
        // (32-bytes).
4,036✔
148
        c.cipher, _ = chacha20poly1305.New(c.secretKey[:])
4,036✔
149
}
4,036✔
150

151
// InitializeKeyWithSalt is identical to InitializeKey however it also sets the
152
// cipherState's salt field which is used for key rotation.
153
func (c *cipherState) InitializeKeyWithSalt(salt, key [32]byte) {
1,182✔
154
        c.salt = salt
1,182✔
155
        c.InitializeKey(key)
1,182✔
156
}
1,182✔
157

158
// rotateKey rotates the current encryption/decryption key for this cipherState
159
// instance. Key rotation is performed by ratcheting the current key forward
160
// using an HKDF invocation with the cipherState's salt as the salt, and the
161
// current key as the input.
162
func (c *cipherState) rotateKey() {
4✔
163
        var (
4✔
164
                info    []byte
4✔
165
                nextKey [32]byte
4✔
166
        )
4✔
167

4✔
168
        oldKey := c.secretKey
4✔
169
        h := hkdf.New(sha256.New, oldKey[:], c.salt[:], info)
4✔
170

4✔
171
        // hkdf(ck, k, zero)
4✔
172
        // |
4✔
173
        // | \
4✔
174
        // |  \
4✔
175
        // ck  k'
4✔
176
        h.Read(c.salt[:])
4✔
177
        h.Read(nextKey[:])
4✔
178

4✔
179
        c.InitializeKey(nextKey)
4✔
180
}
4✔
181

182
// symmetricState encapsulates a cipherState object and houses the ephemeral
183
// handshake digest state. This struct is used during the handshake to derive
184
// new shared secrets based off of the result of ECDH operations. Ultimately,
185
// the final key yielded by this struct is the result of an incremental
186
// Triple-DH operation.
187
type symmetricState struct {
188
        cipherState
189

190
        // chainingKey is used as the salt to the HKDF function to derive a new
191
        // chaining key as well as a new tempKey which is used for
192
        // encryption/decryption.
193
        chainingKey [32]byte
194

195
        // tempKey is the latter 32 bytes resulted from the latest HKDF
196
        // iteration. This key is used to encrypt/decrypt any handshake
197
        // messages or payloads sent until the next DH operation is executed.
198
        tempKey [32]byte
199

200
        // handshakeDigest is the cumulative hash digest of all handshake
201
        // messages sent from start to finish. This value is never transmitted
202
        // to the other side, but will be used as the AD when
203
        // encrypting/decrypting messages using our AEAD construction.
204
        handshakeDigest [32]byte
205
}
206

207
// mixKey implements a basic HKDF-based key ratchet. This method is called
208
// with the result of each DH output generated during the handshake process.
209
// The first 32 bytes extract from the HKDF reader is the next chaining key,
210
// then latter 32 bytes become the temp secret key using within any future AEAD
211
// operations until another DH operation is performed.
212
func (s *symmetricState) mixKey(input []byte) {
1,977✔
213
        var info []byte
1,977✔
214

1,977✔
215
        secret := input
1,977✔
216
        salt := s.chainingKey
1,977✔
217
        h := hkdf.New(sha256.New, secret, salt[:], info)
1,977✔
218

1,977✔
219
        // hkdf(ck, input, zero)
1,977✔
220
        // |
1,977✔
221
        // | \
1,977✔
222
        // |  \
1,977✔
223
        // ck  k
1,977✔
224
        h.Read(s.chainingKey[:])
1,977✔
225
        h.Read(s.tempKey[:])
1,977✔
226

1,977✔
227
        // cipher.k = temp_key
1,977✔
228
        s.InitializeKey(s.tempKey)
1,977✔
229
}
1,977✔
230

231
// mixHash hashes the passed input data into the cumulative handshake digest.
232
// The running result of this value (h) is used as the associated data in all
233
// decryption/encryption operations.
234
func (s *symmetricState) mixHash(data []byte) {
5,645✔
235
        h := sha256.New()
5,645✔
236
        h.Write(s.handshakeDigest[:])
5,645✔
237
        h.Write(data)
5,645✔
238

5,645✔
239
        copy(s.handshakeDigest[:], h.Sum(nil))
5,645✔
240
}
5,645✔
241

242
// EncryptAndHash returns the authenticated encryption of the passed plaintext.
243
// When encrypting the handshake digest (h) is used as the associated data to
244
// the AEAD cipher.
245
func (s *symmetricState) EncryptAndHash(plaintext []byte) []byte {
1,301✔
246
        ciphertext := s.Encrypt(s.handshakeDigest[:], nil, plaintext)
1,301✔
247

1,301✔
248
        s.mixHash(ciphertext)
1,301✔
249

1,301✔
250
        return ciphertext
1,301✔
251
}
1,301✔
252

253
// DecryptAndHash returns the authenticated decryption of the passed
254
// ciphertext. When encrypting the handshake digest (h) is used as the
255
// associated data to the AEAD cipher.
256
func (s *symmetricState) DecryptAndHash(ciphertext []byte) ([]byte, error) {
1,264✔
257
        plaintext, err := s.Decrypt(s.handshakeDigest[:], nil, ciphertext)
1,264✔
258
        if err != nil {
1,321✔
259
                return nil, err
57✔
260
        }
57✔
261

262
        s.mixHash(ciphertext)
1,207✔
263

1,207✔
264
        return plaintext, nil
1,207✔
265
}
266

267
// InitializeSymmetric initializes the symmetric state by setting the handshake
268
// digest (h) and the chaining key (ck) to protocol name.
269
func (s *symmetricState) InitializeSymmetric(protocolName []byte) {
873✔
270
        var empty [32]byte
873✔
271

873✔
272
        s.handshakeDigest = sha256.Sum256(protocolName)
873✔
273
        s.chainingKey = s.handshakeDigest
873✔
274
        s.InitializeKey(empty)
873✔
275
}
873✔
276

277
// handshakeState encapsulates the symmetricState and keeps track of all the
278
// public keys (static and ephemeral) for both sides during the handshake
279
// transcript. If the handshake completes successfully, then two instances of a
280
// cipherState are emitted: one to encrypt messages from initiator to
281
// responder, and the other for the opposite direction.
282
type handshakeState struct {
283
        symmetricState
284

285
        initiator bool
286

287
        localStatic    keychain.SingleKeyECDH
288
        localEphemeral keychain.SingleKeyECDH // nolint (false positive)
289

290
        remoteStatic    *btcec.PublicKey
291
        remoteEphemeral *btcec.PublicKey
292
}
293

294
// newHandshakeState returns a new instance of the handshake state initialized
295
// with the prologue and protocol name. If this is the responder's handshake
296
// state, then the remotePub can be nil.
297
func newHandshakeState(initiator bool, prologue []byte,
298
        localKey keychain.SingleKeyECDH,
299
        remotePub *btcec.PublicKey) handshakeState {
873✔
300

873✔
301
        h := handshakeState{
873✔
302
                initiator:    initiator,
873✔
303
                localStatic:  localKey,
873✔
304
                remoteStatic: remotePub,
873✔
305
        }
873✔
306

873✔
307
        // Set the current chaining key and handshake digest to the hash of the
873✔
308
        // protocol name, and additionally mix in the prologue. If either sides
873✔
309
        // disagree about the prologue or protocol name, then the handshake
873✔
310
        // will fail.
873✔
311
        h.InitializeSymmetric([]byte(protocolName))
873✔
312
        h.mixHash(prologue)
873✔
313

873✔
314
        // In Noise_XK, the initiator should know the responder's static
873✔
315
        // public key, therefore we include the responder's static key in the
873✔
316
        // handshake digest. If the initiator gets this value wrong, then the
873✔
317
        // handshake will fail.
873✔
318
        if initiator {
1,307✔
319
                h.mixHash(remotePub.SerializeCompressed())
434✔
320
        } else {
873✔
321
                h.mixHash(localKey.PubKey().SerializeCompressed())
439✔
322
        }
439✔
323

324
        return h
873✔
325
}
326

327
// EphemeralGenerator is a functional option that allows callers to substitute
328
// a custom function for use when generating ephemeral keys for ActOne or
329
// ActTwo. The function closure returned by this function can be passed into
330
// NewBrontideMachine as a function option parameter.
331
func EphemeralGenerator(gen func() (*btcec.PrivateKey, error)) func(*Machine) {
396✔
332
        return func(m *Machine) {
1,258✔
333
                m.ephemeralGen = gen
862✔
334
        }
862✔
335
}
336

337
// Machine is a state-machine which implements Brontide: an
338
// Authenticated-key Exchange in Three Acts. Brontide is derived from the Noise
339
// framework, specifically implementing the Noise_XK handshake. Once the
340
// initial 3-act handshake has completed all messages are encrypted with a
341
// chacha20 AEAD cipher. On the wire, all messages are prefixed with an
342
// authenticated+encrypted length field. Additionally, the encrypted+auth'd
343
// length prefix is used as the AD when encrypting+decryption messages. This
344
// construction provides confidentiality of packet length, avoids introducing
345
// a padding-oracle, and binds the encrypted packet length to the packet
346
// itself.
347
//
348
// The acts proceeds the following order (initiator on the left):
349
//
350
//        GenActOne()   ->
351
//                          RecvActOne()
352
//                      <-  GenActTwo()
353
//        RecvActTwo()
354
//        GenActThree() ->
355
//                          RecvActThree()
356
//
357
// This exchange corresponds to the following Noise handshake:
358
//
359
//        <- s
360
//        ...
361
//        -> e, es
362
//        <- e, ee
363
//        -> s, se
364
type Machine struct {
365
        sendCipher cipherState
366
        recvCipher cipherState
367

368
        ephemeralGen func() (*btcec.PrivateKey, error)
369

370
        handshakeState
371

372
        // nextCipherHeader is a static buffer that we'll use to read in the
373
        // next ciphertext header from the wire. The header is a 2 byte length
374
        // (of the next ciphertext), followed by a 16 byte MAC.
375
        nextCipherHeader [encHeaderSize]byte
376

377
        // nextHeaderSend holds a reference to the remaining header bytes to
378
        // write out for a pending message. This allows us to tolerate timeout
379
        // errors that cause partial writes.
380
        nextHeaderSend []byte
381

382
        // nextBodySend holds a reference to the remaining body bytes to write
383
        // out for a pending message. This allows us to tolerate timeout errors
384
        // that cause partial writes.
385
        nextBodySend []byte
386
}
387

388
// NewBrontideMachine creates a new instance of the brontide state-machine. If
389
// the responder (listener) is creating the object, then the remotePub should
390
// be nil. The handshake state within brontide is initialized using the ascii
391
// string "lightning" as the prologue. The last parameter is a set of variadic
392
// arguments for adding additional options to the brontide Machine
393
// initialization.
394
func NewBrontideMachine(initiator bool, localKey keychain.SingleKeyECDH,
395
        remotePub *btcec.PublicKey, options ...func(*Machine)) *Machine {
873✔
396

873✔
397
        handshake := newHandshakeState(
873✔
398
                initiator, lightningPrologue, localKey, remotePub,
873✔
399
        )
873✔
400

873✔
401
        m := &Machine{
873✔
402
                handshakeState: handshake,
873✔
403
                ephemeralGen:   ephemeralGen,
873✔
404
        }
873✔
405

873✔
406
        // With the default options established, we'll now process all the
873✔
407
        // options passed in as parameters.
873✔
408
        for _, option := range options {
1,735✔
409
                option(m)
862✔
410
        }
862✔
411

412
        return m
873✔
413
}
414

415
const (
416
        // HandshakeVersion is the expected version of the brontide handshake.
417
        // Any messages that carry a different version will cause the handshake
418
        // to abort immediately.
419
        HandshakeVersion = byte(0)
420

421
        // ActOneSize is the size of the packet sent from initiator to
422
        // responder in ActOne. The packet consists of a handshake version, an
423
        // ephemeral key in compressed format, and a 16-byte poly1305 tag.
424
        //
425
        // 1 + 33 + 16
426
        ActOneSize = 50
427

428
        // ActTwoSize is the size the packet sent from responder to initiator
429
        // in ActTwo. The packet consists of a handshake version, an ephemeral
430
        // key in compressed format and a 16-byte poly1305 tag.
431
        //
432
        // 1 + 33 + 16
433
        ActTwoSize = 50
434

435
        // ActThreeSize is the size of the packet sent from initiator to
436
        // responder in ActThree. The packet consists of a handshake version,
437
        // the initiators static key encrypted with strong forward secrecy and
438
        // a 16-byte poly1035 tag.
439
        //
440
        // 1 + 33 + 16 + 16
441
        ActThreeSize = 66
442
)
443

444
// GenActOne generates the initial packet (act one) to be sent from initiator
445
// to responder. During act one the initiator generates a fresh ephemeral key,
446
// hashes it into the handshake digest, and performs an ECDH between this key
447
// and the responder's static key. Future payloads are encrypted with a key
448
// derived from this result.
449
//
450
//        -> e, es
451
func (b *Machine) GenActOne() ([ActOneSize]byte, error) {
387✔
452
        var actOne [ActOneSize]byte
387✔
453

387✔
454
        // e
387✔
455
        localEphemeral, err := b.ephemeralGen()
387✔
456
        if err != nil {
387✔
457
                return actOne, err
×
458
        }
×
459
        b.localEphemeral = &keychain.PrivKeyECDH{
387✔
460
                PrivKey: localEphemeral,
387✔
461
        }
387✔
462

387✔
463
        ephemeral := localEphemeral.PubKey().SerializeCompressed()
387✔
464
        b.mixHash(ephemeral)
387✔
465

387✔
466
        // es
387✔
467
        s, err := ecdh(b.remoteStatic, b.localEphemeral)
387✔
468
        if err != nil {
387✔
469
                return actOne, err
×
470
        }
×
471
        b.mixKey(s[:])
387✔
472

387✔
473
        authPayload := b.EncryptAndHash([]byte{})
387✔
474

387✔
475
        actOne[0] = HandshakeVersion
387✔
476
        copy(actOne[1:34], ephemeral)
387✔
477
        copy(actOne[34:], authPayload)
387✔
478

387✔
479
        return actOne, nil
387✔
480
}
481

482
// RecvActOne processes the act one packet sent by the initiator. The responder
483
// executes the mirrored actions to that of the initiator extending the
484
// handshake digest and deriving a new shared secret based on an ECDH with the
485
// initiator's ephemeral key and responder's static key.
486
func (b *Machine) RecvActOne(actOne [ActOneSize]byte) error {
375✔
487
        var (
375✔
488
                err error
375✔
489
                e   [33]byte
375✔
490
                p   [16]byte
375✔
491
        )
375✔
492

375✔
493
        // If the handshake version is unknown, then the handshake fails
375✔
494
        // immediately.
375✔
495
        if actOne[0] != HandshakeVersion {
385✔
496
                return fmt.Errorf("act one: invalid handshake version: %v, "+
10✔
497
                        "only %v is valid, msg=%x", actOne[0], HandshakeVersion,
10✔
498
                        actOne[:])
10✔
499
        }
10✔
500

501
        copy(e[:], actOne[1:34])
365✔
502
        copy(p[:], actOne[34:])
365✔
503

365✔
504
        // e
365✔
505
        b.remoteEphemeral, err = btcec.ParsePubKey(e[:])
365✔
506
        if err != nil {
371✔
507
                return err
6✔
508
        }
6✔
509
        b.mixHash(b.remoteEphemeral.SerializeCompressed())
359✔
510

359✔
511
        // es
359✔
512
        s, err := ecdh(b.remoteEphemeral, b.localStatic)
359✔
513
        if err != nil {
359✔
514
                return err
×
515
        }
×
516
        b.mixKey(s)
359✔
517

359✔
518
        // If the initiator doesn't know our static key, then this operation
359✔
519
        // will fail.
359✔
520
        _, err = b.DecryptAndHash(p[:])
359✔
521
        return err
359✔
522
}
523

524
// GenActTwo generates the second packet (act two) to be sent from the
525
// responder to the initiator. The packet for act two is identical to that of
526
// act one, but then results in a different ECDH operation between the
527
// initiator's and responder's ephemeral keys.
528
//
529
//        <- e, ee
530
func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) {
328✔
531
        var actTwo [ActTwoSize]byte
328✔
532

328✔
533
        // e
328✔
534
        localEphemeral, err := b.ephemeralGen()
328✔
535
        if err != nil {
328✔
536
                return actTwo, err
×
537
        }
×
538
        b.localEphemeral = &keychain.PrivKeyECDH{
328✔
539
                PrivKey: localEphemeral,
328✔
540
        }
328✔
541

328✔
542
        ephemeral := localEphemeral.PubKey().SerializeCompressed()
328✔
543
        b.mixHash(localEphemeral.PubKey().SerializeCompressed())
328✔
544

328✔
545
        // ee
328✔
546
        s, err := ecdh(b.remoteEphemeral, b.localEphemeral)
328✔
547
        if err != nil {
328✔
548
                return actTwo, err
×
549
        }
×
550
        b.mixKey(s)
328✔
551

328✔
552
        authPayload := b.EncryptAndHash([]byte{})
328✔
553

328✔
554
        actTwo[0] = HandshakeVersion
328✔
555
        copy(actTwo[1:34], ephemeral)
328✔
556
        copy(actTwo[34:], authPayload)
328✔
557

328✔
558
        return actTwo, nil
328✔
559
}
560

561
// RecvActTwo processes the second packet (act two) sent from the responder to
562
// the initiator. A successful processing of this packet authenticates the
563
// initiator to the responder.
564
func (b *Machine) RecvActTwo(actTwo [ActTwoSize]byte) error {
352✔
565
        var (
352✔
566
                err error
352✔
567
                e   [33]byte
352✔
568
                p   [16]byte
352✔
569
        )
352✔
570

352✔
571
        // If the handshake version is unknown, then the handshake fails
352✔
572
        // immediately.
352✔
573
        if actTwo[0] != HandshakeVersion {
382✔
574
                return fmt.Errorf("act two: invalid handshake version: %v, "+
30✔
575
                        "only %v is valid, msg=%x", actTwo[0], HandshakeVersion,
30✔
576
                        actTwo[:])
30✔
577
        }
30✔
578

579
        copy(e[:], actTwo[1:34])
322✔
580
        copy(p[:], actTwo[34:])
322✔
581

322✔
582
        // e
322✔
583
        b.remoteEphemeral, err = btcec.ParsePubKey(e[:])
322✔
584
        if err != nil {
327✔
585
                return err
5✔
586
        }
5✔
587
        b.mixHash(b.remoteEphemeral.SerializeCompressed())
317✔
588

317✔
589
        // ee
317✔
590
        s, err := ecdh(b.remoteEphemeral, b.localEphemeral)
317✔
591
        if err != nil {
317✔
592
                return err
×
593
        }
×
594
        b.mixKey(s)
317✔
595

317✔
596
        _, err = b.DecryptAndHash(p[:])
317✔
597
        return err
317✔
598
}
599

600
// GenActThree creates the final (act three) packet of the handshake. Act three
601
// is to be sent from the initiator to the responder. The purpose of act three
602
// is to transmit the initiator's public key under strong forward secrecy to
603
// the responder. This act also includes the final ECDH operation which yields
604
// the final session.
605
//
606
//        -> s, se
607
func (b *Machine) GenActThree() ([ActThreeSize]byte, error) {
293✔
608
        var actThree [ActThreeSize]byte
293✔
609

293✔
610
        ourPubkey := b.localStatic.PubKey().SerializeCompressed()
293✔
611
        ciphertext := b.EncryptAndHash(ourPubkey)
293✔
612

293✔
613
        s, err := ecdh(b.remoteEphemeral, b.localStatic)
293✔
614
        if err != nil {
293✔
UNCOV
615
                return actThree, err
×
UNCOV
616
        }
×
617
        b.mixKey(s)
293✔
618

293✔
619
        authPayload := b.EncryptAndHash([]byte{})
293✔
620

293✔
621
        actThree[0] = HandshakeVersion
293✔
622
        copy(actThree[1:50], ciphertext)
293✔
623
        copy(actThree[50:], authPayload)
293✔
624

293✔
625
        // With the final ECDH operation complete, derive the session sending
293✔
626
        // and receiving keys.
293✔
627
        b.split()
293✔
628

293✔
629
        return actThree, nil
293✔
630
}
631

632
// RecvActThree processes the final act (act three) sent from the initiator to
633
// the responder. After processing this act, the responder learns of the
634
// initiator's static public key. Decryption of the static key serves to
635
// authenticate the initiator to the responder.
636
func (b *Machine) RecvActThree(actThree [ActThreeSize]byte) error {
328✔
637
        var (
328✔
638
                err error
328✔
639
                s   [33 + 16]byte
328✔
640
                p   [16]byte
328✔
641
        )
328✔
642

328✔
643
        // If the handshake version is unknown, then the handshake fails
328✔
644
        // immediately.
328✔
645
        if actThree[0] != HandshakeVersion {
361✔
646
                return fmt.Errorf("act three: invalid handshake version: %v, "+
33✔
647
                        "only %v is valid, msg=%x", actThree[0], HandshakeVersion,
33✔
648
                        actThree[:])
33✔
649
        }
33✔
650

651
        copy(s[:], actThree[1:33+16+1])
295✔
652
        copy(p[:], actThree[33+16+1:])
295✔
653

295✔
654
        // s
295✔
655
        remotePub, err := b.DecryptAndHash(s[:])
295✔
656
        if err != nil {
297✔
657
                return err
2✔
658
        }
2✔
659
        b.remoteStatic, err = btcec.ParsePubKey(remotePub)
293✔
660
        if err != nil {
293✔
661
                return err
×
662
        }
×
663

664
        // se
665
        se, err := ecdh(b.remoteStatic, b.localEphemeral)
293✔
666
        if err != nil {
293✔
667
                return err
×
668
        }
×
669
        b.mixKey(se)
293✔
670

293✔
671
        if _, err := b.DecryptAndHash(p[:]); err != nil {
293✔
672
                return err
×
673
        }
×
674

675
        // With the final ECDH operation complete, derive the session sending
676
        // and receiving keys.
677
        b.split()
293✔
678

293✔
679
        return nil
293✔
680
}
681

682
// split is the final wrap-up act to be executed at the end of a successful
683
// three act handshake. This function creates two internal cipherState
684
// instances: one which is used to encrypt messages from the initiator to the
685
// responder, and another which is used to encrypt message for the opposite
686
// direction.
687
func (b *Machine) split() {
591✔
688
        var (
591✔
689
                empty   []byte
591✔
690
                sendKey [32]byte
591✔
691
                recvKey [32]byte
591✔
692
        )
591✔
693

591✔
694
        h := hkdf.New(sha256.New, empty, b.chainingKey[:], empty)
591✔
695

591✔
696
        // If we're the initiator the first 32 bytes are used to encrypt our
591✔
697
        // messages and the second 32-bytes to decrypt their messages. For the
591✔
698
        // responder the opposite is true.
591✔
699
        if b.initiator {
884✔
700
                h.Read(sendKey[:])
293✔
701
                b.sendCipher = cipherState{}
293✔
702
                b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
293✔
703

293✔
704
                h.Read(recvKey[:])
293✔
705
                b.recvCipher = cipherState{}
293✔
706
                b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
293✔
707
        } else {
591✔
708
                h.Read(recvKey[:])
298✔
709
                b.recvCipher = cipherState{}
298✔
710
                b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
298✔
711

298✔
712
                h.Read(sendKey[:])
298✔
713
                b.sendCipher = cipherState{}
298✔
714
                b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
298✔
715
        }
298✔
716
}
717

718
// WriteMessage encrypts and buffers the next message p. The ciphertext of the
719
// message is prepended with an encrypt+auth'd length which must be used as the
720
// AD to the AEAD construction when being decrypted by the other side.
721
//
722
// NOTE: This DOES NOT write the message to the wire, it should be followed by a
723
// call to Flush to ensure the message is written.
724
func (b *Machine) WriteMessage(p []byte) error {
1,245✔
725
        // The total length of each message payload including the MAC size
1,245✔
726
        // payload exceed the largest number encodable within a 16-bit unsigned
1,245✔
727
        // integer.
1,245✔
728
        if len(p) > math.MaxUint16 {
1,247✔
729
                return ErrMaxMessageLengthExceeded
2✔
730
        }
2✔
731

732
        // If a prior message was written but it hasn't been fully flushed,
733
        // return an error as we only support buffering of one message at a
734
        // time.
735
        if len(b.nextHeaderSend) > 0 || len(b.nextBodySend) > 0 {
1,243✔
736
                return ErrMessageNotFlushed
×
737
        }
×
738

739
        // The full length of the packet is only the packet length, and does
740
        // NOT include the MAC.
741
        fullLength := uint16(len(p))
1,243✔
742

1,243✔
743
        var pktLen [2]byte
1,243✔
744
        binary.BigEndian.PutUint16(pktLen[:], fullLength)
1,243✔
745

1,243✔
746
        // First, generate the encrypted+MAC'd length prefix for the packet.
1,243✔
747
        b.nextHeaderSend = b.sendCipher.Encrypt(nil, nil, pktLen[:])
1,243✔
748

1,243✔
749
        // Finally, generate the encrypted packet itself.
1,243✔
750
        b.nextBodySend = b.sendCipher.Encrypt(nil, nil, p)
1,243✔
751

1,243✔
752
        return nil
1,243✔
753
}
754

755
// Flush attempts to write a message buffered using WriteMessage to the provided
756
// io.Writer. If no buffered message exists, this will result in a NOP.
757
// Otherwise, it will continue to write the remaining bytes, picking up where
758
// the byte stream left off in the event of a partial write. The number of bytes
759
// returned reflects the number of plaintext bytes in the payload, and does not
760
// account for the overhead of the header or MACs.
761
//
762
// NOTE: It is safe to call this method again iff a timeout error is returned.
763
func (b *Machine) Flush(w io.Writer) (int, error) {
1,260✔
764
        // First, write out the pending header bytes, if any exist. Any header
1,260✔
765
        // bytes written will not count towards the total amount flushed.
1,260✔
766
        if len(b.nextHeaderSend) > 0 {
2,504✔
767
                // Write any remaining header bytes and shift the slice to point
1,244✔
768
                // to the next segment of unwritten bytes. If an error is
1,244✔
769
                // encountered, we can continue to write the header from where
1,244✔
770
                // we left off on a subsequent call to Flush.
1,244✔
771
                n, err := w.Write(b.nextHeaderSend)
1,244✔
772
                b.nextHeaderSend = b.nextHeaderSend[n:]
1,244✔
773
                if err != nil {
1,248✔
774
                        return 0, err
4✔
775
                }
4✔
776
        }
777

778
        // Next, write the pending body bytes, if any exist. Only the number of
779
        // bytes written that correspond to the ciphertext will be included in
780
        // the total bytes written, bytes written as part of the MAC will not be
781
        // counted.
782
        var nn int
1,256✔
783
        if len(b.nextBodySend) > 0 {
2,506✔
784
                // Write out all bytes excluding the mac and shift the body
1,250✔
785
                // slice depending on the number of actual bytes written.
1,250✔
786
                n, err := w.Write(b.nextBodySend)
1,250✔
787
                b.nextBodySend = b.nextBodySend[n:]
1,250✔
788

1,250✔
789
                // If we partially or fully wrote any of the body's MAC, we'll
1,250✔
790
                // subtract that contribution from the total amount flushed to
1,250✔
791
                // preserve the abstraction of returning the number of plaintext
1,250✔
792
                // bytes written by the connection.
1,250✔
793
                //
1,250✔
794
                // There are three possible scenarios we must handle to ensure
1,250✔
795
                // the returned value is correct. In the first case, the write
1,250✔
796
                // straddles both payload and MAC bytes, and we must subtract
1,250✔
797
                // the number of MAC bytes written from n. In the second, only
1,250✔
798
                // payload bytes are written, thus we can return n unmodified.
1,250✔
799
                // The final scenario pertains to the case where only MAC bytes
1,250✔
800
                // are written, none of which count towards the total.
1,250✔
801
                //
1,250✔
802
                //                 |-----------Payload------------|----MAC----|
1,250✔
803
                // Straddle:       S---------------------------------E--------0
1,250✔
804
                // Payload-only:   S------------------------E-----------------0
1,250✔
805
                // MAC-only:                                        S-------E-0
1,250✔
806
                start, end := n+len(b.nextBodySend), len(b.nextBodySend)
1,250✔
807
                switch {
1,250✔
808

809
                // Straddles payload and MAC bytes, subtract number of MAC bytes
810
                // written from the actual number written.
811
                case start > macSize && end <= macSize:
1,196✔
812
                        nn = n - (macSize - end)
1,196✔
813

814
                // Only payload bytes are written, return n directly.
815
                case start > macSize && end > macSize:
2✔
816
                        nn = n
2✔
817

818
                // Only MAC bytes are written, return 0 bytes written.
819
                default:
52✔
820
                }
821

822
                if err != nil {
1,258✔
823
                        return nn, err
8✔
824
                }
8✔
825
        }
826

827
        return nn, nil
1,248✔
828
}
829

830
// ReadMessage attempts to read the next message from the passed io.Reader. In
831
// the case of an authentication error, a non-nil error is returned.
832
func (b *Machine) ReadMessage(r io.Reader) ([]byte, error) {
1,193✔
833
        pktLen, err := b.ReadHeader(r)
1,193✔
834
        if err != nil {
1,268✔
835
                return nil, err
75✔
836
        }
75✔
837

838
        buf := make([]byte, pktLen)
1,118✔
839
        return b.ReadBody(r, buf)
1,118✔
840
}
841

842
// ReadHeader attempts to read the next message header from the passed
843
// io.Reader. The header contains the length of the next body including
844
// additional overhead of the MAC. In the case of an authentication error, a
845
// non-nil error is returned.
846
//
847
// NOTE: This method SHOULD NOT be used in the case that the io.Reader may be
848
// adversarial and induce long delays. If the caller needs to set read deadlines
849
// appropriately, it is preferred that they use the split ReadHeader and
850
// ReadBody methods so that the deadlines can be set appropriately on each.
851
func (b *Machine) ReadHeader(r io.Reader) (uint32, error) {
1,193✔
852
        _, err := io.ReadFull(r, b.nextCipherHeader[:])
1,193✔
853
        if err != nil {
1,264✔
854
                return 0, err
71✔
855
        }
71✔
856

857
        // Attempt to decrypt+auth the packet length present in the stream.
858
        //
859
        // By passing in `nextCipherHeader` as the destination, we avoid making
860
        // the library allocate a new buffer to decode the plaintext.
861
        pktLenBytes, err := b.recvCipher.Decrypt(
1,122✔
862
                nil, b.nextCipherHeader[:0], b.nextCipherHeader[:],
1,122✔
863
        )
1,122✔
864
        if err != nil {
1,126✔
865
                return 0, err
4✔
866
        }
4✔
867

868
        // Compute the packet length that we will need to read off the wire.
869
        pktLen := uint32(binary.BigEndian.Uint16(pktLenBytes)) + macSize
1,118✔
870

1,118✔
871
        return pktLen, nil
1,118✔
872
}
873

874
// ReadBody attempts to ready the next message body from the passed io.Reader.
875
// The provided buffer MUST be the length indicated by the packet length
876
// returned by the preceding call to ReadHeader. In the case of an
877
// authentication error, a non-nil error is returned.
878
func (b *Machine) ReadBody(r io.Reader, buf []byte) ([]byte, error) {
1,118✔
879
        // Next, using the length read from the packet header, read the
1,118✔
880
        // encrypted packet itself into the buffer allocated by the read
1,118✔
881
        // pool.
1,118✔
882
        _, err := io.ReadFull(r, buf)
1,118✔
883
        if err != nil {
1,118✔
884
                return nil, err
×
885
        }
×
886

887
        // Finally, decrypt the message held in the buffer, and return a new
888
        // byte slice containing the plaintext.
889
        //
890
        // By passing in the buf (the ciphertext) as the first argument, we end
891
        // up re-using it as we don't force the library to allocate a new
892
        // buffer to decode the plaintext.
893
        return b.recvCipher.Decrypt(nil, buf[:0], buf)
1,118✔
894
}
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