NAME
Crypt::Sodium::XS::MemVault - Protected memory objects
SYNOPSIS
use Crypt::Sodium::XS;
use Crypt::Sodium::XS::MemVault;
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 = Crypt::Sodium::XS::MemVault->new_from_file("/other/path");
if ($key1->memcmp($key2)) {
die "randomly generated key matches loaded key: impossible.";
}
my $mv = Crypt::Sodium::XS::MemVault->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("\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 length 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);
my $mv = Crypt::Sodium::XS::MemVault->new($bytes, $flags);
Create a new Crypt::Sodium::XS::MemVault from the content of $bytes
.
The default for $flags
is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
new_from_hex
my $mv = Crypt::Sodium::XS::MemVault->new_from_hex($hex_string);
my $mv = Crypt::Sodium::XS::MemVault->new_from_hex($hex_string, $flags);
Create a new Crypt::Sodium::XS::MemVault from the decoded content of $hex_string
.
The default for $flags
is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
new_from_base64
my $mv = Crypt::Sodium::XS::MemVault->new_from_base64($base64);
my $mv = Crypt::Sodium::XS::MemVault->new_from_base64($base64, $variant);
my $mv
= Crypt::Sodium::XS::MemVault->new_from_base64($base64, $variant, $flags);
my $mv = Crypt::Sodium::XS::MemVault->new_from_base64($base64, undef, $flags);
Create a new Crypt::Sodium::XS::MemVault from the decoded content of $base64
.
The default for $variant
is "BASE64_VARIANT_URLSAFE_NO_PADDING" in Crypt::Sodium::XS::Base64. See "CONSTANTS" in Crypt::Sodium::XS::Base64.
The default for $flags
is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
new_from_file
my $mv = Crypt::Sodium::XS::MemVault->new_from_file($path, $flags);
Create a new Crypt::Sodium::XS::MemVault by slurping all content from the file located at $path
.
The default for $flags
is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
new_from_fd
my $fd = fileno($fh);
my $mv = Crypt::Sodium::XS::MemVault->new_from_fd($fd, $flags);
Create a new Crypt::Sodium::XS::MemVault by reading from $fd
until EOF.
Note: This requires the file descriptor number, not a perl file handle.
The default for $flags
is "protmem_flags_memvault_default" in Crypt::Sodium::XS::ProtMem.
METHODS
clone
my $new_mv = $mv->clone;
Returns a new object $new_mv
with identical flags and contents to the original $mv
.
compare
$mv->compare($bytes, $length);
$mv->compare($other_mv, $length);
Fixed-time (for a given length) comparison of bytes as little-endian arbitrary-length integers. Returns 0
if the bytes are equal, -1
if $mv
is less than $other_mv
(or $bytes
), or 1
if $mv
is greater. Comparible to the cmp
perl operator.
$length
is optional iif $mv
and $other_mv
(or $bytes
) are equal lengths. If provided, only $length
bytes are compared.
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
.
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.
This method will croak if the Crypt::Sodium::XS::MemVault 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 length.
length
my $length = $mv->length;
Returns the byte length 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 and index).
memcmp
$mv->memcmp($bytes, $length);
$mv->memcmp($other_mv, $length);
Fixed-time (for a given length) comparison of bytes as little-endian arbitrary-length integers. Returns true if the bytes are equal, false otherwise.
$length
is optional iif $mv
and $other_mv
(or $bytes
) are equal lengths. If provided, only $length
bytes are compared.
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_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 and "index").
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.
xor
$mv->xor($bytes);
$mv->xor($other_mv);
Modifies protected memory using the exclusive-or operation with the provided argument. The argument must be the same number of bytes in length as the protected memory.
NOTE: Read carefully, this modifies in-place! It is much more performant this way. To instead return a new Crypt::Sodium::XS::MemVault (without modifying the original), use the ^
operator overload instead. An explicit method will be added in a future release.
OVERLOADS
boolean
my $is_empty = !$mv;
my $is_not_empty = !!$mv;
eq
my $is_equal = $mv eq $bytes;
my $is_equal = $bytes eq $mv;
my $is_equal = $mv eq $other_mv;
ne
my $not_equal = $mv ne $bytes;
my $not_equal = $bytes ne $mv;
my $not_equal = $mv ne $other_mv;
stringification
my $var = "$mv";
Stringification will croak if the Crypt::Sodium::XS::MemVault is conceptually "locked". See "lock" and "unlock".
concatenation
my $new_mv = $mv . $string;
my $new_mv = $string . $mv;
my $new_mv = $mv . $other_mv;
Note: .=
is equivalent to "concat".
repetition
my $new_mv = $mv x 3;
exclusive or
my $new_mv = $mv ^ $bytes;
my $new_mv = $bytes ^ $mv;
my $new_mv = $mv ^ $other_mv;
^=
is equivalent to "xor".
FEEDBACK
For reporting bugs, giving feedback, submitting patches, etc. please use the following:
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.