17db96d56Sopenharmony_ci"""Generate cryptographically strong pseudo-random numbers suitable for
27db96d56Sopenharmony_cimanaging secrets such as account authentication, tokens, and similar.
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ciSee PEP 506 for more information.
57db96d56Sopenharmony_cihttps://peps.python.org/pep-0506/
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci"""
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci__all__ = ['choice', 'randbelow', 'randbits', 'SystemRandom',
107db96d56Sopenharmony_ci           'token_bytes', 'token_hex', 'token_urlsafe',
117db96d56Sopenharmony_ci           'compare_digest',
127db96d56Sopenharmony_ci           ]
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ciimport base64
167db96d56Sopenharmony_ciimport binascii
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_cifrom hmac import compare_digest
197db96d56Sopenharmony_cifrom random import SystemRandom
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci_sysrand = SystemRandom()
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_cirandbits = _sysrand.getrandbits
247db96d56Sopenharmony_cichoice = _sysrand.choice
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_cidef randbelow(exclusive_upper_bound):
277db96d56Sopenharmony_ci    """Return a random int in the range [0, n)."""
287db96d56Sopenharmony_ci    if exclusive_upper_bound <= 0:
297db96d56Sopenharmony_ci        raise ValueError("Upper bound must be positive.")
307db96d56Sopenharmony_ci    return _sysrand._randbelow(exclusive_upper_bound)
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ciDEFAULT_ENTROPY = 32  # number of bytes to return by default
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_cidef token_bytes(nbytes=None):
357db96d56Sopenharmony_ci    """Return a random byte string containing *nbytes* bytes.
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci    If *nbytes* is ``None`` or not supplied, a reasonable
387db96d56Sopenharmony_ci    default is used.
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ci    >>> token_bytes(16)  #doctest:+SKIP
417db96d56Sopenharmony_ci    b'\\xebr\\x17D*t\\xae\\xd4\\xe3S\\xb6\\xe2\\xebP1\\x8b'
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci    """
447db96d56Sopenharmony_ci    if nbytes is None:
457db96d56Sopenharmony_ci        nbytes = DEFAULT_ENTROPY
467db96d56Sopenharmony_ci    return _sysrand.randbytes(nbytes)
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_cidef token_hex(nbytes=None):
497db96d56Sopenharmony_ci    """Return a random text string, in hexadecimal.
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci    The string has *nbytes* random bytes, each byte converted to two
527db96d56Sopenharmony_ci    hex digits.  If *nbytes* is ``None`` or not supplied, a reasonable
537db96d56Sopenharmony_ci    default is used.
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    >>> token_hex(16)  #doctest:+SKIP
567db96d56Sopenharmony_ci    'f9bf78b9a18ce6d46a0cd2b0b86df9da'
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci    """
597db96d56Sopenharmony_ci    return binascii.hexlify(token_bytes(nbytes)).decode('ascii')
607db96d56Sopenharmony_ci
617db96d56Sopenharmony_cidef token_urlsafe(nbytes=None):
627db96d56Sopenharmony_ci    """Return a random URL-safe text string, in Base64 encoding.
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci    The string has *nbytes* random bytes.  If *nbytes* is ``None``
657db96d56Sopenharmony_ci    or not supplied, a reasonable default is used.
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci    >>> token_urlsafe(16)  #doctest:+SKIP
687db96d56Sopenharmony_ci    'Drmhze6EPcv0fN_81Bj-nA'
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci    """
717db96d56Sopenharmony_ci    tok = token_bytes(nbytes)
727db96d56Sopenharmony_ci    return base64.urlsafe_b64encode(tok).rstrip(b'=').decode('ascii')
73