diff --git a/test_onetimepad.py b/itest_onetimepad.py similarity index 93% rename from test_onetimepad.py rename to itest_onetimepad.py index f88e0a4..0c45e53 100644 --- a/test_onetimepad.py +++ b/itest_onetimepad.py @@ -23,6 +23,17 @@ class TestOneTimePad(unittest.TestCase): '{1}, actual={2}'.format(self._padsize, width, actual)) + def test_get_randint_on_nonexistent_randomness_file_fails_ioerror(self): + OT._DEV_RANDOM['fp'] = None + self.assertRaises(IOError, OT._get_randint, + randomness_file='/foo/bar/busted/borken', + fallback_to_fake=False) + + def test_get_randint_on_nonexistent_randomness_file_uses_fake(self): + OT._DEV_RANDOM['fp'] = None + random_int = OT._get_randint(randomness_file='/broke/as/joke') + self.assertTrue(random_int in range(0, 255)) + def test_is_padline(self): for lineno in PADLINES: self.assertTrue(OT._is_padline(lineno), diff --git a/onetimepad.py b/onetimepad.py index 8e392b6..92febdf 100644 --- a/onetimepad.py +++ b/onetimepad.py @@ -1,4 +1,3 @@ -import random from itertools import izip PAD_MODULO = 3 @@ -46,7 +45,7 @@ def create_pad_lines(length, width=DEFAULT_PAD_WIDTH): def _create_chars_for_pad(length): chars = [] for char in range(length): - chars.append(_AS_ALPHA[random.randint(CIPHER_FLOOR, CIPHER_CEIL)]) + chars.append(_AS_ALPHA[_get_randint()]) return ''.join(chars) @@ -155,6 +154,34 @@ def _is_cipherline(lineno): return not lineno % PAD_MODULO +def _get_randint(randomness_file='/dev/urandom', fallback_to_fake=True): + if not _DEV_RANDOM.get('fp'): + _get_urandom_fp(randomness_file=randomness_file, + fallback_to_fake=fallback_to_fake) + ret = ord(_DEV_RANDOM['fp'].read(1)) % CIPHER_CEIL + return ret if ret != 0 else _get_randint() + + +class _FakeDevUrandom(object): + + def read(self, nchars): + import random + return ''.join([chr(random.randint(0, 255)) for i in range(0, nchars)]) + + +def _get_urandom_fp(randomness_file='/dev/urandom', fallback_to_fake=True): + try: + _DEV_RANDOM['fp'] = open(randomness_file) + except (OSError, IOError): + if fallback_to_fake: + _DEV_RANDOM['fp'] = _FakeDevUrandom() + else: + raise + + +_DEV_RANDOM = {} + + def _mk_as_alpha_as_nums(): as_alpha = {} as_nums = {}