#!/usr/bin/perl -w use strict; use Getopt::Long qw(:config no_ignore_case); use Pod::Usage; use Digest::SHA; use MIME::Base64; use Math::Random::Secure qw(irand); my %opts; GetOptions(\%opts, qw[ help|?! man! f|format=s l|len=i s|salt=s S|Salt=s z|saltlen:i ] ) or pod2usage(2); pod2usage(1) if $opts{help}; pod2usage(-verbose => 2) if $opts{man}; my $len = 256; if (exists $opts{l}) { my @length = (224, 256, 384, 512); if (grep {$_ eq $opts{l}} @length) { $len = $opts{l}; } else { print "Bad length\n"; exit(1); } } sub fmt_base64 { return encode_base64(shift, '')."\n"; } sub fmt_hex { return unpack('H*', shift)."\n"; } sub fmt_bin { return shift; } my $fmt = \&{'fmt_base64'}; if (exists $opts{f}) { my %format = ('m' => \&{'fmt_base64'}, 'base64' => \&{'fmt_base64'}, 'x' => \&{'fmt_hex'}, 'hex' => \&{'fmt_hex'}, 'b' => \&{'fmt_bin'}, 'bin' => \&{'fmt_bin'}); $fmt = $format{$opts{f}}; if (!defined $fmt) { print "Bad format\n"; exit(1); } } my $password = $ARGV[0]; if (!defined $password) { print "Missing password\n"; exit(1); } my $salt = $opts{s}; if (exists $opts{S}) { if (defined $salt) { print "Redundant salt\n"; exit(1); } $salt = pack('H*', $opts{S}); } elsif (!defined $salt and exists $opts{z}) { my $ssiz = $opts{z}; if ($ssiz == 0) { $ssiz = 8; } elsif ($ssiz < 0) { print "Bad salt length\n"; exit(1); } while ($ssiz >= 4) { $salt .= pack('N', irand()); $ssiz -= 4; } $salt .= substr(pack('N', irand()), 1, $ssiz) if ($ssiz > 0); } my $ctx = Digest::SHA->new($len); $ctx->add($password); $ctx->add($salt) if (defined $salt); my $dig = $ctx->digest; $dig .= $salt if (defined $salt); print &$fmt($dig); __END__ =head1 NAME ssha2passwd - Generate a SHA2 hashed password =head1 DESCRIPTION Hash the given password into a SHA2 digest with optional salt. =head1 SYNOPSIS ssha2passwd [options] =head1 OPTIONS =over =item B<-f> or B<-format> Format options: =over =item B or B : base64 encoded (default) =item B or B : hexadecimal string =item B or B : binary string =back =item B<-l> or B<-length> Hash algorithm bit length (224, 256, 384, or 512 | default: 256). =item B<-s> or B<-salt> =item B<-S> or B<-Salt> Salt string appended to password and hashed. The resultant digest then has the salt string appended. =item B<-z> or B<-saltlen> [] Byte length of random salt appended to password and hashed, if no salt string is explicitly given (0 is default, default: 8). =item B<-?> or B<-help> Print a brief help message. =item B<-man> Print the manual page. =back =cut