NAME
Crypt::Sodium::XS::secretstream - Secret key authenticated encryption for multiple in-order messages
SYNOPSIS
use Crypt::Sodium::XS::secretstream ":default";
my $key = secretstream_xchacha20poly1305_keygen();
# encryption
my ($header, $stream_enc) = secretstream_xchacha20poly1305_init_encrypt($key);
my $ciphertext = $stream_enc->encrypt("hello,");
my $adata = "foo bar";
my $ct2 = $stream_enc->encrypt(
" world!",
secretstream_xchacha20poly1305_TAG_PUSH,
$adata
);
# decryption
# note that $header (created above) is required to begin decryption.
my $stream_dec = secretstream_xchacha20poly1305_init_decrypt($header, $key);
my $plaintext = $stream_dec->decrypt($ciphertext);
# note that $adata (created above) is required to decrypt successfully.
my ($pt2, $tag) = $stream_dec->decrypt($ct2, $adata);
if ($tag == secretstream_xchacha20poly1305_TAG_MESSAGE()) {
# default, most common tag
...
}
elsif ($tag == secretstream_xchacha20poly1305_TAG_PUSH()) {
# in-band mark for application to delimit related messages
...
}
elsif ($tag == secretstream_xchacha20poly1305_TAG_REKEY()) {
# re-keying after this message triggered by sender
...
}
elsif ($tag == secretstream_xchacha20poly1305_TAG_FINAL()) {
# last message
...
}
DESCRIPTION
Crypt::Sodium::XS::secretstream encrypts a sequence of messages, or a single message split into an arbitrary number of chunks, using a secret key, with the following properties:
Messages cannot be truncated, removed, reordered, duplicated or modified without this being detected by the decryption functions.
The same sequence encrypted twice will produce different ciphertexts.
An authentication tag is added to each encrypted message: stream corruption will be detected early, without having to read the stream until the end.
Each message can include additional data (ex: timestamp, protocol version) in the computation of the authentication tag.
Messages can have different sizes.
There are no practical limits to the total length of the stream, or to the total number of individual messages.
Ratcheting: at any point in the stream, it is possible to "forget" the key used to encrypt the previous messages, and switch to a new key.
Crypt::Sodium::XS::secretstream can be used to securely send an ordered sequence of messages to a peer. Since the length of the stream is not limited, it can also be used to encrypt files regardless of their size.
It transparently generates nonces and automatically handles key rotation.
FUNCTIONS
Nothing is exported by default. Crypt::Sodium::XS::secretstream, like libsodium, supports only the primitive-specific functions for one primitive. There is a single :xchacha20poly1305
import tag for the functions and constants listed below.
secretstream_xchacha20poly1305_init_decrypt
my $stream_dec
= secretstream_xchacha20poly1305_init_decrypt($header, $key, $flags);
$header
is an opaque header of "secretstream_xchacha20poly1305_HEADERBYTES" bytes generated by a previous call to "secretstream_xchacha20poly1305_init_encrypt".
$key
is a shared secret key. It must be "secretstream_xchacha20poly1305_KEYBYTES" bytes. It may be a "Crypt::Sodium::XS::MemVault".
$flags
is optional. It is the flags used for the secretstream decryption protected memory object. See Crypt::Sodium::XS::ProtMem.
Returns an opaque protected memory object: a secretstream decryption object.
See "STREAM INTERFACE".
Note: this is the libsodium function crypto_secretstream_xchacha20poly1305_init_pull
. Its name is slightly different for consistency of this API.
secretstream_xchacha20poly1305_init_encrypt
my ($header, $stream_enc)
= secretstream_xchacha20poly1305_init_encrypt($key, $flags);
$key
is a shared secret key. It must be "secretstream_xchacha20poly1305_KEYBYTES" bytes. It may be a "Crypt::Sodium::XS::MemVault".
$flags
is optional. It is the flags used for the secretstream encryption protected memory object. See Crypt::Sodium::XS::ProtMem.
Returns an opaque header of "secretstream_xchacha20poly1305_HEADERBYTES" bytes and an opaque protected memory object: a secretstream encryption object.
See "STREAM INTERFACE".
Note: this is the libsodium function crypto_secretstream_xchacha20poly1305_init_push
. Its name is slightly different for consistency of this API.
secretstream_xchacha20poly1305_keygen
my $key = secretstream_xchacha20poly1305_keygen($flags);
$flags
is optional. It is the flags used for the $key
Crypt::Sodium::XS::MemVault. See Crypt::Sodium::XS::ProtMem.
Returns a Crypt::Sodium::XS::MemVault: a new secret key of "secretstream_xchacha20poly1305_KEYBYTES" bytes.
STREAM INTERFACE
OVERVIEW
An encrypted stream starts with a short header, whose size is "secretstream_xchacha20poly1305_HEADERBYTES" bytes. That header must be sent/stored before the sequence of encrypted messages, as it is required to decrypt the stream. The header content doesn’t have to be secret and decryption with a different header would fail.
A tag is attached to each message. That tag can be any of:
- 0, or "secretstream_xchacha20poly1305_TAG_MESSAGE"
-
The most common tag, that doesn’t add any information about the nature of the message.
- "secretstream_xchacha20poly1305_TAG_FINAL"
-
Indicates that the message marks the end of the stream, and erases the secret key used to encrypt the previous sequence.
- "secretstream_xchacha20poly1305_TAG_PUSH"
-
Indicates that the message marks the end of a set of messages, but not the end of the stream. For example, a huge JSON string sent as multiple chunks can use this tag to indicate to the application that the string is complete and that it can be decoded. But the stream itself is not closed, and more data may follow.
- "secretstream_xchacha20poly1305_TAG_REKEY"
-
“Forget” the key used to encrypt this message and the previous ones, and derive a new secret key.
A typical encrypted stream simply attaches 0 as a tag to all messages, except the last one which is tagged as TAG_FINAL.
Note that tags are encrypted; encrypted streams do not reveal any information about sequence boundaries (PUSH and REKEY tags).
For each message, additional data can be included in the computation of the authentication tag. With this API, additional data is rarely required, and most applications can just omit it.
ENCRYPTION
The "secretstream_xchacha20poly1305_init_encrypt" method returns a header and a secretstream encryption object. This is an opaque object with the following methods:
- encrypt
-
my $ciphertext = $stream_enc->encrypt($plaintext, $tag, $adata);
$tag
is optional, and defaults to "secrestream_xchacha20poly1305_TAG_MESSAGE". The most common use is a tag of "secretstream_xchacha20poly1305_TAG_FINAL" to indicate the last message in a stream.$adata
is optional. If provided, it must match the additional data that was used when encrypting this message. It is rarely needed with the secretstream interface.
DECRYPTION
The "init_decrypt" method is the decryption counterpart for the receiving end of a stream. It takes a header and a secret key; the key must match the one used to create the encryption object, and the header must match the one that was returned when it was created. It returns a secretstream decryption object. This is an opaque object with the following methods:
- decrypt
-
my $plaintext = $stream_dec->decrypt($ciphertext, $adata); my ($plaintext, $tag) = $stream_dec->decrypt($ciphertext, $adata);
Croaks on decryption failure.
$tag
will be one of the tags listed in "CONSTANTS"; the tag used when encrypting this message. The most common use is a tag of "secretstream_xchacha20poly1305_TAG_FINAL" indicating the last message of a stream.$adata
is optional. It is rarely needed with the secretstream interface.
CONSTANTS
secretstream_xchacha20poly1305_ABYTES
my $tag_size = secretstream_ABYTES();
Returns the size, in bytes, of an authentication tag. Note that this is not a restriction on the amount of additional data (adata).
The size of any ciphertext is message size + "secretstream_xchacha20poly1305_ABYTES".
secretstream_xchacha20poly1305_HEADERBYTES
my $header_size = secretstream_xchacha20poly1305_HEADERBYTES();
Returns the size, in bytes, of a header generated by "secretstream_xchacha20poly1305_init_encrypt".
secretstream_xchacha20poly1305_KEYBYTES
my $key_size = secretstream_xchacha20poly1305_KEYBYTES();
Returns the size, in bytes, of a secret key.
secretstream_xchacha20poly1305_MESSAGEBYTES_MAX
my $message_max_size = secretstream_xchacha20poly1305_MESSAGEBYTES_MAX();
Returns the size, in bytes, of the maximum size of any message to be encrypted.
secretstream_xchacha20poly1305_TAG_MESSAGE
my $message_tag = secretstream_xchacha20poly1305_TAG_MESSAGE();
Returns the tag value for a TAG_MESSAGE secretstream tag.
secretstream_xchacha20poly1305_TAG_PUSH
my $push_tag = secretstream_xchacha20poly1305_TAG_PUSH();
Returns the tag value for a TAG_PUSH secretstream tag.
secretstream_xchacha20poly1305_TAG_REKEY
my $rekey_tag = secretstream_xchacha20poly1305_TAG_REKEY();
Returns the tag value for a TAG_REKEY secretstream tag.
secretstream_xchacha20poly1305_TAG_FINAL
my $final_tag = secretstream_xchacha20poly1305_TAG_FINAL();
Returns the tag value for a TAG_FINAL secretstream tag.
PRIMITIVES
libsodium only supports one primitive for secretstream.
xchacha20poly1305
SEE ALSO
- Crypt::Sodium::XS
- https://doc.libsodium.org/secret-key_cryptography/secretstream
- https://doc.libsodium.org/secret-key_cryptography/encrypted-messages
FEEDBACK
For reporting bugs, giving feedback, submitting patches, etc. please use the following:
RT queue at https://rt.cpan.org/Dist/Display.html?Name=Crypt-Sodium-XS
IRC channel
#sodium
onirc.perl.org
.Email the author directly.
For any security sensitive reports, please email the author directly or contact privately via IRC.
AUTHOR
Brad Barden <perlmodules@5c30.org>
COPYRIGHT & LICENSE
Copyright (c) 2022 Brad Barden. All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.