1=head1 NAME
2
3Crypt::Eksblowfish::Bcrypt - Blowfish-based Unix crypt() password hash
4
5=head1 SYNOPSIS
6
7	use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash);
8
9	$hash = bcrypt_hash({
10			key_nul => 1,
11			cost => 8,
12			salt => $salt,
13		}, $password);
14
15	use Crypt::Eksblowfish::Bcrypt qw(en_base64 de_base64);
16
17	$text = en_base64($octets);
18	$octets = de_base64($text);
19
20	use Crypt::Eksblowfish::Bcrypt qw(bcrypt);
21
22	$hashed_password = bcrypt($password, $settings);
23
24=head1 DESCRIPTION
25
26This module implements the Blowfish-based Unix crypt() password hashing
27algorithm, known as "bcrypt".  This hash uses a variant of Blowfish,
28known as "Eksblowfish", modified to have particularly expensive key
29scheduling.  Eksblowfish and bcrypt were devised by Niels Provos and
30David Mazieres for OpenBSD.  The design is described in a paper at
31L<http://www.usenix.org/events/usenix99/provos.html>.
32
33=cut
34
35package Crypt::Eksblowfish::Bcrypt;
36
37{ use 5.006; }
38use warnings;
39use strict;
40
41use Carp qw(croak);
42use Crypt::Eksblowfish 0.005;
43use MIME::Base64 2.21 qw(encode_base64 decode_base64);
44
45our $VERSION = "0.009";
46
47use parent "Exporter";
48our @EXPORT_OK = qw(bcrypt_hash en_base64 de_base64 bcrypt);
49
50=head1 FUNCTIONS
51
52=over
53
54=item bcrypt_hash(SETTINGS, PASSWORD)
55
56Hashes PASSWORD according to the supplied SETTINGS, and returns the
5723-octet hash.  SETTINGS must be a reference to a hash, with these keys:
58
59=over
60
61=item B<key_nul>
62
63Truth value: whether to append a NUL to the password before using it as a key.
64The algorithm as originally devised does not do this, but it was later
65modified to do it.  The version that does append NUL is to be preferred;
66not doing so is supported only for backward compatibility.
67
68=item B<cost>
69
70Non-negative integer controlling the cost of the hash function.
71The number of operations is proportional to 2^cost.
72
73=item B<salt>
74
75Exactly sixteen octets of salt.
76
77=back
78
79=cut
80
81sub bcrypt_hash($$) {
82	my($settings, $password) = @_;
83	$password .= "\0" if $settings->{key_nul} || $password eq "";
84	my $cipher = Crypt::Eksblowfish->new($settings->{cost},
85			$settings->{salt}, substr($password, 0, 72));
86	my $hash = join("", map {
87				my $blk = $_;
88				for(my $i = 64; $i--; ) {
89					$blk = $cipher->encrypt($blk);
90				}
91				$blk;
92			    } qw(OrpheanB eholderS cryDoubt));
93	chop $hash;
94	return $hash;
95}
96
97=item en_base64(BYTES)
98
99Encodes the octet string textually using the form of base 64 that is
100conventionally used with bcrypt.
101
102=cut
103
104sub en_base64($) {
105	my($octets) = @_;
106	my $text = encode_base64($octets, "");
107	$text =~ tr#A-Za-z0-9+/=#./A-Za-z0-9#d;
108	return $text;
109}
110
111=item de_base64(TEXT)
112
113Decodes an octet string that was textually encoded using the form of
114base 64 that is conventionally used with bcrypt.
115
116=cut
117
118sub de_base64($) {
119	my($text) = @_;
120	croak "bad base64 encoding"
121		unless $text =~ m#\A(?>(?:[./A-Za-z0-9]{4})*)
122				  (?:|[./A-Za-z0-9]{2}[.CGKOSWaeimquy26]|
123				      [./A-Za-z0-9][.Oeu])\z#x;
124	$text =~ tr#./A-Za-z0-9#A-Za-z0-9+/#;
125	$text .= "=" x (3 - (length($text) + 3) % 4);
126	return decode_base64($text);
127}
128
129=item bcrypt(PASSWORD, SETTINGS)
130
131This is a version of C<crypt> (see L<perlfunc/crypt>) that implements the
132bcrypt algorithm.  It does not implement any other hashing algorithms,
133so if others are desired then it necessary to examine the algorithm
134prefix in SETTINGS and dispatch between more than one version of C<crypt>.
135
136SETTINGS must be a string which encodes the algorithm parameters,
137including salt.  It must begin with "$2", optional "a", "$", two
138digits, "$", and 22 base 64 digits.  The rest of the string is ignored.
139The presence of the optional "a" means that a NUL is to be appended
140to the password before it is used as a key.  The two digits set the
141cost parameter.  The 22 base 64 digits encode the salt.  The function
142will C<die> if SETTINGS does not have this format.
143
144The PASSWORD is hashed according to the SETTINGS.  The value returned
145is a string which encodes the algorithm parameters and the hash: the
146parameters are in the same format required in SETTINGS, and the hash is
147appended in the form of 31 base 64 digits.  This result is suitable to
148be used as a SETTINGS string for input to this function: the hash part
149of the string is ignored on input.
150
151=cut
152
153sub bcrypt($$) {
154	my($password, $settings) = @_;
155	croak "bad bcrypt settings"
156		unless $settings =~ m#\A\$2(a?)\$([0-9]{2})\$
157					([./A-Za-z0-9]{22})#x;
158	my($key_nul, $cost, $salt_base64) = ($1, $2, $3);
159	my $hash = bcrypt_hash({
160			key_nul => $key_nul,
161			cost => $cost,
162			salt => de_base64($salt_base64),
163		   }, $password);
164	return "\$2${key_nul}\$${cost}\$${salt_base64}".en_base64($hash);
165}
166
167=back
168
169=head1 SEE ALSO
170
171L<Crypt::Eksblowfish>,
172L<http://www.usenix.org/events/usenix99/provos.html>
173
174=head1 AUTHOR
175
176Andrew Main (Zefram) <zefram@fysh.org>
177
178=head1 COPYRIGHT
179
180Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
181Andrew Main (Zefram) <zefram@fysh.org>
182
183=head1 LICENSE
184
185This module is free software; you can redistribute it and/or modify it
186under the same terms as Perl itself.
187
188=cut
189
1901;
191