line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBIx::Class::EncodedColumn::Digest; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
7
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
48
|
|
4
|
2
|
|
|
2
|
|
5
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
35
|
|
5
|
2
|
|
|
2
|
|
7
|
use Digest; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
887
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.00001'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my %digest_lengths = |
10
|
|
|
|
|
|
|
( |
11
|
|
|
|
|
|
|
'MD2' => { base64 => 22, binary => 16, hex => 32 }, |
12
|
|
|
|
|
|
|
'MD4' => { base64 => 22, binary => 16, hex => 32 }, |
13
|
|
|
|
|
|
|
'MD5' => { base64 => 22, binary => 16, hex => 32 }, |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
'SHA-1' => { base64 => 27, binary => 20, hex => 40 }, |
16
|
|
|
|
|
|
|
'SHA-256' => { base64 => 43, binary => 32, hex => 64 }, |
17
|
|
|
|
|
|
|
'SHA-384' => { base64 => 64, binary => 48, hex => 96 }, |
18
|
|
|
|
|
|
|
'SHA-512' => { base64 => 86, binary => 64, hex => 128 }, |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
'CRC-CCITT' => { base64 => 2, binary => 3, hex => 3 }, |
21
|
|
|
|
|
|
|
'CRC-16' => { base64 => 6, binary => 5, hex => 4 }, |
22
|
|
|
|
|
|
|
'CRC-32' => { base64 => 14, binary => 10, hex => 8 }, |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
'Adler-32' => { base64 => 6, binary => 4, hex => 8 }, |
25
|
|
|
|
|
|
|
'Whirlpool' => { base64 => 86, binary => 64, hex => 128 }, |
26
|
|
|
|
|
|
|
'Haval-256' => { base64 => 44, binary => 32, hex => 64 }, |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
my @salt_pool = ('A' .. 'Z', 'a' .. 'z', 0 .. 9, '+','/','='); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub make_encode_sub { |
31
|
7
|
|
|
7
|
1
|
10
|
my($class, $col, $args) = @_; |
32
|
7
|
|
100
|
|
|
22
|
my $for = $args->{format} ||= 'base64'; |
33
|
7
|
|
100
|
|
|
17
|
my $alg = $args->{algorithm} ||= 'SHA-256'; |
34
|
7
|
|
100
|
|
|
19
|
my $slen = $args->{salt_length} ||= 0; |
35
|
|
|
|
|
|
|
|
36
|
7
|
50
|
|
|
|
46
|
die("Valid Digest formats are 'binary', 'hex' or 'base64'. You used '$for'.") |
37
|
|
|
|
|
|
|
unless $for =~ /^(?:hex|base64|binary)$/; |
38
|
7
|
50
|
|
|
|
6
|
defined(my $object = eval{ Digest->new($alg) }) || |
|
7
|
|
|
|
|
23
|
|
39
|
|
|
|
|
|
|
die("Can't use Digest algorithm ${alg}: $@"); |
40
|
|
|
|
|
|
|
|
41
|
7
|
100
|
|
|
|
198
|
my $format_method = $for eq 'binary' ? 'digest' : |
|
|
50
|
|
|
|
|
|
42
|
|
|
|
|
|
|
($for eq 'hex' ? 'hexdigest' : 'b64digest'); |
43
|
|
|
|
|
|
|
#thanks Haval for breaking the standard. thanks! |
44
|
7
|
50
|
33
|
|
|
20
|
$format_method = 'base64digest 'if ($alg eq 'Haval-256' && $for eq 'base64'); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my $encoder = sub { |
47
|
18
|
|
|
18
|
|
89
|
my ($plain_text, $salt) = @_; |
48
|
18
|
|
100
|
|
|
83
|
$salt ||= join('', map { $salt_pool[int(rand(65))] } 1 .. $slen); |
|
28
|
|
|
|
|
54
|
|
49
|
18
|
|
|
|
|
49
|
$object->reset()->add($plain_text.$salt); |
50
|
18
|
|
|
|
|
287
|
my $digest = $object->$format_method; |
51
|
|
|
|
|
|
|
#print "${plain_text}\t ${salt}:\t${digest}${salt}\n" if $salt; |
52
|
18
|
|
|
|
|
69
|
return $digest.$salt; |
53
|
7
|
|
|
|
|
24
|
}; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
#in case i didn't prepopulate it |
56
|
7
|
|
33
|
|
|
14
|
$digest_lengths{$alg}{$for} ||= length($encoder->('test1')); |
57
|
7
|
|
|
|
|
20
|
return $encoder; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub make_check_sub { |
61
|
5
|
|
|
5
|
1
|
6
|
my($class, $col, $args) = @_; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
#this is the digest length |
64
|
5
|
|
|
|
|
9
|
my $len = $digest_lengths{$args->{algorithm}}{$args->{format}}; |
65
|
5
|
50
|
|
|
|
12
|
die("Unable to find digest length") unless defined $len; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
#fast fast fast |
68
|
5
|
|
50
|
1
|
|
443
|
return eval qq^ sub { |
|
1
|
|
|
1
|
|
6
|
|
|
1
|
|
|
1
|
|
40
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
21257
|
|
|
1
|
|
|
|
|
27
|
|
|
1
|
|
|
|
|
18
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
23
|
|
|
1
|
|
|
|
|
15
|
|
69
|
|
|
|
|
|
|
my \$col_v = \$_[0]->get_column('${col}'); |
70
|
|
|
|
|
|
|
my \$salt = substr(\$col_v, ${len}); |
71
|
|
|
|
|
|
|
\$_[0]->_column_encoders->{${col}}->(\$_[1], \$salt) eq \$col_v; |
72
|
|
|
|
|
|
|
} ^ || die($@); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
1; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
__END__; |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head1 NAME |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
DBIx::Class::EncodedColumn::Digest - Digest backend |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head1 SYNOPSYS |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
#SHA-1 / hex encoding / generate check method |
86
|
|
|
|
|
|
|
__PACKAGE__->add_columns( |
87
|
|
|
|
|
|
|
'password' => { |
88
|
|
|
|
|
|
|
data_type => 'CHAR', |
89
|
|
|
|
|
|
|
size => 40 + 10, |
90
|
|
|
|
|
|
|
encode_column => 1, |
91
|
|
|
|
|
|
|
encode_class => 'Digest', |
92
|
|
|
|
|
|
|
encode_args => {algorithm => 'SHA-1', format => 'hex', salt_length => 10}, |
93
|
|
|
|
|
|
|
encode_check_method => 'check_password', |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
#SHA-256 / base64 encoding / generate check method |
97
|
|
|
|
|
|
|
__PACKAGE__->add_columns( |
98
|
|
|
|
|
|
|
'password' => { |
99
|
|
|
|
|
|
|
data_type => 'CHAR', |
100
|
|
|
|
|
|
|
size => 40, |
101
|
|
|
|
|
|
|
encode_column => 1, |
102
|
|
|
|
|
|
|
encode_class => 'Digest', |
103
|
|
|
|
|
|
|
encode_check_method => 'check_password', |
104
|
|
|
|
|
|
|
#no encode_args necessary because these are the defaults ... |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head1 DESCRIPTION |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head1 ACCEPTED ARGUMENTS |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=head2 format |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
The encoding to use for the digest. Valid values are 'binary', 'hex', and |
115
|
|
|
|
|
|
|
'base64'. Will default to 'base64' if not specified. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head2 algorithm |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
The digest algorithm to use for the digest. You may specify any valid L<Digest> |
120
|
|
|
|
|
|
|
algorithm. Examples are L<MD5|Digest::MD5>, L<SHA-1|Digest::SHA>, |
121
|
|
|
|
|
|
|
L<Whirlpool|Digest::Whirlpool> etc. Will default to 'SHA-256' if not specified. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
See L<Digest> for supported digest algorithms. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 salt_length |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
If you would like to use randomly generated salts to encode values make sure |
128
|
|
|
|
|
|
|
this option is set to > 0. Salts will be automatically generated at encode time |
129
|
|
|
|
|
|
|
and will be appended to the end of the digest. Please make sure that you |
130
|
|
|
|
|
|
|
remember to make sure that to expand the size of your db column to have enough |
131
|
|
|
|
|
|
|
space to store both the digest AND the salt. Please see list below for common |
132
|
|
|
|
|
|
|
digest lengths. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head1 METHODS |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head2 make_encode_sub $column_name, \%encode_args |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Returns a coderef that takes two arguments, a plaintext value and an optional |
139
|
|
|
|
|
|
|
salt and returns the encoded value with the salt appended to the end of the |
140
|
|
|
|
|
|
|
digest. If a salt is not provided and the salt_length option was greater than |
141
|
|
|
|
|
|
|
zero it will be randomly generated. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head2 make_check_sub $column_name, \%encode_args |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Returns a coderef that takes the row object and a plaintext value and will |
146
|
|
|
|
|
|
|
return a boolean if the plaintext matches the encoded value. This is typically |
147
|
|
|
|
|
|
|
used for password authentication. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head1 COMMON DIGEST LENGTHS |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
CIPHER | Binary | Base64 | Hex |
152
|
|
|
|
|
|
|
--------------------------------------- |
153
|
|
|
|
|
|
|
| MD2 | 16 | 22 | 32 | |
154
|
|
|
|
|
|
|
| MD4 | 16 | 22 | 32 | |
155
|
|
|
|
|
|
|
| MD5 | 16 | 22 | 32 | |
156
|
|
|
|
|
|
|
| SHA-1 | 20 | 27 | 40 | |
157
|
|
|
|
|
|
|
| SHA-256 | 32 | 43 | 64 | |
158
|
|
|
|
|
|
|
| SHA-384 | 48 | 64 | 96 | |
159
|
|
|
|
|
|
|
| SHA-512 | 64 | 86 | 128 | |
160
|
|
|
|
|
|
|
| CRC-CCITT | 3 | 2 | 3 | |
161
|
|
|
|
|
|
|
| CRC-16 | 5 | 6 | 4 | |
162
|
|
|
|
|
|
|
| CRC-32 | 10 | 14 | 8 | |
163
|
|
|
|
|
|
|
| Adler-32 | 4 | 6 | 8 | |
164
|
|
|
|
|
|
|
| Whirlpool | 64 | 86 | 128 | |
165
|
|
|
|
|
|
|
| Haval-256 | 32 | 44 | 64 | |
166
|
|
|
|
|
|
|
--------------------------------------- |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head1 SEE ALSO |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
L<DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt>, |
171
|
|
|
|
|
|
|
L<DBIx::Class::EncodedColumn>, L<Digest> |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=head1 AUTHOR |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Guillermo Roditi (groditi) <groditi@cpan.org> |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Based on the Vienna WoC ToDo manager code by Matt S trout (mst) |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
See L<DBIx::Class::EncodedColumn> |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head1 LICENSE |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it under |
186
|
|
|
|
|
|
|
the same terms as Perl itself. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=cut |