yet faster web2py_uuid by caching urandom results

This commit is contained in:
mdipierro
2012-09-29 17:56:43 -05:00
parent 1a43e1671f
commit 60a043479c
2 changed files with 28 additions and 8 deletions
+1 -1
View File
@@ -1 +1 @@
Version 2.0.9 (2012-09-29 17:16:28) dev Version 2.0.9 (2012-09-29 17:56:36) dev
+26 -6
View File
@@ -10,6 +10,7 @@ This file specifically includes utilities for security.
""" """
import string import string
import threading
import struct import struct
import hashlib import hashlib
import hmac import hmac
@@ -110,6 +111,7 @@ def initialize_urandom():
random.seed(node_id + microseconds) random.seed(node_id + microseconds)
try: try:
os.urandom(1) os.urandom(1)
have_urandom = True
try: try:
# try to add process-specific entropy # try to add process-specific entropy
frandom = open('/dev/urandom','wb') frandom = open('/dev/urandom','wb')
@@ -121,13 +123,31 @@ def initialize_urandom():
# works anyway # works anyway
pass pass
except NotImplementedError: except NotImplementedError:
have_urandom = False
logger.warning( logger.warning(
"""Cryptographically secure session management is not possible on your system because """Cryptographically secure session management is not possible on your system because
your system does not provide a cryptographically secure entropy source. your system does not provide a cryptographically secure entropy source.
This is not specific to web2py; consider deploying on a different operating system.""") This is not specific to web2py; consider deploying on a different operating system.""")
return ctokens unpacked_ctokens = struct.unpack('=QQ',string.join(
CTOKENS = initialize_urandom() (chr(x) for x in ctokens),''))
UNPACKED_CTOKENS = struct.unpack('=QQ',string.join((chr(x) for x in CTOKENS),'')) return unpacked_ctokens, have_urandom
UNPACKED_CTOKENS, HAVE_URANDOM = initialize_urandom()
def fast_urandom16(urandom=[], locker = threading.RLock()):
"""
this is 4x faster than calling os.urandom(16) and prevents
the "too many files open" issue with concurrent access to os.urandom()
"""
try:
return urandom.pop()
except IndexError:
try:
locker.acquire()
ur = os.urandom(16*1024)
urandom += [ur[i:i+16] for i in xrange(16,1024*16,16)]
return ur[0:16]
finally:
locker.release()
def web2py_uuid(ctokens=UNPACKED_CTOKENS): def web2py_uuid(ctokens=UNPACKED_CTOKENS):
""" """
@@ -139,12 +159,12 @@ def web2py_uuid(ctokens=UNPACKED_CTOKENS):
""" """
rand_longs = struct.unpack('=QQ', bytes(bytearray( rand_longs = struct.unpack('=QQ', bytes(bytearray(
random.randrange(256) for i in xrange(16)))) random.randrange(256) for i in xrange(16))))
try: if HAVE_URANDOM:
urand_longs = struct.unpack('=QQ', os.urandom(16)) urand_longs = struct.unpack('=QQ', fast_urandom16())
byte_s = struct.pack('=QQ', byte_s = struct.pack('=QQ',
rand_longs[0]^urand_longs[0]^ctokens[0], rand_longs[0]^urand_longs[0]^ctokens[0],
rand_longs[1]^urand_longs[1]^ctokens[1]) rand_longs[1]^urand_longs[1]^ctokens[1])
except NotImplementedError: else:
byte_s = struct.pack('=QQ', byte_s = struct.pack('=QQ',
rand_longs[0]^ctokens[0], rand_longs[0]^ctokens[0],
rand_longs[1]^ctokens[1]) rand_longs[1]^ctokens[1])