NAME
Data::Tools::Crypto::Symmetric - authenticated symmetric encryption with a shared secret key
SYNOPSIS
use Data::Tools::Crypto::Symmetric;
use Crypt::PRNG;
use Exception::Sink;
# the key is 32 raw bytes, not a passphrase
my $key = Crypt::PRNG::random_bytes( 32 );
my $crypto = Data::Tools::Crypto::Symmetric->new( $key );
# --------------------------------------------------------------------------
my $ctext = $crypto->encrypt( $ptext );
my $ptext = $crypto->decrypt( $ctext );
boom( "data cannot be decrypted" ) unless defined $ptext;
# --------------------------------------------------------------------------
# the whole encoding and freeze/thaw API comes from
# Data::Tools::Crypto::Base, see there for the full list
my $sealed = $crypto->freeze_base64url( { name => 'test' } );
my $data = $crypto->thaw_base64url( $sealed );
# --------------------------------------------------------------------------
# a new key can be set on an existing object
$crypto->reinit( $another_key );
# --------------------------------------------------------------------------
DESCRIPTION
Data::Tools::Crypto::Symmetric encrypts with ChaCha20-Poly1305, which is authenticated: cryptotext which has been modified in any way will not decrypt at all, rather than decrypting to wrong data. A fresh random nonce is used for every message, so encrypting the same plaintext twice never gives the same cryptotext.
Both sides need the same secret key. If there is no way to share one, use Data::Tools::Crypto::RSA instead.
METHODS
new( $key )
Returns a new object. $key must be exactly 32 raw bytes, undef or an empty key is refused. A key which perl holds as characters is accepted if it can be represented as bytes, and is converted, otherwise it is rejected -- 32 characters are not always 32 bytes.
There are no options yet. Unknown options are refused rather than silently ignored.
reinit( $key )
Sets a new key on an existing object. All previous state is cleared first, so if the key or an option is rejected the object is left without a key and is not usable until a later reinit() succeeds. Catching the exception and handling the unusable object is left to the caller.
encrypt( $plaintext )
Returns the cryptotext, which is always binary. There is no limit on the size of the plaintext, the cryptotext is 29 bytes longer than the plaintext.
decrypt( $cryptotext )
Returns the plaintext, or undef if the cryptotext cannot be decrypted, which covers a wrong key, modified data, truncated data and random input alike. There is deliberately no more detail than that: telling these cases apart would help an attacker more than a caller.
UTF8 HANDLING
encrypt()/decrypt() are transparent. Whatever goes in comes back out, with the same value, the same length and in the same form. A byte string returns as a byte string and a character string returns as a character string, which are not the same thing in perl even when they print identically:
my $chars = "caf\x{e9}"; # 4 characters
my $bytes = "caf\xc3\xa9"; # 5 bytes, the utf8 encoding of it
$crypto->decrypt( $crypto->encrypt( $chars ) ); # 4 characters back
$crypto->decrypt( $crypto->encrypt( $bytes ) ); # 5 bytes back
Cryptotext is always binary. Passing a character string to decrypt() is a mistake and raises an exception, rather than being silently mangled.
ERRORS
The two kinds of failure are reported differently and never confused:
* a caller or configuration error raises an exception with boom(), i.e. a
missing, empty or wrong sized key, an unknown option, an undefined
argument, a character string where binary data is required, or any use
of an object whose reinit() failed
* data which simply does not decrypt returns undef, which is a normal
result the caller is expected to check
DATA FORMAT
nonce (12 bytes) . cryptotext . authentication tag (16 bytes)
The plaintext carries one leading marker byte, 'b' for binary or 'u' for a character string, which is what makes the utf8 handling above transparent. This accounts for the 29 bytes of overhead.
REQUIRED MODULES
Data::Tools::Crypto::Symmetric uses:
* Data::Tools::Crypto::Base
* Crypt::AuthEnc::ChaCha20Poly1305 (CryptX)
* Crypt::PRNG (CryptX)
* Encode
* Exception::Sink
GITHUB REPOSITORY
https://github.com/cade-vs/perl-data-tools-crypto
git clone https://github.com/cade-vs/perl-data-tools-crypto.git
AUTHOR
Vladi Belperchinov-Shabanski "Cade"
<cade@noxrun.com> <cade@bis.bg> <cade@cpan.org>
http://cade.noxrun.com/