From 94165176d31474663043c1237cad68f6421cb622 Mon Sep 17 00:00:00 2001 From: HelloZeroNet Date: Wed, 27 May 2015 16:58:36 +0200 Subject: [PATCH] rev194, Fix for ugly openSSL layer memory leak, memory usage test to openssl stability test --- src/Config.py | 2 +- src/lib/opensslVerify/opensslVerify-alter2.py | 19 ++- src/lib/opensslVerify/opensslVerify.py | 114 +++++++++++------- src/lib/opensslVerify/stablityTest.py | 27 ++++- zeronet.py | 2 +- 5 files changed, 111 insertions(+), 53 deletions(-) diff --git a/src/Config.py b/src/Config.py index 1acd6d13..834e1630 100644 --- a/src/Config.py +++ b/src/Config.py @@ -4,7 +4,7 @@ import ConfigParser class Config(object): def __init__(self): self.version = "0.3.0" - self.rev = 193 + self.rev = 194 self.parser = self.createArguments() argv = sys.argv[:] # Copy command line arguments argv = self.parseConfig(argv) # Add arguments from config file diff --git a/src/lib/opensslVerify/opensslVerify-alter2.py b/src/lib/opensslVerify/opensslVerify-alter2.py index 69b607e2..e0406d75 100644 --- a/src/lib/opensslVerify/opensslVerify-alter2.py +++ b/src/lib/opensslVerify/opensslVerify-alter2.py @@ -74,9 +74,24 @@ def public_key_to_bc_address(public_key): h160 = hash_160(public_key) return hash_160_to_bc_address(h160) +def encode(val, base, minlen=0): + base, minlen = int(base), int(minlen) + code_string = ''.join([chr(x) for x in range(256)]) + result = "" + while val > 0: + result = code_string[val % base] + result + val //= base + return code_string[0] * max(minlen - len(result), 0) + result + +def num_to_var_int(x): + x = int(x) + if x < 253: return chr(x) + elif x < 65536: return chr(253)+encode(x, 256, 2)[::-1] + elif x < 4294967296: return chr(254) + encode(x, 256, 4)[::-1] + else: return chr(255) + encode(x, 256, 8)[::-1] + def msg_magic(message): - #return "\x18Bitcoin Signed Message:\n" + chr( len(message) ) + message - return "\x18Bitcoin Signed Message:\n" + chr( len(message) ) + message + return "\x18Bitcoin Signed Message:\n" + num_to_var_int( len(message) ) + message def get_address(eckey): size = ssl.i2o_ECPublicKey (eckey, 0) diff --git a/src/lib/opensslVerify/opensslVerify.py b/src/lib/opensslVerify/opensslVerify.py index c7736a2e..3ace4db0 100644 --- a/src/lib/opensslVerify/opensslVerify.py +++ b/src/lib/opensslVerify/opensslVerify.py @@ -10,6 +10,8 @@ import ctypes import ctypes.util import hashlib import base64 +import time +import logging addrtype = 0 class _OpenSSL: @@ -17,6 +19,7 @@ class _OpenSSL: Wrapper for OpenSSL using ctypes """ def __init__(self, library): + self.time_opened = time.time() """ Build the wrapper """ @@ -172,14 +175,23 @@ class _OpenSSL: self.i2o_ECPublicKey.restype = ctypes.c_void_p self.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + self.BN_CTX_free = self._lib.BN_CTX_free + self.BN_CTX_free.restype = None + self.BN_CTX_free.argtypes = [ctypes.c_void_p] + + self.EC_POINT_free = self._lib.EC_POINT_free + self.EC_POINT_free.restype = None + self.EC_POINT_free.argtypes = [ctypes.c_void_p] +def openLibrary(): + global ssl + try: + ssl = _OpenSSL("src/lib/opensslVerify/libeay32.dll") + except: + ssl = _OpenSSL(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32') -try: - ssl = _OpenSSL("src/lib/opensslVerify/libeay32.dll") -except: - ssl = _OpenSSL(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32') - +openLibrary() openssl_version = "%.9X" % ssl._lib.SSLeay() NID_secp256k1 = 714 @@ -296,51 +308,58 @@ def SetCompactSignature(pkey, hash, signature): def ECDSA_SIG_recover_key_GFp(eckey, r, s, msg, msglen, recid, check): n = 0 i = recid / 2 + ctx = R = O = Q = None - group = ssl.EC_KEY_get0_group(eckey) - ctx = ssl.BN_CTX_new() - ssl.BN_CTX_start(ctx) - order = ssl.BN_CTX_get(ctx) - ssl.EC_GROUP_get_order(group, order, ctx) - x = ssl.BN_CTX_get(ctx) - ssl.BN_copy(x, order); - ssl.BN_mul_word(x, i); - ssl.BN_add(x, x, r) - field = ssl.BN_CTX_get(ctx) - ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx) + try: + group = ssl.EC_KEY_get0_group(eckey) + ctx = ssl.BN_CTX_new() + ssl.BN_CTX_start(ctx) + order = ssl.BN_CTX_get(ctx) + ssl.EC_GROUP_get_order(group, order, ctx) + x = ssl.BN_CTX_get(ctx) + ssl.BN_copy(x, order); + ssl.BN_mul_word(x, i); + ssl.BN_add(x, x, r) + field = ssl.BN_CTX_get(ctx) + ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx) - if (ssl.BN_cmp(x, field) >= 0): - return False - - R = ssl.EC_POINT_new(group) - ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx) - - if check: - O = ssl.EC_POINT_new(group) - ssl.EC_POINT_mul(group, O, None, R, order, ctx) - if ssl.EC_POINT_is_at_infinity(group, O): + if (ssl.BN_cmp(x, field) >= 0): return False - Q = ssl.EC_POINT_new(group) - n = ssl.EC_GROUP_get_degree(group) - e = ssl.BN_CTX_get(ctx) - ssl.BN_bin2bn(msg, msglen, e) - if 8 * msglen > n: ssl.BN_rshift(e, e, 8 - (n & 7)) + R = ssl.EC_POINT_new(group) + ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx) - zero = ssl.BN_CTX_get(ctx) - ssl.BN_set_word(zero, 0) - ssl.BN_mod_sub(e, zero, e, order, ctx) - rr = ssl.BN_CTX_get(ctx); - ssl.BN_mod_inverse(rr, r, order, ctx) - sor = ssl.BN_CTX_get(ctx) - ssl.BN_mod_mul(sor, s, rr, order, ctx) - eor = ssl.BN_CTX_get(ctx) - ssl.BN_mod_mul(eor, e, rr, order, ctx) - ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx) - ssl.EC_KEY_set_public_key(eckey, Q) - return eckey + if check: + O = ssl.EC_POINT_new(group) + ssl.EC_POINT_mul(group, O, None, R, order, ctx) + if ssl.EC_POINT_is_at_infinity(group, O): + return False -def close(): + Q = ssl.EC_POINT_new(group) + n = ssl.EC_GROUP_get_degree(group) + e = ssl.BN_CTX_get(ctx) + ssl.BN_bin2bn(msg, msglen, e) + if 8 * msglen > n: ssl.BN_rshift(e, e, 8 - (n & 7)) + + zero = ssl.BN_CTX_get(ctx) + ssl.BN_set_word(zero, 0) + ssl.BN_mod_sub(e, zero, e, order, ctx) + rr = ssl.BN_CTX_get(ctx); + ssl.BN_mod_inverse(rr, r, order, ctx) + sor = ssl.BN_CTX_get(ctx) + ssl.BN_mod_mul(sor, s, rr, order, ctx) + eor = ssl.BN_CTX_get(ctx) + ssl.BN_mod_mul(eor, e, rr, order, ctx) + ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx) + ssl.EC_KEY_set_public_key(eckey, Q) + return eckey + finally: + if ctx: ssl.BN_CTX_free(ctx) + if R: ssl.EC_POINT_free(R) + if O: ssl.EC_POINT_free(O) + if Q: ssl.EC_POINT_free(Q) + +def closeLibrary(): import _ctypes if "FreeLibrary" in dir(_ctypes): _ctypes.FreeLibrary(ssl._lib._handle) @@ -354,7 +373,12 @@ def getMessagePubkey(message, sig): size = ssl.i2o_ECPublicKey (eckey, 0) mb = ctypes.create_string_buffer (size) ssl.i2o_ECPublicKey (eckey, ctypes.byref (ctypes.pointer (mb))) - return mb.raw + pub = mb.raw + if time.time()-ssl.time_opened>60*5: # Reopen every 5 min + logging.debug("Reopening OpenSSL...") + closeLibrary() + openLibrary() + return pub def test(): sign = "HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ=" diff --git a/src/lib/opensslVerify/stablityTest.py b/src/lib/opensslVerify/stablityTest.py index d6b498c4..2296e1f0 100644 --- a/src/lib/opensslVerify/stablityTest.py +++ b/src/lib/opensslVerify/stablityTest.py @@ -1,16 +1,35 @@ import opensslVerify, gevent, time -from gevent import monkey; monkey.patch_all(thread=False, ssl=False) +from gevent import monkey +monkey.patch_all(thread=False, ssl=False) def test(): data = "A"*1024 sign = "G2Jo8dDa+jqvJipft9E3kfrAxjESWLBpVtuGIiEBCD/UUyHmRMYNqnlWeOiaHHpja5LOP+U5CanRALfOjCSYIa8=" - for i in range(5*1000): + for i in range(2*1000): if i%1000 == 0: print i, len(data) - data += data+"A" + #data += data+"A" time.sleep(0) pub = opensslVerify.getMessagePubkey(data, sign) print repr(pub), len(data) -gevent.joinall([gevent.spawn(test), gevent.spawn(test)]) \ No newline at end of file +while 1: + s = time.time() + gevent.joinall([gevent.spawn(test), gevent.spawn(test)]) + try: + import psutil, os + process = psutil.Process(os.getpid()) + print "Mem:", process.get_memory_info()[0] / float(2 ** 20) + except: + pass + raw_input("finished, in %.2fs, check memory usage" % (time.time()-s)) + opensslVerify.close() + opensslVerify.open() + try: + import psutil, os + process = psutil.Process(os.getpid()) + print "Mem:", process.get_memory_info()[0] / float(2 ** 20) + except: + pass + raw_input("closed and openssl, check memory again, press enter to start again") diff --git a/zeronet.py b/zeronet.py index 71ce0764..8d1e46d9 100644 --- a/zeronet.py +++ b/zeronet.py @@ -13,7 +13,7 @@ def main(): # Try cleanup openssl try: if "lib.opensslVerify" in sys.modules: - sys.modules["lib.opensslVerify"].opensslVerify.close() + sys.modules["lib.opensslVerify"].opensslVerify.closeLibrary() except Exception, err: print "Error closing openssl", err