summaryrefslogtreecommitdiff
path: root/lib/Crypt/Digest.pm
blob: 5eb1412bf07412758781585da263e2dcee479369 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
package Crypt::Digest;

use strict;
use warnings;
our $VERSION = '0.079_007';

require Exporter; our @ISA = qw(Exporter); ### use Exporter 5.57 'import';
our %EXPORT_TAGS = ( all => [qw( digest_data digest_data_hex digest_data_b64 digest_data_b64u digest_file digest_file_hex digest_file_b64 digest_file_b64u )] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw();

use Carp;
$Carp::Internal{(__PACKAGE__)}++;
use CryptX;

### the following methods/functions are implemented in XS:
# - new
# - hashsize
# - clone
# - reset
# - digest
# - hexdigest
# - b64digest
# - add
# - digest_data
# - digest_data_hex
# - digest_data_b64
# - digest_data_b64u
# - DESTROY

### METHODS

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

### FUNCTIONS

sub digest_file        { local $SIG{__DIE__} = \&CryptX::_croak; Crypt::Digest->new(shift)->addfile(@_)->digest     }
sub digest_file_hex    { local $SIG{__DIE__} = \&CryptX::_croak; Crypt::Digest->new(shift)->addfile(@_)->hexdigest  }
sub digest_file_b64    { local $SIG{__DIE__} = \&CryptX::_croak; Crypt::Digest->new(shift)->addfile(@_)->b64digest  }
sub digest_file_b64u   { local $SIG{__DIE__} = \&CryptX::_croak; Crypt::Digest->new(shift)->addfile(@_)->b64udigest }

1;

=pod

=head1 NAME

Crypt::Digest - Generic interface to hash/digest functions

=head1 SYNOPSIS

   ### Functional interface:
   use Crypt::Digest qw( digest_data digest_data_hex digest_data_b64 digest_data_b64u
                         digest_file digest_file_hex digest_file_b64 digest_file_b64u );

   # calculate digest from string/buffer
   $digest_raw  = digest_data('SHA1', 'data string');
   $digest_hex  = digest_data_hex('SHA1', 'data string');
   $digest_b64  = digest_data_b64('SHA1', 'data string');
   $digest_b64u = digest_data_b64u('SHA1', 'data string');
   # calculate digest from file
   $digest_raw  = digest_file('SHA1', 'filename.dat');
   $digest_hex  = digest_file_hex('SHA1', 'filename.dat');
   $digest_b64  = digest_file_b64('SHA1', 'filename.dat');
   $digest_b64u = digest_file_b64u('SHA1', 'filename.dat');
   # calculate digest from filehandle
   $digest_raw  = digest_file('SHA1', *FILEHANDLE);
   $digest_hex  = digest_file_hex('SHA1', *FILEHANDLE);
   $digest_b64  = digest_file_b64('SHA1', *FILEHANDLE);
   $digest_b64u = digest_file_b64u('SHA1', *FILEHANDLE);

   ### OO interface:
   use Crypt::Digest;

   $d = Crypt::Digest->new('SHA1');
   $d->add('any data');
   $d->addfile('filename.dat');
   $d->addfile(*FILEHANDLE);
   $result_raw  = $d->digest;     # raw bytes
   $result_hex  = $d->hexdigest;  # hexadecimal form
   $result_b64  = $d->b64digest;  # Base64 form
   $result_b64u = $d->b64udigest; # Base64 URL Safe form

=head1 DESCRIPTION

Provides an interface to various hash/digest algorithms.

=head1 EXPORT

Nothing is exported by default.

You can export selected functions:

  use Crypt::Digest qw( digest_data digest_data_hex digest_data_b64 digest_data_b64u
                        digest_file digest_file_hex digest_file_b64 digest_file_b64u );

Or all of them at once:

  use Crypt::Digest ':all';

=head1 FUNCTIONS

Please note that all functions take as its first argument the algorithm name, supported values are:

 'CHAES', 'MD2', 'MD4', 'MD5', 'RIPEMD128', 'RIPEMD160',
 'RIPEMD256', 'RIPEMD320', 'SHA1', 'SHA224', 'SHA256',
 'SHA384', 'SHA512', 'SHA512_224', 'SHA512_256', 'Tiger192', 'Whirlpool',
 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512',
 'BLAKE2b_160', 'BLAKE2b_256', 'BLAKE2b_384', 'BLAKE2b_512',
 'BLAKE2s_128', 'BLAKE2s_160', 'BLAKE2s_224', 'BLAKE2s_256'

 (simply any <NAME> for which there is Crypt::Digest::<NAME> module)

=head2 digest_data

Logically joins all arguments into a single string, and returns its SHA1 digest encoded as a binary string.

 $digest_raw = digest_data('SHA1', 'data string');
 #or
 $digest_raw = digest_data('SHA1', 'any data', 'more data', 'even more data');

=head2 digest_data_hex

Logically joins all arguments into a single string, and returns its SHA1 digest encoded as a hexadecimal string.

 $digest_hex = digest_data_hex('SHA1', 'data string');
 #or
 $digest_hex = digest_data_hex('SHA1', 'any data', 'more data', 'even more data');

=head2 digest_data_b64

Logically joins all arguments into a single string, and returns its SHA1 digest encoded as a Base64 string, B<with> trailing '=' padding.

 $digest_b64 = digest_data_b64('SHA1', 'data string');
 #or
 $digest_b64 = digest_data_b64('SHA1', 'any data', 'more data', 'even more data');

=head2 digest_data_b64u

Logically joins all arguments into a single string, and returns its SHA1 digest encoded as a Base64 URL Safe string (see RFC 4648 section 5).

 $digest_b64url = digest_data_b64u('SHA1', 'data string');
 #or
 $digest_b64url = digest_data_b64u('SHA1', 'any data', 'more data', 'even more data');

=head2 digest_file

Reads file (defined by filename or filehandle) content, and returns its digest encoded as a binary string.

 $digest_raw = digest_file('SHA1', 'filename.dat');
 #or
 $digest_raw = digest_file('SHA1', *FILEHANDLE);

=head2 digest_file_hex

Reads file (defined by filename or filehandle) content, and returns its digest encoded as a hexadecimal string.

 $digest_hex = digest_file_hex('SHA1', 'filename.dat');
 #or
 $digest_hex = digest_file_hex('SHA1', *FILEHANDLE);

B<BEWARE:> You have to make sure that the filehandle is in binary mode before you pass it as argument to the addfile() method.

=head2 digest_file_b64

Reads file (defined by filename or filehandle) content, and returns its digest encoded as a Base64 string, B<with> trailing '=' padding.

 $digest_b64 = digest_file_b64('SHA1', 'filename.dat');
 #or
 $digest_b64 = digest_file_b64('SHA1', *FILEHANDLE);

=head2 digest_file_b64u

Reads file (defined by filename or filehandle) content, and returns its digest encoded as a Base64 URL Safe string (see RFC 4648 section 5).

 $digest_b64url = digest_file_b64u('SHA1', 'filename.dat');
 #or
 $digest_b64url = digest_file_b64u('SHA1', *FILEHANDLE);

=head1 METHODS

=head2 new

Constructor, returns a reference to the digest object.

 $d = Crypt::Digest->new($name);
 # $name could be: 'CHAES', 'MD2', 'MD4', 'MD5', 'RIPEMD128', 'RIPEMD160',
 #                 'RIPEMD256', 'RIPEMD320', 'SHA1', 'SHA224', 'SHA256', 'SHA384',
 #                 'SHA512', 'SHA512_224', 'SHA512_256', 'Tiger192', 'Whirlpool'
 #
 # simply any <FUNCNAME> for which there is Crypt::Digest::<FUNCNAME> module

=head2 clone

Creates a copy of the digest object state and returns a reference to the copy.

 $d->clone();

=head2 reset

Reinitialize the digest object state and returns a reference to the digest object.

 $d->reset();

=head2 add

All arguments are appended to the message we calculate digest for.
The return value is the digest object itself.

 $d->add('any data');
 #or
 $d->add('any data', 'more data', 'even more data');

Note that all the following cases are equivalent:

 # case 1
 $d->add('aa', 'bb', 'cc');

 # case 2
 $d->add('aa');
 $d->add('bb');
 $d->add('cc');

 # case 3
 $d->add('aabbcc');

 # case 4
 $d->add('aa')->add('bb')->add('cc');

=head2 addfile

The content of the file (or filehandle) is appended to the message we calculate digest for.
The return value is the digest object itself.

 $d->addfile('filename.dat');
 #or
 $d->addfile(*FILEHANDLE);

B<BEWARE:> You have to make sure that the filehandle is in binary mode before you pass it as argument to the addfile() method.

=head2 add_bits

This method is available mostly for compatibility with other Digest::SOMETHING modules on CPAN, you are very unlikely to need it.
The return value is the digest object itself.

 $d->add_bits($bit_string);   # e.g. $d->add_bits("111100001010");
 #or
 $d->add_bits($data, $nbits); # e.g. $d->add_bits("\xF0\xA0", 16);

B<BEWARE:> It is not possible to add bits that are not a multiple of 8.

=head2 hashsize

Returns the length of calculated digest in bytes (e.g. 32 for SHA-256).

 $d->hashsize;
 #or
 Crypt::Digest->hashsize('SHA1');
 #or
 Crypt::Digest::hashsize('SHA1');

=head2 digest

Returns the binary digest (raw bytes).

 $result_raw = $d->digest();

=head2 hexdigest

Returns the digest encoded as a hexadecimal string.

 $result_hex = $d->hexdigest();

=head2 b64digest

Returns the digest encoded as a Base64 string, B<with> trailing '=' padding (B<BEWARE:> this padding
style might differ from other Digest::<SOMETHING> modules on CPAN).

 $result_b64 = $d->b64digest();

=head2 b64udigest

Returns the digest encoded as a Base64 URL Safe string (see RFC 4648 section 5).

 $result_b64url = $d->b64udigest();

=head1 SEE ALSO

=over

=item * L<CryptX|CryptX>

=item * L<Crypt::Digest|Crypt::Digest> tries to be compatible with L<Digest|Digest> interface.

=item * Check subclasses like L<Crypt::Digest::SHA1|Crypt::Digest::SHA1>, L<Crypt::Digest::MD5|Crypt::Digest::MD5>, ...

=back

=cut