diff options
-rw-r--r-- | Changes | 2 | ||||
-rw-r--r-- | CryptX.xs | 6 | ||||
-rw-r--r-- | inc/CryptX_Digest_SHAKE.xs.inc | 74 | ||||
-rw-r--r-- | lib/Crypt/Digest/SHAKE.pm | 106 | ||||
-rw-r--r-- | t/003_all_pm_pod.t | 2 | ||||
-rw-r--r-- | t/digest_shake.t | 36 | ||||
-rw-r--r-- | typemap | 1 |
7 files changed, 225 insertions, 2 deletions
@@ -9,13 +9,13 @@ TODO: - maybe: add CCM interface for new-add-add-done mode - maybe: switch yarrow > fortuna for Crypt::PK::* - maybe: add encode_b32/decode_b32 - - maybe: x509_rsa_pubkey + x509_rsa_pubkey_alg 0.047_001 2017/04/07 - NEW: Crypt::Digest::SHA3_224 - NEW: Crypt::Digest::SHA3_256 - NEW: Crypt::Digest::SHA3_384 - NEW: Crypt::Digest::SHA3_512 + - NEW: Crypt::Digest::SHAKE - NEW: Crypt::AuthEnc::ChaCha20Poly1305 - NEW: Crypt::Mac::Poly1305 - NEW: Crypt::PRNG::ChaCha20 @@ -26,6 +26,11 @@ typedef struct digest_struct { /* used by Crypt::Digest */ struct ltc_hash_descriptor *desc; } *Crypt__Digest; +typedef struct digest_shake_struct { /* used by Crypt::Digest::SHAKE */ + hash_state state; + int num; +} *Crypt__Digest__SHAKE; + typedef struct ccm_struct { /* used by Crypt::AuthEnc::CCM */ ccm_state state; int id; @@ -456,6 +461,7 @@ CryptX__decode_base64(SV * in) ############################################################################### INCLUDE: inc/CryptX_Digest.xs.inc +INCLUDE: inc/CryptX_Digest_SHAKE.xs.inc INCLUDE: inc/CryptX_Cipher.xs.inc INCLUDE: inc/CryptX_Checksum_Adler32.xs.inc diff --git a/inc/CryptX_Digest_SHAKE.xs.inc b/inc/CryptX_Digest_SHAKE.xs.inc new file mode 100644 index 00000000..aa5335fa --- /dev/null +++ b/inc/CryptX_Digest_SHAKE.xs.inc @@ -0,0 +1,74 @@ +MODULE = CryptX PACKAGE = Crypt::Digest::SHAKE + +Crypt::Digest::SHAKE +_new(int num) + CODE: + { + int rv; + + Newz(0, RETVAL, 1, struct digest_shake_struct); + if (!RETVAL) croak("FATAL: Newz failed"); + + RETVAL->num = num; + rv = sha3_shake_init(&RETVAL->state, RETVAL->num); + if (rv != CRYPT_OK) croak("FATAL: sha3_shake_init failed: %s", error_to_string(rv)); + } + OUTPUT: + RETVAL + +void +DESTROY(Crypt::Digest::SHAKE self) + CODE: + Safefree(self); + +void +reset(Crypt::Digest::SHAKE self) + CODE: + { + int rv; + rv = sha3_shake_init(&self->state, self->num); + if (rv != CRYPT_OK) croak("FATAL: sha3_shake_init failed: %s", error_to_string(rv)); + } + +Crypt::Digest::SHAKE +clone(Crypt::Digest::SHAKE self) + CODE: + Newz(0, RETVAL, 1, struct digest_shake_struct); + Copy(&self->state, &RETVAL->state, 1, struct digest_shake_struct); + OUTPUT: + RETVAL + +void +add(Crypt::Digest::SHAKE self, ...) + PPCODE: + { + STRLEN inlen; + int rv, i; + unsigned char *in; + + for(i=1; i<items; i++) { + in = (unsigned char *)SvPVbyte(ST(i), inlen); + if (inlen>0) { + rv = sha3_shake_process(&self->state, in, (unsigned long)inlen); + if (rv != CRYPT_OK) croak("FATAL: sha3_shake_process failed: %s", error_to_string(rv)); + } + } + XPUSHs(ST(0)); /* return self */ + } + +SV * +done(Crypt::Digest::SHAKE self, STRLEN out_len) + CODE: + { + int rv; + unsigned char *out_data; + + RETVAL = NEWSV(0, out_len); + SvPOK_only(RETVAL); + SvCUR_set(RETVAL, out_len); + out_data = (unsigned char *)SvPV_nolen(RETVAL); + rv = sha3_shake_done(&self->state, out_data, out_len); + if (rv != CRYPT_OK) croak("FATAL: sha3_shake_done failed: %s", error_to_string(rv)); + } + OUTPUT: + RETVAL diff --git a/lib/Crypt/Digest/SHAKE.pm b/lib/Crypt/Digest/SHAKE.pm new file mode 100644 index 00000000..709859fc --- /dev/null +++ b/lib/Crypt/Digest/SHAKE.pm @@ -0,0 +1,106 @@ +package Crypt::Digest::SHAKE; + +use strict; +use warnings; +our $VERSION = '0.047_001'; + +use Carp; +$Carp::Internal{(__PACKAGE__)}++; +use CryptX; + +sub new { my $class = shift; _new(@_) } + +sub addfile { + my ($self, $file) = @_; + + my $handle; + if (ref(\$file) eq 'SCALAR') { #filename + open($handle, "<", $file) || croak "FATAL: cannot open '$file': $!"; + binmode($handle); + } + else { #handle + $handle = $file + } + croak "FATAL: invalid handle" unless defined $handle; + + my $n; + my $buf = ""; + while (($n = read($handle, $buf, 32*1024))) { + $self->add($buf) + } + croak "FATAL: read failed: $!" unless defined $n; + + return $self; +} + +sub CLONE_SKIP { 1 } # prevent cloning + +1; + +=pod + +=head1 NAME + +Crypt::Digest::SHAKE - Hash functions SHAKE128, SHAKE256 from SHA3 family + +=head1 SYNOPSIS + + use Crypt::Digest::SHAKE + + $d = Crypt::Digest::SHAKE->new(128); + $d->add('any data'); + $d->addfile('filename.dat'); + $d->addfile(*FILEHANDLE); + $part1 = $d->done(100); # 100 raw bytes + $part2 = $d->done(100); # another 100 raw bytes + #... + +=head1 DESCRIPTION + +Provides an interface to the SHA3's sponge function SHAKE. + +=head1 METHODS + +=head2 new + + $d = Crypt::Digest::SHA3-SHAKE->new($num); + # $num ... 128 or 256 + +=head2 clone + + $d->clone(); + +=head2 reset + + $d->reset(); + +=head2 add + + $d->add('any data'); + #or + $d->add('any data', 'more data', 'even more data'); + +=head2 addfile + + $d->addfile('filename.dat'); + #or + $d->addfile(*FILEHANDLE); + +=head2 done + + $result_raw = $d->done($len); + # can be called multiple times + +=head1 SEE ALSO + +=over + +=item * L<CryptX|CryptX>, L<Crypt::Digest|Crypt::Digest> + +=item * L<http://en.wikipedia.org/wiki/SHA-3|http://en.wikipedia.org/wiki/SHA-3> + +=back + +=cut + +__END__
\ No newline at end of file diff --git a/t/003_all_pm_pod.t b/t/003_all_pm_pod.t index 16734ce4..d2228db6 100644 --- a/t/003_all_pm_pod.t +++ b/t/003_all_pm_pod.t @@ -5,7 +5,7 @@ use Test::More; plan skip_all => "File::Find not installed" unless eval { require File::Find }; plan skip_all => "Test::Pod not installed" unless eval { require Test::Pod }; -plan tests => 87; +plan tests => 88; my @files; File::Find::find({ wanted=>sub { push @files, $_ if /\.pm$/ }, no_chdir=>1 }, 'lib'); diff --git a/t/digest_shake.t b/t/digest_shake.t new file mode 100644 index 00000000..c79b5dd5 --- /dev/null +++ b/t/digest_shake.t @@ -0,0 +1,36 @@ +use strict; +use warnings; + +use Test::More tests => 7; + +use Crypt::Digest::SHAKE; + + +my $sh128 = Crypt::Digest::SHAKE->new(128); +ok($sh128, "Crypt::Digest::SHAKE->new(128)"); + +my $sh256 = Crypt::Digest::SHAKE->new(256); +ok($sh256, "Crypt::Digest::SHAKE->new(256)"); + +is(unpack("H*", $sh128->add("")->done(32)), "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26"); +is(unpack("H*", $sh256->add("")->done(64)), "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be"); + +is(unpack("H*", Crypt::Digest::SHAKE->new(128)->add("The quick brown fox jumps over the lazy dog")->done(32)), + "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e"); +is(unpack("H*", Crypt::Digest::SHAKE->new(128)->add("The quick brown fox jumps over the lazy dof")->done(32)), + "853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c"); + +{ + my $sh128 = Crypt::Digest::SHAKE->new(128); + $sh128->add("The qui"); + $sh128->add("ck bro"); + $sh128->add("wn fox j"); + $sh128->add("umps o"); + $sh128->add("ver the l"); + $sh128->add("azy dof"); + my $res = $sh128->done(5); + $res .= $sh128->done(7); + $res .= $sh128->done(8); + $res .= $sh128->done(12); + is(unpack("H*", $res), "853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c"); +} @@ -5,6 +5,7 @@ TYPEMAP Crypt::Cipher T_PTROBJ Crypt::Digest T_PTROBJ +Crypt::Digest::SHAKE T_PTROBJ Crypt::Checksum::Adler32 T_PTROBJ Crypt::Checksum::CRC32 T_PTROBJ |