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/