-
-
Notifications
You must be signed in to change notification settings - Fork 511
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
age,cmd/age: add ParseRecipients and -R for recipient files
- Loading branch information
1 parent
7ab2008
commit f8507c1
Showing
6 changed files
with
199 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,13 +22,15 @@ An alternative interoperable Rust implementation is available at [github.com/str | |
``` | ||
Usage: | ||
age -r RECIPIENT [-a] [-o OUTPUT] [INPUT] | ||
age --passphrase [-a] [-o OUTPUT] [INPUT] | ||
age --decrypt [-i KEY] [-o OUTPUT] [INPUT] | ||
Options: | ||
-o, --output OUTPUT Write the result to the file at path OUTPUT. | ||
-a, --armor Encrypt to a PEM encoded format. | ||
-p, --passphrase Encrypt with a passphrase. | ||
-r, --recipient RECIPIENT Encrypt to the specified RECIPIENT. Can be repeated. | ||
-R, --recipients-file PATH Encrypt to recipients listed at PATH. Can be repeated. | ||
-d, --decrypt Decrypt the input to the output. | ||
-i, --identity KEY Use the private key file at path KEY. Can be repeated. | ||
|
@@ -37,6 +39,9 @@ INPUT defaults to standard input, and OUTPUT defaults to standard output. | |
RECIPIENT can be an age public key, as generated by age-keygen, ("age1...") | ||
or an SSH public key ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). | ||
Recipient files contain one or more recipients, one per line. Empty lines | ||
and lines starting with "#" are ignored as comments. | ||
KEY is a path to a file with age secret keys, one per line | ||
(ignoring "#" prefixed comments and empty lines), or to an SSH key file. | ||
Multiple keys can be provided, and any unused ones will be ignored. | ||
|
@@ -51,6 +56,19 @@ $ age -o example.jpg.age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sf | |
-r age1lggyhqrw2nlhcxprm67z43rta597azn8gknawjehu9d9dl0jq3yqqvfafg example.jpg | ||
``` | ||
|
||
#### Recipient files | ||
|
||
Multiple recipients can also be listed one per line in one or more files passed with the `-R/--recipients-file` flag. | ||
|
||
``` | ||
$ cat recipients.txt | ||
# Alice | ||
age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p | ||
# Bob | ||
age1lggyhqrw2nlhcxprm67z43rta597azn8gknawjehu9d9dl0jq3yqqvfafg | ||
$ age -R recipients.txt example.jpg > example.jpg.age | ||
``` | ||
|
||
### Passphrases | ||
|
||
Files can be encrypted with a passphrase by using `-p/--passphrase`. By default age will automatically generate a secure passphrase. Passphrase protected files are automatically detected at decrypt time. | ||
|
@@ -68,9 +86,7 @@ Enter passphrase: | |
As a convenience feature, age also supports encrypting to `ssh-rsa` and `ssh-ed25519` SSH public keys, and decrypting with the respective private key file. (`ssh-agent` is not supported.) | ||
|
||
``` | ||
$ cat ~/.ssh/id_ed25519.pub | ||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZDRcvS8PnhXr30WKSKmf7WKKi92ACUa5nW589WukJz [email protected] | ||
$ age -r "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZDRcvS8PnhXr30WKSKmf7WKKi92ACUa5nW589WukJz" example.jpg > example.jpg.age | ||
$ age -R ~/.ssh/id_ed25519.pub example.jpg > example.jpg.age | ||
$ age -d -i ~/.ssh/id_ed25519 example.jpg.age > example.jpg | ||
``` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright 2021 Google LLC | ||
// | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file or at | ||
// https://developers.google.com/open-source/licenses/bsd | ||
|
||
package age | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"strings" | ||
) | ||
|
||
// ParseIdentities parses a file with one or more private key encodings, one per | ||
// line. Empty lines and lines starting with "#" are ignored. | ||
// | ||
// This is the same syntax as the private key files accepted by the CLI, except | ||
// the CLI also accepts SSH private keys, which are not recommended for the | ||
// average application. | ||
// | ||
// Currently, all returned values are of type *X25519Identity, but different | ||
// types might be returned in the future. | ||
func ParseIdentities(f io.Reader) ([]Identity, error) { | ||
const privateKeySizeLimit = 1 << 24 // 16 MiB | ||
var ids []Identity | ||
scanner := bufio.NewScanner(io.LimitReader(f, privateKeySizeLimit)) | ||
var n int | ||
for scanner.Scan() { | ||
n++ | ||
line := scanner.Text() | ||
if strings.HasPrefix(line, "#") || line == "" { | ||
continue | ||
} | ||
i, err := ParseX25519Identity(line) | ||
if err != nil { | ||
return nil, fmt.Errorf("error at line %d: %v", n, err) | ||
} | ||
ids = append(ids, i) | ||
} | ||
if err := scanner.Err(); err != nil { | ||
return nil, fmt.Errorf("failed to read secret keys file: %v", err) | ||
} | ||
if len(ids) == 0 { | ||
return nil, fmt.Errorf("no secret keys found") | ||
} | ||
return ids, nil | ||
} | ||
|
||
// ParseRecipients parses a file with one or more public key encodings, one per | ||
// line. Empty lines and lines starting with "#" are ignored. | ||
// | ||
// This is the same syntax as the recipients files accepted by the CLI, except | ||
// the CLI also accepts SSH recipients, which are not recommended for the | ||
// average application. | ||
// | ||
// Currently, all returned values are of type *X25519Recipient, but different | ||
// types might be returned in the future. | ||
func ParseRecipients(f io.Reader) ([]Recipient, error) { | ||
const recipientFileSizeLimit = 1 << 24 // 16 MiB | ||
var recs []Recipient | ||
scanner := bufio.NewScanner(io.LimitReader(f, recipientFileSizeLimit)) | ||
var n int | ||
for scanner.Scan() { | ||
n++ | ||
line := scanner.Text() | ||
if strings.HasPrefix(line, "#") || line == "" { | ||
continue | ||
} | ||
r, err := ParseX25519Recipient(line) | ||
if err != nil { | ||
// Hide the error since it might unintentionally leak the contents | ||
// of confidential files. | ||
return nil, fmt.Errorf("malformed recipient at line %d", n) | ||
} | ||
recs = append(recs, r) | ||
} | ||
if err := scanner.Err(); err != nil { | ||
return nil, fmt.Errorf("failed to read recipients file: %v", err) | ||
} | ||
if len(recs) == 0 { | ||
return nil, fmt.Errorf("no recipients found") | ||
} | ||
return recs, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters