83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"sneak.berlin/go/x/pkg/cbk"
|
|
)
|
|
|
|
// maxMnemonicInputBytes bounds how much of stdin `cbk derive` will read; a
|
|
// 24-word mnemonic is well under 300 bytes.
|
|
const maxMnemonicInputBytes = 64 << 10
|
|
|
|
// newCBKCommand returns `sutil cbk`, the parent of the crypto_box
|
|
// keypair commands.
|
|
func newCBKCommand() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "cbk",
|
|
Short: "crypto_box keypairs derived from BIP39 mnemonics",
|
|
}
|
|
|
|
cmd.AddCommand(newCBKDeriveCommand())
|
|
|
|
return cmd
|
|
}
|
|
|
|
// newCBKDeriveCommand returns `sutil cbk derive`.
|
|
func newCBKDeriveCommand() *cobra.Command {
|
|
var publicOnly bool
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "derive",
|
|
Short: "Derive a crypto_box keypair from a mnemonic read on stdin",
|
|
Long: `Reads a BIP39 mnemonic from stdin, in any letter case and with any
|
|
whitespace between words, and prints the crypto_box keypair derived from it
|
|
as hex. The same mnemonic always yields the same keypair.
|
|
|
|
The mnemonic is read from stdin rather than taken as an argument so that it
|
|
does not end up in shell history or process listings:
|
|
|
|
sutil generate mnemonic > mnemonic.txt
|
|
sutil cbk derive < mnemonic.txt`,
|
|
Args: cobra.NoArgs,
|
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
|
input := io.LimitReader(cmd.InOrStdin(), maxMnemonicInputBytes)
|
|
|
|
mnemonic, err := io.ReadAll(input)
|
|
if err != nil {
|
|
return fmt.Errorf("reading mnemonic from stdin: %w", err)
|
|
}
|
|
|
|
keypair, err := cbk.New(cbk.Params{Mnemonic: string(mnemonic)})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return writeKeypair(cmd.OutOrStdout(), keypair, publicOnly)
|
|
},
|
|
}
|
|
|
|
cmd.Flags().BoolVar(&publicOnly, "public", false, "print only the public key")
|
|
|
|
return cmd
|
|
}
|
|
|
|
// writeKeypair prints the keypair as labeled hex lines, or just the bare
|
|
// public key when publicOnly is set.
|
|
func writeKeypair(w io.Writer, keypair cbk.CryptoBoxKeypair, publicOnly bool) error {
|
|
if publicOnly {
|
|
_, err := fmt.Fprintln(w, keypair.PublicKeyHex())
|
|
|
|
return err
|
|
}
|
|
|
|
_, err := fmt.Fprintf(
|
|
w, "public: %s\nprivate: %s\n", keypair.PublicKeyHex(), keypair.PrivateKeyHex(),
|
|
)
|
|
|
|
return err
|
|
}
|