rage is a simple, modern, and secure file encryption tool, using the age format

Overview

rage: Rust implementation of age

rage is a simple, modern, and secure file encryption tool, using the age format. It features small explicit keys, no config options, and UNIX-style composability.

The format specification is at age-encryption.org/v1. To discuss the spec or other age related topics, please email the mailing list at [email protected]. age was designed by @Benjojo12 and @FiloSottile.

The reference interoperable Go implementation is available at filippo.io/age.

Usage

Usage:
  rage [--encrypt] -r RECIPIENT [-i IDENTITY] [-a] [-o OUTPUT] [INPUT]
  rage --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT]

Positional arguments:
  INPUT                       Path to a file to read from.

Optional arguments:
  -h, --help                  Print this help message and exit.
  -V, --version               Print version info and exit.
  -e, --encrypt               Encrypt the input (the default).
  -d, --decrypt               Decrypt the input.
  -p, --passphrase            Encrypt with a passphrase instead of recipients.
  --max-work-factor WF        Maximum work factor to allow for passphrase decryption.
  -a, --armor                 Encrypt to a PEM encoded format.
  -r, --recipient RECIPIENT   Encrypt to the specified RECIPIENT. May be repeated.
  -R, --recipients-file PATH  Encrypt to the recipients listed at PATH. May be repeated.
  -i, --identity IDENTITY     Use the identity file at IDENTITY. May be repeated.
  -o, --output OUTPUT         Write the result to the file at path OUTPUT.

INPUT defaults to standard input, and OUTPUT defaults to standard output.

RECIPIENT can be:
- An age public key, as generated by rage-keygen ("age1...").
- An SSH public key ("ssh-ed25519 AAAA...", "ssh-rsa AAAA...").

PATH is a path to a file containing age recipients, one per line
(ignoring "#" prefixed comments and empty lines).

IDENTITY is a path to a file with age identities, one per line
(ignoring "#" prefixed comments and empty lines), or to an SSH key file.
Passphrase-encrypted age identity files can be used as identity files.
Multiple identities may be provided, and any unused ones will be ignored.

Multiple recipients

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

$ rage -o example.png.age -r age1uvscypafkkxt6u2gkguxet62cenfmnpc0smzzlyun0lzszfatawq4kvf2u \
    -r age1ex4ty8ppg02555at009uwu5vlk5686k3f23e7mac9z093uvzfp8sxr5jum example.png

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
$ rage -R recipients.txt example.jpg > example.jpg.age

Passphrases

Files can be encrypted with a passphrase by using -p/--passphrase. By default rage will automatically generate a secure passphrase.

$ rage -p -o example.png.age example.png
Type passphrase (leave empty to autogenerate a secure one): [hidden]
Using an autogenerated passphrase:
    kiwi-general-undo-bubble-dwarf-dizzy-fame-side-sunset-sibling
$ rage -d example.png.age >example.png
Type passphrase: [hidden]

Passphrase-protected identity files

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

$ rage -p -o key.age <(rage-keygen)
Public key: age1pymw5hyr39qyuc950tget63aq8vfd52dclj8x7xhm08g6ad86dkserumnz
Type passphrase (leave empty to autogenerate a secure one): [hidden]
Using an autogenerated passphrase:
    flash-bean-celery-network-curious-flower-salt-amateur-fence-giant
$ rage -r age1pymw5hyr39qyuc950tget63aq8vfd52dclj8x7xhm08g6ad86dkserumnz secrets.txt > secrets.txt.age
$ rage -d -i key.age secrets.txt.age > secrets.txt
Type passphrase: [hidden]

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

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

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.

Installation

On macOS or Linux, you can use Homebrew:

brew tap str4d.xyz/rage https://str4d.xyz/rage
brew install rage

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

If your system has Rust 1.51+ installed (either via rustup or a system package), you can build directly from source:

cargo install rage

Note: previously the rage suite of tools was provided in the age Rust crate. This is no longer the case; age now only contains the Rust library.

Help from new packagers is very welcome.

