rage
Added
- Plugin support!
- The new
age-plugin
crate provides a Rust API for building age plugins. - See https://hackmd.io/@str4d/age-plugin-spec for the beta specification.
- The new
- The
-R/--recipients-file
flag, which accepts a path to a file containing age recipients, one per line (ignoring "#" prefixed comments and empty lines). - The
-e/--encrypt
flag, to allow encryption to be an explicit choice (instead of relying on-d/--decrypt
not being present).
Changed
- MSRV is now 1.47.0.
-o/--output
will now overwrite existing files instead of returning an error. This makes the behaviour consistent with most UNIX tools, as well as when using pipes.- Files encrypted with this version of
rage
might not decrypt with previous beta versions, due to changes in how stanza bodies are canonically encoded. This should only affect a small fraction of files (if grease that triggers the change is added, which has a 3% chance per file). -r/--recipient
now has the specific type "recipient" which better reflects its name, rather than the ambiguous "source of recipients" it was previously.-i/--identity
can now be used when encrypting files. This requires the-e/--encrypt
flag (to prevent ambiguity, e.g. if the user wants to decrypt but forgets the-d/--decrypt
flag).
Removed
- Recipients file support from
-r/--recipient
(use-R/--recipients-file
instead). - HTTPS support. This added otherwise-unnecessary networking dependencies to
rage
, and there are many decisions that need to be made when downloading a file (e.g. what roots to trust?) that go beyond the APIs we want to focus on here. Users should use a tool likecurl
orwget
to download a recipients file, and then pass it torage
. - The unstable GitHub feature (which relied on HTTPS support).
- The unstable aliases feature.
Fixed
- Log output is now disabled by default, to prevent non-fatal error messages (such as an unset or invalid
LANG
variable) being printed to stderr while the program succeeds (which is confusing for users). The previous behaviour can be configured by setting the environment variableRUST_LOG=error
. - Output files are now opened lazily, which avoids leaving behind an empty file when an error occurs before we write the header.
age
Security
StreamReader::seek(SeekFrom::End(offset))
did not previously authenticate the ciphertext length; if the ciphertext had been truncated or extended byadversary_offset
, it would instead seek tooffset + adversary_offset
. This allowed an adversary with temporary control of an encrypted age file to control the location of a plaintext read following a seek-from-end.age
now returns an error if the last chunk is invalid.rage
was not affected by this security issue, as it does not useSeek
.rage-mount
may have been affected; it does not useSeekFrom::End
directly, but thetar
orzip
crates might do so.
Added
- Plugin support, enabled by the
plugin
feature flag:age::plugin::{Identity, Recipient}
structs for parsing plugin recipients and identities from strings.age::plugin::RecipientPluginV1
, which implementsage::Recipient
and runs the V1 recipient plugin protocol.age::plugin::IdentityPluginV1
, which implementsage::Identity
and runs the V1 identity plugin protocol.
- The
web-sys
feature flag, which enables calculating the work factor for passphrase encryption with the Performance timer via theweb-sys
crate, when compiling for a WebAssembly target such aswasm32-unknown-unknown
. This feature is ignored for thewasm32-wasi
target, which supportsstd::time::SystemTime
. age::Callbacks::request_public_string
to request non-private input from the user (which will not trigger any OS-level passphrase-style prompt, unlikeCallbacks::request_passphrase
).
Changed
- MSRV is now 1.47.0.
age::cli_common::file_io::OutputWriter::File
will now overwrite the file if it exists, instead of returning an error. This makes it consistent withage::cli_common::file_io::OutputWriter::Stdout
, as well as most UNIX tools.- Files encrypted with this version of
age
might not decrypt with previous beta versions, due to changes in how stanza bodies are canonically encoded. This should only affect a small fraction of files (if grease that triggers the change is added, which has a 3% chance per file). age::decryptor::RecipientsDecryptor
now takesimpl Iterator<Item = &'a dyn Identity>
in its decryption methods, to make decrypting multiple files with the same identities easier.age::cli_common::file_io::OutputWriter::File
now wraps aLazyFile
struct (instead of wrappingstd::io::File
directly), which does not open the file until it is first written to.age::decryptor::Callbacks
has been moved toage::Callbacks
, as it is no longer decryption-specific.
Fixed
age::cli_common::read_identities
now allows either kind of line ending in SSH identity files.- Default
en-US
language strings are now always loaded, even if translations are not loaded by callingage::localizer().select(&requested_languages)
. StreamReader::seek(SeekFrom::End(0))
now seeks to the correct position when the plaintext is an exact multiple of the chunk size.
age-plugin 0.1.0
Initial beta release!
age-core
Security
age_core::primitives::aead_decrypt
now takes asize
argument, checked against the plaintext length. This is to mitigate multi-key attacks, where a ciphertext can be crafted that decrypts successfully under multiple keys. Short ciphertexts can only target two keys, which has limited impact. See this commit message for more details.
Added
age_core::format::FILE_KEY_BYTES
constant.age_core::plugin
module, which contains common backend logic used by both theage
library (to implement client support for plugins) and theage-plugin
library.
Changed
- The stanza prefix
->
and trailing newline are now formal parts of the age stanza;age_core::format::write::age_stanza
now includes them in its output, andage_core::format::read::age_stanza
expects them to be present. - Stanza bodies are now canonically serialized with a short (empty if necessary) last line.
age_core::format::write::age_stanza
outputs the new encoding, andage_core::format::read::age_stanza
accepts only the new encoding. The new APIage_core::format::read::legacy_age_stanza
accepts either kind of stanza body encoding (the legacy minimal encoding, and the new explicit encoding).