| # | |
| # Random/OSRNG/rng_base.py : Base class for OSRNG | |
| # | |
| # Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net> | |
| # | |
| # =================================================================== | |
| # The contents of this file are dedicated to the public domain. To | |
| # the extent that dedication to the public domain is not available, | |
| # everyone is granted a worldwide, perpetual, royalty-free, | |
| # non-exclusive license to exercise all rights associated with the | |
| # contents of this file for any purpose whatsoever. | |
| # No rights are reserved. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| # SOFTWARE. | |
| # =================================================================== | |
| __revision__ = "$Id$" | |
| import sys | |
| if sys.version_info[0] == 2 and sys.version_info[1] == 1: | |
| from Crypto.Util.py21compat import * | |
| class BaseRNG(object): | |
| def __init__(self): | |
| self.closed = False | |
| self._selftest() | |
| def __del__(self): | |
| self.close() | |
| def _selftest(self): | |
| # Test that urandom can return data | |
| data = self.read(16) | |
| if len(data) != 16: | |
| raise AssertionError("read truncated") | |
| # Test that we get different data every time (if we don't, the RNG is | |
| # probably malfunctioning) | |
| data2 = self.read(16) | |
| if data == data2: | |
| raise AssertionError("OS RNG returned duplicate data") | |
| # PEP 343: Support for the "with" statement | |
| def __enter__(self): | |
| pass | |
| def __exit__(self): | |
| """PEP 343 support""" | |
| self.close() | |
| def close(self): | |
| if not self.closed: | |
| self._close() | |
| self.closed = True | |
| def flush(self): | |
| pass | |
| def read(self, N=-1): | |
| """Return N bytes from the RNG.""" | |
| if self.closed: | |
| raise ValueError("I/O operation on closed file") | |
| if not isinstance(N, int): | |
| raise TypeError("an integer is required") | |
| if N < 0: | |
| raise ValueError("cannot read to end of infinite stream") | |
| elif N == 0: | |
| return "" | |
| data = self._read(N) | |
| if len(data) != N: | |
| raise AssertionError("%s produced truncated output (requested %d, got %d)" % (self.name, N, len(data))) | |
| return data | |
| def _close(self): | |
| raise NotImplementedError("child class must implement this") | |
| def _read(self, N): | |
| raise NotImplementedError("child class must implement this") | |
| # vim:set ts=4 sw=4 sts=4 expandtab: | |