Releases: str4d/rage
Releases · str4d/rage
rage v0.11.0
rage
Added
- Partial French translation!
Fixed
- [Unix] Files can now be encrypted with
rage --passphrase
when piped over stdin, without requiring an explicit-
argument asINPUT
.
age
Added
- New streamlined APIs for use with a single recipient or identity and a small amount of data (that can fit entirely in memory):
age::encrypt
age::encrypt_and_armor
age::decrypt
age::Decryptor::{decrypt, decrypt_async, is_scrypt}
age::IdentityFile::to_recipients
age::IdentityFile::with_callbacks
age::IdentityFile::write_recipients_file
age::IdentityFileConvertError
age::NoCallbacks
age::scrypt
, providing recipient and identity types for passphrase-based encryption.- Partial French translation!
Changed
- Migrated to
i18n-embed 0.15
,secrecy 0.10
. age::Encryptor::with_recipients
now takes recipients by reference instead of by value. This aligns it withage::Decryptor
(which takes identities by reference), and also means that errors with recipients are reported earlier. This causes the following changes to the API:Encryptor::with_recipients
takesimpl Iterator<Item = &'a dyn Recipient>
instead ofVec<Box<dyn Recipient + Send>>
.- Verification of recipients and generation of stanzas now happens in
Encryptor::with_recipients
instead ofEncryptor::wrap_output
andEncryptor::wrap_async_output
. Encryptor::with_recipients
returnsResult<Self, EncryptError>
instead ofOption<Self>
, andEncryptor::{wrap_output, wrap_async_output}
returnio::Result<StreamWriter<W>>
instead ofResult<StreamWriter<W>, EncryptError>
.age::EncryptError
has a new variantMissingRecipients
, taking the place of theNone
thatEncryptor::with_recipients
could previously return.
age::Decryptor
is now an opaque struct instead of an enum withRecipients
andPassphrase
variants.age::IdentityFile
now has aC: Callbacks
generic parameter, which defaults toNoCallbacks
.age::IdentityFile::into_identities
now returnsResult<Vec<Box<dyn crate::Identity>>, DecryptError>
instead ofVec<IdentityFileEntry>
.age::Recipient::wrap_file_key
now returns(Vec<Stanza>, HashSet<String>)
: a tuple of the stanzas to be placed in an age file header, and labels that constrain how the stanzas may be combined with those from other recipients.age::plugin::RecipientPluginV1
now supports the labels extension.
Fixed
age::cli_common::read_identities
once again correctly parses identity files that are a single line without a trailing newline. This broke in 0.10.0 due to an unrelated refactor.
Removed
age::decryptor::PassphraseDecryptor
(useage::Decryptor
withage::scrypt::Identity
instead).age::decryptor::RecipientsDecryptor
(useage::Decryptor
instead).age::IdentityFileEntry
age-plugin 0.6.0
Added
age_plugin::PluginHandler
impl age_plugin::identity::IdentityPluginV1 for std::convert::Infallible
impl age_plugin::recipient::RecipientPluginV1 for std::convert::Infallible
Changed
- Migrated to
age-core 0.11
. age_plugin::recipient::RecipientPluginV1
has a newlabels
method. Existing implementations of the trait should either returnHashSet::new()
to maintain existing compatibility, or return labels that apply the desired constraints.age_plugin::run_state_machine
now supports therecipient-v1
labels extension.
Fixed
age_plugin::run_state_machine
now takes animpl age_plugin::PluginHandler
argument, instead of its previous arguments.- This fixes the change from the previous release, because the type parameters were basically impossible to set correctly when attempting to pass
None
.
- This fixes the change from the previous release, because the type parameters were basically impossible to set correctly when attempting to pass
age-core
Added
age_core::format
:FileKey::new
FileKey::init_with_mut
FileKey::try_init_with_mut
is_arbitrary_string
Changed
- Migrated to
secrecy 0.10
. age::plugin::Connection::unidir_receive
now takes an additional argument to enable handling an optional fourth command.
New Contributors
- @AnomalRoil made their first contribution in #499
- @pavelzw made their first contribution in #492
- @BoostCookie made their first contribution in #513
Full Changelog: v0.10.0...v0.11.0
rage v0.10.0
rage
Added
- Russian translation!
rage-keygen -y IDENTITY_FILE
to convert identity files to recipients.- Elvish completions to the Debian package. These are not automatically discovered; Elvish users will need to manually import them.
- Localized manpages to the Debian package.
Changed
- MSRV is now 1.65.0.
- Migrated from
gumdrop
toclap
for argument parsing. -R/--recipients-file
and-i/--identity
now support "read-once" files, like those used by process substitution (-i <(other_binary get-age-identity)
) and named pipes.- The filename
-
(hyphen) is now treated as an explicit request to read from standard input when used with-R/--recipients-file
or-i/--identity
. It must only occur once across the-R/--recipients-file
and-i/--identity
flags, and the input file. It cannot be used if the input file is omitted.
Fixed
- OpenSSH private keys passed to
-i/--identity
that contain invalid public keys are no longer ignored when encrypting, and instead cause an error. - Weak
ssh-rsa
public keys that are smaller than 2048 bits are now rejected. rage-keygen
no longer overwrites existing key files with the-o/--output
flag. This was its behaviour prior to 0.6.0, but was unintentionally changed whenrage
was modified to overwrite existing files. Key file overwriting can still be achieved by omitting-o/--output
and instead piping stdout to the file.rage-keygen
now prints fatal errors directly instead of them being hidden behind theRUST_LOG=error
environment variable. It also now sets its return code appropriately instead of always returning 0.- The Debian package now uses the correct installation paths for fish and Zsh completions.
age
Added
- Russian translation!
age::cli_common
:file_io
:FileReader
impl Debug for {LazyFile, OutputFormat, OutputWriter, StdoutWriter}
StdinGuard
read_recipients
age::identity::IdentityFile::from_input_reader
(behindcli-common
feature flag).impl Eq for age::ssh::{ParseRecipientKeyError, UnsupportedKey}
impl {Debug, PartialEq, Eq, Hash} for age::x25519::Recipient
Changed
- MSRV is now 1.65.0.
- Migrated to
base64 0.21
,rsa 0.9
. age::cli_common
:file_io
:InputReader::File
enum variant now containsFileReader
instead ofstd::fs::File
.OutputWriter::new
now takes anallow_overwrite
boolean argument. IfOutputWriter
will write to a file, this boolean enables the caller to control whether the file will be overwritten if it exists (instead of the implicit behaviour that was previously changed in 0.6.0).
read_identities
now takes an&mut StdinGuard
argument, andfilenames
may now contain at most one entry of"-"
, which will be interpreted as reading from standard input.ReadError
has new variants:EncryptedIdentities
InvalidRecipient
InvalidRecipientsFile
MissingRecipientsFile
MultipleStdin
RsaModulusTooLarge
RsaModulusTooSmall
age::ssh
:ParseRecipientKeyError
has new variants:RsaModulusTooLarge
RsaModulusTooSmall
- The following trait implementations now return
Err(ParseRecipientKeyError::RsaModulusTooLarge)
instead ofErr(ParseRecipientKeyError::Unsupported(_))
when encountering an RSA public key with a modulus larger than 4096 bits:impl FromStr for Recipient
impl TryFrom<Identity> for Recipient
Fixed
age::Encryptor::with_user_passphrase
will now re-measure thescrypt
work factor until it is measurable, instead of setting the work factor to maximum.age::cli_common
:UiCallbacks::confirm
no longer requires erasing the confirmation message before it will accept a response.UiCallbacks::request_public_string
no longer prepends the description to the response string.
- Weak
ssh-rsa
public keys that are smaller than 2048 bits are now rejected from all string-parsing APIs. TheRecipient::SshRsa
enum variant can still be manually constructed with such keys; this will be fixed in a future crate refactor.
age-plugin 0.5.0
Changed
- MSRV is now 1.65.0.
- Migrated to
age-core 0.10
. age_plugin::run_state_machine
now takes optional arguments, to enable the creation of recipient-only or identity-only plugins.
age-core
Added
impl Eq for age_core::format::Stanza
Changed
- MSRV is now 1.65.0.
New Contributors
- @WesleyAC made their first contribution in #400
- @thibmeu made their first contribution in #406
- @gibbz00 made their first contribution in #420
- @ehaupt made their first contribution in #467
- @hexanova made their first contribution in #471
Full Changelog: v0.9.2...v0.10.0
rage v0.9.2
rage
Changed
- Increased parsing speed of age file headers. For single-recipient encrypted decryption throughput increases by 6% for medium (< 1MiB) files, and 40% for small (< 10kiB) files.
- The
pinentry
binary used to request passphrases can now be set manually withPINENTRY_PROGRAM
environment variable. It accepts either a binary name a path. Setting this to the empty string will disablepinentry
usage and back to the CLI interface. - Linux release binaries are now built using Ubuntu 20.04.
age
Added
age::Decryptor::{new_buffered, new_async_buffered}
, which are more efficient types implementingstd::io::BufRead
orfutures::io::AsyncBufRead
includes&[u8]
slices).impl std::io::BufRead for age::armor::ArmoredReader
impl futures::io::AsyncBufRead for age::armor::ArmoredReader
Changed
- The
pinentry
binary used byage::cli_common::read_secret
can now be set with thePINENTRY_PROGRAM
environment variable. It accepts either a name or a path. Setting this to the empty string will disablepinentry
and fall back to the CLI interface.
Fixed
- The
AsyncWrite::poll_write
implementation forage::stream::StreamWriter
never returns 0 if there is data to write. This makesStreamWriter
withfutures::io::copy
.
rage v0.9.1
rage
Added
- Support for encrypted OpenSSH keys exported from 1Password.
age
Added
- Support for encrypted OpenSSH keys exported from 1Password.
rage v0.9.0
rage
Changed
- MSRV is now 1.59.0.
Fixed
- Encryption now returns an error if the file would be encrypted to no recipients. This can occur if only
-R/--recipients-file
flags are provided, and they all point to files that contain only "#" prefixed comments and empty lines.
age
Added
age::armor::ArmoredReadError
, used to wrap armor-specific read errors insidestd::io::Error
.age::ssh
:impl Clone for Identity
Changed
- MSRV is now 1.59.0.
age::Encryptor::with_recipients
now returnsOption<Encryptor>
, withNone
returned if the provided list of recipients is empty (to prevent files being encrypted to no recipients). Therecipients
argument is also nowVec<Box<dyn age::Recipient + Send>>
.age::encrypted::Identity::recipients
now returnsVec<Box<dyn age::Recipient + Send>>
.
Fixed
age::Decryptor
now rejects invalid or non-canonicalscrypt
recipient stanzas (instead of ignoring or accepting them respectively), matching the age specification.age::armor::ArmoredReader
:- It now correctly implements strict parsing as defined in RFC 7468, and rejects armored files with non-canonical final lines (where padding bytes are omitted).
- It now rejects armored files with non-whitespace characters after the end marker.
- It now accepts armored files with no newline after the end marker. Previously these were rejected by the synchronous API, and would cause the async API to hang.
- The async API now correctly rejects some classes of invalid armoring that previously would cause it to hang.
age-plugin 0.4.0
Changed
- MSRV is now 1.59.0.
- Migrated to
age-core 0.9
.
age-core
Changed
- MSRV is now 1.59.0.
- Migrated to
aead 0.5
.
rage v0.8.1
rage
Security
- Require
age 0.8.1
.
age
Security
age::Decryptor
did not previously require "contributory" behaviour forX25519
recipient stanzas. If an age file has anX25519
recipient stanza with an ephemeral share that is a small-order point, the file could previously be decrypted by any native age identity. To ensure we match the behaviour in the age specification, these files are now rejected as invalid.
Fixed
age::Decryptor
now rejects invalid or non-canonicalX25519
recipient stanzas (instead of ignoring or accepting them respectively), matching the age specification.
rage v0.8.0
rage
Changed
- MSRV is now 1.56.0.
- When both reading input from the terminal (e.g. if the user is typing the plaintext to be encrypted) and writing output to the terminal,
rage
now buffers the output until the input is finished, so the output doesn't get in the way of typing. - A warning is now displayed if
rage
detects that the file being encrypted starts with the age magic string or armor begin marker (indicating that an age-encrypted file is being double-encrypted). The file is still encrypted. - A message is now printed if a plugin takes longer than 10 seconds to encrypt or decrypt its header entry (for example, if the plugin is waiting on some user interaction that hasn't occurred yet).
Fixed
- Decryption now returns an error when given a passphrase-encrypted file if
-i/--identity
is present. Previously this could result in scripts hanging forever (given that passphrase decryption is intentionally not scriptable).
age
Added
age::Callbacks::confirm
to request that the user provides confirmation for some action.age::cli_common::file_io::InputReader::is_terminal
age::ssh::ParseRecipientKeyError
, which was previously in the public API but unnameable and could not be matched upon.
Changed
- MSRV is now 1.56.0.
age::Callbacks
now requiresClone + Send + Sync + 'static
bounds.age::cli_common::file_io::OutputWriter::new
now takes aninput_is_tty
boolean argument. Ifinput_is_tty
is set totrue
, then ifOutputWriter
will write to a stdout TTY, it buffers the entire output so it doesn't get in the way of typing the input, and then writes the buffered output to stdout duringOutputWriter::flush
.- Ciphertexts are now required to end in a non-empty STREAM chunk, unless it is the only chunk (meaning that the plaintext is empty). Neither age nor rage generate non-empty files ending in an empty chunk, instead marking the final full chunk as the last chunk.
age-plugin 0.3.0
Added
age_plugin::Callbacks::confirm
Changed
- MSRV is now 1.56.0.
age-core
Added
age_core::io::{DebugReader, DebugWriter}
age_core::plugin::Error::Unsupported
age_core::plugin::Reply::ok_with_metadata
Changed
- MSRV is now 1.56.0.
age_core::plugin
:Connection::open
now returns the debugging-friendly concrete typeConnection<DebugReader<ChildStdout>, DebugWriter<ChildStdin>>
.BidirSend::{send, send_stanza}
now returnOk(Error::Unsupported)
when anunsupported
response is received, instead ofErr(io::Error)
, making it easier for plugins to implement fallback strategies.
rage v0.7.1
rage
Fixed
- Fixed a bug in 0.7.0 where non-canonical recipient stanza bodies in an age
file header would causerage
to crash instead of being rejected.
age
Fixed
- Bumped
age-core
to 0.7.1 to fix a bug where non-canonical recipient stanza
bodies in an age file header would cause a panic instead of being rejected.
age-plugin 0.2.1
Fixed
- Bumped
age-core
to 0.7.1 to fix a bug where non-canonical recipient stanza
bodies in an age file header would cause a panic instead of being rejected.
age-core
Fixed
- In 0.7.0, Base64 decoding was moved to the
AgeStanza::body
method, with the
stanza parser only checking for valid Base64 characters. This caused the
parser to start accepting stanzas with non-canonical last body lines (where
the Base64 encoding would have trailing bits that could not be decoded into
full bytes); callingAgeStanza::body
on these stanzas would cause a panic.
This release fixes the parser to reject non-canonical last body lines, turning
the panic back into an error.
rage v0.7.0
rage
Added
-i/--identity
now accepts passphrase-encrypted age identity files.- The
-j PLUGIN_NAME
flag, which allows decrypting with a plugin using its "default mode" (in which no identity-specific information is required). This flag is equivalent to using-i/--identity
with an identity file containing the default plugin identity (containing no data).
Changed
- MSRV is now 1.51.0.
*-linux.tar.gz
release binaries are now built with Ubuntu 18.04, and require a system with a minimum ofglibc 2.27
.
age
Added
age::encrypted::Identity
, for decrypting files with passphrase-encrypted age identity files.age::IdentityFileEntry
enum, representing the possible kinds of entries within an age identity file.age::{DecryptError, EncryptError, PluginError}: Clone
bounds.age::cli_common::UiCallbacks: Clone + Copy
bounds.age::cli_common::Passphrase::random
, for generating a secure passphrase.age::cli_common::ReadError
age::secrecy
, which re-exports thesecrecy
crate.
Changed
- MSRV is now 1.51.0.
age::IdentityFile::into_identities
now returnsVec<IdentityFileEntry>
.age::cli_common::read_identities
:- Encrypted age files will now be parsed and assumed to be encrypted age identities. This assumption is checked at file-decryption time.
- New
max_work_factor
parameter for controlling the work factor when decrypting encrypted identities. - Identities are now returned in the same order as
filenames
(and top-to-bottom from within each file). Plugin identities are no longer coalesced; there is oneBox<dyn Identity>
per plugin identity. age::cli_common::ReadError
is now returned instead of a user-specified error type. The error constructor parameters have been removed from the function.
age::Callbacks::prompt
has been renamed toCallbacks::display_message
.age::cli_common::UiCallbacks::display_message
no longer usespinentry
(which displays a temporary prompt that can be dismissed), so the message is now part of the visible CLI output.
Removed
IdentityFile::split_into
(replaced byIdentityFileEntry::Plugin
).
age-plugin 0.2.0
Changed
- MSRV is now 1.51.0.
age_plugin::Callbacks
methods now returnage_core::plugin::Error
instead of()
for internal errors, following changes toage_core::plugin::Result
.
age-core
Added
age_core::secrecy
, which re-exports thesecrecy
crate.age_core::plugin::Error
Changed
- MSRV is now 1.51.0.
- The
body
property ofage_core::format::AgeStanza
has been replaced by theAgeStanza::body
method, to enable enclosing parsers to defer Base64 decoding until the very end. age_core::plugin::Result
now only takes a single generic argument, and usesage_core::plugin::Error
for its inner error type.
rage v0.6.0
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).