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_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 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, $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, $flags);

$path is a filesystem path.

$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 slurped bytes from the file located at $path.

Croaks on failure to open or read $path.

new_from_fd

my $mv = Crypt::Sodium::XS::MemVault->new_from_fd($fd, $flags);

$fd is a file descriptor number. Note this is not a perl file handle. You may need to use the fileno function.

$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 reading $fd until end-of-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 number of bytes in length 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

$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.

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_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.

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;

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:

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.