Crypt-NaCl-Sodium

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN


    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

Sodium.xs  view on Meta::CPAN

#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 {

Sodium.xs  view on Meta::CPAN

{
    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) \

Sodium.xs  view on Meta::CPAN

        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

Sodium.xs  view on Meta::CPAN

    }

    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;

Sodium.xs  view on Meta::CPAN

            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);

Sodium.xs  view on Meta::CPAN

        }

        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';

Sodium.xs  view on Meta::CPAN

    {
        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

Sodium.xs  view on Meta::CPAN

    {
        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

Sodium.xs  view on Meta::CPAN

    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);
        }

Sodium.xs  view on Meta::CPAN

    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);
        }

Sodium.xs  view on Meta::CPAN

_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 ) {

Sodium.xs  view on Meta::CPAN

_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 ) {

Sodium.xs  view on Meta::CPAN

    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 ) {

Sodium.xs  view on Meta::CPAN

    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 ) {

Sodium.xs  view on Meta::CPAN

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

Sodium.xs  view on Meta::CPAN


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:

Sodium.xs  view on Meta::CPAN

    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);

Sodium.xs  view on Meta::CPAN


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)

Sodium.xs  view on Meta::CPAN

        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 ) {

Sodium.xs  view on Meta::CPAN

        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 ) {

Sodium.xs  view on Meta::CPAN

        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) );

Sodium.xs  view on Meta::CPAN

        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 ) {

Sodium.xs  view on Meta::CPAN


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 )