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
|
package Crypt::OpenPGP::Digest;
use strict;
use Crypt::OpenPGP::ErrorHandler;
use base qw( Crypt::OpenPGP::ErrorHandler );
use vars qw( %ALG %ALG_BY_NAME );
%ALG = (
1 => 'MD5',
2 => 'SHA1',
3 => 'RIPEMD160',
);
%ALG_BY_NAME = map { $ALG{$_} => $_ } keys %ALG;
sub new {
my $class = shift;
my $alg = shift;
$alg = $ALG{$alg} || $alg;
return $class->error("Unsupported digest algorithm '$alg'")
unless $alg =~ /^\D/;
my $pkg = join '::', $class, $alg;
my $dig = bless { __alg => $alg,
__alg_id => $ALG_BY_NAME{$alg} }, $pkg;
$dig->init(@_);
}
sub init { $_[0] }
sub hash { $_[0]->{md}->($_[1]) }
sub alg {
return $_[0]->{__alg} if ref($_[0]);
$ALG{$_[1]} || $_[1];
}
sub alg_id {
return $_[0]->{__alg_id} if ref($_[0]);
$ALG_BY_NAME{$_[1]} || $_[1];
}
sub supported {
my $class = shift;
my %s;
for my $did (keys %ALG) {
my $digest = $class->new($did);
$s{$did} = $digest->alg if $digest;
}
\%s;
}
package Crypt::OpenPGP::Digest::MD5;
use strict;
use base qw( Crypt::OpenPGP::Digest );
sub init {
my $dig = shift;
require Digest::MD5;
$dig->{md} = \&Digest::MD5::md5;
$dig;
}
package Crypt::OpenPGP::Digest::SHA1;
use strict;
use base qw( Crypt::OpenPGP::Digest );
sub init {
my $dig = shift;
require Digest::SHA1;
$dig->{md} = \&Digest::SHA1::sha1;
$dig;
}
package Crypt::OpenPGP::Digest::RIPEMD160;
use strict;
use base qw( Crypt::OpenPGP::Digest );
sub init {
my $dig = shift;
require Crypt::RIPEMD160;
$dig->{md} = sub { Crypt::RIPEMD160->hash($_[0]) };
$dig;
}
1;
__END__
=head1 NAME
Crypt::OpenPGP::Digest - PGP message digest factory
=head1 SYNOPSIS
use Crypt::OpenPGP::Digest;
my $alg = 'SHA1';
my $dgst = Crypt::OpenPGP::Digest->new( $alg );
my $data = 'foo bar';
my $hashed_data = $dgst->hash($data);
=head1 DESCRIPTION
I<Crypt::OpenPGP::Digest> is a factory class for PGP message digest
objects. All digest objects are subclasses of this class and share a
common interface; when creating a new digest object, the object is
blessed into the subclass to take on algorithm-specific functionality.
A I<Crypt::OpenPGP::Digest> object wraps around a function reference
providing the actual digest implementation (eg. I<Digest::MD::md5> for
an MD5 digest). This allows all digest objects to share a common
interface and a simple instantiation method.
=head1 USAGE
=head2 Crypt::OpenPGP::Digest->new($digest)
Creates a new message digest object of type I<$digest>; I<$digest> can
be either the name of a digest algorithm (in I<Crypt::OpenPGP>
parlance) or the numeric ID of the algorithm (as defined in the
OpenPGP RFC). Using an algorithm name is recommended, for the simple
reason that it is easier to understand quickly (not everyone knows
the algorithm IDs).
Valid digest names are: C<MD5>, C<SHA1>, and C<RIPEMD160>.
Returns the new digest object on success. On failure returns C<undef>;
the caller should check for failure and call the class method I<errstr>
if a failure occurs. A typical reason this might happen is an
unsupported digest name or ID.
=head2 $dgst->hash($data)
Creates a message digest hash of the data I<$data>, a string of
octets, and returns the digest.
=head2 $dgst->alg
Returns the name of the digest algorithm (as listed above in I<new>).
=head2 $dgst->alg_id
Returns the numeric ID of the digest algorithm.
=head1 AUTHOR & COPYRIGHTS
Please see the Crypt::OpenPGP manpage for author, copyright, and
license information.
=cut
|