Crypt-NaCl-Sodium
view release on metacpan or search on metacpan
#define PERL_NO_GET_CONTEXT
#define NO_XSLOCKS
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "patchlevel.h"
#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 {
crypto_hash_sha256_state * state;
} CryptNaClSodiumHashSha256Stream;
typedef struct {
crypto_hash_sha512_state * state;
} CryptNaClSodiumHashSha512Stream;
typedef struct {
crypto_auth_hmacsha256_state * state;
} CryptNaClSodiumAuthHmacsha256Stream;
typedef struct {
crypto_auth_hmacsha512_state * state;
} CryptNaClSodiumAuthHmacsha512Stream;
typedef struct {
crypto_auth_hmacsha512256_state * state;
} CryptNaClSodiumAuthHmacsha512256Stream;
typedef struct {
crypto_onetimeauth_state * state;
} CryptNaClSodiumOnetimeauthStream;
typedef DataBytesLocker * Data__BytesLocker;
#if defined(AES256GCM_IS_AVAILABLE)
typedef CryptNaClSodiumAeadAes256gcmState * Crypt__NaCl__Sodium__aead__aes256gcmstate;
#endif
typedef CryptNaClSodiumGenerichashStream * Crypt__NaCl__Sodium__generichash__stream;
typedef CryptNaClSodiumHashSha256Stream * Crypt__NaCl__Sodium__hash__sha256stream;
typedef CryptNaClSodiumHashSha512Stream * Crypt__NaCl__Sodium__hash__sha512stream;
typedef CryptNaClSodiumAuthHmacsha256Stream * Crypt__NaCl__Sodium__auth__hmacsha256stream;
typedef CryptNaClSodiumAuthHmacsha512Stream * Crypt__NaCl__Sodium__auth__hmacsha512stream;
typedef CryptNaClSodiumAuthHmacsha512256Stream * Crypt__NaCl__Sodium__auth__hmacsha512256stream;
typedef CryptNaClSodiumOnetimeauthStream * Crypt__NaCl__Sodium__onetimeauth__stream;
#define CLONESTATE(streamtype, statetype, padding, extra) \
Newx(new_stream, 1, streamtype);\
if ( new_stream == NULL ) {\
croak("Could not allocate enough memory");\
}\
new_stream->state = sodium_malloc(sizeof(crypto_ ## statetype ## _state) + padding);\
if ( new_stream->state == NULL ) {\
croak("Could not allocate enough memory");\
}\
extra;\
memcpy(new_stream->state,cur_stream->state,sizeof(crypto_ ## statetype ## _state) + padding);
#if defined(USE_ITHREADS) && defined(MGf_DUP)
STATIC int dup_byteslocker(pTHX_ MAGIC *mg, CLONE_PARAMS *params)
{
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) \
STATIC int dup_ ## statetype ## _stream(pTHX_ MAGIC *mg, CLONE_PARAMS *params)\
{\
streamtype *new_stream;\
streamtype *cur_stream;\
PERL_UNUSED_VAR(params);\
cur_stream = (streamtype *)mg->mg_ptr;\
CLONESTATE(streamtype, statetype, padding, extra)\
mg->mg_ptr = (char *)new_stream;\
return 0;\
}
#if defined(AES256GCM_IS_AVAILABLE)
STATIC int dup_aead_aes256gcmstate(pTHX_ MAGIC *mg, CLONE_PARAMS *params)
{
CryptNaClSodiumAeadAes256gcmState *new_state;
CryptNaClSodiumAeadAes256gcmState *cur_state;
size_t sizeof_state = crypto_aead_aes256gcm_statebytes();
PERL_UNUSED_VAR(params);
cur_state = (CryptNaClSodiumAeadAes256gcmState *)mg->mg_ptr;
Newx(new_state, 1, CryptNaClSodiumAeadAes256gcmState);
if ( new_state == NULL ) {
croak("Could not allocate enough memory");
}
new_state->ctx = sodium_malloc(sizeof_state);
if ( new_state->ctx == NULL ) {
croak("Could not allocate enough memory");
}
memcpy(new_state->ctx,cur_state->ctx,sizeof_state);
mg->mg_ptr = (char *)new_state;
return 0;
}
#endif
DUPSTREAM(CryptNaClSodiumGenerichashStream, generichash, (size_t)63U & ~(size_t) 63U, new_stream->init_bytes=cur_stream->init_bytes)
DUPSTREAM(CryptNaClSodiumHashSha256Stream, hash_sha256, 0, ((void)0))
DUPSTREAM(CryptNaClSodiumHashSha512Stream, hash_sha512, 0, ((void)0))
DUPSTREAM(CryptNaClSodiumAuthHmacsha256Stream, auth_hmacsha256, 0, ((void)0))
DUPSTREAM(CryptNaClSodiumAuthHmacsha512Stream, auth_hmacsha512, 0, ((void)0))
DUPSTREAM(CryptNaClSodiumAuthHmacsha512256Stream, auth_hmacsha512256, 0, ((void)0))
DUPSTREAM(CryptNaClSodiumOnetimeauthStream, onetimeauth, 0, ((void)0))
#endif
STATIC MGVTBL vtbl_byteslocker = {
NULL, /* get */ NULL, /* set */ NULL, /* len */ NULL, /* clear */ NULL, /* free */
#ifdef MGf_COPY
NULL, /* copy */
#endif
#endif
#ifdef MGf_DUP
# ifdef USE_ITHREADS
dup_auth_hmacsha512_stream,
# else
NULL, /* dup */
# endif
#endif
#ifdef MGf_LOCAL
NULL /* local */
#endif
};
STATIC MGVTBL vtbl_auth_hmacsha512256 = {
NULL, /* get */ NULL, /* set */ NULL, /* len */ NULL, /* clear */ NULL, /* free */
#ifdef MGf_COPY
NULL, /* copy */
#endif
#ifdef MGf_DUP
# ifdef USE_ITHREADS
dup_auth_hmacsha512256_stream,
# else
NULL, /* dup */
# endif
#endif
#ifdef MGf_LOCAL
NULL /* local */
#endif
};
STATIC MGVTBL vtbl_onetimeauth = {
NULL, /* get */ NULL, /* set */ NULL, /* len */ NULL, /* clear */ NULL, /* free */
#ifdef MGf_COPY
NULL, /* copy */
#endif
#ifdef MGf_DUP
# ifdef USE_ITHREADS
dup_onetimeauth_stream,
# else
NULL, /* dup */
# endif
#endif
#ifdef MGf_LOCAL
NULL /* local */
#endif
};
static DataBytesLocker * InitDataBytesLocker(pTHX_ STRLEN size) {
DataBytesLocker *bl;
Newx(bl, 1, DataBytesLocker);
if ( bl == NULL ) {
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
mg =
#endif
sv_magicext(sv, NULL, PERL_MAGIC_ext, &vtbl_byteslocker, (const char *)bl, 0);
#if defined(USE_ITHREADS) && defined(MGf_DUP)
mg->mg_flags |= MGf_DUP;
#endif
return obj;
}
static DataBytesLocker* GetBytesLocker(pTHX_ SV* sv)
{
MAGIC *mg;
if (!sv_derived_from(sv, "Data::BytesLocker"))
croak("Not a reference to a Data::BytesLocker object");
for (mg = SvMAGIC(SvRV(sv)); mg; mg = mg->mg_moremagic) {
if (mg->mg_type == PERL_MAGIC_ext && mg->mg_virtual == &vtbl_byteslocker) {
return (DataBytesLocker *)mg->mg_ptr;
}
}
croak("Failed to get Data::BytesLocker pointer");
return (DataBytesLocker*)0; /* some compilers insist on a return value */
}
#if defined(AES256GCM_IS_AVAILABLE)
static CryptNaClSodiumAeadAes256gcmState * InitAeadAes256gcmState(pTHX_ unsigned char * key) {
CryptNaClSodiumAeadAes256gcmState *pk;
Newx(pk, 1, CryptNaClSodiumAeadAes256gcmState);
if ( pk == NULL ) {
croak("Could not allocate enough memory");
}
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;
#endif
return obj;
}
static CryptNaClSodiumAeadAes256gcmState* GetAeadAes256gcmState(pTHX_ SV* sv)
{
MAGIC *mg;
if (!sv_derived_from(sv, "Crypt::NaCl::Sodium::aead::aes256gcmstate"))
croak("Not a reference to a Crypt::NaCl::Sodium::aead::aes256gcmstate object");
for (mg = SvMAGIC(SvRV(sv)); mg; mg = mg->mg_moremagic) {
if (mg->mg_type == PERL_MAGIC_ext && mg->mg_virtual == &vtbl_aead_aes256gcmstate) {
return (CryptNaClSodiumAeadAes256gcmState *)mg->mg_ptr;
}
}
croak("Failed to get Crypt::NaCl::Sodium::aead::aes256gcmstate pointer");
return (CryptNaClSodiumAeadAes256gcmState*)0; /* some compilers insist on a return value */
}
#endif
static SV * GenerichashStream2SV(pTHX_ CryptNaClSodiumGenerichashStream *stream) {
SV *sv = newSV(0);
SV *obj = newRV_noinc(sv);
#ifdef USE_ITHREADS
MAGIC *mg;
#endif
sv_bless(obj, gv_stashpv("Crypt::NaCl::Sodium::generichash::stream", 0));
#ifdef USE_ITHREADS
mg =
#endif
sv_magicext(sv, NULL, PERL_MAGIC_ext, &vtbl_generichash, (const char *)stream, 0);
#if defined(USE_ITHREADS) && defined(MGf_DUP)
mg->mg_flags |= MGf_DUP;
#endif
return obj;
}
static CryptNaClSodiumGenerichashStream* GetGenerichashStream(pTHX_ SV* sv)
{
MAGIC *mg;
if (!sv_derived_from(sv, "Crypt::NaCl::Sodium::generichash::stream"))
croak("Not a reference to a Crypt::NaCl::Sodium::generichash::stream object");
STRLEN key_len = 0;
unsigned char * key_buf = NULL;
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState *state;
#endif
PPCODE:
{
PERL_UNUSED_VAR(self);
#if defined(AES256GCM_IS_AVAILABLE)
key_buf = (unsigned char *)SvPV(key, key_len);
if ( key_len != crypto_aead_aes256gcm_KEYBYTES ) {
croak("Invalid key");
}
state = InitAeadAes256gcmState(aTHX_ key_buf);
ST(0) = sv_2mortal(AeadAes256gcmState2SV(aTHX_ state));
XSRETURN(1);
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
void
aes256gcm_encrypt_afternm(self, msg, adata, nonce, precalculated_key)
SV * self
SV * msg
SV * adata
SV * nonce
SV * precalculated_key
PROTOTYPE: $$$$$
INIT:
STRLEN msg_len;
STRLEN adata_len;
STRLEN nonce_len;
STRLEN enc_len;
unsigned char * msg_buf;
unsigned char * adata_buf;
unsigned char * nonce_buf;
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState * precal_key;
#endif
DataBytesLocker *bl;
PPCODE:
{
PERL_UNUSED_VAR(self);
#if defined(AES256GCM_IS_AVAILABLE)
if ( GIMME_V == G_VOID ) {
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);
if (msg_len > SIZE_MAX - crypto_aead_aes256gcm_ABYTES) {
croak("Encrypted length exceeds system memory limit (size_t overflow)");
}
enc_len = msg_len + crypto_aead_aes256gcm_ABYTES;
bl = InitDataBytesLocker(aTHX_ enc_len);
crypto_aead_aes256gcm_encrypt_afternm( bl->bytes, NULL, msg_buf, msg_len,
adata_buf, adata_len, NULL, nonce_buf, (const crypto_aead_aes256gcm_state *)precal_key->ctx);
bl->bytes[enc_len] = '\0';
mXPUSHs( DataBytesLocker2SV(aTHX_ bl) );
XSRETURN(1);
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
void
aes256gcm_decrypt_afternm(self, msg, adata, nonce, precalculated_key)
SV * self
SV * msg
SV * adata
SV * nonce
SV * precalculated_key
PROTOTYPE: $$$$
INIT:
STRLEN msg_len;
STRLEN adata_len;
STRLEN nonce_len;
STRLEN enc_len;
unsigned char * msg_buf;
unsigned char * adata_buf;
unsigned char * nonce_buf;
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState * precal_key;
#endif
DataBytesLocker *bl;
PPCODE:
{
PERL_UNUSED_VAR(self);
#if defined(AES256GCM_IS_AVAILABLE)
if ( GIMME_V == G_VOID ) {
XSRETURN_EMPTY;
}
nonce_buf = (unsigned char *)SvPV(nonce, nonce_len);
if ( nonce_len != crypto_aead_aes256gcm_NPUBBYTES ) {
croak("Invalid nonce");
}
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 - crypto_aead_aes256gcm_ABYTES;
bl = InitDataBytesLocker(aTHX_ enc_len);
if ( crypto_aead_aes256gcm_decrypt_afternm( bl->bytes, NULL, 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';
mXPUSHs( DataBytesLocker2SV(aTHX_ bl) );
XSRETURN(1);
}
else {
sodium_free(bl->bytes);
Safefree(bl);
croak("Message forged");
}
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
MODULE = Crypt::NaCl::Sodium PACKAGE = Crypt::NaCl::Sodium::aead::aes256gcmstate
void
lock(self)
SV * self
PPCODE:
{
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
unlock(self)
SV * self
PPCODE:
{
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
DESTROY(self)
SV * self
PPCODE:
{
#if defined(AES256GCM_IS_AVAILABLE)
CryptNaClSodiumAeadAes256gcmState* state;
state = GetAeadAes256gcmState(aTHX_ self);
sodium_free( state->ctx );
Safefree(state);
#else
croak("AES256-GCM is not supported by this CPU");
#endif
}
MODULE = Crypt::NaCl::Sodium PACKAGE = Crypt::NaCl::Sodium::box
PROTOTYPES: DISABLE
unsigned int
PUBLICKEYBYTES(...)
CODE:
RETVAL = crypto_box_PUBLICKEYBYTES;
OUTPUT:
RETVAL
unsigned int
SECRETKEYBYTES(...)
CODE:
RETVAL = crypto_box_SECRETKEYBYTES;
OUTPUT:
RETVAL
unsigned int
NONCEBYTES(...)
CODE:
RETVAL = crypto_box_NONCEBYTES;
OUTPUT:
RETVAL
unsigned int
MACBYTES(...)
CODE:
RETVAL = crypto_box_MACBYTES;
OUTPUT:
RETVAL
unsigned int
SEEDBYTES(...)
CODE:
DataBytesLocker *bl;
unsigned char *buf;
STRLEN buf_len;
int wipe = 0;
int readonly = 0;
CODE:
{
if ( SvREADONLY(bytes) ) {
buf = (unsigned char *)SvPV(bytes, buf_len);
readonly = 1;
} else {
buf = (unsigned char *)SvPV_force(bytes, buf_len);
}
if ( items > 2 && items != 4 ) {
croak("Invalid number of arguments");
} else if ( items > 2 ) {
int i = 0;
STRLEN keylen = 0;
char * key;
for ( i = 2; i < items; i += 2 ) {
key = SvPV(ST(i), keylen);
if ( keylen == 4 && strnEQ(key, "wipe", 4) ) {
wipe = SvTRUE(ST(i+1));
if ( wipe && readonly ) {
croak("Modification of a read-only value attempted");
}
} else {
croak("Invalid argument: %s", key);
}
}
}
bl = InitDataBytesLocker(aTHX_ buf_len);
memcpy(bl->bytes, buf, buf_len);
if ( wipe ) {
sodium_memzero( buf, buf_len);
}
RETVAL = DataBytesLocker2SV(aTHX_ bl);
}
OUTPUT:
RETVAL
SV *
_overload_mult(self, other, swapped)
SV * self
SV * other
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);
}
RETVAL = DataBytesLocker2SV(aTHX_ bl);
}
OUTPUT:
RETVAL
SV *
_overload_concat(self, other, swapped)
SV * self
SV * other
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);
}
else {
memcpy(memcpy(bl->bytes, sbl->bytes, sbl->length) + sbl->length, buf, buf_len);
}
RETVAL = DataBytesLocker2SV(aTHX_ bl);
}
OUTPUT:
RETVAL
void
_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 ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
}
void
_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 ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
}
void
_overload_eq(self, other, swapped)
SV * self
SV * other
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 ) {
res = 1;
} else {
res = 0;
}
if ( res ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
}
void
_overload_ne(self, other, swapped)
SV * self
SV * other
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 ) {
res = 0;
} else {
res = 1;
}
if ( res ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
}
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
_overload_nomethod(self, ...)
SV * self
OVERLOAD: nomethod
INIT:
char * operator;
PPCODE:
{
operator = SvPV_nolen(ST(3));
croak("Operation \"%s\" is not supported", operator);
}
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:
RETVAL
void
lock(self)
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);
RETVAL = newSVpvn((const char * const)hex, hex_len);
}
OUTPUT:
RETVAL
CLEANUP:
sodium_free(hex);
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)
SV * self
SV * bytes
unsigned long length
PREINIT:
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 ) {
if ( sbl->length != bytes_len ) {
croak("Variables of unequal length cannot be automatically compared. Please provide the length argument");
}
length = bytes_len;
} else {
if ( length > sbl->length ) {
croak("The data is shorter then requested length");
}
else if ( length > bytes_len ) {
croak("The argument is shorter then requested length");
}
}
if ( sodium_memcmp(sbl->bytes, bytes_buf, length) == 0 ) {
XSRETURN_YES;
} else {
XSRETURN_NO;
}
}
void
compare(self, num, length = 0)
SV * self
SV * num
unsigned long length
PREINIT:
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 ) {
if ( sbl->length != num_len ) {
croak("Variables of unequal length cannot be automatically compared. Please provide the length argument");
}
length = num_len;
} else {
if ( length > sbl->length ) {
croak("The data is shorter then requested length");
}
else if ( length > num_len ) {
croak("The argument is shorter then requested length");
}
}
XSRETURN_IV( sodium_compare(sbl->bytes, num_buf, length) );
}
void
increment(self)
SV * self
PREINIT:
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) );
XSRETURN(1);
}
void
add(self, num, ...)
SV * self
SV * num
PREINIT:
DataBytesLocker* sbl = GetBytesLocker(aTHX_ self);
INIT:
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 ) {
inc_len = (STRLEN)SvUV(ST(2));
if ( inc_len > sbl->length ) {
croak("The data is shorter then requested length");
}
else if ( inc_len > num_len ) {
croak("The argument is shorter then requested length");
}
} else {
if ( sbl->length != num_len ) {
croak("Length of argument has to be equal to the length of data. Please provide the length argument");
}
inc_len = num_len;
}
bl = InitDataBytesLocker(aTHX_ sbl->length);
memcpy(bl->bytes, sbl->bytes, sbl->length);
sodium_add( bl->bytes, num_buf, inc_len );
mXPUSHs( DataBytesLocker2SV(aTHX_ bl) );
XSRETURN(1);
}
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;
}
void
DESTROY(self)
SV * self
PREINIT:
DataBytesLocker* bl = GetBytesLocker(aTHX_ self);
PPCODE:
{
sodium_free( bl->bytes );
Safefree(bl);
}
( run in 2.508 seconds using v1.01-cache-2.11-cpan-bbc515a03b3 )