summaryrefslogtreecommitdiffstats
path: root/Lib/secrets.py
blob: e4e9714ac038a1806f2f10c51f79b34f27e325ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"""Generate cryptographically strong pseudo-random numbers suitable for
managing secrets such as account authentication, tokens, and similar.
See PEP 506 for more information.

https://www.python.org/dev/peps/pep-0506/


Random numbers
==============

The ``secrets`` module provides the following pseudo-random functions, based
on SystemRandom, which in turn uses the most secure source of randomness your
operating system provides.


    choice(sequence)
        Choose a random element from a non-empty sequence.

    randbelow(n)
        Return a random int in the range [0, n).

    randbits(k)
        Generates an int with k random bits.

    SystemRandom
        Class for generating random numbers using sources provided by
        the operating system. See the ``random`` module for documentation.


Token functions
===============

The ``secrets`` module provides a number of functions for generating secure
tokens, suitable for applications such as password resets, hard-to-guess
URLs, and similar. All the ``token_*`` functions take an optional single
argument specifying the number of bytes of randomness to use. If that is
not given, or is ``None``, a reasonable default is used. That default is
subject to change at any time, including during maintenance releases.


    token_bytes(nbytes=None)
        Return a random byte-string containing ``nbytes`` number of bytes.

        >>> secrets.token_bytes(16)  #doctest:+SKIP
        b'\\xebr\\x17D*t\\xae\\xd4\\xe3S\\xb6\\xe2\\xebP1\\x8b'


    token_hex(nbytes=None)
        Return a random text-string, in hexadecimal. The string has ``nbytes``
        random bytes, each byte converted to two hex digits.

        >>> secrets.token_hex(16)  #doctest:+SKIP
        'f9bf78b9a18ce6d46a0cd2b0b86df9da'

    token_urlsafe(nbytes=None)
        Return a random URL-safe text-string, containing ``nbytes`` random
        bytes. On average, each byte results in approximately 1.3 characters
        in the final result.

        >>> secrets.token_urlsafe(16)  #doctest:+SKIP
        'Drmhze6EPcv0fN_81Bj-nA'


(The examples above assume Python 3. In Python 2, byte-strings will display
using regular quotes ``''`` with no prefix, and text-strings will have a
``u`` prefix.)


Other functions
===============

    compare_digest(a, b)
        Return True if strings a and b are equal, otherwise False.
        Performs the equality comparison in such a way as to reduce the
        risk of timing attacks.

        See http://codahale.com/a-lesson-in-timing-attacks/ for a
        discussion on how timing attacks against ``==`` can reveal
        secrets from your application.


"""

__all__ = ['choice', 'randbelow', 'randbits', 'SystemRandom',
           'token_bytes', 'token_hex', 'token_urlsafe',
           'compare_digest',
           ]


import base64
import binascii
import os

from hmac import compare_digest
from random import SystemRandom

_sysrand = SystemRandom()

randbits = _sysrand.getrandbits
choice = _sysrand.choice

def randbelow(exclusive_upper_bound):
    return _sysrand._randbelow(exclusive_upper_bound)

DEFAULT_ENTROPY = 32  # number of bytes to return by default

def token_bytes(nbytes=None):
    if nbytes is None:
        nbytes = DEFAULT_ENTROPY
    return os.urandom(nbytes)

def token_hex(nbytes=None):
    return binascii.hexlify(token_bytes(nbytes)).decode('ascii')

def token_urlsafe(nbytes=None):
    tok = token_bytes(nbytes)
    return base64.urlsafe_b64encode(tok).rstrip(b'=').decode('ascii')