diff --git a/src/common/configpaths.py b/src/common/configpaths.py index 9fcefc136..2d80bb0c2 100644 --- a/src/common/configpaths.py +++ b/src/common/configpaths.py @@ -139,9 +139,10 @@ class ConfigPaths: self.config_root = self.cache_root = self.data_root = root d = {'MY_DATA': '', 'LOG_DB': 'logs.db', 'MY_CACERTS': 'cacerts.pem', - 'MY_EMOTS': 'emoticons', 'MY_ICONSETS': 'iconsets', - 'MY_MOOD_ICONSETS': 'moods', 'MY_ACTIVITY_ICONSETS': 'activities', - 'PLUGINS_USER': 'plugins', 'MY_PEER_CERTS': 'certs'} + 'MY_EMOTS': 'emoticons', 'MY_ICONSETS': 'iconsets', + 'MY_MOOD_ICONSETS': 'moods', 'MY_ACTIVITY_ICONSETS': 'activities', + 'PLUGINS_USER': 'plugins', 'MY_PEER_CERTS': 'certs', + 'RNG_SEED': u'rng_seed'} for name in d: self.add(name, TYPE_DATA, windowsify(d[name])) diff --git a/src/common/crypto.py b/src/common/crypto.py index c787df6aa..0b45cbac1 100644 --- a/src/common/crypto.py +++ b/src/common/crypto.py @@ -19,6 +19,7 @@ ## along with Gajim. If not, see . ## +import sys import os import math @@ -75,8 +76,53 @@ def base28(n): else: return base28_chr[n] +def add_entropy_sources_OpenSSL(): + # Other possibly variable data. This are very low quality sources of + # entropy, but some of them are installation dependent and can be hard + # to guess for the attacker. + # Data available on all platforms Unix, Windows + sources = [sys.argv, sys.builtin_module_names, + sys.copyright, sys.getfilesystemencoding(), sys.hexversion, + sys.modules, sys.path, sys.version, sys.api_version, + os.environ, os.getcwd(), os.getpid()] + + for s in sources: + OpenSSL.rand.add(str(s), 0.01) + + # On Windows add the current contents of the screen to the PRNG state. + if os.name == 'nt': + OpenSSL.rand.screen() + # The /proc filesystem on POSIX systems contains many random variables: + # memory statistics, interrupt counts, network packet counts + if os.name == 'posix': + dirs = ['/proc', '/proc/net', '/proc/self'] + for d in dirs: + if os.access(d, os.R_OK): + for filename in os.listdir(d): + OpenSSL.rand.add(filename, 0) + try: + with open(d + os.sep + filename, "r") as fp: + # Limit the ammount of read bytes, in case a memory + # file was opened + OpenSSL.rand.add(str(fp.read(5000)), 0.01) + except: + # Ignore all read and access errors + pass + +PYOPENSSL_PRNG_PRESENT = False +try: + import OpenSSL.rand + PYOPENSSL_PRNG_PRESENT = True +except ImportError: + # PyOpenSSL PRNG not available + pass + def random_bytes(bytes_): - return os.urandom(bytes_) + if PYOPENSSL_PRNG_PRESENT: + OpenSSL.rand.add(os.urandom(bytes_), bytes_) + return OpenSSL.rand.bytes(bytes_) + else: + return os.urandom(bytes_) def generate_nonce(): return random_bytes(8) diff --git a/src/gajim.py b/src/gajim.py index a1dc35575..9ce0361dc 100644 --- a/src/gajim.py +++ b/src/gajim.py @@ -302,6 +302,19 @@ gajimpaths = common.configpaths.gajimpaths pid_filename = gajimpaths['PID_FILE'] config_filename = gajimpaths['CONFIG_FILE'] +# Seed the OpenSSL pseudo random number generator from file and initialize +RNG_SEED = gajimpaths['RNG_SEED'] +PYOPENSSL_PRNG_PRESENT = False +try: + import OpenSSL.rand + from common import crypto + PYOPENSSL_PRNG_PRESENT = True + # Seed from file + OpenSSL.rand.load_file(RNG_SEED) + crypto.add_entropy_sources_OpenSSL() +except ImportError: + log.info("PyOpenSSL PRNG not available") + import traceback import errno import dialogs @@ -448,6 +461,9 @@ except IOError as e2: del pid_dir def on_exit(): + # Save the entropy from OpenSSL PRNG + if PYOPENSSL_PRNG_PRESENT: + OpenSSL.rand.write_file(RNG_SEED) # delete pid file on normal exit if os.path.exists(pid_filename): os.remove(pid_filename)