Add OpenBSD
[freeradius.git] / scripts / Ssha2Passwd
1 #!/usr/bin/perl -w
2 use strict;
3 use Getopt::Long qw(:config no_ignore_case);
4 use Pod::Usage;
5 use Digest::SHA;
6 use MIME::Base64;
7 use Math::Random::Secure qw(irand);
8
9 my %opts;
10 GetOptions(\%opts,
11         qw[ help|?! man! f|format=s l|len=i s|salt=s S|Salt=s z|saltlen:i ]
12 ) or pod2usage(2);
13 pod2usage(1) if $opts{help};
14 pod2usage(-verbose => 2) if $opts{man};
15
16 my $len = 256;
17 if (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
27 sub fmt_base64 {
28         return encode_base64(shift, '')."\n";
29 }
30
31 sub fmt_hex {
32         return unpack('H*', shift)."\n";
33 }
34
35 sub fmt_bin {
36         return shift;
37 }
38
39 my $fmt = \&{'fmt_base64'};
40 if (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
51 my $password = $ARGV[0];
52 if (!defined $password) {
53         print "Missing password\n";
54         exit(1);
55 }
56
57 my $salt = $opts{s};
58 if (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
79 my $ctx = Digest::SHA->new($len);
80 $ctx->add($password);
81 $ctx->add($salt) if (defined $salt);
82 my $dig = $ctx->digest;
83 $dig .= $salt if (defined $salt);
84
85 print &$fmt($dig);
86
87 __END__
88
89 =head1 NAME
90
91 ssha2passwd - Generate a SHA2 hashed password
92
93 =head1 DESCRIPTION
94
95 Hash 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
107 Format 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
121 Hash 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
127 Salt string appended to password and hashed. The resultant digest then
128 has the salt string appended.
129
130 =item B<-z> or B<-saltlen> [<length>]
131
132 Byte length of random salt appended to password and hashed, if no salt
133 string is explicitly given (0 is default, default: 8).
134
135 =item B<-?> or B<-help>
136
137 Print a brief help message.
138
139 =item B<-man>
140
141 Print the manual page.
142
143 =back
144 =cut