[Cryptography] Throwing dice for "random" numbers
Jonathan Thornburg
jthorn4242 at gmail.com
Wed Aug 15 00:32:51 EDT 2018
On Tue, Aug 14, 2018 at 11:33:51PM -0400, Arnold Reinhold via cryptography wrote:
> For random characters from the set {a-z, 0-9}, one can make a six
> by six table with the 36 possible characters and use pairs fo dice
> rolls to select each character. For just letters, one can just
> discard pairs of rolls that produce digits from that table. To
> include upper and lower case letters and some special characters
> (the ten above the digits on standard keyboards), one can use a
> third die and press the shift key if the roll is odd. In the last
> example there are 72 possible characters, giving 6.17 bits of entropy
> per character, compared to 6.57 bits per character selected randomly
> from the 95 printing ASCII characters.
If one has (and is willing to trust) a computer, random alphanumeric
passwords can be generated by
% dd if=/dev/random bs=50 count=1|alphanumeric.encode
where the following script should be somewhere in your search 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
#
# At present we do the encoding "by hand".
# FIXME: It would probably be better to not reinvent the wheel here,
# and instead use an existing Perl module such as Math::Int2Base
# or Math::Base::Convert.
#
# Mixed-case:
# Since 2*26+10 = 62, and 62**4 = 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(',', at 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(',', at out_digits),")\n"; }
my @out_chars = map {$out_alphabet[$_]} @out_digits;
$count_on_line += $N_out;
if ($debug >= 6)
{ print ' :',join('', at out_chars),":\n"; }
else { print join('', at out_chars); }
if ($count_on_line >= 60)
{
print "\n";
$count_on_line = 0;
}
}
More information about the cryptography
mailing list