Crypt-NaCl-Sodium
view release on metacpan or search on metacpan
The length of the $bytes equals the value of $num_of_bytes.
Returns Data::BytesLocker object.
VARIABLES
$Data::BytesLocker::DEFAULT_LOCKED
use Crypt::NaCl::Sodium;
$Data::BytesLocker::DEFAULT_LOCKED = 1;
By default all values returned from the provided methods are unlocked
Data::BytesLocker objects. If this variable is set to true then the
returned objects are locked and require calling "unlock" in
Data::BytesLocker before accessing.
SEE ALSO
* Crypt::NaCl::Sodium::secretbox - Secret-key authenticated encryption
(XSalsa20/Poly1305 MAC)
* Crypt::NaCl::Sodium::auth - Secret-key message authentication
(HMAC-SHA256, HMAC-SHA512, HMAC-SHA512/256 )
* Crypt::NaCl::Sodium::aead - Authenticated Encryption with Additional
#include "ppport.h"
/* libsodium */
#include "sodium.h"
#define DUMP(v) do_sv_dump(0, Perl_debug_log, v, 0, 4, 0, 0);
typedef struct {
unsigned char * bytes;
STRLEN length;
int locked;
} DataBytesLocker;
#if defined(AES256GCM_IS_AVAILABLE)
typedef struct {
int locked;
crypto_aead_aes256gcm_state * ctx;
} CryptNaClSodiumAeadAes256gcmState;
#endif
typedef struct {
crypto_generichash_state * state;
size_t init_bytes;
} CryptNaClSodiumGenerichashStream;
typedef struct {
{
DataBytesLocker *new_bl;
DataBytesLocker *cur_bl;
PERL_UNUSED_VAR(params);
Newx(new_bl, 1, DataBytesLocker);
if ( new_bl == NULL ) {
croak("Could not allocate enough memory");
}
cur_bl = (DataBytesLocker *)mg->mg_ptr;
new_bl->length = cur_bl->length;
new_bl->locked = cur_bl->locked;
new_bl->bytes = sodium_malloc(cur_bl->length + 1 );
if ( new_bl->bytes == NULL ) {
croak("Could not allocate enough memory");
}
memcpy(new_bl->bytes,cur_bl->bytes,cur_bl->length);
mg->mg_ptr = (char *)new_bl;
return 0;
}
#define DUPSTREAM(streamtype, statetype, padding, extra) \
croak("Could not allocate enough memory");
}
bl->bytes = sodium_malloc(size + 1 );
if ( bl->bytes == NULL ) {
croak("Could not allocate enough memory");
}
bl->length = size;
bl->locked = 0;
return bl;
}
static SV * DataBytesLocker2SV(pTHX_ DataBytesLocker *bl) {
SV *sv = newSV(0);
SV *obj = newRV_noinc(sv);
SV *default_locked;
#ifdef USE_ITHREADS
MAGIC *mg;
#endif
sv_bless(obj, gv_stashpv("Data::BytesLocker", 0));
if ( (default_locked = get_sv("Data::BytesLocker::DEFAULT_LOCKED", 0)) ) {
if ( SvTRUE(default_locked) ) {
int rc = sodium_mprotect_noaccess((void *)bl->bytes);
if ( rc != 0 ) {
croak("Unable to protect BytesLocker object");
}
bl->locked = 1;
}
} else {
int rc = sodium_mprotect_readonly((void *)bl->bytes);
if ( rc != 0 ) {
croak("Unable to protect BytesLocker object");
}
}
#ifdef USE_ITHREADS
}
pk->ctx = sodium_malloc(crypto_aead_aes256gcm_statebytes());
if ( pk->ctx == NULL ) {
croak("Could not allocate enough memory");
}
crypto_aead_aes256gcm_beforenm(pk->ctx, key);
pk->locked = 0;
return pk;
}
static SV * AeadAes256gcmState2SV(pTHX_ CryptNaClSodiumAeadAes256gcmState *state) {
SV *sv = newSV(0);
SV *obj = newRV_noinc(sv);
SV *default_locked;
#ifdef USE_ITHREADS
MAGIC *mg;
#endif
sv_bless(obj, gv_stashpv("Crypt::NaCl::Sodium::aead::aes256gcmstate", 0));
if ( (default_locked = get_sv("Data::BytesLocker::DEFAULT_LOCKED", 0)) ) {
if ( SvTRUE(default_locked) ) {
int rc = sodium_mprotect_noaccess((void *)state->ctx);
if ( rc != 0 ) {
croak("Unable to protect AES256GCM precalculated key object");
}
state->locked = 1;
}
}
#ifdef USE_ITHREADS
mg =
#endif
sv_magicext(sv, NULL, PERL_MAGIC_ext, &vtbl_aead_aes256gcmstate, (const char *)state, 0);
#if defined(USE_ITHREADS) && defined(MGf_DUP)
mg->mg_flags |= MGf_DUP;
XSRETURN_EMPTY;
}
nonce_buf = (unsigned char *)SvPV(nonce, nonce_len);
if ( nonce_len != crypto_aead_aes256gcm_NPUBBYTES ) {
croak("Invalid nonce");
}
precal_key = GetAeadAes256gcmState(aTHX_ precalculated_key);
if ( precal_key->locked ) {
croak("Unlock AES256GCM precalculated key object before accessing the state");
}
msg_buf = (unsigned char *)SvPV(msg, msg_len);
adata_buf = (unsigned char *)SvPV(adata, adata_len);
enc_len = msg_len + crypto_aead_aes256gcm_ABYTES;
bl = InitDataBytesLocker(aTHX_ enc_len);
}
msg_buf = (unsigned char *)SvPV(msg, msg_len);
if ( msg_len < crypto_aead_aes256gcm_ABYTES ) {
croak("Invalid ciphertext");
}
precal_key = GetAeadAes256gcmState(aTHX_ precalculated_key);
if ( precal_key->locked ) {
croak("Unlock AES256GCM precalculated key object before accessing the state");
}
adata_buf = (unsigned char *)SvPV(adata, adata_len);
enc_len = msg_len;
bl = InitDataBytesLocker(aTHX_ enc_len);
if ( crypto_aead_aes256gcm_decrypt_afternm( bl->bytes, (unsigned long long *)&enc_len, NULL, msg_buf, msg_len, adata_buf, adata_len, nonce_buf, (const crypto_aead_aes256gcm_state *) precal_key->ctx) == 0 ) {
bl->bytes[enc_len] = '\0';
{
int rc;
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState* state;
state = GetAeadAes256gcmState(aTHX_ self);
rc = sodium_mprotect_noaccess((void *)state->ctx);
if (rc == 0 ) {
state->locked = 1;
XSRETURN_YES;
}
croak("Unable to lock memory: %s", Strerror(errno));
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
void
{
int rc;
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState* state;
state = GetAeadAes256gcmState(aTHX_ self);
rc = sodium_mprotect_readonly((void *)state->ctx);
if (rc == 0 ) {
state->locked = 0;
XSRETURN_YES;
}
croak("Unable to unlock memory: %s", Strerror(errno));
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
void
is_locked(self, ...)
SV * self
PPCODE:
{
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState* state;
state = GetAeadAes256gcmState(aTHX_ self);
if ( state->locked ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
void
SV * swapped
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
DataBytesLocker *bl;
unsigned int count = 0;
unsigned int cur = 0;
OVERLOAD: x
CODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
count = SvUV(other);
bl = InitDataBytesLocker(aTHX_ sbl->length * count);
while(count--) {
memcpy(bl->bytes + sbl->length * cur++, sbl->bytes, sbl->length);
}
SV * swapped
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
unsigned char *buf;
STRLEN buf_len;
DataBytesLocker *bl;
OVERLOAD: .
CODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
buf = (unsigned char *)SvPV(other, buf_len);
bl = InitDataBytesLocker(aTHX_ sbl->length + buf_len);
if ( SvTRUE(swapped) ) {
memcpy(memcpy(bl->bytes, buf, buf_len) + buf_len, sbl->bytes, sbl->length);
}
_overload_bool(self, ...)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
int res;
OVERLOAD: bool
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
if ( sbl->length ) {
res = 1;
} else {
res = 0;
}
if ( res ) {
_overload_not(self, ...)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
int res;
OVERLOAD: !
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
if ( sbl->length ) {
res = 0;
} else {
res = 1;
}
if ( res ) {
SV * swapped
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
unsigned char *buf;
STRLEN buf_len;
int res;
OVERLOAD: eq
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
buf = (unsigned char *)SvPV(other, buf_len);
if ( sbl->length != buf_len ) {
croak("Variables of unequal length cannot be automatically compared. Please use memcmp() with the length argument provided");
}
if ( sodium_memcmp(sbl->bytes, buf, sbl->length) == 0 ) {
SV * swapped
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
unsigned char *buf;
STRLEN buf_len;
int res;
OVERLOAD: ne
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
buf = (unsigned char *)SvPV(other, buf_len);
if ( sbl->length != buf_len ) {
croak("Variables of unequal length cannot be automatically compared. Please use memcmp() with the length argument provided");
}
if ( sodium_memcmp(sbl->bytes, buf, sbl->length) == 0 ) {
void
_overload_str(self, ...)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
SV * pv;
OVERLOAD: \"\"
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
pv = newSVpvn((unsigned char *)sbl->bytes, sbl->length);
SvREADONLY_on(pv);
mXPUSHs(pv);
}
void
SV *
clone(self)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
DataBytesLocker *bl;
CODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
bl = InitDataBytesLocker(aTHX_ sbl->length);
memcpy(bl->bytes, sbl->bytes, sbl->length);
RETVAL = DataBytesLocker2SV(aTHX_ bl);
}
OUTPUT:
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
int rc;
PPCODE:
{
rc = sodium_mprotect_noaccess((void *)sbl->bytes);
if (rc == 0 ) {
sbl->locked = 1;
XSRETURN_YES;
}
croak("Unable to lock memory: %s", Strerror(errno));
}
void
unlock(self)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
int rc;
PPCODE:
{
rc = sodium_mprotect_readonly((void *)sbl->bytes);
if (rc == 0 ) {
sbl->locked = 0;
XSRETURN_YES;
}
croak("Unable to unlock memory: %s", Strerror(errno));
}
SV *
length(self)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
CODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
RETVAL = newSVuv((UV)sbl->length);
}
OUTPUT:
RETVAL
void
is_locked(self, ...)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
PPCODE:
{
if ( sbl->locked ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
}
SV *
to_hex(self)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
char * hex;
size_t hex_len;
CODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
hex_len = sbl->length * 2;
hex = sodium_malloc(hex_len + 1);
if ( hex == NULL ) {
croak("Could not allocate memory");
}
sodium_bin2hex(hex, hex_len + 1, sbl->bytes, sbl->length);
void
bytes(self)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
SV * pv;
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
pv = newSVpvn((unsigned char *)sbl->bytes, sbl->length);
mXPUSHs(pv);
}
void
memcmp(self, bytes, length = 0)
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
unsigned char * bytes_buf;
STRLEN bytes_len;
PPCODE:
{
if ( GIMME_V == G_VOID ) {
XSRETURN_EMPTY;
}
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
if (sv_derived_from(bytes, "Data::BytesLocker")) {
DataBytesLocker* rbl = GetBytesLocker(aTHX_ bytes);
if ( rbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
bytes_buf = rbl->bytes;
bytes_len = rbl->length;
}
else {
bytes_buf = (unsigned char *)SvPV(bytes, bytes_len);
}
if ( length == 0 ) {
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
unsigned char * num_buf;
STRLEN num_len;
PPCODE:
{
if ( GIMME_V == G_VOID ) {
XSRETURN_EMPTY;
}
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
if (sv_derived_from(num, "Data::BytesLocker")) {
DataBytesLocker* rbl = GetBytesLocker(aTHX_ num);
if ( rbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
num_buf = rbl->bytes;
num_len = rbl->length;
}
else {
num_buf = (unsigned char *)SvPV(num, num_len);
}
if ( length == 0 ) {
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
SV * pv;
DataBytesLocker *bl;
PPCODE:
{
if ( GIMME_V == G_VOID ) {
XSRETURN_EMPTY;
}
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
bl = InitDataBytesLocker(aTHX_ sbl->length);
memcpy(bl->bytes, sbl->bytes, sbl->length);
sodium_increment(bl->bytes, sbl->length);
mXPUSHs( DataBytesLocker2SV(aTHX_ bl) );
unsigned char * num_buf;
STRLEN num_len;
STRLEN inc_len;
DataBytesLocker *bl;
PPCODE:
{
if ( GIMME_V == G_VOID ) {
XSRETURN_EMPTY;
}
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
if (sv_derived_from(num, "Data::BytesLocker")) {
DataBytesLocker* rbl = GetBytesLocker(aTHX_ num);
if ( rbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
num_buf = rbl->bytes;
num_len = rbl->length;
}
else {
num_buf = (unsigned char *)SvPV(num, num_len);
}
if ( items == 3 ) {
void
is_zero(self, ...)
SV * self
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
SV * pv;
PPCODE:
{
if ( sbl->locked ) {
croak("Unlock BytesLocker object before accessing the data");
}
if ( sodium_is_zero(sbl->bytes, sbl->length) == 1 ) {
XSRETURN_YES;
}
XSRETURN_NO;
}
lib/Crypt/NaCl/Sodium.pm view on Meta::CPAN
Returns L<Data::BytesLocker> object.
=head1 VARIABLES
=head2 $Data::BytesLocker::DEFAULT_LOCKED
use Crypt::NaCl::Sodium;
$Data::BytesLocker::DEFAULT_LOCKED = 1;
By default all values returned from the provided methods are
unlocked L<Data::BytesLocker> objects. If this variable is set to true then
the returned objects are locked and require calling
L<Data::BytesLocker/"unlock"> before accessing.
=head1 SEE ALSO
=over 4
=item * L<Crypt::NaCl::Sodium::secretbox> - Secret-key authenticated encryption (XSalsa20/Poly1305 MAC)
=item * L<Crypt::NaCl::Sodium::auth> - Secret-key message authentication (HMAC-SHA256, HMAC-SHA512, HMAC-SHA512/256 )
lib/Crypt/NaCl/Sodium/aead.pod view on Meta::CPAN
When called makes the state inaccessible. It cannot be read or written,
but the data are preserved.
=head4 unlock
$precal_key->unlock();
When called makes the state accessible for read access only.
=head4 is_locked
if ( $precal_key->is_locked ) {
$precal_key->unlock;
}
Returns true if the C<$precal_key> object is locked, false otherwise.
=head3 aes256gcm_nonce
my $nonce = $crypto_aead->aes256gcm_nonce();
Helper method to generate a random nonce to be used by C<$crypto_aead>.
The length of the nonce equals L</AES256GCM_NPUBBYTES>.
If initial value has been passed as the argument, it will then padded with
lib/Data/BytesLocker.pod view on Meta::CPAN
$Data::BytesLocker::DEFAULT_LOCKED = 1;
# some sensitive data read from external sources, eg. database
my $password = ...;
my $password_locker = Data::BytesLocker->new($password, wipe => 1);
# $password now is overwritten with null bytes
$password =~ /^\0+$/ or die;
# as requested locker is locked
$password_locker->is_locked or die;
# dies with: "Unlock BytesLocker object before accessing the data"
print "password: ", $password_locker->bytes, "\n";
# unlock the data
$password_locker->unlock;
# as requested locker is unlocked
$password_locker->is_locked and die;
# prints the password using overloaded stringification
print "password: $password_locker\n";
# Crypt::NaCl::Sodium functions and methods return binary data locked in Data::BytesLocker objects
my $random_password = random_bytes( 32 );
# we wanted locked by default
$random_password->unlock;
# helper function to convert into hexadecimal string
print "random password: ", $random_password->to_hex, "\n";
# clone the data into new object
my $copy = $password_locker->clone;
# nonce increment
my $next_nonce = $nonce->increment;
lib/Data/BytesLocker.pod view on Meta::CPAN
=head2 new
my $locker = Data::BytesLocker->new($data, wipe => 1 );
Returns object that stores the input C<$data> in a protected memory location.
If the optional parameter C<wipe> is given and is true, then the input C<$data>
variable will be overwritten with null bytes.
Returned C<$locker> object will contain the data that cannot be modified and if
the object is locked it cannot be accessed as well.
C<Data::BytesLocker> object when used in string context return the protected
data. See L</OVERLOADED OPERATIONS> for more details.
=head2 clone
my $cloned = $locker->clone;
Returns new data object which will contain the copied data from C<$locker>.
lib/Data/BytesLocker.pod view on Meta::CPAN
When called makes the data stored inaccessible. It cannot be read or written,
but the data are preserved.
=head2 unlock
$locker->unlock();
When called makes the data stored accessible for read access only.
=head2 is_locked
if ( $locker->is_locked ) {
$locker->unlock;
}
Returns true if the C<$locker> object is locked, false otherwise.
=head2 length
my $data_length = $locker->length();
Returns the length of protected bytes.
=head2 to_hex
my $hexencoded = $locker->to_hex();
Returns the protected data converted into a hexadecimal string.
B<NOTE:> the C<$locker> object must be unlocked.
Returns regular scalar.
=head2 bytes
my $bytes = $locker->bytes();
Returns the protected data as regular scalar.
B<NOTE:> the C<$locker> object must be unlocked.
=head2 is_zero
if ( $locker->is_zero ) {
print "data contains zero bits only\n";
}
Returns true if the C<$locker> object contains zero bits only.
Runs in constant-time for objects of the same length.
lib/Data/BytesLocker.pod view on Meta::CPAN
Both C<$nonce> and C<$number> are assumed to be numbers encoded in little-endian format.
The argument C<$length> is optional if variables are of the same length. Otherwise it is
required and cannot be greater then the length of the shorter of compared variables.
=head2 increment
my $next_nonce = $nonce->increment();
Increments an arbitrary long unsigned number. Method runs in constant-time
for a given length of locked data and considers it to be encoded in
little-endian format.
This method is meant to be used to increment nonces and counters.
Returns the incremented object.
=head2 add
my $next_nonce = $nonce->add($number, $length);
t/byteslocker.t view on Meta::CPAN
use Crypt::NaCl::Sodium qw(:utils);
$Data::BytesLocker::DEFAULT_LOCKED = 1;
my $crypto_secretbox = Crypt::NaCl::Sodium->secretbox();
for my $i ( 1 .. 2 ) {
my $key = $crypto_secretbox->keygen();
isa_ok($key, "Data::BytesLocker");
ok($key->is_locked, "locked by default");
eval {
my $skey = "$key";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
ok($key->unlock, "...but can unlock");
like($key->to_hex, qr/^[a-f0-9]{64}$/, "->to_hex");
my $skey = $key;
isa_ok($skey, "Data::BytesLocker");
eval { $key lt $skey ? 1 : 0 };
like($@, qr/Operation "lt" is not supported/, 'Operation "lt" is not supported');
eval { $key le $skey ? 1 : 0 };
t/byteslocker.t view on Meta::CPAN
ok($key eq $skey, "key -eq skey");
ok(! ( $key ne $skey), "key -ne skey");
ok($key, "-bool key");
my $key_aaa = $key . "aaa";
isa_ok($key_aaa, "Data::BytesLocker");
eval {
my $skey = "$key_aaa";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "concat result locked");
ok($key_aaa->unlock, "...but can unlock");
is($key_aaa, "${key_str}aaa", "key . STR");
my $aaa_key = "aaa" . $key;
isa_ok($aaa_key, "Data::BytesLocker");
eval {
my $skey = "$aaa_key";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "concat result locked");
ok($aaa_key->unlock, "...but can unlock");
is($aaa_key, "aaa${key_str}", "STR . key");
my $key_x_5 = $key x 5;
isa_ok($key_x_5, "Data::BytesLocker");
eval {
my $skey = "$key_x_5";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "concat result locked");
ok($key_x_5->unlock, "...but can unlock");
is($key_x_5, "${key_str}${key_str}${key_str}${key_str}${key_str}", "key x 5");
$key = "1234";
ok(! ref $key, "key after assignment not longer an object");
}
my $locker1 = Data::BytesLocker->new("readonly protected data");
isa_ok($locker1, "Data::BytesLocker");
eval {
my $s = "$locker1";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
ok($locker1->unlock, "...but can unlock");
is($locker1->to_hex, bin2hex("readonly protected data"), "->to_hex eq bin2hex");
is($locker1->bytes, "readonly protected data", "data is accessible");
eval {
my $locker2 = Data::BytesLocker->new("readonly protected data", wipe => 1 );
};
like($@, qr/^Modification of a read-only value attempted/, "Cannot wipe readonly data");
my $var = "protected data";
my $var_len = length($var);
my $locker3 = Data::BytesLocker->new($var, wipe => 1 );
isa_ok($locker3, "Data::BytesLocker");
eval {
my $s = "$locker3";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
ok($locker3->unlock, "...but can unlock");
is($locker3->to_hex, bin2hex("protected data"), "->to_hex eq bin2hex");
is($var, "\x0" x $var_len, "orginal variable wiped out");
is($locker3->length, $var_len, "->length works");
{
$Data::BytesLocker::DEFAULT_LOCKED = 0;
my $unlocked = Data::BytesLocker->new("not locked");
ok(! $unlocked->is_locked, "not locked by default");
is($unlocked, "not locked", "...and can be accessed");
ok($unlocked->lock, "...but can be locked");
eval {
my $str = "$unlocked";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
}
{
local $Data::BytesLocker::DEFAULT_LOCKED = 1;
my $locked = Data::BytesLocker->new("is locked");
ok($locked->is_locked, "now locked by default");
eval {
my $str = "$locked";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
ok($locked->unlock, "...but can be unlocked");
is($locked, "is locked", "...and can be accessed");
}
{
my $unlocked = Data::BytesLocker->new("fall back to not locked");
ok(! $unlocked->is_locked, "fall back to not locked by default");
is($unlocked, "fall back to not locked", "...and can be accessed");
ok($unlocked->lock, "...but can be locked");
eval {
my $str = "$unlocked";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
}
{ # compare
my $a = Data::BytesLocker->new("abc");
my $b = "abC";
ok( ! $a->memcmp($b), "memcmp: 'abc' and 'abC' differ");
for (1 .. 1000) {
my $bin_len = 1 + random_number(1000);
t/example_byteslocker.t view on Meta::CPAN
# some sensitive data read from external sources, eg. database
my $password = "a secret password";
my $password_len = length($password);
my $password_locker = Data::BytesLocker->new($password, wipe => 1);
# $password now is overwritten with null bytes
ok($password =~ /^\0+$/, "input overwritten");
# as requested locker is locked
ok($password_locker->is_locked, "is_locked");
# dies with: "Unlock BytesLocker object before accessing the data"
eval {
print "password: ", $password_locker->bytes, "\n";
};
like($@, qr/^Unlock BytesLocker object before accessing the data/, "cannot access locked bytes");
# unlock the data
ok($password_locker->unlock, "can unlock");
# as requested locker is unlocked
ok(! $password_locker->is_locked, "is_locked");
# prints the password
is($password_locker, "a secret password", "can access");
# Crypt::NaCl::Sodium functions and methods return binary data locked in Data::BytesLocker objects
my $random_password = random_bytes( 32 );
# we wanted locked by default
ok($random_password->unlock, "can unlock");
# helper function to convert into hexadecimal string
ok($random_password->to_hex, "can convert to hex");
# always lock the data once done using it
ok($password_locker->lock, "can lock");
ok($random_password->lock, "can lock");
done_testing();
t/sodium_aead_aes256gcm.t view on Meta::CPAN
my $decrypted2 =
$crypto_aead->aes256gcm_decrypt_afternm($ciphertext->bytes, $ad, $nonce, $precal_key);
is($decrypted2->to_hex, $msg_hex, "message decrypted (using precalculated key)");
$test_no++;
}
my $key = "\0" x $crypto_aead->AES256GCM_KEYBYTES;
my $precal_key = $crypto_aead->aes256gcm_beforenm($key);
can_ok($precal_key, $_) for qw( lock unlock is_locked );
my $ad = "Shoppping list";
my $msg = "Milk";
my $nonce = "\0" x $crypto_aead->AES256GCM_NPUBBYTES;
ok(! $precal_key->is_locked, "precalculated key is not locked by default");
my $ciphertext = $crypto_aead->aes256gcm_encrypt_afternm($msg, $ad, $nonce,
$precal_key);
is($ciphertext->to_hex, "83ce2c56bf10b9385d1f80e635a26b3c1d1c72b7", "can encrypt with unlocked precalculated key");
my $decrypted =
$crypto_aead->aes256gcm_decrypt_afternm($ciphertext->bytes, $ad, $nonce, $precal_key);
is($decrypted->bytes, $msg, "message decrypted (using unlocked precalculated key)");
ok($precal_key->lock, "and lock the precalculated key");
ok($precal_key->is_locked, "...and confirm it using is_locked()");
eval {
my $tmp = $crypto_aead->aes256gcm_encrypt_afternm($msg, $ad, $nonce,
$precal_key);
};
like($@, qr/Unlock AES256GCM precalculated key object before accessing the state/,
"...and cannot encrypt using locked precalculated key anymore");
eval {
my $tmp =
$crypto_aead->aes256gcm_decrypt_afternm($ciphertext->bytes, $ad, $nonce, $precal_key);
};
like($@, qr/Unlock AES256GCM precalculated key object before accessing the state/,
"...and cannot decrypt using locked precalculated key anymore");
ok($precal_key->unlock, "but can unlock the precalculated key");
ok(! $precal_key->is_locked, "...and confirm it using is_locked()");
my $decrypted2 =
$crypto_aead->aes256gcm_decrypt_afternm($ciphertext->bytes, $ad, $nonce, $precal_key);
is($decrypted2->bytes, $msg, "to decrypted the message (using unlocked precalculated key)");
}
SKIP: {
skip "AES256GCM is available", 1 if $is_available;
my @noargs_methods = qw(
AES256GCM_KEYBYTES
AES256GCM_NPUBBYTES
AES256GCM_ABYTES
t/threads.t view on Meta::CPAN
is $hasher->clone->final->to_hex, $tdigest->to_hex, "final mac matches";
}
SKIP: {
my $crypto_aead = Crypt::NaCl::Sodium->aead;
skip "AES256GCM is not available", 1 unless $crypto_aead->aes256gcm_is_available;
my $key = $crypto_aead->aes256gcm_keygen;
my $precal_key = $crypto_aead->aes256gcm_beforenm($key);
my $tprecal_key = threads->create(sub { $precal_key->lock(); $precal_key->is_locked })->join;
isnt $precal_key->is_locked, $tprecal_key, "unshared object unaffected by the thread";
}
done_testing();
( run in 0.339 second using v1.01-cache-2.11-cpan-bf8d7bb2d05 )