Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / python / randbytes.py
1 # -*- test-case-name: twisted.test.test_randbytes -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Cryptographically secure random implementation, with fallback on normal random.
7 """
8
9 # System imports
10 import warnings, os, random
11
12 getrandbits = getattr(random, 'getrandbits', None)
13
14
15 class SecureRandomNotAvailable(RuntimeError):
16     """
17     Exception raised when no secure random algorithm is found.
18     """
19
20
21
22 class SourceNotAvailable(RuntimeError):
23     """
24     Internal exception used when a specific random source is not available.
25     """
26
27
28
29 class RandomFactory(object):
30     """
31     Factory providing L{secureRandom} and L{insecureRandom} methods.
32
33     You shouldn't have to instantiate this class, use the module level
34     functions instead: it is an implementation detail and could be removed or
35     changed arbitrarily.
36     """
37
38     # This variable is no longer used, and will eventually be removed.
39     randomSources = ()
40
41     getrandbits = getrandbits
42
43
44     def _osUrandom(self, nbytes):
45         """
46         Wrapper around C{os.urandom} that cleanly manage its absence.
47         """
48         try:
49             return os.urandom(nbytes)
50         except (AttributeError, NotImplementedError), e:
51             raise SourceNotAvailable(e)
52
53
54     def secureRandom(self, nbytes, fallback=False):
55         """
56         Return a number of secure random bytes.
57
58         @param nbytes: number of bytes to generate.
59         @type nbytes: C{int}
60         @param fallback: Whether the function should fallback on non-secure
61             random or not.  Default to C{False}.
62         @type fallback: C{bool}
63
64         @return: a string of random bytes.
65         @rtype: C{str}
66         """
67         try:
68             return self._osUrandom(nbytes)
69         except SourceNotAvailable:
70             pass
71
72         if fallback:
73             warnings.warn(
74                 "urandom unavailable - "
75                 "proceeding with non-cryptographically secure random source",
76                 category=RuntimeWarning,
77                 stacklevel=2)
78             return self.insecureRandom(nbytes)
79         else:
80             raise SecureRandomNotAvailable("No secure random source available")
81
82
83     def _randBits(self, nbytes):
84         """
85         Wrapper around C{os.getrandbits}.
86         """
87         if self.getrandbits is not None:
88             n = self.getrandbits(nbytes * 8)
89             hexBytes = ("%%0%dx" % (nbytes * 2)) % n
90             return hexBytes.decode('hex')
91         raise SourceNotAvailable("random.getrandbits is not available")
92
93
94     def _randRange(self, nbytes):
95         """
96         Wrapper around C{random.randrange}.
97         """
98         bytes = ""
99         for i in xrange(nbytes):
100             bytes += chr(random.randrange(0, 255))
101         return bytes
102
103
104     def insecureRandom(self, nbytes):
105         """
106         Return a number of non secure random bytes.
107
108         @param nbytes: number of bytes to generate.
109         @type nbytes: C{int}
110
111         @return: a string of random bytes.
112         @rtype: C{str}
113         """
114         for src in ("_randBits", "_randRange"):
115             try:
116                 return getattr(self, src)(nbytes)
117             except SourceNotAvailable:
118                 pass
119
120
121
122 factory = RandomFactory()
123
124 secureRandom = factory.secureRandom
125
126 insecureRandom = factory.insecureRandom
127
128 del factory
129
130
131 __all__ = ["secureRandom", "insecureRandom", "SecureRandomNotAvailable"]