=encoding utf8

=head1 NAME

Crypt::NaCl::Sodium::secretbox - Secret-key authenticated encryption

=head1 SYNOPSIS

    use Crypt::NaCl::Sodium qw( :utils );

    my $crypto_secretbox = Crypt::NaCl::Sodium->secretbox();

    my ($key, $nonce, $decrypted_msg, $msg, $secret);

    ## Alice
    ########

    # Alice generates secret key
    $key = $crypto_secretbox->keygen();

    # ... and shares it with Bob
    send_to( Bob => { key => $key } );

    # now Alice and Bob can start communicating

    # Alice generates random nonce
    $nonce = $crypto_secretbox->nonce();

    send_to( Bob => { nonce => $nonce } );

    # Alice's message to Bob
    $msg = "Hi Bob!";

    # encrypts using combined mode
    $secret = $crypto_secretbox->encrypt( $msg, $nonce, $key );

    # message is ready for Bob
    send_to( Bob => { secret => $secret } );

    ## Bob
    ########

    # Bob receives the secret key from Alice
    $key = receive_for( Bob => 'key' );

    # and random nonce
    $nonce = receive_for( Bob => 'nonce' );

    # Bob is now ready to receive first message from Alice
    $secret = receive_for( Bob => 'secret' );

    # we have now all information required to decrypt message
    $decrypted_msg = $crypto_secretbox->decrypt( $secret, $nonce, $key );

    # time to reply
    $msg = "Hello Alice!";

    # generates new nonce
    $nonce = $crypto_secretbox->nonce();

    # this time we use detached mode
    ($mac, $secret) = $crypto_secretbox->encrypt( $msg, $nonce, $key );

    # Alice needs all pieces to verify and decrypt Bob's message
    send_to( Alice => { nonce => $nonce } );
    send_to( Alice => { mac => $mac } );
    send_to( Alice => { secret => $secret } );

    ## Alice
    ########

    # Bob used the detached mode
    $nonce  = receive_for( Alice => 'nonce' );
    $mac    = receive_for( Alice => 'mac' );
    $secret = receive_for( Alice => 'secret' );

    # we have now all information required to decrypt message
    $decrypted_msg = $crypto_secretbox->decrypt_detached( $mac, $secret, $nonce, $key );

    # NOTE: send_to() and receive_for() and user functions providing transport of
    # messages


=head1 DESCRIPTION

Secret-key (also known as symmetric-key) cryptography can be compared to
combination lock safe - only those who know the correct lock code can open it.

Therefore the generated key must be distributed in secret.

Nonce (number used once) does not have to be protected, but it is crucial that
the same nonce has not been ever reused with the same key.

The authentication tag confirms that the encrypted data has not been tampered
with before decrypting it.

=head1 METHODS

=head2 keygen

    my $key = $crypto_secretbox->keygen();

Helper method to generate a random key to be used by C<$crypto_secretbox>.

The length of the C<$key> equals L</KEYBYTES>.

B<NOTE:> keep the key confidential.

Returns L<Data::BytesLocker> object.

=head2 nonce

    my $nonce = $crypto_secretbox->nonce();

Helper method to generate a random nonce to be used by C<$crypto_secretbox>.

The length of the nonce equals L</NONCEBYTES>.

If initial value has been passed as the argument, it will then padded with
C<null> bytes.

    my $counter = 121;
    my $nonce = $crypto_secretbox->nonce($counter);
    $nonce =~ /^121\0+$/ or die;

B<NOTE:> nonce does not have to be random nor confidential, but it must never
be reused with the same key. It is large enough that the randomly
generated nonces have negligible risk of collision.

If random nonce is being used it needs to be provided to the other party to
allow decryption.

If counter is being used store it alongside the key to avoid accidental reuse on
the next session. In connection-oriented protocols counter-based nonce could help
rejecting duplicate messages.

Returns L<Data::BytesLocker> object.

=head2 encrypt

    # combined mode - MAC and encrypted message stored together
    my $secret = $crypto_secretbox->encrypt($msg, $nonce, $key);

    # detached mode - MAC and encrypted message returned separate
    my ($mac, $ciphertext) = $crypto_secretbox->encrypt($msg, $nonce, $key);

Encrypts the plaintext message using given C<$nonce> and C<$key>.

In scalar context works in combined mode, where MAC and encrypted message are stored
together.
The length of the C<$secret> is equal to the length of C<$msg> + L</MACBYTES>.

In list context the C<$mac> and C<$ciphertext> are returned separately.
The length of the C<$ciphertext> is equal to the length of C<$msg>, while length
of C<$mac> is L</MACBYTES>.

Returns L<Data::BytesLocker> object.

=head2 decrypt

    my $msg;
    eval {
        $msg = $crypto_secretbox->decrypt($secret, $nonce, $key);
    };
    if ( $@ ) {
        warn "Message forged!";
    } else {
        print "Decrypted message: $msg\n";
    }

Verifies and decrypts the secret message using given C<$nonce> and C<$key>.

Function croaks if the verification fails. Otherwise returns the decrypted message.

The length of the C<$msg> is equal to the length of C<$secret> - L</MACBYTES>.

Returns L<Data::BytesLocker> object.

=head2 decrypt_detached

    my $msg;
    eval {
        $msg = $crypto_secretbox->decrypt_detached($mac, $ciphertext, $nonce, $key);
    };
    if ( $@ ) {
        warn "Message forged!";
    } else {
        print "Decrypted message: $msg\n";
    }

Verifies and decrypts the secret message C<$ciphertext> authenticated with C<$mac>
using given C<$nonce> and C<$key>.

Function croaks if the verification fails. Otherwise returns the decrypted message.

The length of the C<$msg> equals the length of C<$ciphertext>.

Returns L<Data::BytesLocker> object.

=head1 CONSTANTS

=head2 NONCEBYTES

    my $nonce_length = $crypto_secretbox->NONCEBYTES;

Returns the length of nonce.

=head2 KEYBYTES

    my $key_length = $crypto_secretbox->KEYBYTES;

Returns the length of key.

=head2 MACBYTES

    my $mac_length = $crypto_secretbox->MACBYTES;

Returns the length of MAC.

=head1 ALGORITHM DETAILS

C<crypto_secretbox> for encryption uses XSalsa20 stream cipher (which is based
on Salsa20, but with much longer nonce) and Poly1305 MAC for authentication.

=head1 SEE ALSO

=over 4

=item * L<Data::BytesLocker> - guarded data storage

=item * L<Extending the Salsa20 nonce|http://cr.yp.to/snuffle/xsalsa-20110204.pdf>
- the paper introducing XSalsa20

=item * L<The Poly1305-AES message-authentication code|http://cr.yp.to/mac/poly1305-20050329.pdf>

=back

=head1 AUTHOR

Alex J. G. Burzyński <F<ajgb@cpan.org>>

=head1 COPYRIGHT & LICENSE

Copyright (c) 2015 Alex J. G. Burzyński. All rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut
