Created
September 28, 2013 15:22
-
-
Save mprentice/6743089 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use strict; | |
use warnings; | |
use utf8; | |
use Carp; | |
use Getopt::Long; | |
use Math::Random::Secure qw(rand irand); | |
exit main(@ARGV); | |
sub usage { | |
return <<END_USAGE; | |
Usage: genpasswd [--words=<int>] [--minlen=<int>] [--maxlen=<int>] | |
[--file=<filename>] [--digits=<int>] [--symbols=<int>] | |
[--symlist="<symbols>"] | |
[--help] [--verbose] | |
END_USAGE | |
} | |
sub choose_n { | |
my ($n, @lst) = @_; | |
my @items; | |
my $nitems = scalar @lst; | |
for (my $i = 0; $i < $n; $i++) { | |
push @items, $lst[ irand($nitems) ]; | |
} | |
return @items; | |
} | |
sub log2 { | |
my $n = shift; | |
return log($n) / log(2); | |
} | |
sub main { | |
local @ARGV = @_; | |
my ( | |
$help, | |
$verbose, | |
$nwords, | |
$minlen, | |
$maxlen, | |
$file, | |
$digits, | |
$symbols, | |
$symlist, | |
); | |
GetOptions( | |
'help' => \$help, | |
'verbose!' => \$verbose, | |
'words=i' => \$nwords, | |
'minlen=i' => \$minlen, | |
'maxlen=i' => \$maxlen, | |
'file=s' => \$file, | |
'digits=i' => \$digits, | |
'symbols=i' => \$symbols, | |
'symlist=s' => \$symlist, | |
); | |
if ($help) { | |
print usage(); | |
return 0; | |
} | |
$digits //= 0; | |
$symbols //= 0; | |
$nwords //= 4; | |
$minlen //= 3; | |
$file //= '/usr/share/dict/words'; | |
$symlist //= '~!@#$%^&*()-_=+[]{};:<>/?'; | |
# read word file | |
open my $fh, '<', $file or confess "Couldn't open $file for reading: $!"; | |
my @words = <$fh>; | |
close $fh; | |
# assemble word list | |
chomp foreach @words; | |
@words = grep { length($_) >= $minlen } @words; | |
@words = grep { length($_) <= $maxlen } @words if $maxlen; | |
my $totalwords = scalar @words; | |
# get random words, digits, symbols | |
my @passwords; | |
my $digs = q(); | |
my $syms = q(); | |
@passwords = choose_n($nwords, @words); | |
$digs = join(q(), choose_n($digits, split(q(), '0123456789'))) if $digits; | |
$syms = join(q(), choose_n($symbols, split(q(), $symlist))) if $symbols; | |
my $entropy = $nwords * log2($totalwords) | |
+ $digits * log2(10) + $symbols * log2(length($symlist) || 1); | |
# output results | |
print "Total word list considered: $totalwords\n" if $verbose; | |
print sprintf("Approx Entropy: %.1f bits\n", $entropy) if $verbose; | |
print "Words: " . join(q(, ), @passwords) . "\n" if $verbose; | |
print "Digits: $digs\n" if ($verbose && $digits); | |
print "Symbols: $syms\n" if ($verbose && $symbols); | |
print "Password: " . join(q(), @passwords, $digs, $syms) . "\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment