Coder Social home page Coder Social logo

filosottile / age Goto Github PK

View Code? Open in Web Editor NEW
15.4K 148.0 466.0 1.48 MB

A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability.

Home Page: https://age-encryption.org

License: BSD 3-Clause "New" or "Revised" License

Go 100.00%
built-at-rc age-encryption

age's Introduction

The age logo, a wireframe of St. Peters dome in Rome, with the text: age, file encryption

Go Reference man page C2SP specification

age is a simple, modern and secure file encryption tool, format, and Go library.

It features small explicit keys, no config options, and UNIX-style composability.

$ age-keygen -o key.txt
Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
$ tar cvz ~/data | age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age
$ age --decrypt -i key.txt data.tar.gz.age > data.tar.gz

📜 The format specification is at age-encryption.org/v1. age was designed by @Benjojo12 and @FiloSottile.

📬 Follow the maintenance of this project by subscribing to Maintainer Dispatches!

🦀 An alternative interoperable Rust implementation is available at github.com/str4d/rage.

🔑 Hardware PIV tokens such as YubiKeys are supported through the age-plugin-yubikey plugin.

✨ For more plugins, implementations, tools, and integrations, check out the awesome age list.

💬 The author pronounces it [aɡe̞] with a hard g, like GIF, and is always spelled lowercase.

Installation

Homebrew (macOS or Linux) brew install age
MacPorts port install age
Alpine Linux v3.15+ apk add age
Arch Linux pacman -S age
Debian 12+ (Bookworm) apt install age
Debian 11 (Bullseye) apt install age/bullseye-backports (enable backports for age v1.0.0+)
Fedora 33+ dnf install age
Gentoo Linux emerge app-crypt/age
NixOS / Nix nix-env -i age
openSUSE Tumbleweed zypper install age
Ubuntu 22.04+ apt install age
Void Linux xbps-install age
FreeBSD pkg install age (security/age)
OpenBSD 6.7+ pkg_add age (security/age)
Chocolatey (Windows) choco install age.portable
Scoop (Windows) scoop bucket add extras; scoop install age

On Windows, Linux, macOS, and FreeBSD you can use the pre-built binaries.

https://dl.filippo.io/age/latest?for=linux/amd64
https://dl.filippo.io/age/v1.1.1?for=darwin/arm64
...

If your system has a supported version of Go, you can build from source.

go install filippo.io/age/cmd/...@latest

Help from new packagers is very welcome.

Usage

For the full documentation, read the age(1) man page.

Usage:
    age [--encrypt] (-r RECIPIENT | -R PATH)... [--armor] [-o OUTPUT] [INPUT]
    age [--encrypt] --passphrase [--armor] [-o OUTPUT] [INPUT]
    age --decrypt [-i PATH]... [-o OUTPUT] [INPUT]

Options:
    -e, --encrypt               Encrypt the input to the output. Default if omitted.
    -d, --decrypt               Decrypt the input to the output.
    -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.
    -i, --identity PATH         Use the identity file at PATH. Can be repeated.

INPUT defaults to standard input, and OUTPUT defaults to standard output.
If OUTPUT exists, it will be overwritten.

RECIPIENT can be an age public key 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. "-" may be used to
read recipients from standard input.

Identity files contain one or more secret keys ("AGE-SECRET-KEY-1..."),
one per line, or an SSH key. Empty lines and lines starting with "#" are
ignored as comments. Passphrase encrypted age files can be used as
identity files. Multiple key files can be provided, and any unused ones
will be ignored. "-" may be used to read identities from standard input.

When --encrypt is specified explicitly, -i can also be used to encrypt to an
identity file symmetrically, instead or in addition to normal recipients.

Multiple recipients

Files can be encrypted to multiple recipients by repeating -r/--recipient. Every recipient will be able to decrypt the file.

$ age -o example.jpg.age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \
    -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

If the argument to -R (or -i) is -, the file is read from standard input.

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.

$ age -p secrets.txt > secrets.txt.age
Enter passphrase (leave empty to autogenerate a secure one):
Using the autogenerated passphrase "release-response-step-brand-wrap-ankle-pair-unusual-sword-train".
$ age -d secrets.txt.age > secrets.txt
Enter passphrase:

Passphrase-protected key files

If an identity file passed to -i is a passphrase encrypted age file, it will be automatically decrypted.

$ age-keygen | age -p > key.age
Public key: age1yhm4gctwfmrpz87tdslm550wrx6m79y9f2hdzt0lndjnehwj0ukqrjpyx5
Enter passphrase (leave empty to autogenerate a secure one):
Using the autogenerated passphrase "hip-roast-boring-snake-mention-east-wasp-honey-input-actress".
$ age -r age1yhm4gctwfmrpz87tdslm550wrx6m79y9f2hdzt0lndjnehwj0ukqrjpyx5 secrets.txt > secrets.txt.age
$ age -d -i key.age secrets.txt.age > secrets.txt
Enter passphrase for identity file "key.age":

Passphrase-protected identity files are not necessary for most use cases, where access to the encrypted identity file implies access to the whole system. However, they can be useful if the identity file is stored remotely.

SSH keys

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.)

$ age -R ~/.ssh/id_ed25519.pub example.jpg > example.jpg.age
$ age -d -i ~/.ssh/id_ed25519 example.jpg.age > example.jpg

Note that SSH key support employs more complex cryptography, and embeds a public key tag in the encrypted file, making it possible to track files that are encrypted to a specific public key.

Encrypting to a GitHub user

Combining SSH key support and -R, you can easily encrypt a file to the SSH keys listed on a GitHub profile.

