Skip to content

Commit

Permalink
lint: Do not use protected methods from random
Browse files Browse the repository at this point in the history
Secrets was calling protected methods from `class Random`.
Random is already in a protected namespace so that we can
change the access specification of its most useful
methods to public.
  • Loading branch information
Synss committed May 24, 2020
1 parent 0b6b612 commit 82d454d
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 34 deletions.
36 changes: 19 additions & 17 deletions src/mbedtls/_random.pyx
Expand Up @@ -79,7 +79,16 @@ cdef class Random:
def _entropy(self):
return self._entropy

def _urandom(self, size_t length):
def _reseed(self, const unsigned char[:] data=None):
"""Reseed the RNG."""
if data is None:
check_error(_rnd.mbedtls_ctr_drbg_reseed(&self._ctx, NULL, 0))
else:
check_error(
_rnd.mbedtls_ctr_drbg_reseed(&self._ctx, &data[0], data.size)
)

def urandom(self, size_t length):
"""Returns `length` random bytes."""
cdef unsigned char *output = <unsigned char *> malloc(
length * sizeof(unsigned char)
Expand All @@ -96,32 +105,25 @@ cdef class Random:
finally:
free(output)

def _reseed(self, const unsigned char[:] data=None):
"""Reseed the RNG."""
if data is None:
check_error(_rnd.mbedtls_ctr_drbg_reseed(&self._ctx, NULL, 0))
else:
check_error(
_rnd.mbedtls_ctr_drbg_reseed(&self._ctx, &data[0], data.size)
)

def _randbelow(self, n):
def randbelow(self, upper_bound):
"""Return a random int in the range [0, n).
Raises ValueError if n==0.
Raises ValueError if n <= 0.
"""
kk = n.bit_length()
if upper_bound <= 0:
raise ValueError("Upper bound must be positive.")
kk = upper_bound.bit_length()
rr = self.getrandbits(kk)
while rr >= n:
while rr >= upper_bound:
rr = self.getrandbits(kk)
return rr

def random(self):
"""Return the next random floating point number."""
# Algorithm taken from Python's secrets and random libraries.
return float(
_mpi.MPI.from_bytes(self._urandom(7), "big") >> 3
_mpi.MPI.from_bytes(self.urandom(7), "big") >> 3
) * RECIP_BPF

def getrandbits(self, k):
Expand All @@ -132,15 +134,15 @@ cdef class Random:
if not isinstance(k, _numbers.Integral):
raise TypeError("number of bits should be an integer")
numbytes = (k + 7) // 8
value = _mpi.MPI.from_bytes(self._urandom(numbytes), "big")
value = _mpi.MPI.from_bytes(self.urandom(numbytes), "big")
# Trim excess bits:
extra_bits = value.bit_length() - k
return value >> (0 if extra_bits <= 0 else extra_bits)

def choice(self, seq):
"""Return a random element from `seq`."""
try:
ii = self._randbelow(len(seq))
ii = self.randbelow(len(seq))
except ValueError:
raise IndexError("Cannot choose from an empty sequence")
return seq[ii]
Expand Down
10 changes: 2 additions & 8 deletions src/mbedtls/secrets.py
Expand Up @@ -33,13 +33,7 @@

randbits = __rng.getrandbits
choice = __rng.choice


def randbelow(upper_bound):
"""Return a random int in the range [0, n)."""
if upper_bound <= 0:
raise ValueError("Upper bound must be positive.")
return __rng._randbelow(upper_bound)
randbelow = __rng.randbelow


def token_bytes(nbytes=None):
Expand All @@ -50,7 +44,7 @@ def token_bytes(nbytes=None):
"""
if nbytes is None:
nbytes = DEFAULT_ENTROPY
return __rng._urandom(nbytes)
return __rng.urandom(nbytes)


def token_hex(nbytes=None):
Expand Down
9 changes: 0 additions & 9 deletions tests/test_random.py
Expand Up @@ -57,15 +57,6 @@ def random(self):
def test_reseed(self, random):
random._reseed()

@pytest.mark.repeat(10)
@pytest.mark.parametrize("max", range(1, 300))
def test_randbelow(self, random, max):
assert 0 <= random._randbelow(max) < max

def test_randbelow_zero_raises_valueerror(self, random):
with pytest.raises(ValueError):
random._randbelow(0)

@pytest.mark.repeat(100)
def test_random(self, random):
value = random.random()
Expand Down
6 changes: 6 additions & 0 deletions tests/test_secrets.py
Expand Up @@ -50,6 +50,12 @@ def test_randbits():
assert 0 <= secrets.randbits(32) < (1 << 32)


@pytest.mark.parametrize("upper_bound", [0, -1])
def test_randbelow_zero_raises_valueerror(upper_bound):
with pytest.raises(ValueError):
secrets.randbelow(upper_bound)


@pytest.mark.repeat(100)
@pytest.mark.parametrize("upper_bound", [1, 1 << 32, 1 << 128, 1 << 1024])
def test_randbelow(upper_bound):
Expand Down

0 comments on commit 82d454d

Please sign in to comment.