Releases: str4d/rage
Releases · str4d/rage
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).
rage v0.5.1
Fixed
- Bumped dependencies to
i18n-embed-fl 0.3
andi18n-embed 0.10.2
to fix a
transient dependency breakage, that brokecargo install rage
because
cargo install
ignoresCargo.lock
.
rage v0.5.0
rage
Added
- Italian, Spanish, and Chinese translations!
ssh
feature flag, enabled by default. It can be disabled to remove support
forssh-rsa
andssh-ed25519
recipients and identities.ssh-rsa
keys are
now supported without theunstable
feature flag.
Changed
- MSRV is now 1.45.0.
Removed
- Default identity path (identities should instead be set per-use).
- Default alias path (for unstable aliases feature).
age
Added
- Italian, Spanish, and Chinese translations!
- New core traits, implemented by all relevant
age
types:age::Identity
, representing an identity that can decrypt an age file.age::Recipient
, representing a potential recipient of an age file.
- Separate modules and structs for different recipient types:
age::x25519
age::ssh
(behind thessh
feature flag).
age::EncryptError
, representing errors that can occur during encryption.age::IdentityFile
struct, for parsing a list of native age identities
(currently onlyage::x25519::Identity
) from a file.- Asynchronous APIs for encryption and decryption, enabled by the
async
feature flag:age::Encryptor::wrap_async_output()
age::Decryptor::new_async()
age::decryptor::RecipientsDecryptor::decrypt_async()
age::decryptor::PassphraseDecryptor::decrypt_async()
- Explicit armoring support, enabled by the
armor
feature flag:age::armor::ArmoredReader
, which can be wrapped around an input to handle
a potentially-armored age file.age::armor::ArmoredWriter
, which can be wrapped around an output to
optionally apply the armored age format.
Changed
- MSRV is now 1.45.0.
- Changes due to the new core traits:
age::Encryptor::with_recipients
now takesVec<Box<dyn Recipient>>
.age::decryptor::RecipientsDecryptor
now takes
impl Iterator<Item = Box<dyn Identity>>
in its decryption methods.age::cli_common::read_identities
now returnsVec<Box<dyn Identity>>
, as
it abstracts overage::IdentityFile
andage::ssh::Identity
. When the
ssh
feature flag is enabled, it also takes anunsupported_ssh
argument
for handling unsupported SSH identities.age::Error
has been renamed toage::DecryptError
.
- Changes due to explicit armoring support:
age::Encryptor::wrap_output
now only generates the non-malleable binary
age format. To optionally generate armored age files, use
encryptor.wrap_output(ArmoredWriter::wrap_output(output, format))
.age::Decryptor
now only decrypts the non-malleable binary age format. To
handle age files that are potentially armored, use
Decryptor::new(ArmoredReader::new(input))
.age::Format
has been moved toage::armor::Format
.
- SSH support is now disabled by default, behind the
ssh
feature flag.
ssh-rsa
keys are now supported without theunstable
feature flag. age::Callbacks
has been moved toage::decryptor::Callbacks
.
Removed
age::SecretKey
(replaced byage::x25519::Identity
and
age::ssh::Identity
).age::keys::RecipientKey
(replaced byage::x25519::Recipient
and
age::ssh::Recipient
).age::keys::{Identity, IdentityKey}
(replaced byage::Identity
trait on
individual identities, andage::IdentityFile
for parsing identities).age::decryptor::RecipientsDecryptor::decrypt_with_callbacks()
(identities
are now expected to handle their own callbacks, and
age::cli_common::read_identities
now adds callbacks to SSH identities).- Default identity path:
age::cli_common::get_config_dir
.- The
no_default
parameter forage::cli_common::read_identities
.
age-core
Added
- Several structs used when implementing the
age::Identity
and
age::Recipient
traits:age_core::format::FileKey
age_core::format::Stanza
age_core::format::grease_the_joint
, for generating a random valid recipient
stanza. No other guarantees are made about the stanza's fields.age_core::primitives::{aead_decrypt, aead_encrypt, hkdf}
, to enable these
common primitives to be reused in plugins.
Changed
- MSRV is now 1.41.0.
age_core::format::write::age_stanza
now takesargs: &[impl AsRef<str>]
.
rage v0.4.0
rage
Added
rage-mount
can now mount ASCII-armored age files.
Changed
- [
rage
]-p/--passphrase
flag can no longer be used with-d/--decrypt
(passphrase-encrypted files are now detected automatically).
Removed
-p/--passphrase
flag fromrage-mount
(passphrase-encrypted files are now
detected automatically).
Fixed
- [Unix] Files encrypted with a passphrase can now be decrypted with
rage
when
piped over stdin.
age
Added
age::Decryptor::new(R: Read)
, which parses an age file header and returns
a context-specific decryptor.age::decryptor
module containing the context-specific decryptors.- Their decryption methods return the concrete type
StreamReader<R>
,
enabling them to handle seekable readers.
- Their decryption methods return the concrete type
age::Encryptor::with_recipients(Vec<RecipientKey>)
age::Encryptor::with_user_passphrase(SecretString)
- Support for encrypted OpenSSH keys created with
ssh-keygen
prior to OpenSSH
7.6. age::cli_common::file_io::OutputWriter::is_terminal
Changed
age::Decryptor
has been refactored to auto-detect the decryption type. As a
result, both identity-based and passphrase-based decryption need to be
handled.age::StreamReader
has been moved into theage::stream
module, along with
StreamWriter
which was previously public but has now been formally exposed
in the API for documentation purposes.age::Encryptor
is now an opaque struct, and must be created via its new
constructors.age::Encryptor::wrap_output
now consumesself
, making it harder to
accidentally reuse a passphrase for multiple encrypted files.age::cli_common::read_identities
now takes an additionalfile_not_found
parameter for customising the error when an identity filename is not found.
Removed
age::Decryptor::trial_decrypt
(replaced by context-specific decryptors).age::Decryptor::trial_decrypt_seekable
(merged into the context-specific
decryptors).age::Error::ArmoredWhenSeeking
age::Error::MessageRequiresKeys
age::Error::MessageRequiresPassphrase
Fixed
- Key files with Windows line endings are now correctly parsed.
age-core
No changes; version bumped to keep it in sync with age
.
rage v0.3.1
Version bump to fix nightly builds. No other changes from v0.3.0.
rage v0.3.0
Crates galore! The changes in the age
library crate are reflected in the CLI tools in the rage
crate.
rage
(relative to the CLI tools in age 0.2.0
)
Added
-V / --version
flags to all binaries.- Completion files for Bash, Elvish, Fish, PowerShell, and Zsh can be generated
withcargo run --example generate-completions
. - The Debian package will install completion files for Bash, Fish, and Zsh.
Changed
- If a
pinentry
binary is available, it will be used preferentially to request
secrets such as passphrases. The previous CLI input will be used ifpinentry
is not available.
age
Added
age::Callbacks
, which encapsulates any requests that might be necessary
during the decryption process.age::cli_common::UiCallbacks
, which implementsCallbacks
with requests to
the user viaage::cli_common::read_secret
.age::Decryptor::with_identities(Vec<Identity>)
age::Decryptor::with_identities_and_callbacks(Vec<Identity>, Box<dyn Callbacks>)
age::Encryptor
will insert a random recipient stanza into the header, to
keep age's joint well oiled.
Changed
- The CLI tools have been moved into the
rage
crate. - The
age::Decryptor::Keys
enum case has been renamed toIdentities
and
altered to store aBox<dyn Callbacks>
internally. age::Decryptor::trial_decrypt
andage::Decryptor::trial_decrypt_seekable
both no longer take arequest_passphrase
argument.age::cli_common::read_secret
:- Takes an additional
prompt
parameter. - Uses the system
pinentry
binary for requesting secrets if available. - Returns
pinentry::Error
instead ofio::Error
.
- Takes an additional
age::cli_common::read_or_generate_passphrase
now returnspinentry::Error
instead ofio::Error
.- Core age parsers and serializers have been moved into the
age-core
crate.
Fixed
- Fixed several crashes in the armored format reader, found by fuzzing. The
reader also now correctly enforces a canonical armor marker and line lengths. - Recipient stanzas with empty bodies are correctly parsed.
age-core
(relative to age 0.2.0
)
Fixed
- Base64 padding is now correctly rejected by the age stanza parser.
rage v0.2.0
Added
- The library crate can be compiled to WASM.
- When encrypting to a passphrase, rage will generate a secure passphrase if the
user does not provide one. SecretKey::to_string -> secrecy::SecretString
, which zeroizes most internal
state. (Zeroizing all internal state requires changes to thebech32
crate.)RecipientKey
implementsDisplay
, and can be converted to a string using
recipient.to_string()
.Decryptor::with_passphrase
constructor.--max-work-factor WF
argument for rage and rage-mount, to enable overriding
the default maximum (which is around 16 seconds of work).
Changed
age::Encryptor::wrap_output
now takes anage::Format
enum argument instead
of a boolean flag.- Recipients are now parsed as filenames last instead of first. If a filename
happens to also be a valid recipient format, the file will be ignored. This
can be overridden by using an absolute file path. - The filename
-
(hyphen) is now treated as an explicit request to read from
standard input or write to standard output when used as an input or output
filename. -o -
will override protections for terminals when standard output is not
being piped elsewhere: output will not be truncated, and binary data will be
printed directly to the terminal.- Armored encrypted output can now be printed to the terminal. Large files will
be truncated (to protect the terminal), corrupting the encryption. This can be
overriden with-o -
. - The
Decryptor::Passphrase
enum case has been altered to store an optional
maximum work factor.
Removed
SecretKey::to_str
(replaced bySecretKey::to_string
).RecipientKey::to_str
(replaced byDisplay
implementation and
recipient.to_string()
).
Fixed
- Corrected encoding of example recipients in manpages.
- Re-enabled the default identities file (#41).
- Fixed parser to reject encrypted OpenSSH keys if they contain invalid
bcrypt_pbkdf
parameters. - [Unix]
rage-keygen -o filename
now creates files with mode600
(i.e. the
output file is no longer world-readable). - Unknown recipient lines are now parsed and ignored during decryption, instead
of causing a hard failure.
rage v0.1.1
This time with binaries!
Added
- Debian packaging support via
cargo deb
. See docs/debian.md
for details.
Changed
- Moved the
num_traits
dependency behind theunstable
feature flag. - The
generate-docs
example now generates (the equivalent of )gzip -9
manpages, for ease of use in Debian packaging.
Fixed
- Decrypted chunks inside the STREAM implementation are now zeroized after use.