Home | History | Annotate | Download | only in Lib
      1 """Generate cryptographically strong pseudo-random numbers suitable for
      2 managing secrets such as account authentication, tokens, and similar.
      3 
      4 See PEP 506 for more information.
      5 https://www.python.org/dev/peps/pep-0506/
      6 
      7 """
      8 
      9 __all__ = ['choice', 'randbelow', 'randbits', 'SystemRandom',
     10            'token_bytes', 'token_hex', 'token_urlsafe',
     11            'compare_digest',
     12            ]
     13 
     14 
     15 import base64
     16 import binascii
     17 import os
     18 
     19 from hmac import compare_digest
     20 from random import SystemRandom
     21 
     22 _sysrand = SystemRandom()
     23 
     24 randbits = _sysrand.getrandbits
     25 choice = _sysrand.choice
     26 
     27 def randbelow(exclusive_upper_bound):
     28     """Return a random int in the range [0, n)."""
     29     if exclusive_upper_bound <= 0:
     30         raise ValueError("Upper bound must be positive.")
     31     return _sysrand._randbelow(exclusive_upper_bound)
     32 
     33 DEFAULT_ENTROPY = 32  # number of bytes to return by default
     34 
     35 def token_bytes(nbytes=None):
     36     """Return a random byte string containing *nbytes* bytes.
     37 
     38     If *nbytes* is ``None`` or not supplied, a reasonable
     39     default is used.
     40 
     41     >>> token_bytes(16)  #doctest:+SKIP
     42     b'\\xebr\\x17D*t\\xae\\xd4\\xe3S\\xb6\\xe2\\xebP1\\x8b'
     43 
     44     """
     45     if nbytes is None:
     46         nbytes = DEFAULT_ENTROPY
     47     return os.urandom(nbytes)
     48 
     49 def token_hex(nbytes=None):
     50     """Return a random text string, in hexadecimal.
     51 
     52     The string has *nbytes* random bytes, each byte converted to two
     53     hex digits.  If *nbytes* is ``None`` or not supplied, a reasonable
     54     default is used.
     55 
     56     >>> token_hex(16)  #doctest:+SKIP
     57     'f9bf78b9a18ce6d46a0cd2b0b86df9da'
     58 
     59     """
     60     return binascii.hexlify(token_bytes(nbytes)).decode('ascii')
     61 
     62 def token_urlsafe(nbytes=None):
     63     """Return a random URL-safe text string, in Base64 encoding.
     64 
     65     The string has *nbytes* random bytes.  If *nbytes* is ``None``
     66     or not supplied, a reasonable default is used.
     67 
     68     >>> token_urlsafe(16)  #doctest:+SKIP
     69     'Drmhze6EPcv0fN_81Bj-nA'
     70 
     71     """
     72     tok = token_bytes(nbytes)
     73     return base64.urlsafe_b64encode(tok).rstrip(b'=').decode('ascii')
     74