-
Notifications
You must be signed in to change notification settings - Fork 18
/
cmd_gen_seed.go
138 lines (120 loc) · 3.94 KB
/
cmd_gen_seed.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"crypto/rand"
"fmt"
"os"
"strings"
"time"
"github.com/jessevdk/go-flags"
"github.com/lightningnetwork/lnd/aezeed"
)
const (
defaultEntropyBytes = 16
)
type jsonSeed struct {
Seed string `json:"seed"`
Birthday int64 `json:"birthday_timestamp"`
}
type genSeedCommand struct {
EntropySourceFile string `long:"entropy-source-file" description:"The file descriptor to read the seed entropy from; if set lndinit will read exactly 16 bytes from the file, otherwise the default crypto/rand source will be used"`
PassphraseFile string `long:"passphrase-file" description:"The file to read the seed passphrase from; if not set, no seed passphrase will be used, unless --passhprase-k8s is used"`
PassphraseK8s *k8sSecretOptions `group:"Flags for reading seed passphrase from Kubernetes" namespace:"passphrase-k8s"`
Output string `long:"output" short:"o" description:"Output format" choice:"raw" choice:"json"`
}
func newGenSeedCommand() *genSeedCommand {
return &genSeedCommand{
Output: outputFormatRaw,
PassphraseK8s: &k8sSecretOptions{
Namespace: defaultK8sNamespace,
},
}
}
func (x *genSeedCommand) Register(parser *flags.Parser) error {
_, err := parser.AddCommand(
"gen-seed",
"Generate an lnd wallet seed",
"Generate a fresh lnd wallet seed (aezeed) with 16 bytes of "+
"entropy read from the given entropy file or the "+
"system's default cryptographic entropy source; the "+
"seed is printed to stdout, either as raw text or "+
"formatted as JSON",
x,
)
return err
}
func (x *genSeedCommand) Execute(_ []string) error {
// First find out if we want to set a seed passphrase.
var (
passPhrase string
err error
)
switch {
// Both file and Kubernetes input set.
case x.PassphraseFile != "" && x.PassphraseK8s.AnySet():
return fmt.Errorf("invalid passphrase input, either use file " +
"or k8s but not both")
// Read passphrase from file.
case x.PassphraseFile != "":
passPhrase, err = readFile(x.PassphraseFile)
// Read passphrase from Kubernetes secret.
case x.PassphraseK8s.AnySet():
k8sSecret := &k8sObjectOptions{
Namespace: x.PassphraseK8s.Namespace,
Name: x.PassphraseK8s.SecretName,
KeyName: x.PassphraseK8s.SecretKeyName,
Base64: x.PassphraseK8s.Base64,
ObjectType: ObjectTypeSecret,
}
passPhrase, _, err = readK8s(k8sSecret)
}
if err != nil {
return err
}
// Next read our entropy either from the given source or the default
// crypto/rand source.
var entropy [defaultEntropyBytes]byte
if x.EntropySourceFile != "" {
file, err := os.Open(x.EntropySourceFile)
if err != nil {
return fmt.Errorf("unable to open entropy source file "+
"%s: %v", x.EntropySourceFile, err)
}
// Try to read exactly the number of bytes we require and make
// sure we've actually also read that many.
numRead, err := file.Read(entropy[:])
if err != nil {
return fmt.Errorf("unable to read from entropy source "+
"file %s: %v", x.EntropySourceFile, err)
}
if numRead != defaultEntropyBytes {
return fmt.Errorf("unable to read %d bytes from "+
"entropy source, only got %d",
defaultEntropyBytes, numRead)
}
} else {
if _, err := rand.Read(entropy[:]); err != nil {
return fmt.Errorf("unable get seed entropy: %v", err)
}
}
// We now have everything we need for creating the cipher seed.
seed, err := aezeed.New(aezeed.CipherSeedVersion, &entropy, time.Now())
if err != nil {
return fmt.Errorf("error creating cipher seed: %v", err)
}
mnemonic, err := seed.ToMnemonic([]byte(passPhrase))
if err != nil {
return fmt.Errorf("error encrypting cipher seed: %v", err)
}
seedWords := strings.Join(mnemonic[:], " ")
if x.Output == outputFormatJSON {
seedWords, err = asJSON(&jsonSeed{
Seed: seedWords,
Birthday: seed.BirthdayTime().Unix(),
})
if err != nil {
return fmt.Errorf("error encoding as JSON: %v", err)
}
}
fmt.Printf("%s", seedWords)
return nil
}