Crypt-NaCl-Sodium
view release on metacpan or search on metacpan
288289290291292293294295296297298299300301302303304305306307308309310
The
length
of the
$bytes
equals the value of
$num_of_bytes
.
Returns Data::BytesLocker object.
VARIABLES
$Data::BytesLocker::DEFAULT_LOCKED
$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
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
89101112131415161718192021222324252627282930313233#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 {
8384858687888990919293949596979899100101102103{
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) \
301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
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
379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
}
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;
22022203220422052206220722082209221022112212221322142215221622172218221922202221
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);
226922702271227222732274227522762277227822792280228122822283228422852286228722882289}
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'
;
231023112312231323142315231623172318231923202321232223232324232523262327232823292330
{
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
233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372
{
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
500150025003500450055006500750085009501050115012501350145015501650175018501950205021SV * 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
);
}
503350345035503650375038503950405041504250435044504550465047504850495050505150525053SV * 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
);
}
506450655066506750685069507050715072507350745075507650775078507950805081508250835084_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 ) {
509250935094509550965097509850995100510151025103510451055106510751085109511051115112_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 ) {
512351245125512651275128512951305131513251335134513551365137513851395140514151425143SV * 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 ) {
516151625163516451655166516751685169517051715172517351745175517651775178517951805181SV * 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 ) {
519451955196519751985199520052015202520352045205520652075208520952105211521252135214void
_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
522552265227522852295230523152325233523452355236523752385239524052415242524352445245SV *
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:
52505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335
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
);
534353445345534653475348534953505351535253535354535553565357535853595360536153625363void
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)
536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394
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 ) {
542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448
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 ) {
546954705471547254735474547554765477547854795480548154825483548454855486548754885489
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) );
550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527
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 ) {
5552555355545555555655575558555955605561556255635564556555665567556855695570void
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
490491492493494495496497498499500501502503504505506507508509510Returns 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
283284285286287288289290291292293294295296297298299300301302303304305306307308309When 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
232425262728293031323334353637383940414243444546474849505152535455565758596061$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"
"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
"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
"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
117118119120121122123124125126127128129130131132133134135136=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
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190When 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
211212213214215216217218219220221222223224225226227228229230Both 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
567891011121314151617181920212223242526272829$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
48495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
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
101112131415161718192021222324252627282930313233343536373839404142434445464748495051# 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
{
"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
313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191
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
107108109110111112113114115116117118119120121122123
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.275 second using v1.01-cache-2.11-cpan-bf8d7bb2d05 )