mirror of
https://github.com/FiloSottile/age.git
synced 2026-01-09 21:27:20 +00:00
cmd/age: implement -p/--passphrase
This commit is contained in:
@@ -31,13 +31,15 @@ func main() {
|
||||
log.SetFlags(0)
|
||||
|
||||
var (
|
||||
outFlag string
|
||||
decryptFlag, armorFlag bool
|
||||
recipientFlags, identityFlags multiFlag
|
||||
outFlag string
|
||||
decryptFlag, armorFlag, passFlag bool
|
||||
recipientFlags, identityFlags multiFlag
|
||||
)
|
||||
|
||||
flag.BoolVar(&decryptFlag, "d", false, "decrypt the input")
|
||||
flag.BoolVar(&decryptFlag, "decrypt", false, "decrypt the input")
|
||||
flag.BoolVar(&passFlag, "p", false, "use a passphrase")
|
||||
flag.BoolVar(&passFlag, "passphrase", false, "use a passphrase")
|
||||
flag.StringVar(&outFlag, "o", "", "output to `FILE` (default stdout)")
|
||||
flag.BoolVar(&armorFlag, "a", false, "generate an armored file")
|
||||
flag.BoolVar(&armorFlag, "armor", false, "generate an armored file")
|
||||
@@ -66,9 +68,12 @@ func main() {
|
||||
log.Printf("Error: -i/--identity can't be used in encryption mode.")
|
||||
log.Fatalf("Did you forget to specify -d/--decrypt?")
|
||||
}
|
||||
if len(recipientFlags) == 0 {
|
||||
if len(recipientFlags) == 0 && !passFlag {
|
||||
log.Printf("Error: missing recipients.")
|
||||
log.Fatalf("Did you forget to specify -r/--recipient?")
|
||||
log.Fatalf("Did you forget to specify -r/--recipient or -p/--passphrase?")
|
||||
}
|
||||
if len(recipientFlags) > 0 && passFlag {
|
||||
log.Fatalf("Error: -p/--passphrase can't be combined with -r/--recipient.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +85,8 @@ func main() {
|
||||
}
|
||||
defer f.Close()
|
||||
in = f
|
||||
} else {
|
||||
stdinInUse = true
|
||||
}
|
||||
if name := outFlag; name != "" && name != "-" {
|
||||
f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
|
||||
@@ -104,23 +111,45 @@ func main() {
|
||||
}
|
||||
|
||||
switch {
|
||||
case passFlag:
|
||||
fmt.Fprintf(os.Stderr, "Enter passphrase: ")
|
||||
pass, err := readPassphrase()
|
||||
if err != nil {
|
||||
log.Fatalf("Error: could not read passphrase: %v", err)
|
||||
}
|
||||
if decryptFlag {
|
||||
decryptPass(string(pass), in, out)
|
||||
} else {
|
||||
encryptPass(string(pass), in, out, armorFlag)
|
||||
}
|
||||
case decryptFlag:
|
||||
decrypt(identityFlags, in, out)
|
||||
decryptKeys(identityFlags, in, out)
|
||||
default:
|
||||
encrypt(recipientFlags, in, out, armorFlag)
|
||||
encryptKeys(recipientFlags, in, out, armorFlag)
|
||||
}
|
||||
}
|
||||
|
||||
func encrypt(args []string, in io.Reader, out io.Writer, armor bool) {
|
||||
func encryptKeys(keys []string, in io.Reader, out io.Writer, armor bool) {
|
||||
var recipients []age.Recipient
|
||||
for _, arg := range args {
|
||||
for _, arg := range keys {
|
||||
r, err := parseRecipient(arg)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %v", err)
|
||||
}
|
||||
recipients = append(recipients, r)
|
||||
}
|
||||
encrypt(recipients, in, out, armor)
|
||||
}
|
||||
|
||||
func encryptPass(pass string, in io.Reader, out io.Writer, armor bool) {
|
||||
r, err := age.NewScryptRecipient(pass)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %v", err)
|
||||
}
|
||||
encrypt([]age.Recipient{r}, in, out, armor)
|
||||
}
|
||||
|
||||
func encrypt(recipients []age.Recipient, in io.Reader, out io.Writer, armor bool) {
|
||||
ageEncrypt := age.Encrypt
|
||||
if armor {
|
||||
ageEncrypt = age.EncryptWithArmor
|
||||
@@ -137,18 +166,29 @@ func encrypt(args []string, in io.Reader, out io.Writer, armor bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func decrypt(args []string, in io.Reader, out io.Writer) {
|
||||
func decryptKeys(keys []string, in io.Reader, out io.Writer) {
|
||||
var identities []age.Identity
|
||||
// TODO: use the default location if no arguments are provided:
|
||||
// os.UserConfigDir()/age/keys.txt, ~/.ssh/id_rsa, ~/.ssh/id_ed25519
|
||||
for _, name := range args {
|
||||
for _, name := range keys {
|
||||
ids, err := parseIdentitiesFile(name)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %v", err)
|
||||
}
|
||||
identities = append(identities, ids...)
|
||||
}
|
||||
decrypt(identities, in, out)
|
||||
}
|
||||
|
||||
func decryptPass(pass string, in io.Reader, out io.Writer) {
|
||||
i, err := age.NewScryptIdentity(pass)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %v", err)
|
||||
}
|
||||
decrypt([]age.Identity{i}, in, out)
|
||||
}
|
||||
|
||||
func decrypt(identities []age.Identity, in io.Reader, out io.Writer) {
|
||||
r, err := age.Decrypt(in, identities...)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %v", err)
|
||||
|
||||
@@ -91,23 +91,23 @@ func (i *EncryptedSSHIdentity) Matches(block *format.Recipient) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func passphrasePrompt(name string) func() ([]byte, error) {
|
||||
return func() ([]byte, error) {
|
||||
fd := int(os.Stdin.Fd())
|
||||
if !terminal.IsTerminal(fd) {
|
||||
tty, err := os.Open("/dev/tty")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read passphrase for %q: standard input is not a terminal, and opening /dev/tty failed: %v", name, err)
|
||||
}
|
||||
defer tty.Close()
|
||||
fd = int(tty.Fd())
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Enter passphrase for %q: ", name)
|
||||
defer fmt.Fprintf(os.Stderr, "\n")
|
||||
p, err := terminal.ReadPassword(fd)
|
||||
// stdinInUse is set in main. It's a singleton like os.Stdin.
|
||||
var stdinInUse bool
|
||||
|
||||
func readPassphrase() ([]byte, error) {
|
||||
fd := int(os.Stdin.Fd())
|
||||
if !terminal.IsTerminal(fd) || stdinInUse {
|
||||
tty, err := os.Open("/dev/tty")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read passphrase for %q: %v", name, err)
|
||||
return nil, fmt.Errorf("standard input is not available or not a terminal, and opening /dev/tty failed: %v", err)
|
||||
}
|
||||
return p, nil
|
||||
defer tty.Close()
|
||||
fd = int(tty.Fd())
|
||||
}
|
||||
defer fmt.Fprintf(os.Stderr, "\n")
|
||||
p, err := terminal.ReadPassword(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
@@ -91,7 +91,15 @@ func parseSSHIdentity(name string, pemBytes []byte) ([]age.Identity, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
i, err := NewEncryptedSSHIdentity(pubKey, pemBytes, passphrasePrompt(name))
|
||||
passphrasePrompt := func() ([]byte, error) {
|
||||
fmt.Fprintf(os.Stderr, "Enter passphrase for %q: ", name)
|
||||
pass, err := readPassphrase()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read passphrase for %q: %v", name, err)
|
||||
}
|
||||
return pass, nil
|
||||
}
|
||||
i, err := NewEncryptedSSHIdentity(pubKey, pemBytes, passphrasePrompt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user