NAME
Crypt::Sodium::XS::MemVault - Protected memory objects
SYNOPSIS
use Crypt::Sodium::XS;
use Crypt::Sodium::XS::MemVault ':constructors';
my $key = Crypt::Sodium::XS->generichash->keygen;
# keygen returns a Crypt::Sodium::XS::MemVault
$key->to_file("/some/path");
print "hex: ", $key->to_hex->unlock, "\n";
print "base64: ", $key->to_base64->unlock, "\n";
my $key2 = mv_from_file("/other/path");
if ($key1->memcmp($key2)) {
die "randomly generated key matches loaded key: inconceivable!";
}
my $mv = mv_new("hello");
my $extracted_data_mv = $mv->extract(1, 3); # "ell"
print $extracted_data_mv->unlock, "\n";
undef $extracted_data_mv;
$mv->unlock;
my $mv2 = $mv->clone; # unlocked clone is unlocked
$mv2->xor_equals("\x{1f}\x{0a}\x{1e}\x{00}\x{0b}");
print "$mv, $mv2!\n";
my $colon_idx = $mv->index('ll'); # 2
my $unlocked_mv = $mv->clone;
$mv->lock;
DESCRIPTION
Crypt::Sodium::XS::MemVault is the container for protected memory objects in Crypt::Sodium::XS which can be accessed from perl. It has constructors which can read in the sensitive data without going through perl. It also provides methods for manipulating the data while it remains only in protected memory. These methods (except "index") are time-dependent only on the size of protected data, not its content, so using them should not create any sidechannels.
Memory protections are documented in Crypt::Sodium::XS::ProtMem.
CONSTRUCTORS
new
my $mv = Crypt::Sodium::XS::MemVault->new($bytes, $flags);
$bytes
is an arbitrary string of bytes.
$flags
is optional. If not provided, the default is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
Returns a Crypt::Sodium::XS::MemVault: the content of $bytes
.
new_from_hex
my $mv = Crypt::Sodium::XS::MemVault->new_from_hex($hex_string, $flags);
$hex_string
is an arbitrary length string. Decoding of $hex_string
will stop at the first non-hex character.
$flags
is optional. If not provided, the default is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
Returns a Crypt::Sodium::XS::MemVault: the decoded content of $hex_string
.
new_from_base64
my $mv
= Crypt::Sodium::XS::MemVault->new_from_base64($base64, $variant, $flags);
$base64
is an arbitrary length string. Decoding of $base64
will stop at the first non-base64 character.
$variant
is optional. If not provided, the default is "BASE64_VARIANT_URLSAFE_NO_PADDING" in Crypt::Sodium::XS::Base64. See "CONSTANTS" in Crypt::Sodium::XS::Base64.
$flags
is optional. If not provided, the default is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
Returns a Crypt::Sodium::XS::MemVault: the decoded content of $base64
.
new_from_file
my $mv = Crypt::Sodium::XS::MemVault->new_from_file($path, $size, $flags);
$path
is a filesystem path.
$size
is optional. It is the maximum number of bytes to read from $fd
. If not provided or it numifies to 0, $fd
will be read until end-of-file.
$flags
is optional. If not provided, the default is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
Returns a Crypt::Sodium::XS::MemVault: the bytes read from the file located at $path
, up to $size
bytes or until end-of-file if $size
is 0.
Croaks on failure to open or read $path
.
new_from_fd
my $mv = Crypt::Sodium::XS::MemVault->new_from_fd($fd, $size, $flags);
$fd
is a file descriptor number. Note this is not a perl file handle. You may need to use the fileno
function.
$size
is optional. It is the maximum number of bytes to read from $fd
. If not provided or it numifies to 0, $fd
will be read until end-of-file.
$flags
is optional. If not provided, the default is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
Returns a Crypt::Sodium::XS::MemVault: the bytes from read $fd
, up to $size
bytes or until end-of-file if $size
is 0.
FUNCTIONS
Nothing is exported by default. A :constructors
tag imports the "CONSTRUCTOR FUNCTIONS". A :all
tag imports everything.
CONSTRUCTOR FUNCTIONS
mv_new
Shortcut to "new".
mv_from_base64
Shortcut to "new_from_base64".
mv_from_hex
Shortcut to "new_from_hex".
mv_from_fd
Shortcut to "new_from_fd".
mv_from_file
Shortcut to "new_from_file".
METHODS
bitwise_and
bitwise_and_equals
bitwise_or
bitwise_or_equals
bitwise_xor
bitwise_xor_equals
$mv2 = $mv->bitwise_and($bytes);
$mv2 = $mv->bitwise_or($other_mv);
$mv->bitwise_xor_equals($bytes);
$mv->bitwise_and_equals($other_mv);
Modifies protected memory using the associated bitwise operation with the provided argument. The argument must be the same size, in bytes, as the protected memory.
The *_equals
functions modify in-place. Other functions return a new Crypt::Sodium::XS::MemVault.
clone
my $new_mv = $mv->clone;
Returns a new object $new_mv
with identical flags and contents to the original $mv
.
compare
!!WARNING!!: The results of this comparison method can be used to leak information about the protected memory. If one can make arbitrary comparisons and has any visibility to the result, the protected data can be determined in (nbits - trailing_zero_bits) iterations! For a 256-bit key, that means it takes no more than 256 tries to extract the key. This method is fixed-time, but the only safe use of the result is whether it equals 0 or not, and "memcmp" is a better way to determine equality.
$mv->compare($bytes, $size);
$mv->compare($other_mv, $size);
Returns 0
if the bytes are equal, -1
if $mv
is less than $other_mv
(or $bytes
), or 1
if $mv
is greater. This method runs in fixed-time (for a given size), and compares bytes as little-endian arbitrary-length integers. Comparible to the cmp
perl operator.
$size
is optional iif $mv
and $other_mv
(or $bytes
) are equal sizes. If provided, only $size
bytes are compared. Note: Croaks if a comparison is of unequal sizes and $size
was not provided, or if $size
is larger than either of the operands.
Croaks if $mv
or $other_mv
is conceptually "locked". See "lock" and "unlock".
Note: This method is similar to memcmp(3); that is, it returns -1, 0, or 1 for the comparison results. For simple true/false equality comparisons, see "memcmp". The naming is chosen here to be consistent with libsodium.
concat
my $new_mv = $mv->concat($bytes);
my $new_mv = $mv->concat($other_mv);
Returns a new Crypt::Sodium::Memvault with the concatenated contents of $mv
followed by $bytes
or the contents of $other_mv
. The new object's flags will be the combined restrictions of $mv
and $new_mv
.
concat_inplace
$mv->concat_inplace($appended_bytes);
$mv->concat_inplace($another_mv);
Appends $appended_bytes
or the contents of $another_mv
to the end of <$mv>. Returns $mv
.
flags
my $flags = $mv->flags;
$mv->flags($new_flags);
Return or set memory protection flags. See Crypt::Sodium::XS::ProtMem.
from_base64
Shortcut for "new_from_base64" in Crypt::Sodium::XS::MemVault.
from_hex
Shortcut for "new_from_hex" in Crypt::Sodium::XS::MemVault.
index
!!WARNING!!: This method does not run in constant-time and may leak information about the protected memory.
my $pos = $mv->index($substr, $offset);
Searches for an occurence of $substr
in protected memory. This is similar to perl's own index function. Returns the first match of $substr
at or after $offset
, or -1 if $substr
is not found.
$offset
is optional. If not provided, the search will begin at the start of the protected memory. Unlike perl's index function, $offset
may not be negative, and the method will croak if offset is beyond the last byte of protected memory.
This method should only be used when protected memory starts with non-sensitive data, and is guaranteed to find $substr
before any sensitive data.
Croaks if $mv
is conceptually "locked". See "lock" and "unlock".
The Crypt::Sodium::XS::MemVault
object must be unlocked ("unlock") before using this method.
is_locked
my $is_locked = $mv->is_locked;
Returns a boolean indicating if the object is conceptually "locked."
is_zero
my $is_null = $mv->is_zero;
Returns a boolean indicating if the protected memory consists of all null bytes. Runs in constant time for a given size.
size
length (deprecated)
my $size = $mv->size;
my $size = $mv->length;
Returns the size, in bytes, of the protected memory. Runtime does not depend on data.
lock
$mv->lock;
Conceptually "lock" the object. This prevents use of the protected memory from perl in a way which could leak the data (i.e., stringification, "index", and "compare").
memcmp
$mv->memcmp($bytes, $size);
$mv->memcmp($other_mv, $size);
Returns true if the bytes are exactly equal, false otherwise. This method runs in fixed-time (for a given size), and compares bytes as little-endian arbitrary-length integers.
$size
is optional iif $mv
and $other_mv
(or $bytes
) are equal sizes. If provided, only $size
bytes are compared. Note: Croaks if operands are unequal sizes and $size
was not provided, or if $size
is larger than either of the operands.
When a comparison involves secret data (e.g. a key, a password, etc.), it is critical to use a constant-time comparison function. This property does not relate to computational complexity: it means the time needed to perform the comparison is the same for all data of the same size. The goal is to mitigate side-channel attacks.
Note: "memcmp" in libsodium is different than memcmp(3). This method returns only true/false for equality, not -1, 0, or 1 for the comparison results. For that, see "compare". The naming is chosen here to be consistent with libsodium.
pad
unpad
my $padded_mv = $mv->pad(32);
my $unpadded_mv = $padded->unpad(32);
Returns a new Crypt::Sodium::XS::MemVault with the contents of $mv
padded or unpadded respectively, to the next multiple of $blocksize
bytes.
These functions use the ISO/IEC 7816-4 padding algorithm. It supports arbitrary block sizes, ensures that the padding data are checked for computing the unpadded length, and is more resistant to some classes of attacks than other standard padding algorithms.
Notes:
Padding should be applied before encryption and removed after decryption.
Usage of padding to hide the length of a password is not recommended. A client willing to send a password to a server should hash it instead, even with a single iteration of the hash function.
This ensures that the length of the transmitted data is constant and that the server doesn’t effortlessly get a copy of the password.
Applications may eventually leak the unpadded length via side channels, but the sodium_pad() and sodium_unpad() functions themselves try to minimize side channels for a given length & <block size mask> value.
to_fd
$mv->to_fd(fileno($fh));
close($fh) or die "error: $!";
Returns number of bytes written. Croaks on failure.
to_file
$mv->to_file($path);
Returns number of bytes written. Croaks on failure.
to_base64
my $new_mv = $mv->to_base64($variant);
Returns a new Crypt::Sodium::XS::MemVault with the contents encoded in base64.
$variant
is optional (default: "BASE64_VARIANT_URLSAFE_NO_PADDING" in Crypt::Sodium::XS::Base64). See "CONSTANTS" in Crypt::Sodium::XS::Base64.
to_bytes
!!WARNING!!: This method returns protected memory as a normal perl byte string. This should not normally be necessary.
my $bytes = $mv->to_bytes;
Returns the protected memory as a byte string. This is the method used to overload stringification. Consider carefully before using.
Croaks if $mv
is conceptually "locked". See "lock" and "unlock".
to_hex
my $new_mv = $mv->to_hex;
Returns a new Crypt::Sodium::XS::MemVault with the contents encoded as a hexadecimal string.
unlock
$mv->unlock;
Conceptually "unlock" the object. This allows access to the protected memory from perl (i.e., stringification, "index", and "compare").
memzero
$mv->memzero;
Overwrites protected memory with null bytes.
You may not need to call this yourself; unless using both of the non-default flags "PROTMEM_FLAGS_MALLOC_PLAIN" in Crypt::Sodium::XS::ProtMem and "PROTMEM_FLAGS_MEMZERO_DISABLED" in Crypt::Sodium::XS::ProtMem (or "PROTMEM_ALL_DISABLED" in Crypt::Sodium::XS::ProtMem), the memory is zeroed when the object is destroyed.
OVERLOADS
boolean
my $is_empty = !$mv;
my $is_not_empty = !!$mv;
Equality eq, ==, ne, !=
my $is_equal = $mv eq $bytes;
my $is_equal = $bytes eq $mv;
my $is_equal = $mv eq $other_mv;
my $not_equal = $mv ne $bytes;
my $not_equal = $bytes ne $mv;
my $not_equal = $mv ne $other_mv;
Compares operands as arbitrary-length little-endian integers. Comparisons are made in fixed-time (for a given size). See "memcmp".
Comparisons lt, <, le, <=, gt, >, ge, >=
my $less = $mv < $bytes;
my $less = $mv lt $bytes;
my $less = $bytes < $mv;
my $less = $bytes lt $mv;
my $less = $mv < $other_mv;
my $less = $mv lt $other_mv;
...
All comparisons treat their operands as arbitrary-length little-endian integers. Comparisons are made in fixed-type (for a given size), but the results can leak information about protected memory. See "compare".
Croaks if $mv
or $other_mv
is conceptually "locked". See "lock" and "unlock".
stringification
my $var = "$mv";
Equivalent to "to_bytes". Stringification will croak if the Crypt::Sodium::XS::MemVault is conceptually "locked". See "lock" and "unlock". See also "to_bytes".
concatenation
my $new_mv = $mv . $string;
my $new_mv = $string . $mv;
my $new_mv = $mv . $other_mv;
Note: .=
is equivalent to "concat_inplace".
repetition
my $new_mv = $mv x 3;
bitwise and
my $new_mv = $mv & $bytes;
my $new_mv = $bytes & $mv;
my $new_mv = $mv & $other_mv;
$mv &= $other_mv;
&
is equivalent to "bitwise_and".
&=
is equivalent to "bitwise_and_equals".
bitwise or
my $new_mv = $mv | $bytes;
my $new_mv = $bytes | $mv;
my $new_mv = $mv | $other_mv;
$new_mv |= $other_mv;
|
is equivalent to "bitwise_or".
|=
is equivalent to "bitwise_or_equals".
bitwise exclusive-or
my $new_mv = $mv ^ $bytes;
my $new_mv = $bytes ^ $mv;
my $new_mv = $mv ^ $other_mv;
^
is equivalent to "bitwise_xor".
^=
is equivalent to "bitwise_xor_equals".
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.
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.