#! /usr/bin/perl -w use strict; our $cgi = exists $ENV{GATEWAY_INTERFACE}; %ENV = (PATH => "/bin:/usr/bin"); our $element = "pw000"; # TODO: taint? # TODO: mlock possible in perl? sub getrand ($) { my ($bytes) = @_; my $randomfile = '/dev/urandom'; # TODO: warn on /proc/sys/kernel/random/entropy_avail our $randomhandle; if (!$randomhandle) { die unless open $randomhandle, '<', $randomfile; } die if $bytes != sysread $randomhandle, my $data='', $bytes; return $data; } sub product (@) { my (@term) = @_; use bigint; my $product = 1; for my $term (@term) { $product *= $term; } return $product; } sub poolary (\$@) { my ($poolref, @size) = @_; my @value; # TODO: % with non power of two gives slight bias for low values # read extra entropy for now to mitigate use bigint; my $required = product @size; my $entropy = 2**(8*length$$poolref); $required = ($required->blog(2)-$entropy->blog(2)+16)/8|0; $$poolref .= getrand $required if $required > 0; my $pool = 0; $pool = $pool * 256 + ord$_ for split //, $$poolref; for my $size (@size) { my $rand; push @value, $pool % $size; $pool /= $size; } return @value; } sub poolstr (\$$$) { my ($poolref, $char, $bits) = @_; use POSIX; my $len = ceil $bits * log(2)/log(length$char); return join '', map {substr $char, $_, 1} poolary $$poolref, (length$char) x $len; } sub poolphr (\$\@$) { my ($poolref, $word, $bits) = @_; use POSIX; my $len = ceil $bits * log(2)/log(scalar @$word); return join ' ', map {$word->[$_]} poolary $$poolref, (scalar @$word) x $len; } our $passpool = ''; our $saltpool = ''; our %set = ( b95 => q~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ . '~', #" b94 => q~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ . '~', #" wide => '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~' . q~!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~, #" b85 => q~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu~, #" inv => q# !"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz#, salt => './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', b64 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', b64f => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', b64u => q~`!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_~, #` b64x => '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', b62 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', safe => 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789', b32 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', b32h => '0123456789ABCDEFGHIJKLMNOPQRSTUV', b32c => '0123456789ABCDEFGHJKMNPQRSTVWXYZ', b32g => '0123456789bcdfghjklmnpqrstvwxyz-', uc => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', lc => 'abcdefghijklmnopqrstuvwxyz', HEX => '0123456789ABCDEF', hex => '0123456789abcdef', dec => '0123456789', oct => '01234567', ); for (split "\n\n", join "", ) { my $ref = [split /\s+/]; $set{"w".scalar@$ref} = $ref; } die unless exists $set{w10513} && exists $set{w23276}; sub autocrypt ($) { my ($pass) = @_; my $salt = poolstr $saltpool, $set{salt}, 96; my @crypt; my $crypt; $crypt = crypt $pass, substr($salt, 0, 2); push @crypt, [unix => $crypt] unless length $pass > 8; $crypt = crypt $pass, '$1$' . substr($salt, 0, 8) . '$'; push @crypt, [linux => $crypt] if $crypt =~ /^\$.\$.*\$/; $crypt = crypt $pass, '$5$' . substr($salt, 0, 16) . '$'; push @crypt, [f8_32 => $crypt] if $crypt =~ /^\$.\$.*\$/; $crypt = crypt $pass, '$6$' . substr($salt, 0, 16) . '$'; push @crypt, [f8_64 => $crypt] if $crypt =~ /^\$.\$.*\$/; return ($pass, @crypt); } print q{Content-type: text/html; charset=UTF-8 password and passphrase generator

password and passphrase generator

All the passwords on this page use the same entropy. If you need more than one password then you must reload.

} if $cgi; sub output ($@) { my ($text, $pass, @crypt) = @_; if ($cgi) { $pass =~ s|<|<|g; printf qq{

%s\n

%s\n
crypt

\n"; } else { printf "\n"; } } poolary $saltpool, (256) x 14; poolary $passpool, (256) x 18; # 24; @ARGV = (48,80,128) unless @ARGV; my $DEFAULT = $ARGV[0]; if ($cgi) { print qq{

Select strength: }; my $first = 0; for my $select (@ARGV) { printf qq{%s$select\n}; } print qq{ bit.

\n}; } for my $bits (@ARGV) { printf qq{
}, $bits == $DEFAULT ? '' : 'hidden' if $cgi; output qq{Password with safe characters:}, autocrypt poolstr $passpool, $set{safe}, $bits; output qq{Passphrase:}, autocrypt poolphr $passpool, @{$set{w10513}}, $bits; output qq{Password with special characters:}, autocrypt poolstr $passpool, $set{wide}, $bits; print qq{
} if $cgi; print "\n"; } print qq{

Linux users can download this script and execute it locally for better confidentiality.

software and systems