$ curl https://github.com/benjojo.keys | age -R - example.jpg > example.jpg.age

Keep in mind that people might not protect SSH keys long-term, since they are revokable when used only for authentication, and that SSH keys held on YubiKeys can't be used to decrypt files.

age's People

Contributors

0x2b3bfa0 avatar a1346054 avatar alerque avatar andreaswachowski avatar andros21 avatar brandsimon avatar buriedintheground avatar codesoap avatar eclipseo avatar exsplashit avatar filosottile avatar hakerdefo avatar indrayam avatar mehrbeniss avatar mfs avatar mikecook avatar mjkalyan avatar mschneider82 avatar puenka avatar qbit avatar rex4539 avatar rkinsey avatar ryancdotorg avatar shimmy1996 avatar tionis avatar twpayne avatar y-yagi avatar z399 avatar zhsj avatar zombiezen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

age's Issues

UX: Handle Multiple SSH Keys/Recipients in Single Flag Input

What were you trying to do

Use age to encrypt a file with multiple SSH recipients in a single flag-passed -r, --recipient value.

What happened

(didn't "happened", rather cannot happen)

I'm trying to encrypt a file with multiple SSH recipients by grabbing their public SSH keys set on Github. The command is:

age -r "$(curl https://github.com/<username>.keys)" -o encrypted-file.txt to-encrypt.txt

Currently, the -r,--recipient flag can be used multiple times to pass multiple keys. However, it doesn't expect a single passing to contain multiple keys, and discards the rest returned from ssh.ParseAuthorizedKey (4th-positioned return value):

age/internal/age/ssh.go

Lines 150 to 152 in bbab440

func ParseSSHRecipient(s string) (Recipient, error) {
pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(s))
if err != nil {

The ssh.ParseAuthorizedKey func will look for the first \n, split the input at the point, and return the rest:

https://github.com/golang/crypto/blob/53104e6ec876ad4e22ad27cce588b01392043c1b/ssh/keys.go#L178-L180

Without -r,--recipient accepting multiple SSH keys at once, user will either have to download the keys (i.e. wget https://github.com/<username>.keys), split them into multiple files, and pass -r as many times as the number of files resulting from splitting <username.keys>; or they will have to use some clever shell tricks to split them and pass multiple -r in a one-liner.

UX: Encrypt private key by default

What were you trying to do

I was playing with the Age beta, generating keys

What happened

I think that in spite of solid UNIX file permissions, the default behaviour should be to encrypt private keys with a symmetric key derived from a password.

Is there an intention to add this feature to Age? If not how best should users. secure plaintext private key material?

Reading the document on Age I see:

Maybe native support for key wrapping (to implement password-protected keys)

However surely that's a fundamental need, otherwise private key material sits in plaintext.

UX: Confirm passphrase

What were you trying to do

Encrypting a file with a passphrase.

What happened

Passphrase was only asked once (no confirmation was asked).

While asking for a confirmation of the passphrase is not foolproof, it may help prevent typos when encrypting files (the user may assume that everything went fine and delete the unencrypted file, only to later find out that the file had been encrypted with a wrong passphrase).

Question: What's the maximum file size to encrypt/decrypt

I'm a simple developer with very little crypto knowledge, so I'm trying to understand how age works internally.

age is using authenticated encryption and is using streaming/chunking so that you can encrypt/decrypt large files without having to put the whole file into the RAM.

The chunk size is 64 KiB, the encrypted chunk size is encChunkSize = ChunkSize + poly1305.TagSize, what's 65 KiB + 16 KiB = 81 KiB.

I've read that we have to include the order of the chunk in the encrypted chunk so that you cannot change the ciphertext (mix up encrypted chunks).

How I read the age documentation, the Poly1305 authenticator (16 bytes) is a random nonce. Also, in the STREAM algorithm, a 11 byte nonce and a 1 byte last block flag is used.

As far as I understand, the 11 byte nonce is for indicating the order of the chunk, with chunk1, the 11 byte nonce is 1, with chunk2, the 11 byte nonce is 2, etc.

So, does this mean that the theoretical max. size of file age can handle is 2^(11*8)*64 KiB?

Sorry in case it does not make any sense, I'm just trying to understand. 😄

UX: Command arguments are order sensitive

What were you trying to do

Decrypt using a custom key.

What happened

I received an error stating too many arguments. The problem seemed to be that I had the -d <filename> before the -i <filename>. Reversing these two arguments caused age to behave as I expected.

The error message as stated made me think the problem was in the -i <filename> component of the command as it just says "input file", but I think the problem was that it tried to keep reading more files for the -d parameter when I expected it to stop and go on to the -i parameter input.

$ age -d test.age -i ~/.config/age/keys.txt
Error: too many arguments.
age accepts a single optional argument for the input file.
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]

$ age -i ~/.config/age/keys.txt -d test.age
hello there

Inspect encrypted file details

What were you trying to do

Identify file's recipients, or at least how many recipients there are.

What happened

I created an ascii armored encrypted file. age gives no way to list its recipients, as it does in the binary format (excluding some bash magic relying on the knowledge that the PEM uses base64).

$ age-keygen -o key.txt
Public key: age13u320nw4pv6pv7qrve2epr4r7233ms2x68r3y3tt653nyvg5y3jst3apxw
[0]$ echo 'Hello age' | age -a -r 'age13u320nw4pv6pv7qrve2epr4r7233ms2x68r3y3tt653nyvg5y3jst3apxw' -o encrypted.age.ascii
[0]$ cat encrypted.age.ascii
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyUElIMVBpZThuVkh0WDVZ
TUwrSmxuNk1xZFI1dHliNy9Nd0ptZ0UrOVUwCi8wRzc0djRwemZHanJGTGhNb0pB
M0NQTzFQUzFzNEtpclIxeTh2ZkFwR0kKLS0tIFMxUjdZczEyVzZBczNvTGJmZ1VN
Z1hoMWxVOHEwcm40TnZ1VWcvRGM4R0kKQASOAFMfE0DMdj++onPwdeByjMGRP6Sj
3PbGzfjpktCw9HJ14r+qX9B/
-----END AGE ENCRYPTED FILE-----
[0]$ tail -n +2 encrypted.age.ascii | base64 -d
age-encryption.org/v1
-> X25519 2PIH1Pie8nVHtX5YML+Jln6MqdR5tyb7/MwJmgE+9U0
/0G74v4pzfGjrFLhMoJA3CPO1PS1s4KirR1y8vfApGI
--- S1R7Ys12W6As3oLbfgUMgXh1lU8q0rn4NvuUg/Dc8GI
@�S@�v?��s�u�r���?���������а�ru⿪_�base64: invalid input

As a matter of fact, a pretty listing of recipients would also be useful for non-armored files, if it could present the files in the same format as originially (e.g. to visually match/grep ssh pubkey to one of the files in ~/.ssh/id_rsa). And be a good follow up for the error message "Error: no identity matched a recipient".

Side note - confusing feature set of beta

By browsing this repo's issues, the mailing list and the age specification, I encountered various potential methods of storing the keys and specifying recipients (the ~/.config/age/keys.txt path, recipient's github username, providing https url of the keys). None of them seemed to work. It would be nice for the repo's readme to be more explicit about which parts are NOT implemented in the current version.

Don't take passphrase via CLI param

On unix systems, each unprivileged user has read access to the CLI params of all processes running on the system. Thus, CLI params are to be considered public information and are to be deemed unfit as a means to transport secret data like passphrases. age shouldn't support a mode that takes the passphrase as CLI params. Safer alternatives are manual prompting as well as environment variables.

An Argument for Signing Support

According to the specification, signing of any type is out of scope:

  • Any kind of signing (which is not a tooling problem, but a trust and key distribution problem, and to the extent that tools matter you should just use signify/minisign, and for keys we should probably use SSH ones)

This is, in my opinion, a missed opportunity. This project is an opportunity to not only build a new tool that addresses issues that plague other tools (such as GPG), but also to build support in the community around this tool. By placing this restriction on the functionality that age may contain, age is less useful, and will require the use off additional tools (and additional keys to manage) to achieve the same functionality that users will likely expect.

This expectation can be demonstrated by looking at the open issues (such as #38 & #49), and conversation on Twitter about age - the lack of signing support is striking potential users as a surprise, as it would be assumed that a tool of this nature would include signing support. There is, without question, user interest in this feature.

There are, as noted in the quoted section above, issues with signing support, in that it can involve key distribution and trust, which are complex issues - that said, these issues need not be addressed by age, as a solution is not required to allow users that wish to validate that an encrypted file is from the expected sender/system to perform this validation. Adding optional support for signing a file with the sender's key is a trivial matter; adding an additional header to the age file format is a simple matter, adding CLI support for this is likewise, a simple matter.

In use cases where it is desirable to validate the sender, it would not be unreasonable to require users to transmit their public key out-of-band (from a UX perspective, this could use the proposed aliases.txt file to display a friendly name for known senders). It is possible that key distribution methods could evolve around age, though these should be allowed to evolve organically, and it is not necessary for age to address this at this point in time.

While there are tools such as signify and minisign (which I am personally a fan of), it is not a good user experience to require users to make use of an additional tool, with additional keys, to perform signing of files they produce.

I would propose that an optional header be added, which includes the sender's public key and a signature of the hash of the encrypted data. When a file is decrypted, this signature would be validated, and decryption should fail if this check fails. The user can either manually review the public key for a match to known senders, or age could look up the public key in the proposed aliases.txt file and display a friendly name. This could be done with minimal impact, would improve protection of files that have been signed, and require no extra effort from those that don't have a need to perform this validation.

I appreciate that this could lead to a push for greater development of a key distribution & trust solution (which could evolve into a interesting side project, though that's another conversation), though it will without doubt lead to a better user experience and lead to further use cases for age.

UX: Confusing error message when decrypting with incorrect passphrase

I’ve encrypted simple string using a passphrase. Then I tried to decrypt it, and got message saying saying “Error: no identity matched a recipient”. It took me a few retries to understand that entered passphrase is incorrect. If possible, can this message be improved?

~/age$ cat out | ./age -d
Enter passphrase: <wrong>
Error: no identity matched a recipient
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
~/age$ 

UX: Support reading password from file(descriptor)

It would be very useful, if age supported reading password from file descriptor/path.
It can be done safely, it would be useful for automation and AFAIU it is the only encryption mode that actually does authenticated encryption.

AFAIK types of usage shown below should be safe. Both can less or more practically be read by the same user, but a more permanent private key would be even easier to read.

age --password-fd <( <<< "$PASS") ...
pwfile=$(mktemp /dev/shm/XXXXXX)
cat > "$pwfile" << EOF
$PASS
EOF
age --password-fd "$pwfile" ...
rm "$pwfile"

Don't decrypt unless it's a ramdisk

Currently age, just like gpg, supports decrypting to files. However, files are usually stored on permanent storage media. However, on contemporary file systems, deletion of a file does not lead to deletion of its contents in the block device. And even tools like shred don't help you with modern SSDs which have a complicated wear levelling layer between you and the hardware: shredding won't necessarily overwrite the data at all.

The only way to use age safely is by using a ramdisk. Therefore, age should refuse operation if the location of the decrypted file is not on a ramdisk. If swap is available on the system, even tmpfs is a danger as it can be paged as well. Maybe if swap is detected, a warning could be emitted?

[spec] Per-recipient format is unspecified

The spec currently says:

Each recipient line starts with -> and its type name and can be followed by any number of arguments and additional lines. Unknown recipient types are ignored.

encode(data) is canonical base64url from RFC 4648 without padding, wrapped at 57 cols.

[...]

An X25519 recipient line is
-> X25519 encode(X25519(ephemeral secret, basepoint))
encode(encrypt[HKDF[salt, label](X25519(ephemeral secret, public key), 32)](file key))

This is insufficiently-specified, and does not indicate how arguments and additional lines should be parsed. In particular:

  • Should multi-space separators be allowed? (@FiloSottile has already said no)
  • For each recipient line type, which arguments should be space-separated and which should be newline-separated? The current Google Doc format in particular makes it very difficult to distinguish between the two.
  • How should cross-platform newlines be handled? (see also #2)
  • How should multiple arguments that require wrapping be handled? In particular, how should a parser distinguish a single wrapped argument, and two wrapped arguments where the first one's encoding is an integer multiple of 57 characters?

UX: encrypting to multiple recipients in a file

What were you trying to do

Encrypt to multiple recipients in a file called age1aaaa:

$ age -a -r age1aaaa`

What happened

Error: unknown recipient type: "age1aaaa"

I suspect that this feature is not implemented yet. But anyway, how does age is supposed to know if -r is a path or a Bech32 identity? Should it try to open that file or print a warning?

[spec] Consider storing log(N) in scrypt recipient line

The scrypt library I am using in my Rust implementation takes log(N) as a parameter, which requires a bit of additional logic to handle (computing log(N) from N and verifying that N was an exact power of 2).

Per RFC 7914 section 6:

N: CPU/Memory cost parameter, must be larger than 1, a power of 2, and less than 2^(128 * r / 8).

If N must always be a power of 2, then we could simplify the format and implementations by instead storing log(N). This would remove the need for power-of-two checks, and converting log(N) to N for APIs that take N is a trivial bitshift.

CLI user interface?

Hi,

thanks a lot for writing age, I'm really looking forward to using it!

Is the CLI user interface already fixed, or are you open to a discussion about it?

I'd like to propose the following:

  • Add subcommands (like git and go):
    • age encrypt (maybe default?)
    • age decrypt
    • age generate
  • Use the double-dash syntax (maybe with pflag?) to distinguish between short and long options

With these proposed modifications, the commands from the spec would look as follows:

$ age generate > key.txt

$ echo "_o/" | age encrypt pubkey:98W5ph53zfPGOzEOH-fMojQ4jUY7VLEmtmozREqnw4I > hello.txt.age

$ age decrypt key.txt < hello.txt.age
_o/

$ tar cv ~/xxx | age encrypt github:Benjojo github:FiloSottile | nc 192.0.2.0 1234

$ echo "_o/" | age encrypt -o hello.age pubkey:98W5ph53zfPGOzEOH-fMojQ4jUY7VLEmtmozREqnw4I

$ age encrypt -i hello.txt -o hello.txt.age -p
Type passphrase:

The upsides are:

  • Adding subcommands would avoid ambiguities by forcing the user to be explicit about the intended operation. With gpg, I'm never entirely sure if it is in encrypt or decrypt or signing or whatever mode. In addition, this makes it easy to distinguish between a command (generate, encrypt) and an option (--output, --recipient etc.).
  • Make it clear to the user that subcommands are mutually exclusive: age encrypt generate -o foo is clearly wrong, but age -encrypt -generate -o foo is not so clear in my opinion.

For the flag parsing, I really like http://github.com/spf13/pflag, we could also implement that ourselves. Subcommands can be implemented without an external dependency. What's your take on dependencies for age? Stdlib only?

What do you think? I'm willing to help set this up if you're up for it, if not please just close this issue and carry on. Thanks!

Feature request: Support for symmetric key files

I would like to consider the age format for some future applications, however a common requirement is the use of key files instead of passwords, especially where no user interaction is given.
The key files in these scenarios are used as symmetric keys and optionally protected by a master password. One of the application ideas is similar to a rachet with pre shared symmetric keys, where the user enters a password to access an app and decrypt the keyfiles for the session.

Currently supported in age:

  • asymmetric keys
  • passwords (interactive only)

Wanted feature:

  • symmetric keys

Can't compile: undefined: ssh.PassphraseNeededError

Trying to build it, I get:

dreadnought:~ fastidious$ go get github.com/FiloSottile/age/cmd/age/
# github.com/FiloSottile/age/cmd/age
go/src/github.com/FiloSottile/age/cmd/age/parse.go:86:25: undefined: ssh.PassphraseNeededError

Go version go1.13.1 darwin/amd64.

UX: RECIPIENT

What were you trying to do

Tried to understand the purpose of RECIPIENT

What will it happen if someone tried to brute force with RECIPIENT key, are the mechanism to avoid encrypted files in form of binary or plaintext from being decrypt?

Signing and signature validation

As I understand, the project is "pgp killer" that sounds incredibly cool.

  1. Is it possible to sign a text and validate signature?
  2. Is it possible to use ssh key pair for it?

Sorry if I missed something from the readme.

UX: Can't intermix arguments and options

I keep getting this:

~/age/cmd/age % ./age -d blorp --output snort
Error: too many arguments.
age accepts a single optional argument for the input file.
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
~/age/cmd/age % ./age -d --output snort blorp 
... success

One way to handle this would be to make the input an option (-i, --input), and not have any arguments at all. (But see bug #30 about using arguments for subcommands.) That would be maximally consistent and clear.

UX:

What were you trying to do

encrypt and then decrypt a message to myself

What happened

[her@noodlieness keys]$ keepo-keygen -o blinko.txt
Public key: age1uk0cpzk0m6yvhy4nhu636hmeq5taklwedxyvq5yqw2pjezec3aeqr6z6tf
[her@noodlieness keys]$ cat blinko.txt 
# created: 2019-12-27T18:11:59-08:00
# public key: age1uk0cpzk0m6yvhy4nhu636hmeq5taklwedxyvq5yqw2pjezec3aeqr6z6tf
AGE-SECRET-KEY-18WHG2YFG6XTTJASHXXUFD3WRAD0MN6VSR6H3C4FWPE00FUQ6LP2QKMLPLV
[her@noodlieness keys]$ touch psst.txt
[her@noodlieness keys]$ echo BANANARAMA >> psst.txt
[her@noodlieness keys]$ age -i psst.txt -o psst.age
bash: age: command not found...
Failed to search for file: Failed to download gpg key for repo 'google-cloud-sdk': Status code: 404 for https://packages.cloud.google.com/yum/doc/yum-key.gpg;https:/packages.cloud.google.com/yum/doc/rpm-package-key.gpg (IP: 172.217.14.238)
[her@noodlieness keys]$ keepo -i psst.txt -o psst.keepo
Error: -i/--identity can't be used in encryption mode.
Did you forget to specify -d/--decrypt?
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ age -e psst.txt
bash: age: command not found...
Failed to search for file: Failed to download gpg key for repo 'google-cloud-sdk': Status code: 404 for https://packages.cloud.google.com/yum/doc/yum-key.gpg;https:/packages.cloud.google.com/yum/doc/rpm-package-key.gpg (IP: 172.217.14.238)
[her@noodlieness keys]$ keepo -e psst.txt
flag provided but not defined: -e
Usage:
    age -r RECIPIENT [-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.
    -d, --decrypt               Decrypt the input to the output.
    -i, --identity KEY          Use the private key file at path KEY. Can be repeated.

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...").

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.

Example:
    $ age-keygen -o key.txt
    Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
    $ tar cvz ~/data | age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age
    $ age -d -i key.txt -o data.tar.gz data.tar.gz.age
[her@noodlieness keys]$ ls
blinko.txt  psst.txt
[her@noodlieness keys]$ keepo -i blinko.txt -r blinko.txt -o psst.keepo
Error: -i/--identity can't be used in encryption mode.
Did you forget to specify -d/--decrypt?
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ keepo -r blinko.txt -o psst.keepo
Error: unknown recipient type: "blinko.txt"
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ cat blinko.txt 
# created: 2019-12-27T18:11:59-08:00
# public key: age1uk0cpzk0m6yvhy4nhu636hmeq5taklwedxyvq5yqw2pjezec3aeqr6z6tf
AGE-SECRET-KEY-18WHG2YFG6XTTJASHXXUFD3WRAD0MN6VSR6H3C4FWPE00FUQ6LP2QKMLPLV
[her@noodlieness keys]$ keepo -r age1uk0cpzk0m6yvhy4nhu636hmeq5taklwedxyvq5yqw2pjezec3aeqr6z6tf -o psst.keepo psst.txt
Error: failed to open output file "psst.keepo": open psst.keepo: file exists
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ rm psst.keepo
[her@noodlieness keys]$ keepo -r age1uk0cpzk0m6yvhy4nhu636hmeq5taklwedxyvq5yqw2pjezec3aeqr6z6tf -o psst.keepo psst.txt
[her@noodlieness keys]$ ls
blinko.txt  psst.keepo  psst.txt
[her@noodlieness keys]$ cat psst.keepo
age-encryption.org/v1
-> X25519 kvPkGMflX3AUVKiNx6kSwRFh+pHbSqBiKPl9cHaQVwQ
UmUNKlfqVvtay5VF8NBvTm94pFF1TwzqzISAZsC7riw
--- tl8SAlrTcCE1sAiKz/wRzv7VKu1wDmit3cc1RV+Mk5c
�
����8o�@�U�=����-6�[`��
q�g]$���c��Y[her@noodlieness keys]$ keepo -d psst.keepo
Error: no identity matched a recipient
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ keepo -d psst.keepo -i blinko.txt
Error: too many arguments.
age accepts a single optional argument for the input file.
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ keepo -d psst.keepo
Error: no identity matched a recipient
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ rm psst.keepo
[her@noodlieness keys]$ keepo -r age1uk0cpzk0m6yvhy4nhu636hmeq5taklwedxyvq5yqw2pjezec3aeqr6z6tf -o keepo.psst psst.txt
[her@noodlieness keys]$ keepo -d keepo.psst
Error: no identity matched a recipient
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ keepo -i AGE-SECRET-KEY-18WHG2YFG6XTTJASHXXUFD3WRAD0MN6VSR6H3C4FWPE00FUQ6LP2QKMLPLV -d keepo.psst
Error: failed to open file: open AGE-SECRET-KEY-18WHG2YFG6XTTJASHXXUFD3WRAD0MN6VSR6H3C4FWPE00FUQ6LP2QKMLPLV: no such file or directory
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
[her@noodlieness keys]$ keepo -i blinko.txt -d keepo.psst
BANANARAMA
[her@noodlieness keys]$ 

In the end it was the fact that I had to use the raw key as a recipient, and the identity file itself when decoding.

Otherwise, I love it! Thank you! I'm going to use it in production, because I'm a frothing mad data scientist.

On FreeBSD tests output unprintable/undersired characters

Environment

  • OS: FreeBSD 13-CURRENT
  • age version: 18edf29

What were you trying to do

Run go test -v ./...

What happened

--- PASS: TestEncryptDecryptX25519 (0.00s)
    age_test.go:54: age-encryption.org/v1
        -> X25519 q3dn6jIZ6k8iKh+gzunWgZTdaCQUrhIRB7yKScaVMkI
        tEWRgdEAtRhUwyDZ0NjhYtA0put9gRJSs4yglLzBQDA
        -> X25519 3LZOn5XR3Nv4B1VVquM/yJw0b+YeMwG8DsGYxTaxqD8
        pcDSuDIk/CIjsxDDSzhruhTMpGvza+Hq83tqGWuwn7E
        --- +R/FzWzYipcHNaaYJoovYt5iQ9tKJIE7xw70TVVPr4Y
        J�9M7�M�v��*�T���(�%8|hr��nϹ�s

Noticed while trying to add FreeBSD CI via Cirrus-CI and it seems that Cirrus does not display the test output: https://cirrus-ci.com/task/5140345440698368

Output is visible in the full log https://api.cirrus-ci.com/v1/task/5140345440698368/logs/test.log

age fails to decrypt files generated in Windows PowerShell

When attempting a round trip on Windows using PowerShell, age errors out when trying to decrypt a file. I have confirmed the exact same steps work fine in WSL.

It creates the key file and the encrypted .age file properly as far as I can tell.

Steps to reproduce:

  1. ./age -generate > key.txt
  2. echo "Gophers" | ./age pubkey:h-yq6lhyIAdDc23LVXP_h1X5wpIgHvNk8kvbV0auhG4 > test.txt.age
  3. /.age -d key.txt | Get-Content -raw test.txt.age
  4. See error of: error: malformed secret keys file "key.txt": malformed secret key: ��# c r e a t e d : 2 0 1 9 - 1 0 - 0 7 T 0 0 : 0 5 : 3 7 - 0 5 : 0 0

key.txt contents (CRLF line endings):

# created: 2019-10-07T00:22:04-05:00
# pubkey:xmAE7g4IsPELqsEkUEner7mlIu4pi2qwda0-s8eq3jw
AGE_SECRET_KEY_MZuIdDrlt4dRUXlmO6FdVwXMHrhzXdgxxgj4yaj9Z14

ssh agent support

I've made a POC for ssh agent support by creating a ssh-agent which uses the ssh-agent extension mechanism. (this way we can keep our keys secure on our devices)

Is this something you would want to support (I can make a PR) or is this out of scope?

UX: Show usage on naked command

What were you trying to do

Show the usage documentation.

What happened

$ age
Error: missing recipients.
Did you forget to specify -r/--recipient or -p/--passphrase?
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]

Additional detail

Right after installing age, most people are going want to see the usage output. It makes for a better user experience if you show the usage / help for all things that the user might try, instead of making the user try multiple different flags to get the usage to appear.

I'd suggest displaying the usage output when age is run with any of the following arguments:

  • age
  • age help
  • age --help
  • age -h

Release binaries for linux/arm64

Perhaps as a piece of #25, consider producing linux/arm64 binaries.

I was able to build on this platform and go test -v ./... passed. There's also test support for arch: arm64 on Travis CI.

UX: Consistent capitalisation on public/private keys

What were you trying to do

I generated a new public/private key.

What happened

Keys are generated, but the public key have all lower case letters, whilst the private key have all capitalised. Can they both be set to be capitalised—or lowercased, it doesn't matter, I am looking for consistency.

UX: Program naming and potential searchability difficulty

What were you trying to do

Discover age as a potential tool to use having heard of it only by formal name or seen in a lightly-commented script file.

What happened

Standalone, age is a simple English word and a notable substring of other words used in package managers. For example, while Macports is currently not a supported package manage for installing age on MacOS, the following searches show how the name is essentially useless for finding the package without necessarily an exact match:

$ port search --name age | grep Found
Found 313 ports.
$ port search age | grep Found
Found 2336 ports.

It would be fairly impractical to sort through these long lists trying to see if age is available without prior knowledge.

Search-confounding words include, but are not limited to: manager, management, language, package, damage, agent, image, message, usage.

Is there a way to improve the naming or searchability of the name of this utility?

[spec] format for armored files

I noticed that @str4d recently implemented support for an ASCII armored file format in rage:

str4d/rage@da92349
str4d/rage@9e779dd

But I don't see anything in the spec about this format currently. I assume at this point that the two of you are in touch about it (or will be soon anyway), but it'd be good to keep the spec up to date as well.

Consider goreleaser for building releases

goreleaser makes it really easy to build Go binaries for multiple platforms, including generating .rpms, .debs, tarballs, zip files, Homebrew formulae, Snapcrafts, Scoops, and the like. It would be a great fit for age.

Let me know if you'd like a PR that adds this. Thanks to @joemiller who contributed this to chezmoi in twpayne/chezmoi#33 - I'd like to pay the contribution forward.

Feature request: Support public key authenticated encryption

Currently age encryption with X25519 or ssh keys is unauthenticated. While the use of an AEAD for encryption of the file contents prevents tampering with the ciphertext, an attacker who is in a position to do such tampering can instead just replace the entire file with their own encrypted contents.

Although this doesn’t impact the confidentiality of age-encrypted files, it has practical impacts on the security of streaming use-cases for which an online AE mode was (I think) selected. For example, in agl’s blog post linked from the spec he talks about cases such as:

gpg -d your_archive.tgz.gpg | tar xz

This is insecure if an attacker could replace the archive with one of their choosing. Such an attack is possible in most situations a chosen ciphertext attack is.

While you could argue that origin authentication can be done by another tool like minisign or signify, use of those tools implies giving up on streaming as a signature over the entire archive would need to be verified before any output can be processed.

Public key authenticated encryption could be achieved by making the encryptor supply a X25519 private key and using crypto_box (or equivalent) to encrypt the file key in the header rather than the current ECIES-like scheme.

(NB where there are multiple recipients then each recipient can use the decrypted file key to create new encrypted file contents with the same header and make it look as if the original user produced the new ciphertext, so the threat model would need to be worked out in detail - perhaps only supporting a single recipient when using this mode).

I wrote a bit more about this here: https://neilmadden.blog/2019/12/30/a-few-comments-on-age/

Padmé padding for age?

I was tempted to open this as a bug, but that would be provocative: age does not make an effort to hide the size of the encrypted payload. Since many sensitive payloads can be identified by their size alone, this has obvious privacy implications.

The PURB paper (https://bford.info/pub/sec/purb.pdf)) defines an interesting padding scheme called Padmé that introduces at most 12% overhead, and where the overhead decreases with file size. The key quote from the paper Is ...

We show that Padmé can significantly reduce the number of objects uniquely identifiable by their sizes: from 83% to 3% for 56k Ubuntu packages, from 87% to 3% for 191k Youtube videos, from 45% to 8% for 848k hard-drive user files, and from 68% to 6% for 2.8k websites from the Alexa top 1M list. This much stronger leakage protection in- curs an average space overhead of only 3%.

To my mind, adding 3% overhead for a ~5x improvement in file obfuscation is more than worth it, and that's the worst performing of the examples.

There are Go implementations already, for example: https://github.com/dedis/purb/blob/master/purbs/padding.go

it certainly doesn't look like a big performance hit or anything like that. Is a padding scheme like this something that would be considered for age?

I'm happy to work on adding it myself, in Go and rust. I've opened this issue for discussion.

RFE: Allow use of ssh public key *path* rather than key contents for recipient

Environment

  • OS: fedora 30
  • age version: e43cf8b

What were you trying to do

I wish that I could encrypt to a public key by specifying a path to the public key file:

age -r ~/keys/someperson.pub

Rather than the *contents * of the public key file:

age -r $(cat ~/keys/someperson.pub)

(Maybe this would require a new option (-R?) rather than overloading the behavior of the existing --recipient/-r option)

And obviously it would be nice if this same feature were available for age public keys as well.

Empty password

UX appear to be complex for non-technical user, could return Sorry, you have enter incorrect passphrase regardless of empty or wrong passphrase.

 age -d README.md.age 
Enter passphrase: 
Error: empty scrypt password
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]

Use chacha20 without poly for more speed? Aka AEAD?

According to the specification https://age-encryption.org/v1, signing is out of scope, thus authentication is out of scope, thus AEAD is a misfeature slowing decryption and bloating the file size, and worse, implies nonexistent authentication to an unattentive reader.

The specification misquotes an authenticated streaming encryption endorsement https://www.imperialviolet.org/2014/06/27/streamingencryption.html, as it doesn't actually provide any authentication in the recommended usage scheme.

Is there actually a reasonable case for encryption without authentication? Is it not a bad idea to release an encryption tool without authentication, as masses will forget to sign when they should?

On a more serious note, if we were to take recommendation from the quoted document:
https://www.imperialviolet.org/2014/06/27/streamingencryption.html, age would provide a semblance of nacl's crypto_box, with streaming, on a command line. It seems reasonable to support encryption to either a symmetric or asymmetric key and verify authenticity via a symmetric or asymmetric key. No web of trust, key distribution etc.

It might be nice if it were interoperable with signify, meaning it could use the same key, at least for signing. It might even be possible to reuse the format to sign the header and that might be sufficient.

Autogenerated passphrase

Environment

  • OS: macOS
  • age version: Latest on brew

What were you trying to do

Following the example on README.md, age -p secrets.txt > secrets.txt.age.

What happened

This:

dreadnought: fastidious$ age -p secrets.txt > secrets.txt.age
Enter passphrase:
Error: empty scrypt password
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]

There is no more autogenerated password?

[spec] scrypt doesn't specify an output length

The scrypt definition has no length parameter, but references RFC 7914 which specifies that the output length is variable within bounds. In practice it is constrained by its sole usage as an input to encrypt (which per RFC 7539 takes a 256-bit key), but this is inconsistent with the specification of hkdf (which is similarly only used for 256-bit outputs but has an explicit length parameter). To save on indirection, the spec should either add an an explicit length parameter to scrypt, or just hard-code the 32-byte length in the definitions of scrypt and hkdf.

[spec] clarifications on HTTP hyperlink recipients in CLI

I was retooling my website a bit today and also set up https://mdlayher.com/.well-known/age.keys while I was at it. This motivated me to play around and add support for keys residing at a HTTP hyperlink, per the spec.

I've got that code mostly ready whenever you're open to more contributions, but I have a few questions I'd like clarification on:

  1. Is it ever reasonable to accept a plaintext HTTP URL for recipients? Since it's trivial to get proper TLS up and running these days, and sending a message to someone whose key you grabbed over plaintext HTTP seems totally insane, I personally am a strong no on this one.

  2. What should happen if a server's TLS certificate is invalid or expired? Should a flag like curl's -k/--insecure exist?

  3. How do you feel about using a domain with no path to mean "use the well-known path"? For example, https://mdlayher.com would expand to https://mdlayher.com/.well-known/age.keys. Maybe a trailing slash could be permitted too.

Thanks again! Looking forward to more Twitch streams in the future!

Missing Close error check when writing output to a file

Environment

  • OS: macOS 10.15.2
  • age version: e43cf8b

What were you trying to do

Check how output to file is handled (-o flag) to make sure data is flushed.

What happened

When output file is opened, its Close method is deferred, but result of this Close call isn't checked, so theoretically it is possible to end up with file that wasn't completely written even when age returned successfully.

age/cmd/age/age.go

Lines 126 to 131 in e43cf8b

f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
if err != nil {
logFatalf("Error: failed to open output file %q: %v", name, err)
}
defer f.Close()
out = f

One way to improve this is to check for error in deferred function:

diff --git cmd/age/age.go cmd/age/age.go
index a604bb6..fa832a1 100644
--- cmd/age/age.go
+++ cmd/age/age.go
@@ -127,7 +127,11 @@ func main() {
 		if err != nil {
 			logFatalf("Error: failed to open output file %q: %v", name, err)
 		}
-		defer f.Close()
+		defer func() {
+			if err := f.Close(); err != nil {
+				logFatalf("Error: %v", err)
+			}
+		}()
 		out = f
 	} else if terminal.IsTerminal(int(os.Stdout.Fd())) && !decryptFlag {
 		if armorFlag {

...or explicitly call Close on asserted io.Closer in encode/decode functions:

diff --git cmd/age/age.go cmd/age/age.go
index a604bb6..a28749d 100644
--- cmd/age/age.go
+++ cmd/age/age.go
@@ -220,6 +220,11 @@ func encrypt(recipients []age.Recipient, in io.Reader, out io.Writer, armor bool
 	if err := w.Close(); err != nil {
 		logFatalf("Error: %v", err)
 	}
+	if c, ok := out.(io.Closer); ok {
+		if err := c.Close(); err != nil {
+			logFatalf("Error: %v", err)
+		}
+	}
 }
 
 func decrypt(keys []string, in io.Reader, out io.Writer) {
@@ -246,6 +251,11 @@ func decrypt(keys []string, in io.Reader, out io.Writer) {
 	if _, err := io.Copy(out, r); err != nil {
 		logFatalf("Error: %v", err)
 	}
+	if c, ok := out.(io.Closer); ok {
+		if err := c.Close(); err != nil {
+			logFatalf("Error: %v", err)
+		}
+	}
 }
 
 func passphrasePrompt() (string, error) {

Output files are created even if encryption/decryption failed

Environment

  • OS: Arch Linux 5.4.6-arch3-1 #1 SMP PREEMPT Tue, 24 Dec 2019 04:36:53 +0000 x86_64
  • age version*: 1.0.0beta2-1

What were you trying to do

Decrypt a file without providing the -i argument and subsequently fix the mistake.

What happened

The first decryption attempt already created an empty output file, and a next invocation with fixed argument refused to overwrite it.

$ echo 'Hello age' | age -a -r 'age1fh296r26vut9rpdarl89765z5qh9pavgmlam3w9s69uh5t82darqat8yat' -o encrypted.age.ascii
$ age -d -o decrypted.txt encrypted.age.ascii
Error: no identity matched a recipient
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
# fix the mistake
$ age -d -o decrypted.txt -i key.txt encrypted.age.ascii 
Error: failed to open output file "decrypted.txt": open decrypted.txt: file exists
[ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
$ ls -lh
total 8.0K
-rw-r--r-- 1 wojciech wojciech   0 Dec 30 01:52 decrypted.txt

Encryption

Creation of empty files is observed also when encrypting, when given incorrect -r argument:

$ echo 'Hello age' | age -a -o encrypted -r BAD
Error: unknown recipient type: "BAD"
$ ls -l encrypted
-rw-r--r-- 1 wojciech wojciech 0 Dec 30 02:02 encrypted

UX side

Apart from the incorrect, I assume, behaviour of creating empty files, I am not a fan of the no-overwrite policy. I think it would be better to match most unix tools' behaviour of overwriting by default or add an -f/--force flag.

* would be nice to have age --version to properly check that

Feature request: Post quantum crypto

Given that age aims to be the encryption tool for the future, it should include (asymmetric) crypto that will survive the expected arrival of quantum computers.

openssh already has this implemented:

... based on a combination of Streamlined NTRU Prime 4591^761 and X25519.
https://www.openssh.com/releasenotes.html

Alternatively the NIST Competition for post-quantum crypto is getting to the final round in summer 2020
https://en.wikipedia.org/wiki/Post-Quantum_Cryptography_Standardization

Default keys and aliases location on non-Unix platforms

The specification gives the Unix path ~/.config/age/* as the default location it looks for keys and aliases. How should this map to Windows and macOS? The directories Rust crate (which aims to follow per-OS conventions) appears to indicate the following as being approximately OS-shaped:

  • Windows: C:\Users\Alice\AppData\Roaming\age tool\age\config\*
  • macOS: /Users/Alice/Library/Preferences/com.age-tool.age/*

We could also go simpler by just using the known folders for program settings as the base:

  • Windows: C:\Users\Alice\AppData\Roaming\age\*
  • macOS: /Users/Alice/Library/Preferences/age/*

Thoughts? Is there somewhere else these should go? Are users expected to be editing these by hand (in which case maybe a Documents-like folder should be used, which is more accessible)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.