changeset bcfdd6de09ae in /home/hg/repos/python-nbxmpp
details:http://hg.gajim.org/python-nbxmpp?cmd=changeset;node=bcfdd6de09ae
description: [Fedor Brunner] Use better random number generator when openssl is available. Fixes #12
diffstat:
nbxmpp/auth_nb.py | 9 ++++-----
nbxmpp/bosh.py | 8 ++++----
nbxmpp/rndg.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+), 9 deletions(-)
diffs (125 lines):
diff -r 2d6e5d6949e8 -r bcfdd6de09ae nbxmpp/auth_nb.py
--- a/nbxmpp/auth_nb.py Fri Dec 06 21:19:37 2013 +0100
+++ b/nbxmpp/auth_nb.py Sat Dec 14 10:04:51 2013 +0100
@@ -27,7 +27,6 @@
from plugin import PlugIn
from smacks import Smacks
import base64
-import random
import itertools
import dispatcher_nb
import hashlib
@@ -37,6 +36,8 @@
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 ':'.join(some)
@@ -433,8 +434,7 @@
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
@@ -464,8 +464,7 @@
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 = (self.scram_gs2 + self.scram_soup).encode('base64').\
diff -r 2d6e5d6949e8 -r bcfdd6de09ae nbxmpp/bosh.py
--- a/nbxmpp/bosh.py Fri Dec 06 21:19:37 2013 +0100
+++ b/nbxmpp/bosh.py Sat Dec 14 10:04:51 2013 +0100
@@ -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 @@
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 @@
# 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 -r 2d6e5d6949e8 -r bcfdd6de09ae nbxmpp/rndg.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nbxmpp/rndg.py Sat Dec 14 10:04:51 2013 +0100
@@ -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(a)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