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

lightningnetwork / lnd / 13566028875

27 Feb 2025 12:09PM UTC coverage: 49.396% (-9.4%) from 58.748%
13566028875

Pull #9555

github

ellemouton
graph/db: populate the graph cache in Start instead of during construction

In this commit, we move the graph cache population logic out of the
ChannelGraph constructor and into its Start method instead.
Pull Request #9555: graph: extract cache from CRUD [6]

34 of 54 new or added lines in 4 files covered. (62.96%)

27464 existing lines in 436 files now uncovered.

101095 of 204664 relevant lines covered (49.4%)

1.54 hits per line

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

60.26
/lnencrypt/crypto.go
1
package lnencrypt
2

3
import (
4
        "crypto/rand"
5
        "crypto/sha256"
6
        "fmt"
7
        "io"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/lightningnetwork/lnd/keychain"
11
        "golang.org/x/crypto/chacha20poly1305"
12
)
13

14
// baseEncryptionKeyLoc is the KeyLocator that we'll use to derive the base
15
// encryption key used for encrypting all payloads. We use this to then
16
// derive the actual key that we'll use for encryption. We do this
17
// rather than using the raw key, as we assume that we can't obtain the raw
18
// keys, and we don't want to require that the HSM know our target cipher for
19
// encryption.
20
//
21
// TODO(roasbeef): possibly unique encrypt?
22
var baseEncryptionKeyLoc = keychain.KeyLocator{
23
        Family: keychain.KeyFamilyBaseEncryption,
24
        Index:  0,
25
}
26

27
// EncrypterDecrypter is an interface representing an object that encrypts or
28
// decrypts data.
29
type EncrypterDecrypter interface {
30
        // EncryptPayloadToWriter attempts to write the set of provided bytes
31
        // into the passed io.Writer in an encrypted form.
32
        EncryptPayloadToWriter([]byte, io.Writer) error
33

34
        // DecryptPayloadFromReader attempts to decrypt the encrypted bytes
35
        // within the passed io.Reader instance using the key derived from
36
        // the passed keyRing.
37
        DecryptPayloadFromReader(io.Reader) ([]byte, error)
38
}
39

40
// Encrypter is a struct responsible for encrypting and decrypting data.
41
type Encrypter struct {
42
        encryptionKey []byte
43
}
44

45
// KeyRingEncrypter derives an encryption key to encrypt all our files that are
46
// written to disk and returns an Encrypter object holding the key.
47
//
48
// The key itself, is the sha2 of a base key that we get from the keyring. We
49
// derive the key this way as we don't force the HSM (or any future
50
// abstractions) to be able to derive and know of the cipher that we'll use
51
// within our protocol.
52
func KeyRingEncrypter(keyRing keychain.KeyRing) (*Encrypter, error) {
3✔
53
        //  key = SHA256(baseKey)
3✔
54
        baseKey, err := keyRing.DeriveKey(
3✔
55
                baseEncryptionKeyLoc,
3✔
56
        )
3✔
57
        if err != nil {
3✔
UNCOV
58
                return nil, err
×
UNCOV
59
        }
×
60

61
        encryptionKey := sha256.Sum256(
3✔
62
                baseKey.PubKey.SerializeCompressed(),
3✔
63
        )
3✔
64

3✔
65
        // TODO(roasbeef): throw back in ECDH?
3✔
66

3✔
67
        return &Encrypter{
3✔
68
                encryptionKey: encryptionKey[:],
3✔
69
        }, nil
3✔
70
}
71

