diff options
-rw-r--r-- | lib/Crypto/Random/OSRNG/posix.py | 27 | ||||
-rw-r--r-- | lib/Crypto/SelfTest/Util/test_number.py | 12 | ||||
-rw-r--r-- | src/_fastmath.c | 35 |
3 files changed, 62 insertions, 12 deletions
diff --git a/lib/Crypto/Random/OSRNG/posix.py b/lib/Crypto/Random/OSRNG/posix.py index f88cd77..ca6ac05 100644 --- a/lib/Crypto/Random/OSRNG/posix.py +++ b/lib/Crypto/Random/OSRNG/posix.py @@ -25,10 +25,12 @@ __revision__ = "$Id$" __all__ = ['DevURandomRNG'] +import errno import os import stat from rng_base import BaseRNG +from Crypto.Util.py3compat import b class DevURandomRNG(BaseRNG): @@ -46,7 +48,6 @@ class DevURandomRNG(BaseRNG): raise TypeError("%r is not a character special device" % (self.name,)) self.__file = f - self._read = f.read BaseRNG.__init__(self) @@ -54,7 +55,29 @@ class DevURandomRNG(BaseRNG): self.__file.close() def _read(self, N): - return self.__file.read(N) + # Starting with Python 3 open with buffering=0 returns a FileIO object. + # FileIO.read behaves like read(2) and not like fread(3) and thus we + # have to handle the case that read returns less data as requested here + # more carefully. + data = b("") + while len(data) < N: + try: + d = self.__file.read(N - len(data)) + except IOError, e: + # read(2) has been interrupted by a signal; redo the read + if e.errno == errno.EINTR: + continue + raise + + if d is None: + # __file is in non-blocking mode and no data is available + return data + if len(d) == 0: + # __file is in blocking mode and arrived at EOF + return data + + data += d + return data def new(*args, **kwargs): return DevURandomRNG(*args, **kwargs) diff --git a/lib/Crypto/SelfTest/Util/test_number.py b/lib/Crypto/SelfTest/Util/test_number.py index 7a74e3a..0502e9e 100644 --- a/lib/Crypto/SelfTest/Util/test_number.py +++ b/lib/Crypto/SelfTest/Util/test_number.py @@ -252,10 +252,14 @@ class MiscTests(unittest.TestCase): def test_isPrime(self): """Util.number.isPrime""" + self.assertEqual(number.isPrime(-3), False) # Regression test: negative numbers should not be prime + self.assertEqual(number.isPrime(-2), False) # Regression test: negative numbers should not be prime + self.assertEqual(number.isPrime(1), False) # Regression test: isPrime(1) caused some versions of PyCrypto to crash. self.assertEqual(number.isPrime(2), True) self.assertEqual(number.isPrime(3), True) self.assertEqual(number.isPrime(4), False) self.assertEqual(number.isPrime(2L**1279-1), True) + self.assertEqual(number.isPrime(-(2L**1279-1)), False) # Regression test: negative numbers should not be prime # test some known gmp pseudo-primes taken from # http://www.trnicely.net/misc/mpzspsp.html for composite in (43 * 127 * 211, 61 * 151 * 211, 15259 * 30517, @@ -272,6 +276,14 @@ class MiscTests(unittest.TestCase): self.assertEqual(number.size(0xa2ba40),8*3) self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5L), 1024) + def test_negative_number_roundtrip_mpzToLongObj_longObjToMPZ(self): + """Test that mpzToLongObj and longObjToMPZ (internal functions) roundtrip negative numbers correctly.""" + n = -100000000000000000000000000000000000L + e = 2L + k = number._fastmath.rsa_construct(n, e) + self.assertEqual(n, k.n) + self.assertEqual(e, k.e) + def get_tests(config={}): from Crypto.SelfTest.st_common import list_test_cases return list_test_cases(MiscTests) diff --git a/src/_fastmath.c b/src/_fastmath.c index 4b5dede..b8b24b6 100644 --- a/src/_fastmath.c +++ b/src/_fastmath.c @@ -66,19 +66,26 @@ static void longObjToMPZ (mpz_t m, PyLongObject * p) { int size, i; + long negative; mpz_t temp, temp2; mpz_init (temp); mpz_init (temp2); #ifdef IS_PY3K - if (p->ob_base.ob_size > 0) + if (p->ob_base.ob_size > 0) { size = p->ob_base.ob_size; - else + negative = 1; + } else { size = -p->ob_base.ob_size; + negative = -1; + } #else - if (p->ob_size > 0) + if (p->ob_size > 0) { size = p->ob_size; - else + negative = 1; + } else { size = -p->ob_size; + negative = -1; + } #endif mpz_set_ui (m, 0); for (i = 0; i < size; i++) @@ -91,6 +98,7 @@ longObjToMPZ (mpz_t m, PyLongObject * p) #endif mpz_add (m, m, temp2); } + mpz_mul_si(m, m, negative); mpz_clear (temp); mpz_clear (temp2); } @@ -104,12 +112,15 @@ mpzToLongObj (mpz_t m) #else int size = (mpz_sizeinbase (m, 2) + SHIFT - 1) / SHIFT; #endif + int sgn; int i; mpz_t temp; PyLongObject *l = _PyLong_New (size); if (!l) return NULL; - mpz_init_set (temp, m); + sgn = mpz_sgn(m); + mpz_init(temp); + mpz_mul_si(temp, m, sgn); for (i = 0; i < size; i++) { #ifdef IS_PY3K @@ -124,9 +135,9 @@ mpzToLongObj (mpz_t m) while ((i > 0) && (l->ob_digit[i - 1] == 0)) i--; #ifdef IS_PY3K - l->ob_base.ob_size = i; + l->ob_base.ob_size = i * sgn; #else - l->ob_size = i; + l->ob_size = i * sgn; #endif mpz_clear (temp); return (PyObject *) l; @@ -1062,7 +1073,7 @@ isPrime (PyObject * self, PyObject * args, PyObject * kwargs) longObjToMPZ (n, (PyLongObject *) l); Py_BEGIN_ALLOW_THREADS; - /* first check if n is known to be prime and do some trail division */ + /* first check if n is known to be prime and do some trial division */ for (i = 0; i < SIEVE_BASE_SIZE; ++i) { if (mpz_cmp_ui (n, sieve_base[i]) == 0) @@ -1342,8 +1353,12 @@ rabinMillerTest (mpz_t n, int rounds, PyObject *randfunc) } Py_BEGIN_ALLOW_THREADS; - if ((mpz_tstbit (n, 0) == 0) || (mpz_cmp_ui (n, 3) < 0)) - return (mpz_cmp_ui (n, 2) == 0); + /* check special cases (n==2, n even, n < 2) */ + if ((mpz_tstbit (n, 0) == 0) || (mpz_cmp_ui (n, 3) < 0)) { + return_val = (mpz_cmp_ui (n, 2) == 0); + Py_BLOCK_THREADS; + return return_val; + } mpz_init (tmp); mpz_init (n_1); |