age

Simple, secure encryption with UNIX-style composability.
git clone git://git.sgregoratto.me/age
Log | Files | Refs | README | LICENSE

commit e82447cddb6020f668e68457891fe147cf0b931f
parent c4269b618599be45fcc3fafe04a10216791ad84c
Author: Stephen Gregoratto <dev@sgregoratto.me>
Date:   Wed,  9 Oct 2019 15:14:27 +1100

Change flags, prefix logs, add usage func

- All command flags are now one rune long.
- Logs are prefixed with the program name similar to err(3).
- `flags.Usage` is replaced with a custom function.
- Log messages are converted to lowercase.

Diffstat:
Mcmd/age/age.go | 119++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mgo.mod | 5++++-
Mgo.sum | 3++-
3 files changed, 87 insertions(+), 40 deletions(-)

diff --git a/cmd/age/age.go b/cmd/age/age.go @@ -20,76 +20,119 @@ import ( ) func main() { + var ( + gen = flag.Bool("G", false, "generate a new age key pair") + dec = flag.Bool("D", false, "decrypt the input") + help = flag.Bool("h", false, "show this help") + inFile = flag.String("i", "", "output file") + outFile = flag.String("o", "", "input file") + + in = os.Stdin + out = os.Stdout + err error + progname = filepath.Base(os.Args[0]) + ) + log.SetFlags(0) + log.SetPrefix(progname + ": ") - generateFlag := flag.Bool("generate", false, "generate a new age key pair") - decryptFlag := flag.Bool("d", false, "decrypt the input") + flag.Usage = func() { + fmt.Fprintf(os.Stderr, + `usage: %s [-o file] -G + %s [-i file] [-o file] recipient ... + %s [-i file] [-o file] -D [identity-file ... ] +`, progname, progname, progname) + os.Exit(1) + } flag.Parse() + args := flag.Args() - switch { - case *generateFlag: - if *decryptFlag { - log.Fatalf("Invalid flag combination") + if *help { + flag.Usage() + } + + if *dec && *gen { + log.Printf("multiple modes selected") + flag.Usage() + } + + if *inFile != "" { + if *gen { + log.Printf("-g takes no input") + flag.Usage() + } + + in, err = os.Open(*inFile) + if err != nil { + log.Fatalf("cannot open file %q: %v", *inFile, err) } - generate() - case *decryptFlag: - if *generateFlag { - log.Fatalf("Invalid flag combination") + } + + if *outFile != "" { + out, err = os.Create(*outFile) + if err != nil { + log.Fatalf("cannot open file %q: %v", *outFile, err) } - decrypt() - default: - encrypt() } -} -func generate() { - if len(flag.Args()) != 0 { - log.Fatalf("-generate takes no arguments") + switch { + case *gen: + if len(args) != 0 { + log.Printf("-g takes no arguments") + flag.Usage() + } + generate(out) + case *dec: + decrypt(in, out, args) + default: + encrypt(in, out, args) } +} +func generate(out *os.File) { key := make([]byte, 32) if _, err := rand.Read(key); err != nil { - log.Fatalf("Internal error: %v", err) + log.Fatalf("cannot get random bytes: %v", err) } k, err := age.NewX25519Identity(key) if err != nil { - log.Fatalf("Internal error: %v", err) + log.Fatalf("cannot create new identity: %v", err) } - fmt.Printf("# created: %s\n", time.Now().Format(time.RFC3339)) - fmt.Printf("# %s\n", k.Recipient()) - fmt.Printf("%s\n", k) + fmt.Fprintf(out, "# created: %s\n", time.Now().Format(time.RFC3339)) + fmt.Fprintf(out, "# %s\n", k.Recipient()) + fmt.Fprintf(out, "%s\n", k) } -func encrypt() { +func encrypt(in, out *os.File, args []string) { var recipients []age.Recipient - for _, arg := range flag.Args() { + for _, arg := range args { r, err := parseRecipient(arg) if err != nil { - log.Fatalf("Error: %v", err) + log.Fatalf("cannot parse recipient %q: %v", arg, err) } recipients = append(recipients, r) } if len(recipients) == 0 { - log.Fatalf("Missing recipients!") + log.Printf("no recipients") } - w, err := age.Encrypt(os.Stdout, recipients...) + w, err := age.Encrypt(out, recipients...) if err != nil { - log.Fatalf("Error initializing encryption: %v", err) + log.Fatalf("cannot initialize encryption: %v", err) } - if _, err := io.Copy(w, os.Stdin); err != nil { - log.Fatalf("Error encrypting the input: %v", err) + if _, err := io.Copy(w, in); err != nil { + log.Fatalf("cannot encrypt input: %v", err) } if err := w.Close(); err != nil { - log.Fatalf("Error finalizing encryption: %v", err) + log.Fatalf("cannot close output: %v", err) } } -func decrypt() { +func decrypt(in, out *os.File, args []string) { var identities []age.Identity // TODO: use the default location if no arguments are provided. - for _, name := range flag.Args() { + for _, name := range args { var ( ids []age.Identity err error @@ -102,16 +145,16 @@ func decrypt() { ids, err = parseIdentitiesFile(name) } if err != nil { - log.Fatalf("Error: %v", err) + log.Fatalf("cannot parse identity %q: %v", name, err) } identities = append(identities, ids...) } - r, err := age.Decrypt(os.Stdin, identities...) + r, err := age.Decrypt(in, identities...) if err != nil { - log.Fatalf("Error initializing decryption: %v", err) + log.Fatalf("cannot initialize encryption: %v", err) } - if _, err := io.Copy(os.Stdout, r); err != nil { - log.Fatalf("Error decrypting the input: %v", err) + if _, err := io.Copy(out, r); err != nil { + log.Fatalf("cannot decrypt input: %v", err) } } diff --git a/go.mod b/go.mod @@ -2,4 +2,7 @@ module github.com/FiloSottile/age go 1.13 -require golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc +require ( + golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc + golang.org/x/sys v0.0.0-20191008105621-543471e840be // indirect +) diff --git a/go.sum b/go.sum @@ -3,6 +3,7 @@ golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5 golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=