NAME
Crypt::Age - Perl implementation of age encryption (age-encryption.org)
VERSION
version 0.001
SYNOPSIS
use Crypt::Age;
# Generate keypair
my ($public, $secret) = Crypt::Age->generate_keypair();
# $public = "age1ql3z7hjy..."
# $secret = "AGE-SECRET-KEY-1..."
# Encrypt data
my $encrypted = Crypt::Age->encrypt(
plaintext => "Hello, World!",
recipients => [$public],
);
# Decrypt data
my $decrypted = Crypt::Age->decrypt(
ciphertext => $encrypted,
identities => [$secret],
);
# Encrypt file
Crypt::Age->encrypt_file(
input => 'secret.txt',
output => 'secret.txt.age',
recipients => [$public],
);
# Decrypt file
Crypt::Age->decrypt_file(
input => 'secret.txt.age',
output => 'secret.txt',
identities => [$secret],
);
DESCRIPTION
Crypt::Age is a pure Perl implementation of the age encryption format, compatible with the reference Go implementation (https://github.com/FiloSottile/age) and the Rust implementation (https://github.com/str4d/rage).
age is a simple, modern and secure file encryption tool with small explicit keys, no config options, and UNIX-style composability. The format specification is available at https://github.com/C2SP/C2SP/blob/main/age.md.
This implementation uses X25519 for key exchange, ChaCha20-Poly1305 for authenticated encryption, and HKDF-SHA256 for key derivation. All cryptographic primitives are provided by CryptX.
Files encrypted with Crypt::Age can be decrypted with the age and rage command-line tools, and vice versa.
generate_keypair
my ($public_key, $secret_key) = Crypt::Age->generate_keypair();
Generates a new X25519 keypair for age encryption.
Returns a list of two elements:
$public_key- Bech32-encoded public key starting withage1$secret_key- Bech32-encoded secret key starting withAGE-SECRET-KEY-1
The public key can be shared with others to encrypt files for you. The secret key must be kept private and is used to decrypt files encrypted to your public key.
encrypt
my $ciphertext = Crypt::Age->encrypt(
plaintext => $data,
recipients => \@public_keys,
);
Encrypts plaintext data for one or more recipients.
Parameters:
plaintext- The data to encrypt (required)recipients- ArrayRef of Bech32-encoded public keys (required)
Returns the encrypted data in age format, which includes a text header followed by the encrypted payload. The file key is wrapped separately for each recipient, allowing any of them to decrypt the data.
The returned data can be written to a file or transmitted directly.
decrypt
my $plaintext = Crypt::Age->decrypt(
ciphertext => $encrypted,
identities => \@secret_keys,
);
Decrypts age-encrypted data using one or more identities.
Parameters:
ciphertext- The age-encrypted data (required)identities- ArrayRef of Bech32-encoded secret keys (required)
Returns the decrypted plaintext.
The method tries each identity against each recipient stanza in the header until one successfully unwraps the file key. Dies if no matching identity is found or if the MAC verification fails.
encrypt_file
Crypt::Age->encrypt_file(
input => 'plaintext.txt',
output => 'encrypted.age',
recipients => \@public_keys,
);
Encrypts a file for one or more recipients.
Parameters:
input- Path to input file (required)output- Path to output file (required)recipients- ArrayRef of Bech32-encoded public keys (required)
The output file will be in age format and can be decrypted with the age or rage command-line tools.
Returns 1 on success. Dies on error (file not found, permission denied, etc).
decrypt_file
Crypt::Age->decrypt_file(
input => 'encrypted.age',
output => 'plaintext.txt',
identities => \@secret_keys,
);
Decrypts an age-encrypted file using one or more identities.
Parameters:
input- Path to encrypted input file (required)output- Path to decrypted output file (required)identities- ArrayRef of Bech32-encoded secret keys (required)
Returns 1 on success. Dies if no matching identity is found, if the MAC verification fails, or on file I/O errors.
KEY FORMAT
Public Keys
Public keys are Bech32-encoded X25519 public keys with the human-readable part age:
age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
Secret Keys
Secret keys are uppercase Bech32-encoded X25519 secret keys with the human-readable part AGE-SECRET-KEY-:
AGE-SECRET-KEY-1QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ3290DG
INTEROPERABILITY
This module is designed to be compatible with:
https://github.com/FiloSottile/age - Reference Go implementation
https://github.com/str4d/rage - Rust implementation
Files encrypted with Crypt::Age can be decrypted with these tools and vice versa.
SECURITY
age uses modern cryptographic primitives:
X25519 for key agreement (Curve25519 Diffie-Hellman)
ChaCha20-Poly1305 for authenticated encryption
HKDF-SHA256 for key derivation
The file key is randomly generated for each encryption operation. The payload is encrypted in 64 KiB chunks with unique nonces derived from a counter and final-chunk flag.
SEE ALSO
https://age-encryption.org - age encryption homepage
https://github.com/C2SP/C2SP/blob/main/age.md - age format specification
CryptX - Cryptographic toolkit providing all primitives
Crypt::Age::Keys - Key generation and encoding
Crypt::Age::Primitives - Low-level cryptographic operations
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-crypt-age/issues.
IRC
You can reach Getty on irc.perl.org for questions and support.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <torsten@raudssus.de>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.