Feature flags

  • mount enables the rage-mount tool, which can mount age-encrypted TAR or ZIP archives as read-only. It is currently only usable on Unix systems, as it relies on libfuse.

  • ssh (enabled by default) enables support for reusing existing SSH key files for age encryption.

  • unstable enables in-development functionality. Anything behind this feature flag has no stability or interoperability guarantees.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • rage-mount: update dependencies fuse_mt, time and zip

    rage-mount: update dependencies fuse_mt, time and zip

    I picked the first commit of fuse_mt that switched from using fuse to fuser (fuse_mt hasn't had any new releases since 0.5.1). That way rage-mount can be built against libfuse3. time and zip dependencies update is a side effect due to TimeSpec being obsolete.

    WARNING: I've never written any Rust code before, so please bear with my ignorance in the PR.

    opened by FollieHiyuki 16
  • Unicode feast in time of COVID19 plague

    Unicode feast in time of COVID19 plague

    Windows 7, rage 0.5.1

    [?] marks are related neither to the chosen console font, nor to the code page (866, 1251, 65001). 0.4.0 was the last one w/o them. Consider figuring out whoโ€™s responsible for this freaking decoration.

    opened by sergeevabc 12
  • YubiKey plugin

    YubiKey plugin

    Discuss this draft on the age-dev mailing list thread!

    Current draft specification:

    age PIV identities use ECC P-256 keys, generated on the hardware token, with certificates that never expire.

    For hardware tokens that support PIN and/or touch policies (such as YubiKeys), the default PIN policy is "once per session", and the default touch policy is "every decryption".

    A PIV recipient has the following form:

    Bech32("age1piv", SEC-1-C(public key))
    

    where SEC-1-C is the 33-byte compressed SEC-1 encoding.

    A PIV recipient line is of the form:

    -> piv encode(SHA-256(recipient)[:4]) encode(SEC-1-C(ECDH(ephemeral secret, p256-basepoint)))\n
    encode(encrypt[HKDF[salt, label](ECDH(ephemeral secret, public key))](file key))\n
    

    where ephemeral secret is a random scalar within the scalar field of P-256 and MUST be new for every file key, salt is SEC-1-C(ECDH(ephemeral secret, basepoint)) || SEC-1-C(public key), and label is age-encryption.org/v1/piv.

    A YubiKey "identity" is managed locally as a key stub with the following form:

    Uppercase(Bech32("age-yubikey-stub-", serial || slot || SHA-256(recipient)[:4]))
    

    The stub may exist in files alongside age X25519 secret keys, and is similarly passed to the age / rage binary with the -i flag.

    Note that the common tag in the recipient line and key stub means that recipients can trivially identify whether they can decrypt a particular recipient line, at the cost of making recipients linkable across different encrypted files.


    Usage example (responses out-of-date):

    $ cargo install --path . --features yubikey
    $ rage-keygen --yubikey -o keystub.txt
    Enter PIN for YubiKey with serial 12345678: [hidden]
    Use the up/down arrow keys to select a PIV slot (q to quit): Retired(R1) (Empty)
    Select a PIN policy: Once   (A PIN is required once per session, if set)
    Select a touch policy: Always (A physical touch is required for every decryption),
    Generate new key in Retired(R1) slot? yes
    $ cat keystub.txt 
    # created: 2019-12-07T23:13:09Z
    # yubikey:A_y2TWFFIZ8AhuFCjpxGzt_qiZrwMfEyDG6M8fqgG3ET
    AGE_YUBIKEY_STUB_00bc614e_9d_6ecc74ff
    $ echo "YubiKey FTW!" | rage -o test.age -r yubikey:A_y2TWFFIZ8AhuFCjpxGzt_qiZrwMfEyDG6M8fqgG3ET
    $ rage -d -i keystub.txt test.age
    Enter PIN for YubiKey with serial 12345678: [hidden]
    YubiKey FTW!
    
    opened by str4d 11
  • rage package naming

    rage package naming

    While wanting to package your rage program I realized package and binary name will probably conflict with Rage [0] that is already available in the target linux distribution as "rage".

    Do you know if others ran into this situation as well and how they solved it?

    Does this upstream project has preferences if and what alternative name I can use instead (rustage, ager, ...) ?

    Do you have experience/ideas what parts of the code have to be touched/changed downstream to use a different name than "rage"?

    Is it maintainable by replacing some strings programatically or are issues and new bugs likely if I have to change name, man pages, bash completetion, ... and propably more in order to make it work with a different name?

    Thank you for this software!

    [0] https://www.enlightenment.org/about-rage

    opened by cunyx 10
  • `cargo install rage` fails

    `cargo install rage` fails

    Environment

    • OS: Linux
    • rage version: v0.5.0

    What were you trying to do

    What happened

    Using:
       stable-x86_64-unknown-linux-gnu unchanged - rustc 1.49.0 (e1884a8e3 2020-12-29)
       
     $ cargo install rage
         Updating crates.io index
      Installing rage v0.5.0
     (...)
     error[E0599]: no method named `insert_and_get` found for struct `DOMAINS` in the current scope
       --> /home/gw/.cargo/registry/src/github.com-1ecc6299db9ec823/i18n-embed-fl-0.2.0/src/lib.rs:360:17
        |
    136 | / lazy_static::lazy_static! {
    137 | |     /// Cached data specific to each localization domain, to improve
    138 | |     /// performance of subsequent macro invokations.
    139 | |     static ref DOMAINS: dashmap::DashMap<String, DomainSpecificData> =
    140 | |         dashmap::DashMap::new();
    141 | | }
        | |_- method `insert_and_get` not found for this
    ...
    360 |           DOMAINS.insert_and_get(domain.clone(), data)
        |                   ^^^^^^^^^^^^^^ method not found in `DOMAINS`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0599`.
    error: could not compile `i18n-embed-fl`
    
    To learn more, run the command again with --verbose.
    warning: build failed, waiting for other jobs to finish...
    error: failed to compile `rage v0.5.0`, intermediate artifacts can be found at `/tmp/cargo-installJwMnWy`
    
    Caused by:
      build failed
    
    
    opened by gwpl 10
  • Performance improvements

    Performance improvements

    The performance improvement comes from the upgraded chacha20 dependency. Performance is slightly improved by default, and compiling with RUSTFLAGS="-Ctarget-feature=+avx2" will boost performance significantly.

    Part of #57.

    opened by str4d 10
  • Link to musl instead of glibc for .deb files

    Link to musl instead of glibc for .deb files

    Environment

    • OS: Debian stretch/buster
    • rage version: 0.6.0

    I recently set up an apt repo for Rust command line tools at https://apt.0xe.me, and I was hoping to add rage. However, to support the widest set of OS versions, linking to musl libc seems to give the best portability.

    Would you consider linking your .deb files to musl instead of glibc?

    Edit: See e.g. this ripgrep issue where linking to glibc was an issue: https://github.com/BurntSushi/ripgrep/issues/1890

    opened by ethanhs 9
  • Rage refuses to write to stdout even when armor is enabled

    Rage refuses to write to stdout even when armor is enabled

    PS C:\Users\Alice> rage -r age1wssqv0rf9ctp5w7j3dfmngurhe2xrj5869rv9x8a0gex5r0f6ejqy0prkw -a .\Desktop\age.txt
    Error: not printing to stdout
    
    [ Did rage not do what you expected? Could an error be more useful? ]
    [ Tell us: https://github.com/str4d/rage/issues/new/choose          ]
    
    opened by alajpie 7
  • Some questions about using

    Some questions about using

    Hi @str4d,

    Thanks for your great project. I have some questions during using rage.

    Why it spend almost same time for encrypting 100MB's video or 14KB's text file?

    I have use the crate made a test. The time is a second or so.

    Does passphrase support non-ASCII characters?

    Generally, we use ASCII characters to generate a passphrase. But I am curious if it has potential risk to use non-ASCII characters for a passphrase. I have tested with Chinese, it seems all right.

    question 
    opened by percy507 6
  • add Identity support for RSA PKCS#8 nocrypt

    add Identity support for RSA PKCS#8 nocrypt

    Hi @str4d,

    I realize that this feature is unlikely to see much use in practice, but I picked an old issue that seemed simple enough for a very new rustacean to be able to tackle (first real attempt at Rust).


    fully parse unencrypted PKCS#8 RSA private key

    parse encrypted PKCS#8 enough to recognize it as an unsupported key format

    add test coverage for key format support

    • PEM (PKCS#1) unencrypted RSA (supported)
    • PEM (PKCS#1) encrypted RSA (never support)
    • PKCS#8 unencrypted RSA (supported)
    • PKCS#8 encrypted (not supported, yet?)

    fixes #14

    opened by dwhjames 6
  • Add -j flag for invoking data-less plugins

    Add -j flag for invoking data-less plugins

    Some plugins (like yubikey-agent, or an sshpass equivalent) just need the user to inform rage that they exist and should be used, but not to actually pass any data across. A user can currently achieve this with an "empty plugin identity", which looks like:

    AGE-PLUGIN-NAME-1SIXCHR

    where name is the plugin name, and SIXCHR is the Bech32 checksum. This has two UX flaws:

    • The empty identity is a "magic string", that users need to know about in order to use these plugins.
    • It needs to go into a file (since -i only accepts files). For a user that only uses yubikey-agent this would mean having a loose file around with a single magic string, the location of which they need to remember.

    In a long UX discussion with @FiloSottile and @benjojo, we decided to add a new -j flag, which does this all for the user. When rage sees -j name, it internally behaves as if it had seen a -i file where the file contained AGE-PLUGIN-NAME-1SIXCHR (with valid checksum).

    This has a downstream effect on plugins: they can now distinguish a "default" behaviour. If a plugin only normally gives out plugin identities containing data, they can behave differently if they are sent (via the plugin protocol) an add-identity command with a known plugin name but empty data. This could be used to e.g. decrypt with a default set of identities, instead of a specific one.

    -j is intended to be handled in-line with -i for deterministic decryption (#236). For simplicity, rage will only support a single -j flag, and make it incompatible with -i flags.

    opened by str4d 6
  • RUSTSEC-2021-0145 RUSTSEC-2021-0127 RUSTSEC-2020-0071

    RUSTSEC-2021-0145 RUSTSEC-2021-0127 RUSTSEC-2020-0071

    user@linux ~ $ osv-scanner rage/
    Scanning dir rage/
    Scanning /home/user/rage/ at commit 3ff541a0a59864b782aeaca4d33cee1c8d61c2e9
    Scanned /home/user/rage/Cargo.lock file and found 304 packages
    โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
    โ”‚ OSV URL (ID IN BOLD)                              โ”‚ ECOSYSTEM โ”‚ PACKAGE    โ”‚ VERSION โ”‚ SOURCE          โ”‚
    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
    โ”‚ https://osv.dev/vulnerability/RUSTSEC-2021-0145   โ”‚ crates.io โ”‚ atty       โ”‚ 0.2.14  โ”‚ rage/Cargo.lock โ”‚
    โ”‚ https://osv.dev/vulnerability/RUSTSEC-2021-0127   โ”‚ crates.io โ”‚ serde_cbor โ”‚ 0.11.2  โ”‚ rage/Cargo.lock โ”‚
    โ”‚ https://osv.dev/vulnerability/GHSA-wcg3-cvx6-7396 โ”‚ crates.io โ”‚ time       โ”‚ 0.1.44  โ”‚ rage/Cargo.lock โ”‚
    โ”‚ https://osv.dev/vulnerability/RUSTSEC-2020-0071   โ”‚           โ”‚            โ”‚         โ”‚                 โ”‚
    โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
    
    opened by critkitten 0
  • How To Sign Blobs With Age Keypairs?

    How To Sign Blobs With Age Keypairs?

    Hello, I'm looking to sign blobs of data with the age keypairs generated through rage, however unless I'm missing something, it doesnt seem possible to do this?

    Any links to docs or examples would be appreciated.

    opened by bonedaddy 0
  • Initialize Vector With Capacity When Known

    Initialize Vector With Capacity When Known

    Overview

    There's a few places within the codebase where vectors are declared, but not initialized with any capacity, ie let a = vec![]. When one knows in advance with reasonable certainty the size of the data that the vector will hold, initializing the vector with that size as the capacity can potentially save on allocations.

    For example consider this line without the pre-initialization

                    // vector initialized without capacity
                    let mut salt = vec![];
                    // memory is allocated for 32 bytes and then the the bytes of `epk` pushed onto the vec
                    // total memory allocated: 32 bytes
                    salt.extend_from_slice(epk.as_bytes()); 
                    // to avoid excessive allocations, rust will allocate twice the capacity (64 bytes)
                    // total memory allocated: 96 bytes
                    salt.extend_from_slice(pk.as_bytes());
    
                    // total memory allocation cycles: 2
    

    Now consider the following which uses a pre-initialized capacity

                    // vector initialized with a capacity of 64 bytes
                    // as we know the values returned by `pk.as_bytes()` and `epk.as_bytes()` are 32 bytes each
                    // total memory allocated: 64 bytes
                    let mut salt = Vec::with_capacity(64);
                    // capacity is sufficient, no allocations
                    // total memory allocated: 64 bytes
                    salt.extend_from_slice(epk.as_bytes()); 
                    // capacity is sufficient, no allocations
                    // total memory allocated: 64 bytes
                    salt.extend_from_slice(pk.as_bytes());
    
                    // total memory allocation cycles: 1
    

    So as is demonstrated above, in these circumstances by using pre-initialized vectors memory usage is reduced by 32 bytes, and there will be 1 less syscall since an additional memory allocation cycle is avoided.

    opened by bonedaddy 0
  • Deterministic output

    Deterministic output

    I'm trying to use rage in a reproducible way, but the output varies between runs for the same key and plaintext. The key I tried with is an ssh-ed25519 public key and I'm using --armor.

    The use case is building system configurations with NixOS that contain encrypted secrets, decrypted on demand by the target system. It works, but since the rage output is non deterministic, secrets are seen as changed by Nix on every build causing unnecessary churn.

    I was wondering if there's a way rage could be deterministic. Maybe take a RNG seed as CLI argument? I tried patching out the randomness of the nonce and just using zeros but the output still varies. Is this doable? Would there be security implications besides being able to tell 2 messages have the same content?

    The alternative for me would be to generate the cipher text outside of Nix, and storing that in a way Nix can import. That way Nix would always see the same cipher text and the build would be reproducible. But I'd prefer not having a separate step required to build/deploy system configs.

    Thanks for the great tool!

    opened by ThinkChaos 0
  • Read each identity file in a single pass

    Read each identity file in a single pass

    read_identities now performs a single pass over each identity file in order to read it. Besides being perhaps a bit more efficient by reducing the amount of I/O performed by rage, the main improvement that this allows is that it's now possible to pass in the key from another program or through some sort of keychain. For instance, it's now possible to pass in a key using process substitution, i.e.

    rage -d -i <(...) encrypted_file.age
    

    This also makes the behavior of rage a little more consistent with the reference implementation (which allows this behavior).

    opened by kernelmethod 1
Releases(v0.9.0)
  • v0.9.0(Oct 27, 2022)

    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 inside std::io::Error.
    • age::ssh:
      • impl Clone for Identity

    Changed

    • MSRV is now 1.59.0.
    • age::Encryptor::with_recipients now returns Option<Encryptor>, with None returned if the provided list of recipients is empty (to prevent files being encrypted to no recipients). The recipients argument is also now Vec<Box<dyn age::Recipient + Send>>.
    • age::encrypted::Identity::recipients now returns Vec<Box<dyn age::Recipient + Send>>.

    Fixed

    • age::Decryptor now rejects invalid or non-canonical scrypt 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.
    Source code(tar.gz)
    Source code(zip)
    rage-musl_0.9.0_amd64.deb(1.02 MB)
    rage-musl_0.9.0_arm64.deb(897.86 KB)
    rage-musl_0.9.0_armhf.deb(864.90 KB)
    rage-v0.9.0-arm64-linux.tar.gz(3.89 MB)
    rage-v0.9.0-armv7-linux.tar.gz(3.84 MB)
    rage-v0.9.0-x86_64-darwin.tar.gz(2.25 MB)
    rage-v0.9.0-x86_64-linux.tar.gz(6.61 MB)
    rage-v0.9.0-x86_64-windows.zip(1.74 MB)
    rage_0.9.0_amd64.deb(1.50 MB)
    rage_0.9.0_arm64.deb(895.26 KB)
    rage_0.9.0_armhf.deb(848.47 KB)
  • v0.8.1(Jun 18, 2022)

    rage

    Security

    • Require age 0.8.1.

    age

    Security

    • age::Decryptor did not previously require "contributory" behaviour for X25519 recipient stanzas. If an age file has an X25519 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-canonical X25519 recipient stanzas (instead of ignoring or accepting them respectively), matching the age specification.
    Source code(tar.gz)
    Source code(zip)
    rage-musl_0.8.1_amd64.deb(1.00 MB)
    rage-musl_0.8.1_arm64.deb(878.23 KB)
    rage-musl_0.8.1_armhf.deb(848.42 KB)
    rage-v0.8.1-arm64-linux.tar.gz(3.83 MB)
    rage-v0.8.1-armv7-linux.tar.gz(3.77 MB)
    rage-v0.8.1-x86_64-darwin.tar.gz(2.23 MB)
    rage-v0.8.1-x86_64-linux.tar.gz(6.26 MB)
    rage-v0.8.1-x86_64-windows.zip(1.73 MB)
    rage_0.8.1_amd64.deb(1.31 MB)
    rage_0.8.1_arm64.deb(874.46 KB)
    rage_0.8.1_armhf.deb(828.08 KB)
  • v0.8.0(May 2, 2022)

    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 requires Clone + Send + Sync + 'static bounds.
    • age::cli_common::file_io::OutputWriter::new now takes an input_is_tty boolean argument. If input_is_tty is set to true, then if OutputWriter 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 during OutputWriter::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 type Connection<DebugReader<ChildStdout>, DebugWriter<ChildStdin>>.
      • BidirSend::{send, send_stanza} now return Ok(Error::Unsupported) when an unsupported response is received, instead of Err(io::Error), making it easier for plugins to implement fallback strategies.
    Source code(tar.gz)
    Source code(zip)
    rage-musl_0.8.0_amd64.deb(1009.72 KB)
    rage-musl_0.8.0_arm64.deb(862.83 KB)
    rage-musl_0.8.0_armhf.deb(842.81 KB)
    rage-v0.8.0-arm64-linux.tar.gz(3.71 MB)
    rage-v0.8.0-armv7-linux.tar.gz(3.70 MB)
    rage-v0.8.0-x86_64-darwin.tar.gz(2.16 MB)
    rage-v0.8.0-x86_64-linux.tar.gz(6.05 MB)
    rage-v0.8.0-x86_64-windows.zip(1.72 MB)
    rage_0.8.0_amd64.deb(1.27 MB)
    rage_0.8.0_arm64.deb(858.56 KB)
    rage_0.8.0_armhf.deb(822.23 KB)
  • v0.7.1(Dec 27, 2021)

    rage

    Fixed

    • Fixed a bug in 0.7.0 where non-canonical recipient stanza bodies in an age file header would cause rage 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); calling AgeStanza::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.
    Source code(tar.gz)
    Source code(zip)
    rage-v0.7.1-arm64-linux.tar.gz(3.68 MB)
    rage-v0.7.1-armv7-linux.tar.gz(3.67 MB)
    rage-v0.7.1-x86_64-darwin.tar.gz(2.17 MB)
    rage-v0.7.1-x86_64-linux.tar.gz(6.08 MB)
    rage-v0.7.1-x86_64-windows.zip(1.73 MB)
    rage_0.7.1_amd64.deb(1.29 MB)
    rage_0.7.1_armhf.deb(811.44 KB)
  • v0.7.0(Oct 18, 2021)

    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 of glibc 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 the secrecy crate.

    Changed

    • MSRV is now 1.51.0.
    • age::IdentityFile::into_identities now returns Vec<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 one Box<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 to Callbacks::display_message.
      • age::cli_common::UiCallbacks::display_message no longer uses pinentry (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 by IdentityFileEntry::Plugin).

    age-plugin 0.2.0

    Changed

    • MSRV is now 1.51.0.
    • age_plugin::Callbacks methods now return age_core::plugin::Error instead of () for internal errors, following changes to age_core::plugin::Result.

    age-core

    Added

    • age_core::secrecy, which re-exports the secrecy crate.
    • age_core::plugin::Error

    Changed

    • MSRV is now 1.51.0.
    • The body property of age_core::format::AgeStanza has been replaced by the AgeStanza::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 uses age_core::plugin::Error for its inner error type.
    Source code(tar.gz)
    Source code(zip)
    rage-v0.7.0-arm64-linux.tar.gz(3.55 MB)
    rage-v0.7.0-armv7-linux.tar.gz(3.58 MB)
    rage-v0.7.0-x86_64-darwin.tar.gz(2.14 MB)
    rage-v0.7.0-x86_64-linux.tar.gz(5.88 MB)
    rage-v0.7.0-x86_64-windows.zip(1.72 MB)
    rage_0.7.0_amd64.deb(1.27 MB)
    rage_0.7.0_arm64.deb(835.26 KB)
    rage_0.7.0_armhf.deb(819.07 KB)
  • v0.6.0(May 2, 2021)

    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 -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 like curl or wget to download a recipients file, and then pass it to rage.
    • 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 variable RUST_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 by adversary_offset, it would instead seek to offset + 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 use Seek.
      • rage-mount may have been affected; it does not use SeekFrom::End directly, but the tar or zip 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 implements age::Recipient and runs the V1 recipient plugin protocol.
      • age::plugin::IdentityPluginV1, which implements age::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 the web-sys crate, when compiling for a WebAssembly target such as wasm32-unknown-unknown. This feature is ignored for the wasm32-wasi target, which supports std::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, unlike Callbacks::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 with age::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 takes impl 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 a LazyFile struct (instead of wrapping std::io::File directly), which does not open the file until it is first written to.
    • age::decryptor::Callbacks has been moved to age::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 calling age::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 a size 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 the age library (to implement client support for plugins) and the age-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, and age_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, and age_core::format::read::age_stanza accepts only the new encoding. The new API age_core::format::read::legacy_age_stanza accepts either kind of stanza body encoding (the legacy minimal encoding, and the new explicit encoding).
    Source code(tar.gz)
    Source code(zip)
    rage-v0.6.0-arm64-linux.tar.gz(3.43 MB)
    rage-v0.6.0-armv7-linux.tar.gz(3.55 MB)
    rage-v0.6.0-x86_64-darwin.tar.gz(2.11 MB)
    rage-v0.6.0-x86_64-linux.tar.gz(5.86 MB)
    rage-v0.6.0-x86_64-windows.zip(1.68 MB)
    rage_0.6.0_amd64.deb(1.26 MB)
    rage_0.6.0_arm64.deb(825.24 KB)
    rage_0.6.0_armhf.deb(801.80 KB)
  • v0.5.0(Nov 22, 2020)

    rage

    Added

    • Italian, Spanish, and Chinese translations!
    • ssh feature flag, enabled by default. It can be disabled to remove support for ssh-rsa and ssh-ed25519 recipients and identities. ssh-rsa keys are now supported without the unstable 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 the ssh feature flag).
    • age::EncryptError, representing errors that can occur during encryption.
    • age::IdentityFile struct, for parsing a list of native age identities (currently only age::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 takes Vec<Box<dyn Recipient>>.
      • age::decryptor::RecipientsDecryptor now takes impl Iterator<Item = Box<dyn Identity>> in its decryption methods.
      • age::cli_common::read_identities now returns Vec<Box<dyn Identity>>, as it abstracts over age::IdentityFile and age::ssh::Identity. When the ssh feature flag is enabled, it also takes an unsupported_ssh argument for handling unsupported SSH identities.
      • age::Error has been renamed to age::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 to age::armor::Format.
    • SSH support is now disabled by default, behind the ssh feature flag. ssh-rsa keys are now supported without the unstable feature flag.
    • age::Callbacks has been moved to age::decryptor::Callbacks.

    Removed

    • age::SecretKey (replaced by age::x25519::Identity and age::ssh::Identity).
    • age::keys::RecipientKey (replaced by age::x25519::Recipient and age::ssh::Recipient).
    • age::keys::{Identity, IdentityKey} (replaced by age::Identity trait on individual identities, and age::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 for age::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 takes args: &[impl AsRef<str>].
    Source code(tar.gz)
    Source code(zip)
    rage-v0.5.0-arm64-linux.tar.gz(4.04 MB)
    rage-v0.5.0-armv7-linux.tar.gz(4.03 MB)
    rage-v0.5.0-x86_64-darwin.tar.gz(2.59 MB)
    rage-v0.5.0-x86_64-linux.tar.gz(6.30 MB)
    rage-v0.5.0-x86_64-windows.zip(2.16 MB)
    rage_0.5.0_amd64.deb(1.63 MB)
    rage_0.5.0_arm64.deb(1.15 MB)
    rage_0.5.0_armhf.deb(1.01 MB)
  • v0.4.0(Mar 25, 2020)

    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 from rage-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.
    • 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 the age::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 consumes self, making it harder to accidentally reuse a passphrase for multiple encrypted files.
    • age::cli_common::read_identities now takes an additional file_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.

    Source code(tar.gz)
    Source code(zip)
    rage-v0.4.0-arm64-linux.tar.gz(3.14 MB)
    rage-v0.4.0-armv7-linux.tar.gz(3.19 MB)
    rage-v0.4.0-x86_64-darwin.tar.gz(1.99 MB)
    rage-v0.4.0-x86_64-linux.tar.gz(3.27 MB)
    rage-v0.4.0-x86_64-windows.zip(1.72 MB)
    rage_0.4.0_amd64.deb(1.35 MB)
    rage_0.4.0_arm64.deb(983.72 KB)
    rage_0.4.0_armhf.deb(979.53 KB)
  • v0.3.0(Feb 9, 2020)

    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 with cargo 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 if pinentry is not available.

    age

    Added

    • age::Callbacks, which encapsulates any requests that might be necessary during the decryption process.
    • age::cli_common::UiCallbacks, which implements Callbacks with requests to the user via age::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 to Identities and altered to store a Box<dyn Callbacks> internally.
    • age::Decryptor::trial_decrypt and age::Decryptor::trial_decrypt_seekable both no longer take a request_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 of io::Error.
    • age::cli_common::read_or_generate_passphrase now returns pinentry::Error instead of io::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.
    Source code(tar.gz)
    Source code(zip)
    rage-v0.3.0-arm64-linux.tar.gz(3.12 MB)
    rage-v0.3.0-armv7-linux.tar.gz(3.17 MB)
    rage-v0.3.0-x86_64-darwin.tar.gz(1.97 MB)
    rage-v0.3.0-x86_64-linux.tar.gz(3.25 MB)
    rage-v0.3.0-x86_64-windows.zip(1.71 MB)
    rage_0.3.0_amd64.deb(1.34 MB)
    rage_0.3.0_arm64.deb(970.74 KB)
    rage_0.3.0_armhf.deb(966.50 KB)
  • v0.2.0(Jan 11, 2020)

    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 the bech32 crate.)
    • RecipientKey implements Display, 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 an age::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 by SecretKey::to_string).
    • RecipientKey::to_str (replaced by Display 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 mode 600 (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.
    Source code(tar.gz)
    Source code(zip)
    rage-v0.2.0-arm64-linux.tar.gz(3.05 MB)
    rage-v0.2.0-armv7-linux.tar.gz(3.11 MB)
    rage-v0.2.0-x86_64-darwin.tar.gz(1.91 MB)
    rage-v0.2.0-x86_64-linux.tar.gz(4.69 MB)
    rage-v0.2.0-x86_64-windows.zip(1.65 MB)
    rage_0.2.0_amd64.deb(1.29 MB)
    rage_0.2.0_arm64.deb(941.64 KB)
    rage_0.2.0_armhf.deb(944.64 KB)
  • v0.1.1(Dec 30, 2019)

    This time with binaries!

    Added

    • Debian packaging support via cargo deb. See docs/debian.md for details.

    Changed

    • Moved the num_traits dependency behind the unstable 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.
    Source code(tar.gz)
    Source code(zip)
    rage-v0.1.1-x86_64-darwin.tar.gz(1.88 MB)
    rage-v0.1.1-x86_64-linux.tar.gz(4.65 MB)
    rage-v0.1.1-x86_64-windows.zip(1.63 MB)
    rage_0.1.1_amd64.deb(1.27 MB)
  • v0.1.0(Dec 28, 2019)

    This is the first beta release of the age crate and rage tool suite.

    Note: The 0.X version series is being used for beta releases. The first non-beta release will be version 1.0.0.

    Source code(tar.gz)
    Source code(zip)
Diemโ€™s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.

Note to readers: On December 1, 2020, the Libra Association was renamed to Diem Association. The project repos are in the process of being migrated. A

Diem 16.7k Dec 29, 2022
The new, performant, and simplified version of Holochain on Rust (sometimes called Holochain RSM for Refactored State Model)

Holochain License: This repository contains the core Holochain libraries and binaries. This is the most recent and well maintained version of Holochai

Holochain 737 Dec 28, 2022
The Nervos CKB is a public permissionless blockchain, and the layer 1 of Nervos network.

Nervos CKB - The Common Knowledge Base master develop About CKB CKB is the layer 1 of Nervos Network, a public/permissionless blockchain. CKB uses Pro

Nervos Network 1k Dec 31, 2022
The fast, light, and robust client for the Ethereum mainnet.

OpenEthereum Fast and feature-rich multi-network Ethereum client. ยป Download the latest release ยซ Table of Contents Description Technical Overview Bui

OpenEthereum 1.6k Dec 28, 2022
The Phala Network Blockchain, pRuntime and the bridge.

Phala Blockchain Phala Network is a TEE-Blockchain hybrid architecture implementing Confidential Contract. This repo includes: node/: the main blockch

Phala Network 313 Dec 20, 2022
Python bindings for rage (age in Rust)

pyrage Python bindings for the Rust implementation of age. Index Installation Usage Development Licensing Installation You can install pyrage with pip

William Woodruff 14 Nov 23, 2022
WebAssembly wrapper of the rage encryption library

rage-wasm: WebAssembly wrapper of rage rage is a simple, modern, and secure file encryption tool, using the age format. It features small explicit key

Kan-Ru Chen 35 Dec 16, 2022
A Password Manager Using age for Encryption

A Password Manager Using age for Encryption Contents Features Usage Install Import from pass How It Works Features It is inspired by pass. senior's fe

Retirement Home 3 Nov 2, 2023
A gitweb/cgit-like interface for the modern age

rgit See it in action! A gitweb/cgit-like interface for the modern age. Written in Rust using Axum, git2, Askama and Sled. Sled is used to store all m

jordan 14 Apr 8, 2023
A secure file encryption utility, written in rust.

Dexios Dexios What is it? Building notes Checksums Performance Output file sizes Environment Variables Key Inputs Usage Examples To Do What is it? Dex

brxken 156 Dec 22, 2022
Cyg will help you to secure files in your repository directly using PGP encryption

cyg: Secure files in your repository Cyg will help you to secure files in your repository directly using PGP encryption. The name "cyg" was inspired b

Hisam Fahri 2 Aug 31, 2022
Authenticated Encryption with Associated Data Algorithms: high-level encryption ciphers

RustCrypto: Authenticated Encryption with Associated Data (AEAD) Algorithms Collection of Authenticated Encryption with Associated Data (AEAD) algorit

Rust Crypto 457 Jan 4, 2023
A set of cryptographic primitives for building a multi-hop Proxy Re-encryption scheme, known as Transform Encryption.

recrypt A pure-Rust library that implements a set of cryptographic primitives for building a multi-hop Proxy Re-encryption scheme, known as Transform

IronCore Labs 122 Dec 30, 2022
Rust encryption library for practical time-lock encryption.

tlock_age: Hybrid Timelock Encryption/Decryption in Rust tlock_age is a library to encrypt and decrypt age filekey using tlock scheme. It provides an

Thibault 5 Mar 29, 2023
Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust.

Deno Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust. Features Secure by default. No file,

Derek Jones 2 Aug 13, 2022
Rust command-line tool to encrypt and decrypt files or directories with age

Bottle A Rust command-line tool that can compress and encrypt (and decrypt and extract) files or directories using age, gzip, and tar. Bottle has no c

Sam Schlinkert 1 Aug 1, 2022
A Modern And Secure CLI Tool For Managing Environment Variables

Envio is a command-line tool that simplifies the management of environment variables across multiple profiles. It allows users to easily switch between different configurations and apply them to their current environment

Humble Penguin 536 Apr 16, 2023
Rust File Management CLI is a command-line tool written in Rust that provides essential file management functionalities. Whether you're working with files or directories, this tool simplifies common file operations with ease.

Rust FileOps Rust File Management CLI is a command-line tool written in Rust that provides essential file management functionalities. Whether you're w

Harikesh Ranjan Sinha 5 May 2, 2024
๐Ÿ” UPLINK is a Rust lightweight (2MB) tool for file transfer and remote management that uses AES-GCM and Envelope Encryption over WebSockets.

UPLINK โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–’โ–“โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘ โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–’โ–“โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘ โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘ โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–’โ–“โ–ˆโ–“โ–’โ–‘โ–‘โ–’โ–“โ–ˆ

Krystian Bajno 5 Sep 28, 2024
Tight Model format is a lossy 3D model format focused on reducing file size as much as posible without decreasing visual quality of the viewed model or read speeds.

What is Tight Model Format The main goal of the tmf project is to provide a way to save 3D game assets compressed in such a way, that there are no not

null 59 Mar 6, 2023