bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-bash] $RANDOM not Cryptographically secure pseudorandom number


From: Quentin
Subject: Re: [bug-bash] $RANDOM not Cryptographically secure pseudorandom number generator
Date: Tue, 22 Jan 2019 00:13:23 +0000
User-agent: K-9 Mail for Android


On January 20, 2019 2:39:45 PM UTC, Martijn Dekker <martijn@inlv.org> wrote:
>filename_suffix() {
>   chars=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
>    length=${#chars}
>    for ((i=0; i<10; i++)) do
>        printf '%s' "${chars:$(( SECURE_RANDOM % length + 1 )):1}"
>    done
>}

The character distribution here will be biased, because ${#chars} is not a 
power-of-2.

TL;DR: discard out-of-range values instead of wrapping them with %:

  filename_suffix() {
    chars=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
    pow2length=64
    result=
    while (( ${#result} < 10 )); do
      result+="${chars:$(( SECURE_RANDOM % pow2length )):1}"
    done
    printf '%s' "$result"
  }

$pow2length is the next greater-or-equal power-of-2 starting from ${#chars}. It 
is fixed here for brevity, since the array is fixed as well, but could be 
computed.
If the value of $(( SECURE_RANDOM % pow2length )) is greater than the length of 
$chars, no character is added. This means that the loop may iterate more than 
10 times to yield 10 characters.

To elaborate on why % doesn't work, consider this: $RNG generates 3-bits random 
values, so in the range 0-7, and I want integers in the range 0-4. If I naively 
use %, I get this distribution:

  $RNG -> $RNG % 5
  0 -> 0
  1 -> 1
  2 -> 2
  3 -> 3
  4 -> 4
  5 -> 0
  6 -> 1
  7 -> 2

Clearly I'm less likely to get 3s and 4s. The same logic applies to your use of 
% with ${#chars}.

If external tools are not an issue and somewhat wasted resources do not itch 
you, for this purpose of generating random strings, dd+tr usually nails it 
(brevity-wise at least):

  dd if=/dev/urandom bs=1024 count=1 status=none | tr -d -c A-Za-z0-9

Then truncate to whatever length you need, or repeat if more characters are 
needed.

Cheers,
Quentin



reply via email to

[Prev in Thread] Current Thread [Next in Thread]