Skip to content

Instantly share code, notes, and snippets.

@mprentice
Created September 28, 2013 15:22
Show Gist options
  • Save mprentice/6743089 to your computer and use it in GitHub Desktop.
Save mprentice/6743089 to your computer and use it in GitHub Desktop.
#!/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