1#!/usr/bin/perl -w
2use strict;
3use Getopt::Long qw(:config no_ignore_case);
4use Pod::Usage;
5use Digest::SHA;
6use MIME::Base64;
7use Math::Random::Secure qw(irand);
8
9my %opts;
10GetOptions(\%opts,
11	qw[ help|?! man! f|format=s l|len=i s|salt=s S|Salt=s z|saltlen:i ]
12) or pod2usage(2);
13pod2usage(1) if $opts{help};
14pod2usage(-verbose => 2) if $opts{man};
15
16my $len = 256;
17if (exists $opts{l}) {
18	my @length = (224, 256, 384, 512);
19	if (grep {$_ eq $opts{l}} @length) {
20		$len = $opts{l};
21	} else {
22		print "Bad length\n";
23		exit(1);
24	}
25}
26
27sub fmt_base64 {
28	return encode_base64(shift, '')."\n";
29}
30
31sub fmt_hex {
32	return unpack('H*', shift)."\n";
33}
34
35sub fmt_bin {
36	return shift;
37}
38
39my $fmt = \&{'fmt_base64'};
40if (exists $opts{f}) {
41	my %format = ('m' => \&{'fmt_base64'}, 'base64' => \&{'fmt_base64'},
42		'x' => \&{'fmt_hex'}, 'hex' => \&{'fmt_hex'},
43		'b' => \&{'fmt_bin'}, 'bin' => \&{'fmt_bin'});
44	$fmt = $format{$opts{f}};
45	if (!defined $fmt) {
46		print "Bad format\n";
47		exit(1);
48	}
49}
50
51my $password = $ARGV[0];
52if (!defined $password) {
53	print "Missing password\n";
54	exit(1);
55}
56
57my $salt = $opts{s};
58if (exists $opts{S}) {
59	if (defined $salt) {
60		print "Redundant salt\n";
61		exit(1);
62	}
63	$salt = pack('H*', $opts{S});
64} elsif (!defined $salt and exists $opts{z}) {
65	my $ssiz = $opts{z};
66	if ($ssiz == 0) {
67		$ssiz = 8;
68	} elsif ($ssiz < 0) {
69		print "Bad salt length\n";
70		exit(1);
71	}
72	while ($ssiz >= 4) {
73		$salt .= pack('N', irand());
74		$ssiz -= 4;
75	}
76	$salt .= substr(pack('N', irand()), 1, $ssiz) if ($ssiz > 0);
77}
78
79my $ctx = Digest::SHA->new($len);
80$ctx->add($password);
81$ctx->add($salt) if (defined $salt);
82my $dig = $ctx->digest;
83$dig .= $salt if (defined $salt);
84
85print &$fmt($dig);
86
87__END__
88
89=head1 NAME
90
91ssha2passwd - Generate a SHA2 hashed password
92
93=head1 DESCRIPTION
94
95Hash the given password into a SHA2 digest with optional salt.
96
97=head1 SYNOPSIS
98
99   ssha2passwd [options] <password>
100
101=head1 OPTIONS
102
103=over
104
105=item B<-f> or B<-format> <format>
106
107Format options:
108
109=over
110
111=item B<m> or B<base64> : base64 encoded (default)
112
113=item B<x> or B<hex> : hexadecimal string
114
115=item B<b> or B<bin> : binary string
116
117=back
118
119=item B<-l> or B<-length> <length>
120
121Hash algorithm bit length (224, 256, 384, or 512 | default: 256).
122
123=item B<-s> or B<-salt> <string>
124
125=item B<-S> or B<-Salt> <hexadecimal string>
126
127Salt string appended to password and hashed. The resultant digest then
128has the salt string appended.
129
130=item B<-z> or B<-saltlen> [<length>]
131
132Byte length of random salt appended to password and hashed, if no salt
133string is explicitly given (0 is default, default: 8).
134
135=item B<-?> or B<-help>
136
137Print a brief help message.
138
139=item B<-man>
140
141Print the manual page.
142
143=back
144=cut
145