Bugtraq mailing list archives

Re: Generating a true random number?


From: bet () std sbi com (Bennett Todd)
Date: Fri, 3 Jun 1994 16:30:18 -0400 (EDT)


Security applications have a different sense of ``random'' from the
statistical definitions that apply to pseudo-random number generators used
for (e.g.) Monte Carlo simulation.

In a security setting, the heart of the matter is unguessability. I've got a
script I use for generating passwords, and that sort of thing. It shoots for
unguessability. I append it after my .sig.

-Bennett
bet () sbi com

#!/usr/local/bin/perl
($progname=$0)=~s#.*/##;
$syntax="syntax: $progname [-n] [len [printable|all|hex|HEX]]\n";
require 'getopts.pl';
&Getopts('n') || die $syntax;

defined($max = shift)      || ($max = 8);
defined($alphabet = shift) || ($alphabet = 'printable');
($#ARGV == -1)             || die $syntax;

domain: {
        $_ = $alphabet;
        /^printable$/ && do { $chars = pack("C*", (32 .. 126)); last domain; };
        /^all$/ && do       { $chars = pack("C*", ( 0 .. 255)); last domain; };
        /^hex$/ && do       { $chars = "0123456789abcdef";      last domain; };
        /^HEX$/ && do       { $chars = "0123456789ABCDEF";      last domain; };
        die $syntax;
};

@chars = split('', $chars);

@randstring = split('', &randbits($max));

foreach $i (@randstring) {
        print $chars[ord($i) % $#chars];
}

print "\n" unless $opt_n;

exit 0;

sub randbits {
        local($nbytes) = @_;
        local(*_, $noise, $buf, $limit, $discard, $newlen);

        # Here's the big non-portability. This command works really well on
        # Sun workstations running SunOS; on other platforms, root around for
        # commands that report lots of detailed OS internals state, plus a
        # compressor or other program to smear the bits about.
        $noise = '(ps -agxlww;free;pstat -afipSsT)2>/dev/null|compress';

        # Run the noise command; in case it croaks, slap on whatever other state we
        # can conveniently (portably) find.
        $buf = `$noise` . $$ . getppid() . time . join('', %ENV);

        # Gotta have enough bits for at least one good fold.
        $limit = int(length($buf)/2);
        die "Insufficient random state; try less than $limit\n" if $nbytes > $limit;

        # Get Perl to treat ^ as bit-string op
        $discard = vec($buf, 0, 8);

        # Now fold the noise down by repeated xor, halving the buffer until it's but
        # little bigger than xauth(1) wants.
        while (length($buf) >= $nbytes*2) {
                $newlen = int((length($buf) + 1) / 2);
                $buf = (substr($buf, 0, $newlen) ^ substr($buf, $newlen, $newlen));
        }

        # Final fold may turn in some nulls, but fits it exactly to $nbytes without
        # discarding any bits.
        substr($buf, 0, $nbytes) ^ substr($buf, $nbytes, $nbytes);
}



Current thread: