RAHHH
This commit is contained in:
128
backend/lib/python3.12/site-packages/twisted/python/randbytes.py
Normal file
128
backend/lib/python3.12/site-packages/twisted/python/randbytes.py
Normal file
@@ -0,0 +1,128 @@
|
||||
# -*- test-case-name: twisted.test.test_randbytes -*-
|
||||
# Copyright (c) Twisted Matrix Laboratories.
|
||||
# See LICENSE for details.
|
||||
|
||||
"""
|
||||
Cryptographically secure random implementation, with fallback on normal random.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import random
|
||||
import warnings
|
||||
|
||||
getrandbits = getattr(random, "getrandbits", None)
|
||||
|
||||
_fromhex = bytes.fromhex
|
||||
|
||||
|
||||
class SecureRandomNotAvailable(RuntimeError):
|
||||
"""
|
||||
Exception raised when no secure random algorithm is found.
|
||||
"""
|
||||
|
||||
|
||||
class SourceNotAvailable(RuntimeError):
|
||||
"""
|
||||
Internal exception used when a specific random source is not available.
|
||||
"""
|
||||
|
||||
|
||||
class RandomFactory:
|
||||
"""
|
||||
Factory providing L{secureRandom} and L{insecureRandom} methods.
|
||||
|
||||
You shouldn't have to instantiate this class, use the module level
|
||||
functions instead: it is an implementation detail and could be removed or
|
||||
changed arbitrarily.
|
||||
"""
|
||||
|
||||
# This variable is no longer used, and will eventually be removed.
|
||||
randomSources = ()
|
||||
|
||||
getrandbits = getrandbits
|
||||
|
||||
def _osUrandom(self, nbytes: int) -> bytes:
|
||||
"""
|
||||
Wrapper around C{os.urandom} that cleanly manage its absence.
|
||||
"""
|
||||
try:
|
||||
return os.urandom(nbytes)
|
||||
except (AttributeError, NotImplementedError) as e:
|
||||
raise SourceNotAvailable(e)
|
||||
|
||||
def secureRandom(self, nbytes: int, fallback: bool = False) -> bytes:
|
||||
"""
|
||||
Return a number of secure random bytes.
|
||||
|
||||
@param nbytes: number of bytes to generate.
|
||||
@type nbytes: C{int}
|
||||
@param fallback: Whether the function should fallback on non-secure
|
||||
random or not. Default to C{False}.
|
||||
@type fallback: C{bool}
|
||||
|
||||
@return: a string of random bytes.
|
||||
@rtype: C{str}
|
||||
"""
|
||||
try:
|
||||
return self._osUrandom(nbytes)
|
||||
except SourceNotAvailable:
|
||||
pass
|
||||
|
||||
if fallback:
|
||||
warnings.warn(
|
||||
"urandom unavailable - "
|
||||
"proceeding with non-cryptographically secure random source",
|
||||
category=RuntimeWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.insecureRandom(nbytes)
|
||||
else:
|
||||
raise SecureRandomNotAvailable("No secure random source available")
|
||||
|
||||
def _randBits(self, nbytes: int) -> bytes:
|
||||
"""
|
||||
Wrapper around C{os.getrandbits}.
|
||||
"""
|
||||
if self.getrandbits is not None:
|
||||
n = self.getrandbits(nbytes * 8)
|
||||
hexBytes = ("%%0%dx" % (nbytes * 2)) % n
|
||||
return _fromhex(hexBytes)
|
||||
raise SourceNotAvailable("random.getrandbits is not available")
|
||||
|
||||
_maketrans = bytes.maketrans
|
||||
_BYTES = _maketrans(b"", b"")
|
||||
|
||||
def _randModule(self, nbytes: int) -> bytes:
|
||||
"""
|
||||
Wrapper around the C{random} module.
|
||||
"""
|
||||
return b"".join([bytes([random.choice(self._BYTES)]) for i in range(nbytes)])
|
||||
|
||||
def insecureRandom(self, nbytes: int) -> bytes:
|
||||
"""
|
||||
Return a number of non secure random bytes.
|
||||
|
||||
@param nbytes: number of bytes to generate.
|
||||
@type nbytes: C{int}
|
||||
|
||||
@return: a string of random bytes.
|
||||
@rtype: C{str}
|
||||
"""
|
||||
try:
|
||||
return self._randBits(nbytes)
|
||||
except SourceNotAvailable:
|
||||
pass
|
||||
return self._randModule(nbytes)
|
||||
|
||||
|
||||
factory = RandomFactory()
|
||||
|
||||
secureRandom = factory.secureRandom
|
||||
|
||||
insecureRandom = factory.insecureRandom
|
||||
|
||||
del factory
|
||||
|
||||
|
||||
__all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"]
|
||||
Reference in New Issue
Block a user