Crypt::Digest::SHAKE
Karel Miko
7 years ago
8 | 8 | - maybe: add CCM interface for new-add-add-done mode |
9 | 9 | - maybe: switch yarrow > fortuna for Crypt::PK::* |
10 | 10 | - maybe: add encode_b32/decode_b32 |
11 | - maybe: x509_rsa_pubkey + x509_rsa_pubkey_alg | |
12 | 11 | |
13 | 12 | 0.047_001 2017/04/07 |
14 | 13 | - NEW: Crypt::Digest::SHA3_224 |
15 | 14 | - NEW: Crypt::Digest::SHA3_256 |
16 | 15 | - NEW: Crypt::Digest::SHA3_384 |
17 | 16 | - NEW: Crypt::Digest::SHA3_512 |
17 | - NEW: Crypt::Digest::SHAKE | |
18 | 18 | - NEW: Crypt::AuthEnc::ChaCha20Poly1305 |
19 | 19 | - NEW: Crypt::Mac::Poly1305 |
20 | 20 | - NEW: Crypt::PRNG::ChaCha20 |
24 | 24 | int id; |
25 | 25 | struct ltc_hash_descriptor *desc; |
26 | 26 | } *Crypt__Digest; |
27 | ||
28 | typedef struct digest_shake_struct { /* used by Crypt::Digest::SHAKE */ | |
29 | hash_state state; | |
30 | int num; | |
31 | } *Crypt__Digest__SHAKE; | |
27 | 32 | |
28 | 33 | typedef struct ccm_struct { /* used by Crypt::AuthEnc::CCM */ |
29 | 34 | ccm_state state; |
455 | 460 | ############################################################################### |
456 | 461 | |
457 | 462 | INCLUDE: inc/CryptX_Digest.xs.inc |
463 | INCLUDE: inc/CryptX_Digest_SHAKE.xs.inc | |
458 | 464 | INCLUDE: inc/CryptX_Cipher.xs.inc |
459 | 465 | |
460 | 466 | INCLUDE: inc/CryptX_Checksum_Adler32.xs.inc |
0 | MODULE = CryptX PACKAGE = Crypt::Digest::SHAKE | |
1 | ||
2 | Crypt::Digest::SHAKE | |
3 | _new(int num) | |
4 | CODE: | |
5 | { | |
6 | int rv; | |
7 | ||
8 | Newz(0, RETVAL, 1, struct digest_shake_struct); | |
9 | if (!RETVAL) croak("FATAL: Newz failed"); | |
10 | ||
11 | RETVAL->num = num; | |
12 | rv = sha3_shake_init(&RETVAL->state, RETVAL->num); | |
13 | if (rv != CRYPT_OK) croak("FATAL: sha3_shake_init failed: %s", error_to_string(rv)); | |
14 | } | |
15 | OUTPUT: | |
16 | RETVAL | |
17 | ||
18 | void | |
19 | DESTROY(Crypt::Digest::SHAKE self) | |
20 | CODE: | |
21 | Safefree(self); | |
22 | ||
23 | void | |
24 | reset(Crypt::Digest::SHAKE self) | |
25 | CODE: | |
26 | { | |
27 | int rv; | |
28 | rv = sha3_shake_init(&self->state, self->num); | |
29 | if (rv != CRYPT_OK) croak("FATAL: sha3_shake_init failed: %s", error_to_string(rv)); | |
30 | } | |
31 | ||
32 | Crypt::Digest::SHAKE | |
33 | clone(Crypt::Digest::SHAKE self) | |
34 | CODE: | |
35 | Newz(0, RETVAL, 1, struct digest_shake_struct); | |
36 | Copy(&self->state, &RETVAL->state, 1, struct digest_shake_struct); | |
37 | OUTPUT: | |
38 | RETVAL | |
39 | ||
40 | void | |
41 | add(Crypt::Digest::SHAKE self, ...) | |
42 | PPCODE: | |
43 | { | |
44 | STRLEN inlen; | |
45 | int rv, i; | |
46 | unsigned char *in; | |
47 | ||
48 | for(i=1; i<items; i++) { | |
49 | in = (unsigned char *)SvPVbyte(ST(i), inlen); | |
50 | if (inlen>0) { | |
51 | rv = sha3_shake_process(&self->state, in, (unsigned long)inlen); | |
52 | if (rv != CRYPT_OK) croak("FATAL: sha3_shake_process failed: %s", error_to_string(rv)); | |
53 | } | |
54 | } | |
55 | XPUSHs(ST(0)); /* return self */ | |
56 | } | |
57 | ||
58 | SV * | |
59 | done(Crypt::Digest::SHAKE self, STRLEN out_len) | |
60 | CODE: | |
61 | { | |
62 | int rv; | |
63 | unsigned char *out_data; | |
64 | ||
65 | RETVAL = NEWSV(0, out_len); | |
66 | SvPOK_only(RETVAL); | |
67 | SvCUR_set(RETVAL, out_len); | |
68 | out_data = (unsigned char *)SvPV_nolen(RETVAL); | |
69 | rv = sha3_shake_done(&self->state, out_data, out_len); | |
70 | if (rv != CRYPT_OK) croak("FATAL: sha3_shake_done failed: %s", error_to_string(rv)); | |
71 | } | |
72 | OUTPUT: | |
73 | RETVAL |
0 | package Crypt::Digest::SHAKE; | |
1 | ||
2 | use strict; | |
3 | use warnings; | |
4 | our $VERSION = '0.047_001'; | |
5 | ||
6 | use Carp; | |
7 | $Carp::Internal{(__PACKAGE__)}++; | |
8 | use CryptX; | |
9 | ||
10 | sub new { my $class = shift; _new(@_) } | |
11 | ||
12 | sub addfile { | |
13 | my ($self, $file) = @_; | |
14 | ||
15 | my $handle; | |
16 | if (ref(\$file) eq 'SCALAR') { #filename | |
17 | open($handle, "<", $file) || croak "FATAL: cannot open '$file': $!"; | |
18 | binmode($handle); | |
19 | } | |
20 | else { #handle | |
21 | $handle = $file | |
22 | } | |
23 | croak "FATAL: invalid handle" unless defined $handle; | |
24 | ||
25 | my $n; | |
26 | my $buf = ""; | |
27 | while (($n = read($handle, $buf, 32*1024))) { | |
28 | $self->add($buf) | |
29 | } | |
30 | croak "FATAL: read failed: $!" unless defined $n; | |
31 | ||
32 | return $self; | |
33 | } | |
34 | ||
35 | sub CLONE_SKIP { 1 } # prevent cloning | |
36 | ||
37 | 1; | |
38 | ||
39 | =pod | |
40 | ||
41 | =head1 NAME | |
42 | ||
43 | Crypt::Digest::SHAKE - Hash functions SHAKE128, SHAKE256 from SHA3 family | |
44 | ||
45 | =head1 SYNOPSIS | |
46 | ||
47 | use Crypt::Digest::SHAKE | |
48 | ||
49 | $d = Crypt::Digest::SHAKE->new(128); | |
50 | $d->add('any data'); | |
51 | $d->addfile('filename.dat'); | |
52 | $d->addfile(*FILEHANDLE); | |
53 | $part1 = $d->done(100); # 100 raw bytes | |
54 | $part2 = $d->done(100); # another 100 raw bytes | |
55 | #... | |
56 | ||
57 | =head1 DESCRIPTION | |
58 | ||
59 | Provides an interface to the SHA3's sponge function SHAKE. | |
60 | ||
61 | =head1 METHODS | |
62 | ||
63 | =head2 new | |
64 | ||
65 | $d = Crypt::Digest::SHA3-SHAKE->new($num); | |
66 | # $num ... 128 or 256 | |
67 | ||
68 | =head2 clone | |
69 | ||
70 | $d->clone(); | |
71 | ||
72 | =head2 reset | |
73 | ||
74 | $d->reset(); | |
75 | ||
76 | =head2 add | |
77 | ||
78 | $d->add('any data'); | |
79 | #or | |
80 | $d->add('any data', 'more data', 'even more data'); | |
81 | ||
82 | =head2 addfile | |
83 | ||
84 | $d->addfile('filename.dat'); | |
85 | #or | |
86 | $d->addfile(*FILEHANDLE); | |
87 | ||
88 | =head2 done | |
89 | ||
90 | $result_raw = $d->done($len); | |
91 | # can be called multiple times | |
92 | ||
93 | =head1 SEE ALSO | |
94 | ||
95 | =over | |
96 | ||
97 | =item * L<CryptX|CryptX>, L<Crypt::Digest|Crypt::Digest> | |
98 | ||
99 | =item * L<http://en.wikipedia.org/wiki/SHA-3|http://en.wikipedia.org/wiki/SHA-3> | |
100 | ||
101 | =back | |
102 | ||
103 | =cut | |
104 | ||
105 | __END__⏎ |
4 | 4 | |
5 | 5 | plan skip_all => "File::Find not installed" unless eval { require File::Find }; |
6 | 6 | plan skip_all => "Test::Pod not installed" unless eval { require Test::Pod }; |
7 | plan tests => 87; | |
7 | plan tests => 88; | |
8 | 8 | |
9 | 9 | my @files; |
10 | 10 | File::Find::find({ wanted=>sub { push @files, $_ if /\.pm$/ }, no_chdir=>1 }, 'lib'); |
0 | use strict; | |
1 | use warnings; | |
2 | ||
3 | use Test::More tests => 7; | |
4 | ||
5 | use Crypt::Digest::SHAKE; | |
6 | ||
7 | ||
8 | my $sh128 = Crypt::Digest::SHAKE->new(128); | |
9 | ok($sh128, "Crypt::Digest::SHAKE->new(128)"); | |
10 | ||
11 | my $sh256 = Crypt::Digest::SHAKE->new(256); | |
12 | ok($sh256, "Crypt::Digest::SHAKE->new(256)"); | |
13 | ||
14 | is(unpack("H*", $sh128->add("")->done(32)), "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26"); | |
15 | is(unpack("H*", $sh256->add("")->done(64)), "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be"); | |
16 | ||
17 | is(unpack("H*", Crypt::Digest::SHAKE->new(128)->add("The quick brown fox jumps over the lazy dog")->done(32)), | |
18 | "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e"); | |
19 | is(unpack("H*", Crypt::Digest::SHAKE->new(128)->add("The quick brown fox jumps over the lazy dof")->done(32)), | |
20 | "853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c"); | |
21 | ||
22 | { | |
23 | my $sh128 = Crypt::Digest::SHAKE->new(128); | |
24 | $sh128->add("The qui"); | |
25 | $sh128->add("ck bro"); | |
26 | $sh128->add("wn fox j"); | |
27 | $sh128->add("umps o"); | |
28 | $sh128->add("ver the l"); | |
29 | $sh128->add("azy dof"); | |
30 | my $res = $sh128->done(5); | |
31 | $res .= $sh128->done(7); | |
32 | $res .= $sh128->done(8); | |
33 | $res .= $sh128->done(12); | |
34 | is(unpack("H*", $res), "853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c"); | |
35 | } |