diff options
author | Yann Leboulanger <asterix@lagaule.org> | 2013-12-14 13:04:51 +0400 |
---|---|---|
committer | Yann Leboulanger <asterix@lagaule.org> | 2013-12-14 13:04:51 +0400 |
commit | c4c7e1868968d5478c65da3af35052d51f2a41f4 (patch) | |
tree | cbc9f95443db4554ce598a2e35592056d2ef07f5 | |
parent | 8eb22e12ca6366939fea39ed8f11be8df1b63dcb (diff) |
[Fedor Brunner] Use better random number generator when openssl is available. Fixes #12
-rw-r--r-- | nbxmpp/auth_nb.py | 9 | ||||
-rw-r--r-- | nbxmpp/bosh.py | 8 | ||||
-rw-r--r-- | nbxmpp/rndg.py | 49 |
3 files changed, 57 insertions, 9 deletions
diff --git a/nbxmpp/auth_nb.py b/nbxmpp/auth_nb.py index 720fac2..aaa8d0b 100644 --- a/nbxmpp/auth_nb.py +++ b/nbxmpp/auth_nb.py @@ -27,7 +27,6 @@ from .protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID from .plugin import PlugIn from .smacks import Smacks import base64 -import random import itertools from . import dispatcher_nb import hashlib @@ -37,6 +36,8 @@ import hashlib import logging log = logging.getLogger('nbxmpp.auth_nb') +import rndg + def HH(some): return hashlib.md5(some).hexdigest() def H(some): return hashlib.md5(some).digest() def C(some): return b':'.join(some) @@ -440,8 +441,7 @@ class SASL(PlugIn): else: self.resp['realm'] = self._owner.Server self.resp['nonce'] = chal['nonce'] - self.resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint \ - in itertools.repeat(random.randint, 7)) + self.resp['cnonce'] = '%x' % rngd.getrandbits(196) self.resp['nc'] = ('00000001') self.resp['qop'] = 'auth' self.resp['digest-uri'] = 'xmpp/' + self._owner.Server @@ -471,8 +471,7 @@ class SASL(PlugIn): def set_password(self, password): self.password = '' if password is None else password if self.mechanism == 'SCRAM-SHA-1': - nonce = ''.join('%x' % randint(0, 2 ** 28) for randint in \ - itertools.repeat(random.randint, 7)) + nonce = '%x' % rndg.getrandbits(196) self.scram_soup = 'n=' + self.username + ',r=' + nonce self.scram_gs2 = 'n,,' # No CB yet. sasl_data = base64.b64encode((self.scram_gs2 + self.scram_soup).\ diff --git a/nbxmpp/bosh.py b/nbxmpp/bosh.py index 47b1784..6eb5877 100644 --- a/nbxmpp/bosh.py +++ b/nbxmpp/bosh.py @@ -18,7 +18,7 @@ ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. -import locale, random +import locale from hashlib import sha1 from .transports_nb import NonBlockingTransport, NonBlockingHTTPBOSH,\ CONNECTED, CONNECTING, DISCONNECTED, DISCONNECTING,\ @@ -29,6 +29,8 @@ from .simplexml import Node import logging log = logging.getLogger('nbxmpp.bosh') +import rndg + KEY_COUNT = 10 # Fake file descriptor - it's used for setting read_timeout in idlequeue for @@ -486,9 +488,7 @@ def get_rand_number(): # to 7881299347898368 messages to raise rid over 2**53 # (see http://www.xmpp.org/extensions/xep-0124.html#rids) # it's also used for sequence key initialization - r = random.Random() - r.seed() - return r.getrandbits(50) + return rndg.getrandbits(50) diff --git a/nbxmpp/rndg.py b/nbxmpp/rndg.py new file mode 100644 index 0000000..42d1851 --- /dev/null +++ b/nbxmpp/rndg.py @@ -0,0 +1,49 @@ +## rndg.py +## +## cryptographically secure pseudo-random number generator. +## When possible use OpenSSL PRNG combined with os.random, +## if OpenSSL PRNG is not available, use only os.random. +## +## Copyright (C) 2013 Fedor Brunner <fedor.brunner@azet.sk> +## +## This file is part of Gajim. +## +## Gajim is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## Gajim is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Gajim. If not, see <http://www.gnu.org/licenses/>. + +USE_PYOPENSSL = False +try: + import OpenSSL.rand + import binascii, os + USE_PYOPENSSL = True +except ImportError: + import random + +if not USE_PYOPENSSL: + getrandbits = random.SystemRandom().getrandbits +else: + def getrandbits(k): + """getrandbits(k) -> x. Generates a long int with k random bits.""" + if k <= 0: + raise ValueError('number of bits must be greater than zero') + if k != int(k): + raise TypeError('number of bits should be an integer') + + bytes = (k + 7) // 8 # bits / 8 and rounded up + + # Add system entropy to OpenSSL PRNG + OpenSSL.rand.add(os.urandom(bytes), bytes) + # Extract random bytes from OpenSSL PRNG + random_str = OpenSSL.rand.bytes(bytes) + + x = long(binascii.hexlify(random_str), 16) + return x >> (bytes * 8 - k) # trim excess bits |