Commit Graph

79 Commits

Author SHA1 Message Date
Filippo Valsorda
9d4b2ae7ac age: move the scrypt lone recipient check out of Decrypt
The important one is the decryption side one, because when a user types
a password they expect it to both decrypt and authenticate the file.
Moved that one out of Decrypt and into ScryptIdentity, now that
Identities get all the stanzas. special_cases--

This also opens the door to other Identity implementations that do allow
multiple scrypt recipients, if someone really wants that. The CLI will
never allow it, but an explicit choice by an API consumer feels like
something we shouldn't interfere with.

Moreover, this also allows alternative Identity implementations that use
different recipient types to replicate the behavior if they have the
same authentication semantics.

The encryption side one is only a courtesy, to stop API users from
making files that won't decrypt. Unfortunately, that one needs to stay
as a special case in Encrypt, as the Recipient can't see around itself.
However, changed it to a type assertion, so custom recipients can
generate multiple scrypt recipient stanzas, if they really want.
2021-06-15 14:00:10 +02:00
Filippo Valsorda
0703f86521 cmd/age,cmd/age-keygen: normalize errors, warnings, and hints 2021-06-14 13:24:26 +02:00
Filippo Valsorda
fb97277f8d cmd/age: add support for encrypted identity files
Updates #252
Closes #132
2021-06-14 13:24:26 +02:00
Filippo Valsorda
fa5b575ceb cmd/age: use CONIN$/CONOUT$ on Windows for password prompts
Fixes #128
Closes #274