72
// ECDHEncrypter derives an encryption key by performing an ECDH operation on
73
// the passed keys. The resulting key is used to encrypt or decrypt files with
74
// sensitive content.
75
func ECDHEncrypter(localKey *btcec.PrivateKey,
UNCOV
76
        remoteKey *btcec.PublicKey) (*Encrypter, error) {
×
UNCOV
77

×
UNCOV
78
        ecdh := keychain.PrivKeyECDH{
×
UNCOV
79
                PrivKey: localKey,
×
UNCOV
80
        }
×
UNCOV
81
        encryptionKey, err := ecdh.ECDH(remoteKey)
×
UNCOV
82
        if err != nil {
×
83
                return nil, fmt.Errorf("error deriving encryption key: %w", err)
×
84
        }
×
85

UNCOV
86
        return &Encrypter{
×
UNCOV
87
                encryptionKey: encryptionKey[:],
×
UNCOV
88
        }, nil
×
89
}
90

91
// EncryptPayloadToWriter attempts to write the set of provided bytes into the
92
// passed io.Writer in an encrypted form. We use a 24-byte chachapoly AEAD
93
// instance with a randomized nonce that's pre-pended to the final payload and
94
// used as associated data in the AEAD.
95
func (e Encrypter) EncryptPayloadToWriter(payload []byte,
96
        w io.Writer) error {
3✔
97

3✔
98
        // Before encryption, we'll initialize our cipher with the target
3✔
99
        // encryption key, and also read out our random 24-byte nonce we use
3✔
100
        // for encryption. Note that we use NewX, not New, as the latter
3✔
101
        // version requires a 12-byte nonce, not a 24-byte nonce.
3✔
102
        cipher, err := chacha20poly1305.NewX(e.encryptionKey)
3✔
103
        if err != nil {
3✔
104
                return err
×
105
        }
×
106
        var nonce [chacha20poly1305.NonceSizeX]byte
3✔
107
        if _, err := rand.Read(nonce[:]); err != nil {
3✔
108
                return err
×
109
        }
×
110

111
        // Finally, we encrypted the final payload, and write out our
112
        // ciphertext with nonce pre-pended.
113
        ciphertext := cipher.Seal(nil, nonce[:], payload, nonce[:])
3✔
114

3✔
115
        if _, err := w.Write(nonce[:]); err != nil {
3✔
116
                return err
×
117
        }
×
118
        if _, err := w.Write(ciphertext); err != nil {
3✔
119
                return err
×
120
        }
×
121

122
        return nil
3✔
123
}
124

125
// DecryptPayloadFromReader attempts to decrypt the encrypted bytes within the
126
// passed io.Reader instance using the key derived from the passed keyRing. For
127
// further details regarding the key derivation protocol, see the
128
// KeyRingEncrypter function.
129
func (e Encrypter) DecryptPayloadFromReader(payload io.Reader) ([]byte,
130
        error) {
3✔
131

3✔
132
        // Next, we'll read out the entire blob as we need to isolate the nonce
3✔
133
        // from the rest of the ciphertext.
3✔
134
        packedPayload, err := io.ReadAll(payload)
3✔
135
        if err != nil {
3✔
136
                return nil, err
×
137
        }
×
138
        if len(packedPayload) < chacha20poly1305.NonceSizeX {
3✔
UNCOV
139
                return nil, fmt.Errorf("payload size too small, must be at "+
×
UNCOV
140
                        "least %v bytes", chacha20poly1305.NonceSizeX)
×
UNCOV
141
        }
×
142

143
        nonce := packedPayload[:chacha20poly1305.NonceSizeX]
3✔
144
        ciphertext := packedPayload[chacha20poly1305.NonceSizeX:]
3✔
145

3✔
146
        // Now that we have the cipher text and the nonce separated, we can go
3✔
147
        // ahead and decrypt the final blob so we can properly serialize.
3✔
148
        cipher, err := chacha20poly1305.NewX(e.encryptionKey)
3✔
149
        if err != nil {
3✔
150
                return nil, err
×
151
        }
×
152
        plaintext, err := cipher.Open(nil, nonce, ciphertext, nonce)
3✔
153
        if err != nil {
3✔
UNCOV
154
                return nil, err
×
UNCOV
155
        }
×
156

157
        return plaintext, nil
3✔
158
}
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