In <http://marc.info/?l=openbsd-misc&m=148467025402122&w=1:,
Flipchan suggested creating a "random" password via
> I just grep some binary and encode it as passwords
Alas, this produces high-nonrandom (i.e., relatively easy-to-guess)
passwords. A much safer -- and easier -- approach is to take data
directly from /dev/arandom and encode it as alphanumerics:
% dd if=/dev/arandom bs=50 count=1|alphanumeric.encode
1+0 records in
1+0 records out
50 bytes transferred in 0.000 secs (602410 bytes/sec)
0WZr76geW6c6kipRUITDTNkpbGvmiS19ounWDqhCzBPIRDP6e6h7kiqx%
%
This makes use of the following script 'alphanumeric.encode', which
should be somewhere in $PATH:
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
my $false = 0;
my $true = 1;
########################################
my $help_msg = <<'EOF';
Usage:
dd if=/dev/arandom bs=100 count=1| alphanumeric.encode
or
dd if=/dev/arandom bs=100 count=1| alphanumeric.encode --lower-case
By default, this program encodes standard input binary-data into mixed-case
alphanumeric characgers ([a-zA-Z0-9]).
If the --lower-case option is specified, then this program encodes into
lower-case alphanumeric characters ([a-z0-9]).
EOF
#
# Bugs:
# The implementation might be cleaner if we used Math::Base36 and/or
# Math::Int2Base instead of hand-rolling our own base conversion.
#
#
# Mixed-case:
# Since 2*26+10 = 62, and 62**3 = 14776336 = less than 256**3 = 16777216,
# we can encode 3 chars (24 bits) of binary input into 4 base62 output
# characters. If we get an "unencodable" input 3-tuple we just discard
# it and try again with the next input 3-tuple.
#
# Lower-case
# Since 26+10 = 36, and 36**3 = 46656 = less than 256**2 = 65536,
# we can encode 2 chars (16 bits) of binary input into 3 base36 output
# characters. If we get an "unencodable" input 2-tuple we just discard
# it and try again with the next input 2-tuple.
#
########################################
my $debug = 0;
my $help_flag = $false;
my $lower_case_flag = $false;
GetOptions(
'debug=i' => \$debug,
'help' => \$help_flag,
'lower-case' => \$lower_case_flag,
) || die $help_msg; # *** ERROR EXIT ***
if ($help_flag)
{ print $help_msg; exit; } # *** --help EXIT ***
########################################
my $N_in = $lower_case_flag ? 2 : 3;
my $in_base = 256;
my $in_limit = $in_base ** $N_in;
my $N_out = $lower_case_flag ? 3 : 4;
my @out_alphabet = $lower_case_flag ? (0..9, 'a'..'z')
: (0..9, 'a'..'z', 'A'..'Z');
my $out_base = scalar(@out_alphabet);
my $out_limit = $out_base ** $N_out;
if ($debug > 0)
{
print "in_base=${in_base} N_in=${N_in} ==> in_limit = ${in_limit}\n";
print "out_base=${out_base} N_out=${N_out} ==> out_limit =
${out_limit}\n";
}
binmode(STDIN);
my $count_on_line = 0;
my $buffer;
while (my $N_read = read(STDIN, $buffer, $N_in))
{
if ($N_read != $N_in)
{ last; } # *** LOOP EXIT ***
my @in_chars = split(//, $buffer);
my @in_digits = map {ord($_)} @in_chars;
# integer in [0, $in_limit)
my $N = $lower_case_flag
? $in_digits[0] + $in_base*$in_digits[1]
: $in_digits[0] + $in_base
*($in_digits[1] + $in_base*$in_digits[2]);
if ($debug >= 6)
{ print "in_digits=(",join(',',@in_digits),") ==> N=${N}\n"; }
if ($N >= $out_limit)
{
if ($debug >= 6)
{ print " N > out_limit ==> try again\n"; }
next; # *** LOOP CONTROL ***
}
my @out_digits = ();
for (my $i = 0 ; $i < $N_out ; ++$i)
{
my $d = $N % $out_base;
$N = int($N / $out_base);
push @out_digits, $d;
}
if ($debug >= 6)
{ print " out_digits=(",join(',',@out_digits),")\n"; }
my @out_chars = map {$out_alphabet[$_]} @out_digits;
$count_on_line += $N_out;
if ($debug >= 6)
{ print ' :',join('',@out_chars),":\n"; }
else { print join('',@out_chars); }
if ($count_on_line >= 60)
{
print "\n";
$count_on_line = 0;
}
}