Co-authored-by: codesoap <codesoap@mailbox.org>
2021-06-02 11:04:02 +02:00
Filippo Valsorda
e58a8859b9 doc: add age(1) and age-keygen(1) man pages
Closes #131
2021-05-25 20:36:23 +02:00
Ryan Castellucci
759a88d3e8 cmd/age-keygen: don't warn about world-readable output for public keys (#268)
Fixes #267
2021-05-18 20:35:29 -04:00
Filippo Valsorda
7a335c9d5d cmd/age: allow reading both passphrase and input from a terminal
Fixes #196
Closes #258
2021-04-23 02:06:50 -04:00
Filippo Valsorda
ff1b4ffb08 cmd/age,cmd/age-keygen: check Close() error on output files
Fixes #81
2021-04-23 00:11:12 -04:00
Richard Ulmer
bad2c0d2e0 cmd/age: use golang.org/x/term instead of deprecated package (#205) 2021-04-05 09:22:51 -04:00
Filippo Valsorda
53f0ebda67 cmd/age: improve a couple error messages 2021-03-10 05:38:47 -05:00
Filippo Valsorda
f3fdc33c9e cmd/age-keygen: add -y mode to convert identity file to recipients
Copied -y from ssh-keygen. Copied the INPUT as only optional argument
from cmd/age.

Fixes #122
Closes #146
2021-03-10 05:38:47 -05:00
Filippo Valsorda
732f3e8a94 cmd/age: add -e and support encrypting with -i
This will come in handy for symmetric plugins, but make it require an
explicit -e so that missing a -d can't cause a mistaken encryption.
2021-03-10 05:38:47 -05:00
Filippo Valsorda
801a7e8b33 cmd/age: overwrite output file if existing
Not really the safest UX, but age is a UNIX tool, and this is what all
UNIX tools do, so adopt the principle of least surprise.
2021-03-10 05:38:47 -05:00
Filippo Valsorda
710644eef8 Revert "cmd/age: automatically load default SSH key paths"
It's not clear the convenience for SSH keys is worth having any
implicitly configured identity at all. Will revisit after v1.0.0.

This reverts commit 225044b061.
2021-03-10 05:38:47 -05:00
Filippo Valsorda
225044b061 cmd/age: automatically load default SSH key paths 2021-02-08 19:55:28 +01:00
Filippo Valsorda
19e87b75b7 cmd/age: expand test vectors suite 2021-02-08 19:55:28 +01:00
Filippo Valsorda
5d96bfa9a9 age: make Identity and Recipient work on multiple stanzas
This is a breaking change, but like the other changes to these
interfaces it should not matter to consumers of the API that don't
implement custom Recipients or Identities, which is all of them so far,
as far as I can tell.

It became clear working on plugins that we might want Recipient to
return multiple recipient stanzas, for example if the plugin recipient
is an alias or a group. The Identity side is less important, but it
might help avoid round-trips and it makes sense to keep things
symmetric.
2021-02-08 19:55:28 +01:00
Filippo Valsorda
f04064a41b age: add NoIdentityMatchError
Closes #147
2021-02-08 19:55:28 +01:00
Filippo Valsorda
6546df3bac age: remove Type method from Recipient and Identity interfaces
The Type() method was a mistake, as proven by the fact that I can remove
it without losing any functionality. It gives special meaning to the
"0th argument" of recipient stanzas, when actually it should be left up
to Recipient implementations to make their own stanzas recognizable to
their Identity counterparts.

More importantly, there are totally reasonable Identity (and probably
Recipient) implementations that don't know their own stanza type in
advance. For example, a proxy plugin.

Concretely, it was only used to special-case "scrypt" recipients, and to
skip invoking Unwrap. The former can be done based on the returned
recipient stanza, and the latter is best avoided entirely: the Identity
should start by looking at the stanza and returning ErrIncorrectIdentity
if it's of the wrong type.

This is a breaking API change. However, we are still in beta, and none
of the public downstreams look like they would be affected, as they only
use Recipient and Identity implementations from this package, they only
use them with the interfaces defined in this package, and they don't
directly use the Type() method.
2021-02-08 19:55:28 +01:00
Filippo Valsorda
15df6e2cf7 internal/format: require the last line of stanzas to be short
We are going to reuse the stanza format for IPC in the plugin protocol,
but in that context we need stanzas to be self-closing. Currently they
almost are, but if the body is 0 modulo 48, there is no way to know if
the stanza is over after the last line.

Now, all stanzas have to end with a short line, even if empty.

No ciphertexts generated by age in the past are affected, but 3% of the
ciphertexts generated by rage will now stop working. They are still
supported by rage going forward. If it turns out to be a common issue,
we can add an exception.
2021-02-08 19:55:28 +01:00
Filippo Valsorda
c418992942 cmd/age: touch up help text 2021-01-15 14:26:33 +01:00
codesoap
902a3d4e6b cmd/age: decide to buffer output based on stdin source
Buffering only when the armorFlag is set disregards use cases where data
from a tty stdin is decrypted or where binary data goes to a tty stdout.

Buffering is only necessary if stdin is a tty and stdout is a tty.

Co-authored-by: Filippo Valsorda <hi@filippo.io>
2021-01-07 16:51:43 -05:00
codesoap
4a5a042583 cmd/age: decouple output buffer and output denial decision
Co-authored-by: Filippo Valsorda <hi@filippo.io>
2021-01-07 16:51:43 -05:00
Tom Payne
6fc795057f cmd/age-keygen: add --output option as an alias for -o (#177) 2021-01-07 19:20:55 +01:00
Richard Ulmer
a8573a5c8d cmd/age: improve help text (#175) 2021-01-04 20:05:33 +01:00
Filippo Valsorda
4147b86ac8 cmd/age: support "-R -" if stdin is not in use 2021-01-03 09:10:21 -05:00
Daan Sprenkels
dc8716d8fc cmd/age: support "-i -" if stdin is not in use
Fixes #143
Closes #145

Co-authored-by: Filippo Valsorda <hi@filippo.io>
2021-01-03 09:10:21 -05:00
Filippo Valsorda
3f2deb5a3b cmd/age: be less clever in the lazyOpener implementation
I am a fan of closures and DoerFunc interface adapters, but the boring
thing is more readable. Sigh.
2021-01-03 09:10:21 -05:00
Filippo Valsorda
97b6569a66 cmd/age: lazily open output file at first write
This avoids leaving behind an empty file when an error occurs before we
write the header (for example, because the passphrase is invalid). Do a
best-effort check before taking user input for whether the file exists
so we don't waste user effort. An error might still happen after user
input if other kind of open errors happen (for example, a permission
issue, or disk full).

Fixes #159
Fixes #57
Closes #169
2021-01-03 09:10:21 -05:00
Filippo Valsorda
02ee8b969a internal/format: buffer newlineWriter writes
Most writes in the cmd/age Writer stack are chunk-sized, so
approximately 64KiB. However, the newlineWriter, which splits lines at
64 columns, was doing a Write on the underlying Writer for each line,
making chunks effectively 48 bytes (before base64). There is no
buffering underneath it, so it was resulting in a lot of write syscalls.

Add a reusable bytes.Buffer to buffer the output of each
(*newlineWriter).Write call, and Write it all at once on the
destination.

This makes --armor just 50% slower than plain, instead of 10x.

Fixes #167
2021-01-03 09:10:21 -05:00
Filippo Valsorda
cb4d1de4b7 cmd/age: show usage if no arguments and flags are specified
Fixes #74
2021-01-03 09:10:21 -05:00
Filippo Valsorda
e665eeafb0 cmd/age-keygen: make world-readable warning less obscure
Fixes #149
Fixes #75
2021-01-03 09:10:21 -05:00
Filippo Valsorda
4dee0155ee cmd/age,cmd/age-keygen: improve help text
Closes #168
2021-01-03 09:10:21 -05:00
Filippo Valsorda
0522803919 cmd/age,cmd/age-keygen: add -version flag
Fixes #157
Fixes #101
Closes #97
2021-01-03 09:10:21 -05:00
Filippo Valsorda
f8507c1cac age,cmd/age: add ParseRecipients and -R for recipient files
Fixes #84
Fixes #66
Closes #165
Closes #158
Closes #115
Closes #64
Closes #43
Closes #20
2021-01-03 09:10:21 -05:00
Filippo Valsorda
7ab2008136 .github/workflows: extend testing matrix 2021-01-03 00:28:03 +01:00
Filippo Valsorda
22e598d458 age: replace ParseX25519Identities with ParseIdentities
The latter returns a []Identity that can be used with Decrypt directly.
2020-09-20 12:54:15 +02:00
Filippo Valsorda
65f171a239 age: add ParseX25519Identities and key management docs 2020-09-20 12:17:15 +02:00
Filippo Valsorda
2194f6962c age: mitigate multi-key attacks on ChaCha20Poly1305
It's possible to craft ChaCha20Poly1305 ciphertexts that decrypt under
multiple keys. (I know, it's wild.)

The impact is different for different recipients, but in general only
applies to Chosen Ciphertext Attacks against online decryption oracles:

* With the scrypt recipient, it lets the attacker make a recipient
  stanza that decrypts with multiple passwords, speeding up a bruteforce
  in terms of oracle queries (but not scrypt work, which can be
  precomputed) to logN by binary search.

  Limiting the ciphertext size limits the keys to two, which makes this
  acceptable: it's a loss of only one bit of security in a scenario
  (online decryption oracles) that is not recommended.

* With the X25519 recipient, it lets the attacker search for accepted
  public keys without using multiple recipient stanzas in the message.
  That lets the attacker bypass the 20 recipients limit (which was not
  actually intended to defend against deanonymization attacks).

  This is not really in the threat model for age: we make no attempt to
  provide anonymity in an online CCA scenario.

  Anyway, limiting the keys to two by enforcing short ciphertexts
  mitigates the attack: it only lets the attacker test 40 keys per
  message instead of 20.

* With the ssh-ed25519 recipient, the attack should be irrelevant, since
  the recipient stanza includes a 32-bit hash of the public key, making
  it decidedly not anonymous.

  Also to avoid breaking the abstraction in the agessh package, we don't
  mitigate the attack for this recipient, but we document the lack of
  anonymity.

This was reported by Paul Grubbs in the context of the upcoming paper
"Partitioning Oracle Attacks", USENIX Security 2021 (to appear), by
Julia Len, Paul Grubbs, and Thomas Ristenpart.
2020-09-19 18:52:59 +02:00
Filippo Valsorda
189041b668 age: move package from filippo.io/age/age to filippo.io/age 🤦‍♂️ 2020-06-27 22:06:32 -04:00
Filippo Valsorda
e609359651 age,agessh,armor: unleash public API 💥🦑 2020-06-27 21:08:42 -04:00
Filippo Valsorda
9b83d948f5 internal/age: surface format.Recipient as type Stanza 2020-06-27 19:44:26 -04:00
Filippo Valsorda
c9a35c0727 internal/agessh: move EncryptedSSHIdentity out of cmd/age 2020-05-19 02:07:27 -04:00
Filippo Valsorda
6782356e45 internal/age: add some docs and polish API 2020-05-18 02:53:37 -04:00
Filippo Valsorda
292c3aaeea internal/agessh: new package
Move the SSH recipient types out of the main package to declutter the
godoc. This also allows us to drop the x/crypto/ssh build dependency
entirely from the age package import tree.
2020-05-18 01:20:08 -04:00
Filippo Valsorda
b32ea4c1f6 cmd/age: add a TODO about not dumping decrypted binary to the terminal 2020-05-18 00:21:41 -04:00
Filippo Valsorda
c7c7f1870f internal/armor: new package 2020-05-18 00:12:36 -04:00
Filippo Valsorda
a7c4274d23 internal/age: remove EncryptWithArmor and armor support in Decrypt
The caller can take care of the armor. For consistency move the
responsibility to close the armor to the caller, and make the stream
Writer not propagate Close.

This also will also allow us to spin the armor implementation out into
its won package that imports format, without getting an import loop from
format.Parse magically invoking armor decoding.

Less magic in the API, more magic in the CLI.
2020-05-18 00:11:21 -04:00
Filippo Valsorda
7088a73234 internal/age: unexport SSHFingerprint 2020-05-18 00:05:25 -04:00
Filippo Valsorda
f54bb8daab internal/format: don't generate and reject empty lines in recipient bodies
Detected by https://github.com/str4d/rage/runs/532262359 and by go-fuzz.
2020-03-25 02:22:58 -04:00