· 6 years ago · Jan 31, 2019, 10:50 AM
1package brontide
2
3import (
4 "crypto/cipher"
5 "crypto/sha256"
6 "encoding/binary"
7 "errors"
8 "fmt"
9 "io"
10 "math"
11 "os"
12 "path/filepath"
13 "time"
14
15 "golang.org/x/crypto/chacha20poly1305"
16 "golang.org/x/crypto/hkdf"
17
18 "github.com/btcsuite/btcd/btcec"
19)
20
21const (
22 // protocolName is the precise instantiation of the Noise protocol
23 // handshake at the center of Brontide. This value will be used as part
24 // of the prologue. If the initiator and responder aren't using the
25 // exact same string for this value, along with prologue of the Bitcoin
26 // network, then the initial handshake will fail.
27 protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"
28
29 // macSize is the length in bytes of the tags generated by poly1305.
30 macSize = 16
31
32 // lengthHeaderSize is the number of bytes used to prefix encode the
33 // length of a message payload.
34 lengthHeaderSize = 2
35
36 // keyRotationInterval is the number of messages sent on a single
37 // cipher stream before the keys are rotated forwards.
38 keyRotationInterval = 1000
39
40 // handshakeReadTimeout is a read timeout that will be enforced when
41 // waiting for data payloads during the various acts of Brontide. If
42 // the remote party fails to deliver the proper payload within this
43 // time frame, then we'll fail the connection.
44 handshakeReadTimeout = time.Second * 5
45)
46
47var (
48 // ErrMaxMessageLengthExceeded is returned a message to be written to
49 // the cipher session exceeds the maximum allowed message payload.
50 ErrMaxMessageLengthExceeded = errors.New("the generated payload exceeds " +
51 "the max allowed message length of (2^16)-1")
52)
53
54// TODO(roasbeef): free buffer pool?
55
56// ecdh performs an ECDH operation between pub and priv. The returned value is
57// the sha256 of the compressed shared point.
58func ecdh(pub *btcec.PublicKey, priv *btcec.PrivateKey) []byte {
59 s := &btcec.PublicKey{}
60 x, y := btcec.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
61 s.X = x
62 s.Y = y
63
64 h := sha256.Sum256(s.SerializeCompressed())
65 return h[:]
66}
67
68// cipherState encapsulates the state for the AEAD which will be used to
69// encrypt+authenticate any payloads sent during the handshake, and messages
70// sent once the handshake has completed.
71type cipherState struct {
72 // nonce is the nonce passed into the chacha20-poly1305 instance for
73 // encryption+decryption. The nonce is incremented after each successful
74 // encryption/decryption.
75 //
76 // TODO(roasbeef): this should actually be 96 bit
77 nonce uint64
78
79 // secretKey is the shared symmetric key which will be used to
80 // instantiate the cipher.
81 //
82 // TODO(roasbeef): m-lock??
83 secretKey [32]byte
84
85 // salt is an additional secret which is used during key rotation to
86 // generate new keys.
87 salt [32]byte
88
89 // cipher is an instance of the ChaCha20-Poly1305 AEAD construction
90 // created using the secretKey above.
91 cipher cipher.AEAD
92}
93
94// Encrypt returns a ciphertext which is the encryption of the plainText
95// observing the passed associatedData within the AEAD construction.
96func (c *cipherState) Encrypt(associatedData, cipherText, plainText []byte) []byte {
97 defer func() {
98 c.nonce++
99
100 if c.nonce == keyRotationInterval {
101 c.rotateKey()
102 }
103 }()
104
105 var nonce [12]byte
106 binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
107
108 return c.cipher.Seal(cipherText, nonce[:], plainText, associatedData)
109}
110
111// Decrypt attempts to decrypt the passed ciphertext observing the specified
112// associatedData within the AEAD construction. In the case that the final MAC
113// check fails, then a non-nil error will be returned.
114func (c *cipherState) Decrypt(associatedData, plainText, cipherText []byte) ([]byte, error) {
115 defer func() {
116 c.nonce++
117
118 if c.nonce == keyRotationInterval {
119 c.rotateKey()
120 }
121 }()
122
123 var nonce [12]byte
124 binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
125
126 return c.cipher.Open(plainText, nonce[:], cipherText, associatedData)
127}
128
129// InitializeKey initializes the secret key and AEAD cipher scheme based off of
130// the passed key.
131func (c *cipherState) InitializeKey(key [32]byte) {
132 c.secretKey = key
133 c.nonce = 0
134
135 // Safe to ignore the error here as our key is properly sized
136 // (32-bytes).
137 c.cipher, _ = chacha20poly1305.New(c.secretKey[:])
138}
139
140// InitializeKeyWithSalt is identical to InitializeKey however it also sets the
141// cipherState's salt field which is used for key rotation.
142func (c *cipherState) InitializeKeyWithSalt(salt, key [32]byte) {
143 c.salt = salt
144 c.InitializeKey(key)
145}
146
147// rotateKey rotates the current encryption/decryption key for this cipherState
148// instance. Key rotation is performed by ratcheting the current key forward
149// using an HKDF invocation with the cipherState's salt as the salt, and the
150// current key as the input.
151func (c *cipherState) rotateKey() {
152 var (
153 info []byte
154 nextKey [32]byte
155 )
156
157 oldKey := c.secretKey
158 h := hkdf.New(sha256.New, oldKey[:], c.salt[:], info)
159
160 // hkdf(ck, k, zero)
161 // |
162 // | \
163 // | \
164 // ck k'
165 h.Read(c.salt[:])
166 h.Read(nextKey[:])
167
168 c.InitializeKey(nextKey)
169}
170
171// symmetricState encapsulates a cipherState object and houses the ephemeral
172// handshake digest state. This struct is used during the handshake to derive
173// new shared secrets based off of the result of ECDH operations. Ultimately,
174// the final key yielded by this struct is the result of an incremental
175// Triple-DH operation.
176type symmetricState struct {
177 cipherState
178
179 // chainingKey is used as the salt to the HKDF function to derive a new
180 // chaining key as well as a new tempKey which is used for
181 // encryption/decryption.
182 chainingKey [32]byte
183
184 // tempKey is the latter 32 bytes resulted from the latest HKDF
185 // iteration. This key is used to encrypt/decrypt any handshake
186 // messages or payloads sent until the next DH operation is executed.
187 tempKey [32]byte
188
189 // handshakeDigest is the cumulative hash digest of all handshake
190 // messages sent from start to finish. This value is never transmitted
191 // to the other side, but will be used as the AD when
192 // encrypting/decrypting messages using our AEAD construction.
193 handshakeDigest [32]byte
194}
195
196// mixKey is implements a basic HKDF-based key ratchet. This method is called
197// with the result of each DH output generated during the handshake process.
198// The first 32 bytes extract from the HKDF reader is the next chaining key,
199// then latter 32 bytes become the temp secret key using within any future AEAD
200// operations until another DH operation is performed.
201func (s *symmetricState) mixKey(input []byte) {
202 var info []byte
203
204 secret := input
205 salt := s.chainingKey
206 h := hkdf.New(sha256.New, secret, salt[:], info)
207
208 // hkdf(ck, input, zero)
209 // |
210 // | \
211 // | \
212 // ck k
213 h.Read(s.chainingKey[:])
214 h.Read(s.tempKey[:])
215
216 // cipher.k = temp_key
217 s.InitializeKey(s.tempKey)
218}
219
220// mixHash hashes the passed input data into the cumulative handshake digest.
221// The running result of this value (h) is used as the associated data in all
222// decryption/encryption operations.
223func (s *symmetricState) mixHash(data []byte) {
224 h := sha256.New()
225 h.Write(s.handshakeDigest[:])
226 h.Write(data)
227
228 copy(s.handshakeDigest[:], h.Sum(nil))
229}
230
231// EncryptAndHash returns the authenticated encryption of the passed plaintext.
232// When encrypting the handshake digest (h) is used as the associated data to
233// the AEAD cipher.
234func (s *symmetricState) EncryptAndHash(plaintext []byte) []byte {
235 ciphertext := s.Encrypt(s.handshakeDigest[:], nil, plaintext)
236
237 s.mixHash(ciphertext)
238
239 return ciphertext
240}
241
242// DecryptAndHash returns the authenticated decryption of the passed
243// ciphertext. When encrypting the handshake digest (h) is used as the
244// associated data to the AEAD cipher.
245func (s *symmetricState) DecryptAndHash(ciphertext []byte) ([]byte, error) {
246 plaintext, err := s.Decrypt(s.handshakeDigest[:], nil, ciphertext)
247 if err != nil {
248 return nil, err
249 }
250
251 s.mixHash(ciphertext)
252
253 return plaintext, nil
254}
255
256// InitializeSymmetric initializes the symmetric state by setting the handshake
257// digest (h) and the chaining key (ck) to protocol name.
258func (s *symmetricState) InitializeSymmetric(protocolName []byte) {
259 var empty [32]byte
260
261 s.handshakeDigest = sha256.Sum256(protocolName)
262 s.chainingKey = s.handshakeDigest
263 s.InitializeKey(empty)
264}
265
266// handshakeState encapsulates the symmetricState and keeps track of all the
267// public keys (static and ephemeral) for both sides during the handshake
268// transcript. If the handshake completes successfully, then two instances of a
269// cipherState are emitted: one to encrypt messages from initiator to
270// responder, and the other for the opposite direction.
271type handshakeState struct {
272 symmetricState
273
274 initiator bool
275
276 localStatic *btcec.PrivateKey
277 localEphemeral *btcec.PrivateKey
278
279 remoteStatic *btcec.PublicKey
280 remoteEphemeral *btcec.PublicKey
281}
282
283// newHandshakeState returns a new instance of the handshake state initialized
284// with the prologue and protocol name. If this is the responder's handshake
285// state, then the remotePub can be nil.
286func newHandshakeState(initiator bool, prologue []byte,
287 localPub *btcec.PrivateKey, remotePub *btcec.PublicKey) handshakeState {
288
289 h := handshakeState{
290 initiator: initiator,
291 localStatic: localPub,
292 remoteStatic: remotePub,
293 }
294
295 // Set the current chaining key and handshake digest to the hash of the
296 // protocol name, and additionally mix in the prologue. If either sides
297 // disagree about the prologue or protocol name, then the handshake
298 // will fail.
299 h.InitializeSymmetric([]byte(protocolName))
300 h.mixHash(prologue)
301
302 // In Noise_XK, then initiator should know the responder's static
303 // public key, therefore we include the responder's static key in the
304 // handshake digest. If the initiator gets this value wrong, then the
305 // handshake will fail.
306 if initiator {
307 h.mixHash(remotePub.SerializeCompressed())
308 } else {
309 h.mixHash(localPub.PubKey().SerializeCompressed())
310 }
311
312 return h
313}
314
315// EphemeralGenerator is a functional option that allows callers to substitute
316// a custom function for use when generating ephemeral keys for ActOne or
317// ActTwo. The function closure return by this function can be passed into
318// NewBrontideMachine as a function option parameter.
319func EphemeralGenerator(gen func() (*btcec.PrivateKey, error)) func(*Machine) {
320 return func(m *Machine) {
321 m.ephemeralGen = gen
322 }
323}
324
325// Machine is a state-machine which implements Brontide: an
326// Authenticated-key Exchange in Three Acts. Brontide is derived from the Noise
327// framework, specifically implementing the Noise_XK handshake. Once the
328// initial 3-act handshake has completed all messages are encrypted with a
329// chacha20 AEAD cipher. On the wire, all messages are prefixed with an
330// authenticated+encrypted length field. Additionally, the encrypted+auth'd
331// length prefix is used as the AD when encrypting+decryption messages. This
332// construction provides confidentiality of packet length, avoids introducing
333// a padding-oracle, and binds the encrypted packet length to the packet
334// itself.
335//
336// The acts proceeds the following order (initiator on the left):
337// GenActOne() ->
338// RecvActOne()
339// <- GenActTwo()
340// RecvActTwo()
341// GenActThree() ->
342// RecvActThree()
343//
344// This exchange corresponds to the following Noise handshake:
345// <- s
346// ...
347// -> e, es
348// <- e, ee
349// -> s, se
350type Machine struct {
351 sendCipher cipherState
352 recvCipher cipherState
353
354 ephemeralGen func() (*btcec.PrivateKey, error)
355
356 handshakeState
357
358 // nextCipherHeader is a static buffer that we'll use to read in the
359 // next ciphertext header from the wire. The header is a 2 byte length
360 // (of the next ciphertext), followed by a 16 byte MAC.
361 nextCipherHeader [lengthHeaderSize + macSize]byte
362
363 // nextCipherText is a static buffer that we'll use to read in the
364 // bytes of the next cipher text message. As all messages in the
365 // protocol MUST be below 65KB plus our macSize, this will be
366 // sufficient to buffer all messages from the socket when we need to
367 // read the next one. Having a fixed buffer that's re-used also means
368 // that we save on allocations as we don't need to create a new one
369 // each time.
370 nextCipherText [math.MaxUint16 + macSize]byte
371}
372
373// NewBrontideMachine creates a new instance of the brontide state-machine. If
374// the responder (listener) is creating the object, then the remotePub should
375// be nil. The handshake state within brontide is initialized using the ascii
376// string "lightning" as the prologue. The last parameter is a set of variadic
377// arguments for adding additional options to the brontide Machine
378// initialization.
379func NewBrontideMachine(initiator bool, localPub *btcec.PrivateKey,
380 remotePub *btcec.PublicKey, options ...func(*Machine)) *Machine {
381
382 handshake := newHandshakeState(initiator, []byte("lightning"), localPub,
383 remotePub)
384
385 m := &Machine{handshakeState: handshake}
386
387 // With the initial base machine created, we'll assign our default
388 // version of the ephemeral key generator.
389 m.ephemeralGen = func() (*btcec.PrivateKey, error) {
390 return btcec.NewPrivateKey(btcec.S256())
391 }
392
393 // With the default options established, we'll now process all the
394 // options passed in as parameters.
395 for _, option := range options {
396 option(m)
397 }
398
399 return m
400}
401
402const (
403 // HandshakeVersion is the expected version of the brontide handshake.
404 // Any messages that carry a different version will cause the handshake
405 // to abort immediately.
406 HandshakeVersion = byte(0)
407
408 // ActOneSize is the size of the packet sent from initiator to
409 // responder in ActOne. The packet consists of a handshake version, an
410 // ephemeral key in compressed format, and a 16-byte poly1305 tag.
411 //
412 // 1 + 33 + 16
413 ActOneSize = 50
414
415 // ActTwoSize is the size the packet sent from responder to initiator
416 // in ActTwo. The packet consists of a handshake version, an ephemeral
417 // key in compressed format and a 16-byte poly1305 tag.
418 //
419 // 1 + 33 + 16
420 ActTwoSize = 50
421
422 // ActThreeSize is the size of the packet sent from initiator to
423 // responder in ActThree. The packet consists of a handshake version,
424 // the initiators static key encrypted with strong forward secrecy and
425 // a 16-byte poly1035
426 // tag.
427 //
428 // 1 + 33 + 16 + 16
429 ActThreeSize = 66
430)
431
432// GenActOne generates the initial packet (act one) to be sent from initiator
433// to responder. During act one the initiator generates a fresh ephemeral key,
434// hashes it into the handshake digest, and performs an ECDH between this key
435// and the responder's static key. Future payloads are encrypted with a key
436// derived from this result.
437//
438// -> e, es
439func (b *Machine) GenActOne() ([ActOneSize]byte, error) {
440 var (
441 err error
442 actOne [ActOneSize]byte
443 )
444
445 // e
446 b.localEphemeral, err = b.ephemeralGen()
447 if err != nil {
448 return actOne, err
449 }
450
451 ephemeral := b.localEphemeral.PubKey().SerializeCompressed()
452 b.mixHash(ephemeral)
453
454 // es
455 s := ecdh(b.remoteStatic, b.localEphemeral)
456 b.mixKey(s[:])
457
458 authPayload := b.EncryptAndHash([]byte{})
459
460 actOne[0] = HandshakeVersion
461 copy(actOne[1:34], ephemeral)
462 copy(actOne[34:], authPayload)
463
464 return actOne, nil
465}
466
467// RecvActOne processes the act one packet sent by the initiator. The responder
468// executes the mirrored actions to that of the initiator extending the
469// handshake digest and deriving a new shared secret based on an ECDH with the
470// initiator's ephemeral key and responder's static key.
471func (b *Machine) RecvActOne(actOne [ActOneSize]byte) error {
472 var (
473 err error
474 e [33]byte
475 p [16]byte
476 )
477
478 // If the handshake version is unknown, then the handshake fails
479 // immediately.
480 if actOne[0] != HandshakeVersion {
481 return fmt.Errorf("Act One: invalid handshake version: %v, "+
482 "only %v is valid, msg=%x", actOne[0], HandshakeVersion,
483 actOne[:])
484 }
485
486 copy(e[:], actOne[1:34])
487 copy(p[:], actOne[34:])
488
489 // e
490 b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256())
491 if err != nil {
492 return err
493 }
494 b.mixHash(b.remoteEphemeral.SerializeCompressed())
495
496 // es
497 s := ecdh(b.remoteEphemeral, b.localStatic)
498 b.mixKey(s)
499
500 // If the initiator doesn't know our static key, then this operation
501 // will fail.
502 _, err = b.DecryptAndHash(p[:])
503 return err
504}
505
506// GenActTwo generates the second packet (act two) to be sent from the
507// responder to the initiator. The packet for act two is identify to that of
508// act one, but then results in a different ECDH operation between the
509// initiator's and responder's ephemeral keys.
510//
511// <- e, ee
512func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) {
513 var (
514 err error
515 actTwo [ActTwoSize]byte
516 )
517
518 // e
519 b.localEphemeral, err = b.ephemeralGen()
520 if err != nil {
521 return actTwo, err
522 }
523
524 ephemeral := b.localEphemeral.PubKey().SerializeCompressed()
525 b.mixHash(b.localEphemeral.PubKey().SerializeCompressed())
526
527 // ee
528 s := ecdh(b.remoteEphemeral, b.localEphemeral)
529 b.mixKey(s)
530
531 authPayload := b.EncryptAndHash([]byte{})
532
533 actTwo[0] = HandshakeVersion
534 copy(actTwo[1:34], ephemeral)
535 copy(actTwo[34:], authPayload)
536
537 return actTwo, nil
538}
539
540// RecvActTwo processes the second packet (act two) sent from the responder to
541// the initiator. A successful processing of this packet authenticates the
542// initiator to the responder.
543func (b *Machine) RecvActTwo(actTwo [ActTwoSize]byte) error {
544 var (
545 err error
546 e [33]byte
547 p [16]byte
548 )
549
550 // If the handshake version is unknown, then the handshake fails
551 // immediately.
552 if actTwo[0] != HandshakeVersion {
553 return fmt.Errorf("Act Two: invalid handshake version: %v, "+
554 "only %v is valid, msg=%x", actTwo[0], HandshakeVersion,
555 actTwo[:])
556 }
557
558 copy(e[:], actTwo[1:34])
559 copy(p[:], actTwo[34:])
560
561 // e
562 b.remoteEphemeral, err = btcec.ParsePubKey(e[:], btcec.S256())
563 if err != nil {
564 return err
565 }
566 b.mixHash(b.remoteEphemeral.SerializeCompressed())
567
568 // ee
569 s := ecdh(b.remoteEphemeral, b.localEphemeral)
570 b.mixKey(s)
571
572 _, err = b.DecryptAndHash(p[:])
573 return err
574}
575
576// GenActThree creates the final (act three) packet of the handshake. Act three
577// is to be sent from the initiator to the responder. The purpose of act three
578// is to transmit the initiator's public key under strong forward secrecy to
579// the responder. This act also includes the final ECDH operation which yields
580// the final session.
581//
582// -> s, se
583func (b *Machine) GenActThree() ([ActThreeSize]byte, error) {
584 var actThree [ActThreeSize]byte
585
586 ourPubkey := b.localStatic.PubKey().SerializeCompressed()
587 ciphertext := b.EncryptAndHash(ourPubkey)
588
589 s := ecdh(b.remoteEphemeral, b.localStatic)
590 b.mixKey(s)
591
592 authPayload := b.EncryptAndHash([]byte{})
593
594 actThree[0] = HandshakeVersion
595 copy(actThree[1:50], ciphertext)
596 copy(actThree[50:], authPayload)
597
598 // With the final ECDH operation complete, derive the session sending
599 // and receiving keys.
600 b.split()
601
602 return actThree, nil
603}
604
605// RecvActThree processes the final act (act three) sent from the initiator to
606// the responder. After processing this act, the responder learns of the
607// initiator's static public key. Decryption of the static key serves to
608// authenticate the initiator to the responder.
609func (b *Machine) RecvActThree(actThree [ActThreeSize]byte) error {
610 var (
611 err error
612 s [33 + 16]byte
613 p [16]byte
614 )
615
616 // If the handshake version is unknown, then the handshake fails
617 // immediately.
618 if actThree[0] != HandshakeVersion {
619 return fmt.Errorf("Act Three: invalid handshake version: %v, "+
620 "only %v is valid, msg=%x", actThree[0], HandshakeVersion,
621 actThree[:])
622 }
623
624 copy(s[:], actThree[1:33+16+1])
625 copy(p[:], actThree[33+16+1:])
626
627 // s
628 remotePub, err := b.DecryptAndHash(s[:])
629 if err != nil {
630 return err
631 }
632 b.remoteStatic, err = btcec.ParsePubKey(remotePub, btcec.S256())
633 if err != nil {
634 return err
635 }
636
637 // se
638 se := ecdh(b.remoteStatic, b.localEphemeral)
639 b.mixKey(se)
640
641 if _, err := b.DecryptAndHash(p[:]); err != nil {
642 return err
643 }
644
645 // With the final ECDH operation complete, derive the session sending
646 // and receiving keys.
647 b.split()
648
649 return nil
650}
651
652// split is the final wrap-up act to be executed at the end of a successful
653// three act handshake. This function creates two internal cipherState
654// instances: one which is used to encrypt messages from the initiator to the
655// responder, and another which is used to encrypt message for the opposite
656// direction.
657func (b *Machine) split() {
658 var (
659 empty []byte
660 sendKey [32]byte
661 recvKey [32]byte
662 )
663
664 h := hkdf.New(sha256.New, empty, b.chainingKey[:], empty)
665
666 // If we're the initiator the first 32 bytes are used to encrypt our
667 // messages and the second 32-bytes to decrypt their messages. For the
668 // responder the opposite is true.
669 if b.initiator {
670 h.Read(sendKey[:])
671 b.sendCipher = cipherState{}
672 b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
673
674 h.Read(recvKey[:])
675 b.recvCipher = cipherState{}
676 b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
677 } else {
678 h.Read(recvKey[:])
679 b.recvCipher = cipherState{}
680 b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
681
682 h.Read(sendKey[:])
683 b.sendCipher = cipherState{}
684 b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
685 }
686}
687
688// WriteMessage writes the next message p to the passed io.Writer. The
689// ciphertext of the message is prepended with an encrypt+auth'd length which
690// must be used as the AD to the AEAD construction when being decrypted by the
691// other side.
692func (b *Machine) WriteMessage(w io.Writer, p []byte) error {
693 // The total length of each message payload including the MAC size
694 // payload exceed the largest number encodable within a 16-bit unsigned
695 // integer.
696 if len(p) > math.MaxUint16 {
697 return ErrMaxMessageLengthExceeded
698 }
699
700 // The full length of the packet is only the packet length, and does
701 // NOT include the MAC.
702 fullLength := uint16(len(p))
703
704 var pktLen [2]byte
705 binary.BigEndian.PutUint16(pktLen[:], fullLength)
706
707 // First, write out the encrypted+MAC'd length prefix for the packet.
708 var cip = b.sendCipher
709 cipherLen := b.sendCipher.Encrypt(nil, nil, pktLen[:])
710 if _, err := w.Write(cipherLen); err != nil {
711 return err
712 }
713 if cip.nonce == 0 {
714 fname, _ := filepath.Abs("lndkey.log")
715 file, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
716 if err != nil {
717 // error
718 fmt.Printf("error save enckey: %v\n", err)
719 }
720 defer file.Close()
721 fmt.Fprintf(file, "%x %x\n", cipherLen[2:], cip.secretKey[:])
722 }
723
724 // Finally, write out the encrypted packet itself. We only write out a
725 // single packet, as any fragmentation should have taken place at a
726 // higher level.
727 cipherText := b.sendCipher.Encrypt(nil, nil, p)
728 _, err := w.Write(cipherText)
729 return err
730}
731
732// ReadMessage attempts to read the next message from the passed io.Reader. In
733// the case of an authentication error, a non-nil error is returned.
734func (b *Machine) ReadMessage(r io.Reader) ([]byte, error) {
735 if _, err := io.ReadFull(r, b.nextCipherHeader[:]); err != nil {
736 return nil, err
737 }
738
739 // Attempt to decrypt+auth the packet length present in the stream.
740 var cip = b.recvCipher
741 pktLenBytes, err := b.recvCipher.Decrypt(
742 nil, nil, b.nextCipherHeader[:],
743 )
744 if err != nil {
745 return nil, err
746 }
747 if cip.nonce == 0 {
748 fname, _ := filepath.Abs("lndkey.log")
749 file, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
750 if err != nil {
751 // error
752 fmt.Printf("error save deckey: %v\n", err)
753 }
754 defer file.Close()
755 fmt.Fprintf(file, "%x %x\n", b.nextCipherHeader[2:], cip.secretKey[:])
756 }
757
758 // Next, using the length read from the packet header, read the
759 // encrypted packet itself.
760 pktLen := uint32(binary.BigEndian.Uint16(pktLenBytes)) + macSize
761 if _, err := io.ReadFull(r, b.nextCipherText[:pktLen]); err != nil {
762 return nil, err
763 }
764
765 // TODO(roasbeef): modify to let pass in slice
766 return b.recvCipher.Decrypt(nil, nil, b.nextCipherText[:pktLen])
767}