#!perl
use strictures 2;
use POSIX ();
use App::bmkpasswd -all;
use Time::HiRes qw/ gettimeofday tv_interval /;
use Try::Tiny;
my $type = 'bcrypt';
my $bcost = 8;
my ($bench, $strong, $check);
use Pod::Usage;
use Getopt::Long;
GetOptions(
'benchmark!' => \$bench,
'strong!' => \$strong,
'check=s' => \$check,
'm|method|type=s' => \$type,
'workcost=s' => \$bcost,
'version' => sub {
require Crypt::Eksblowfish::Bcrypt;
my $bvers = $App::bmkpasswd::VERSION || '(git)';
print(
"App::bmkpasswd $bvers\n\n",
" Using Crypt::Eksblowfish::Bcrypt-",
$Crypt::Eksblowfish::Bcrypt::VERSION, "\n",
);
my $vialib = App::bmkpasswd::have_passwd_xs() ?
'Crypt::Passwd::XS' : 'system crypt';
my @avail;
push @avail, 'SHA256' if mkpasswd_available('sha256');
push @avail, 'SHA512' if mkpasswd_available('sha512');
print ' ', join(', ', @avail), " available (via $vialib)\n";
exit 0
},
'help' => sub { pod2usage(0) },
'man' => sub { pod2usage(-verbose => 2, -noperldoc => 1) },
'usage' => sub { pod2usage(2) },
);
my $pwd;
if (@ARGV) {
$pwd = $ARGV[0];
} else {
$|++;
print {*STDERR} "Password: ";
my $term = POSIX::Termios->new;
$term->getattr(0);
$term->setlflag( $term->getlflag & ~POSIX::ECHO );
$term->setattr(0);
$pwd = <STDIN>;
$term->setlflag( $term->getlflag | POSIX::ECHO );
$term->setattr(0);
chomp($pwd);
print {*STDERR} "\n";
}
my $timer = $bench ? [gettimeofday] : ();
if ($check) {
if ( passwdcmp($pwd, $check) ) {
print "Match\n", "$check\n";
} else {
exit 1
}
} else {
print mkpasswd($pwd, $type, $bcost, $strong)."\n";
}
if ($bench) {
my $interval = tv_interval($timer);
print " bench: $type, time: $interval\n";
}
exit 0
__END__
=pod
=head1 NAME
bmkpasswd - bcrypt-enabled mkpasswd
=head1 SYNOPSIS
bmkpasswd [OPTIONS]... [PASSWD]
=head1 OPTIONS
-m, --method=TYPE [default: bcrypt]
Types: bcrypt (recommended; guaranteed available)
sha512 (requires recent libc or Crypt::Passwd::XS)
sha256 (requires recent libc or Crypt::Passwd::XS)
-w, --workcost=NUM Bcrypt work-cost factor; default 08.
Higher is slower. Should be a two-digit power of 2.
-c, --check=HASH Compare password against given HASH
-s, --strong Use strongly-random salt generation
-b, --benchmark Show timers; useful for comparing hash generation
--version Display version information and available methods
If PASSWD is missing, it is prompted for interactively.
=head1 DESCRIPTION
Simple bcrypt-enabled mkpasswd.
While SHA512 isn't a bad choice if you have it, bcrypt has the
advantage of including a configurable work cost factor.
A higher work cost factor exponentially increases hashing time, meaning
a brute-force attack against stolen hashes can take a B<very> long time.
Salts are randomly generated using L<Bytes::Random::Secure>.
Using the C<--strong> option requires a reliable source of entropy; try
B<haveged> (L<http://www.issihosts.com/haveged/downloads.html>), especially on
headless Linux systems.
See L<App::bmkpasswd> for more details on bcrypt and the inner workings of
this software.
See L<Crypt::Bcrypt::Easy> if you'd like a simple interface to creating and
comparing bcrypted passwords from your own modules.
=head1 AUTHOR
Jon Portnoy <avenj@cobaltirc.org>
=cut