rev122, 40x faster openssl based sign verify, Openssl verify benchmark, Socket objects stat, Dont trace notification stack, uiserver memory leak fix
This commit is contained in:
parent
eb79556bb8
commit
71be41ade0
15 changed files with 636 additions and 12 deletions
|
@ -42,7 +42,8 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network
|
|||
After the peers have verified the `content.json` integrity (using the
|
||||
signature), they download the modified files and publish the new content to
|
||||
other peers.
|
||||
* More details: [Slideshow about how ZeroNet works](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
|
||||
|
||||
#### [Slideshow about ZeroNet cryptography, site updates, multi-user sites »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -155,6 +155,11 @@ class UiRequestPlugin(object):
|
|||
for obj in objs:
|
||||
yield " - %.1fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
|
||||
|
||||
from socket import socket
|
||||
objs = [obj for obj in gc.get_objects() if isinstance(obj, socket)]
|
||||
yield "<br>Sockets (%s):<br>" % len(objs)
|
||||
for obj in objs:
|
||||
yield " - %.1fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
|
||||
|
||||
from msgpack import Unpacker
|
||||
objs = [obj for obj in gc.get_objects() if isinstance(obj, Unpacker)]
|
||||
|
@ -305,11 +310,23 @@ class UiRequestPlugin(object):
|
|||
|
||||
|
||||
address = CryptBitcoin.privatekeyToAddress(privatekey)
|
||||
with benchmark("verify x 10", 1.6):
|
||||
if CryptBitcoin.opensslVerify: # Openssl avalible
|
||||
with benchmark("openssl verify x 100", 0.37):
|
||||
for i in range(100):
|
||||
if i%10==0: yield "."
|
||||
ok = CryptBitcoin.verify(data, address, sign)
|
||||
assert ok, "does not verify from %s" % address
|
||||
else:
|
||||
yield " - openssl verify x 100...not avalible :(<br>"
|
||||
|
||||
opensslVerify_bk = CryptBitcoin.opensslVerify # Emulate openssl not found in any way
|
||||
CryptBitcoin.opensslVerify = None
|
||||
with benchmark("pure-python verify x 10", 1.6):
|
||||
for i in range(10):
|
||||
yield "."
|
||||
ok = CryptBitcoin.verify(data, address, sign)
|
||||
assert ok, "does not verify from %s" % address
|
||||
CryptBitcoin.opensslVerify = opensslVerify_bk
|
||||
|
||||
|
||||
yield "<br>CryptHash:<br>"
|
||||
|
|
|
@ -27,7 +27,6 @@ class UiRequestPlugin(object):
|
|||
|
||||
if self.isProxyRequest(): # Match to site domain
|
||||
referer = re.sub("^http://zero[/]+", "http://", referer) # Allow /zero access
|
||||
print referer
|
||||
referer_site_address = re.match("http[s]{0,1}://(.*?)(/|$)", referer).group(1)
|
||||
else: # Match to request path
|
||||
referer_site_address = re.match("/(?P<address>[A-Za-z0-9\.]+)(?P<inner_path>/.*|$)", referer_path).group("address")
|
||||
|
|
|
@ -4,7 +4,7 @@ import ConfigParser
|
|||
class Config(object):
|
||||
def __init__(self):
|
||||
self.version = "0.2.9"
|
||||
self.rev = 120
|
||||
self.rev = 122
|
||||
self.parser = self.createArguments()
|
||||
argv = sys.argv[:] # Copy command line arguments
|
||||
argv = self.parseConfig(argv) # Add arguments from config file
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
from lib.BitcoinECC import BitcoinECC
|
||||
from lib.pybitcointools import bitcoin as btctools
|
||||
import logging
|
||||
# Try to load openssl
|
||||
try:
|
||||
from lib.opensslVerify import opensslVerify
|
||||
logging.info("OpenSSL loaded, version: %s" % opensslVerify.openssl_version)
|
||||
except Exception, err:
|
||||
logging.info("OpenSSL load failed: %s, falling back to slow bitcoin verify" % err)
|
||||
opensslVerify = None
|
||||
|
||||
|
||||
def newPrivatekey(uncompressed=True): # Return new private key
|
||||
|
@ -45,8 +53,12 @@ def signOld(data, privatekey): # Return sign to data using private key (backward
|
|||
|
||||
def verify(data, address, sign): # Verify data using address and sign
|
||||
if hasattr(sign, "endswith"):
|
||||
pub = btctools.ecdsa_recover(data, sign)
|
||||
sign_address = btctools.pubtoaddr(pub)
|
||||
if opensslVerify: # Use the faster method if avalible
|
||||
pub = opensslVerify.getMessagePubkey(data, sign)
|
||||
sign_address = btctools.pubtoaddr(pub)
|
||||
else: # Use pure-python
|
||||
pub = btctools.ecdsa_recover(data, sign)
|
||||
sign_address = btctools.pubtoaddr(pub)
|
||||
return sign_address == address
|
||||
else: # Backward compatible old style
|
||||
bitcoin = BitcoinECC.Bitcoin()
|
||||
|
|
|
@ -10,6 +10,7 @@ class Notify(Exception):
|
|||
|
||||
|
||||
def formatException(err=None):
|
||||
if type(err) == Notify: return err
|
||||
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||
if not err: err = exc_obj.message
|
||||
tb = []
|
||||
|
@ -21,6 +22,7 @@ def formatException(err=None):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
try:
|
||||
print 1/0
|
||||
except Exception, err:
|
||||
|
@ -36,4 +38,10 @@ if __name__ == "__main__":
|
|||
except Exception, err:
|
||||
print err
|
||||
print "Json load error: %s" % formatException(err)
|
||||
|
||||
try:
|
||||
raise Notify("nothing...")
|
||||
except Exception, err:
|
||||
print "Notify: %s" % formatException(err)
|
||||
|
||||
loadJson()
|
||||
|
|
|
@ -20,17 +20,25 @@ class UiWSGIHandler(WSGIHandler):
|
|||
def run_application(self):
|
||||
self.server.sockets[self.client_address] = self.socket
|
||||
if "HTTP_UPGRADE" in self.environ: # Websocket request
|
||||
ws_handler = WebSocketHandler(*self.args, **self.kwargs)
|
||||
ws_handler.__dict__ = self.__dict__ # Match class variables
|
||||
ws_handler.run_application()
|
||||
try:
|
||||
ws_handler = WebSocketHandler(*self.args, **self.kwargs)
|
||||
ws_handler.__dict__ = self.__dict__ # Match class variables
|
||||
ws_handler.run_application()
|
||||
except Exception, err:
|
||||
logging.error("UiWSGIHandler websocket error: %s" % Debug.formatException(err))
|
||||
if config.debug: # Allow websocket errors to appear on /Debug
|
||||
import sys
|
||||
del self.server.sockets[self.client_address]
|
||||
sys.modules["main"].DebugHook.handleError()
|
||||
else: # Standard HTTP request
|
||||
#print self.application.__class__.__name__
|
||||
try:
|
||||
return super(UiWSGIHandler, self).run_application()
|
||||
super(UiWSGIHandler, self).run_application()
|
||||
except Exception, err:
|
||||
logging.error("UiWSGIHandler error: %s" % Debug.formatException(err))
|
||||
if config.debug: # Allow websocket errors to appear on /Debug
|
||||
import sys
|
||||
del self.server.sockets[self.client_address]
|
||||
sys.modules["main"].DebugHook.handleError()
|
||||
del self.server.sockets[self.client_address]
|
||||
|
||||
|
|
BIN
src/lib/opensslVerify/HashInfo.txt
Normal file
BIN
src/lib/opensslVerify/HashInfo.txt
Normal file
Binary file not shown.
126
src/lib/opensslVerify/OpenSSL License.txt
Normal file
126
src/lib/opensslVerify/OpenSSL License.txt
Normal file
|
@ -0,0 +1,126 @@
|
|||
|
||||
LICENSE ISSUES
|
||||
==============
|
||||
|
||||
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
|
||||
the OpenSSL License and the original SSLeay license apply to the toolkit.
|
||||
See below for the actual license texts. Actually both licenses are BSD-style
|
||||
Open Source licenses. In case of any license issues related to OpenSSL
|
||||
please contact openssl-core@openssl.org.
|
||||
|
||||
OpenSSL License
|
||||
---------------
|
||||
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
*/
|
||||
|
||||
Original SSLeay License
|
||||
-----------------------
|
||||
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
59
src/lib/opensslVerify/ReadMe.txt
Normal file
59
src/lib/opensslVerify/ReadMe.txt
Normal file
|
@ -0,0 +1,59 @@
|
|||
=============================================================================
|
||||
OpenSSL v1.0.2a Precompiled Binaries for Win32
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
*** Release Information ***
|
||||
|
||||
Release Date: Mrz 20, 2015
|
||||
|
||||
Author: Frederik A. Winkelsdorf (opendec.wordpress.com)
|
||||
for the Indy Project (www.indyproject.org)
|
||||
|
||||
Requirements: Indy 10.5.5+ (SVN Version or Delphi 2009 and newer)
|
||||
|
||||
Dependencies: The libraries have no noteworthy dependencies
|
||||
|
||||
Installation: Copy both DLL files into your application directory
|
||||
|
||||
Supported OS: Windows 2000 up to Windows 8
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
*** Legal Disclaimer ***
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ITS AUTHOR AND THE INDY PROJECT "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
OpenSSL license terms are provided in the file "OpenSSL License.txt".
|
||||
|
||||
PLEASE CHECK IF YOU NEED TO COMPLY WITH EXPORT RESTRICTIONS FOR CRYPTOGRAPHIC
|
||||
SOFTWARE AND/OR PATENTS.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
*** Build Information Win32 ***
|
||||
|
||||
Built with: Microsoft Visual C++ 2008 Express Edition
|
||||
The Netwide Assembler (NASM) v2.11.05 Win32
|
||||
Strawberry Perl v5.20.0.1 Win32 Portable
|
||||
Windows PowerShell
|
||||
FinalBuilder 7 Embarcadero Edition
|
||||
|
||||
Commands: perl configure VC-WIN32
|
||||
ms\do_nasm
|
||||
adjusted ms\ntdll.mak (replaced "/MD" with "/MT")
|
||||
adjusted ms\version32.rc (Indy Information inserted)
|
||||
nmake -f ms\ntdll.mak
|
||||
nmake -f ms\ntdll.mak test
|
||||
editbin.exe /rebase:base=0x11000000 libeay32.dll
|
||||
editbin.exe /rebase:base=0x12000000 ssleay32.dll
|
||||
|
||||
=============================================================================
|
0
src/lib/opensslVerify/__init__.py
Normal file
0
src/lib/opensslVerify/__init__.py
Normal file
BIN
src/lib/opensslVerify/libeay32.dll
Normal file
BIN
src/lib/opensslVerify/libeay32.dll
Normal file
Binary file not shown.
392
src/lib/opensslVerify/opensslVerify.py
Normal file
392
src/lib/opensslVerify/opensslVerify.py
Normal file
|
@ -0,0 +1,392 @@
|
|||
# Code is borrowed from https://github.com/blocktrail/python-bitcoinlib
|
||||
# Thanks!
|
||||
|
||||
import base64, hashlib
|
||||
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
_bchr = chr
|
||||
_bord = ord
|
||||
try:
|
||||
_ssl = ctypes.CDLL("src/lib/opensslVerify/libeay32.dll")
|
||||
except:
|
||||
_ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32')
|
||||
|
||||
import sys
|
||||
|
||||
openssl_version = "%.9X" % _ssl.SSLeay()
|
||||
|
||||
|
||||
# this specifies the curve used with ECDSA.
|
||||
_NID_secp256k1 = 714 # from openssl/obj_mac.h
|
||||
|
||||
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
|
||||
def _check_result (val, func, args):
|
||||
if val == 0:
|
||||
raise ValueError
|
||||
else:
|
||||
return ctypes.c_void_p(val)
|
||||
|
||||
_ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
|
||||
_ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
|
||||
|
||||
# From openssl/ecdsa.h
|
||||
class ECDSA_SIG_st(ctypes.Structure):
|
||||
_fields_ = [("r", ctypes.c_void_p),
|
||||
("s", ctypes.c_void_p)]
|
||||
|
||||
class CECKey:
|
||||
"""Wrapper around OpenSSL's EC_KEY"""
|
||||
|
||||
POINT_CONVERSION_COMPRESSED = 2
|
||||
POINT_CONVERSION_UNCOMPRESSED = 4
|
||||
|
||||
def __init__(self):
|
||||
self.k = _ssl.EC_KEY_new_by_curve_name(_NID_secp256k1)
|
||||
|
||||
def __del__(self):
|
||||
if _ssl:
|
||||
_ssl.EC_KEY_free(self.k)
|
||||
self.k = None
|
||||
|
||||
def set_secretbytes(self, secret):
|
||||
priv_key = _ssl.BN_bin2bn(secret, 32, _ssl.BN_new())
|
||||
group = _ssl.EC_KEY_get0_group(self.k)
|
||||
pub_key = _ssl.EC_POINT_new(group)
|
||||
ctx = _ssl.BN_CTX_new()
|
||||
if not _ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx):
|
||||
raise ValueError("Could not derive public key from the supplied secret.")
|
||||
_ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx)
|
||||
_ssl.EC_KEY_set_private_key(self.k, priv_key)
|
||||
_ssl.EC_KEY_set_public_key(self.k, pub_key)
|
||||
_ssl.EC_POINT_free(pub_key)
|
||||
_ssl.BN_CTX_free(ctx)
|
||||
return self.k
|
||||
|
||||
def set_privkey(self, key):
|
||||
self.mb = ctypes.create_string_buffer(key)
|
||||
return _ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
|
||||
|
||||
def set_pubkey(self, key):
|
||||
self.mb = ctypes.create_string_buffer(key)
|
||||
return _ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
|
||||
|
||||
def get_privkey(self):
|
||||
size = _ssl.i2d_ECPrivateKey(self.k, 0)
|
||||
mb_pri = ctypes.create_string_buffer(size)
|
||||
_ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri)))
|
||||
return mb_pri.raw
|
||||
|
||||
def get_pubkey(self):
|
||||
size = _ssl.i2o_ECPublicKey(self.k, 0)
|
||||
mb = ctypes.create_string_buffer(size)
|
||||
_ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb)))
|
||||
return mb.raw
|
||||
|
||||
def get_raw_ecdh_key(self, other_pubkey):
|
||||
ecdh_keybuffer = ctypes.create_string_buffer(32)
|
||||
r = _ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32,
|
||||
_ssl.EC_KEY_get0_public_key(other_pubkey.k),
|
||||
self.k, 0)
|
||||
if r != 32:
|
||||
raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed')
|
||||
return ecdh_keybuffer.raw
|
||||
|
||||
def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
|
||||
# FIXME: be warned it's not clear what the kdf should be as a default
|
||||
r = self.get_raw_ecdh_key(other_pubkey)
|
||||
return kdf(r)
|
||||
|
||||
def sign(self, hash):
|
||||
if not isinstance(hash, bytes):
|
||||
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
|
||||
if len(hash) != 32:
|
||||
raise ValueError('Hash must be exactly 32 bytes long')
|
||||
|
||||
sig_size0 = ctypes.c_uint32()
|
||||
sig_size0.value = _ssl.ECDSA_size(self.k)
|
||||
mb_sig = ctypes.create_string_buffer(sig_size0.value)
|
||||
result = _ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
|
||||
assert 1 == result
|
||||
if bitcoin.core.script.IsLowDERSignature(mb_sig.raw[:sig_size0.value]):
|
||||
return mb_sig.raw[:sig_size0.value]
|
||||
else:
|
||||
return self.signature_to_low_s(mb_sig.raw[:sig_size0.value])
|
||||
|
||||
def sign_compact(self, hash):
|
||||
if not isinstance(hash, bytes):
|
||||
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
|
||||
if len(hash) != 32:
|
||||
raise ValueError('Hash must be exactly 32 bytes long')
|
||||
|
||||
sig_size0 = ctypes.c_uint32()
|
||||
sig_size0.value = _ssl.ECDSA_size(self.k)
|
||||
mb_sig = ctypes.create_string_buffer(sig_size0.value)
|
||||
result = _ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
|
||||
assert 1 == result
|
||||
|
||||
if bitcoin.core.script.IsLowDERSignature(mb_sig.raw[:sig_size0.value]):
|
||||
sig = mb_sig.raw[:sig_size0.value]
|
||||
else:
|
||||
sig = self.signature_to_low_s(mb_sig.raw[:sig_size0.value])
|
||||
|
||||
sig = bitcoin.core.DERSignature.deserialize(sig)
|
||||
|
||||
r_val = sig.r
|
||||
s_val = sig.s
|
||||
|
||||
# assert that the r and s are less than 32 long, excluding leading 0s
|
||||
assert len(r_val) <= 32 or r_val[0:-32] == b'\x00'
|
||||
assert len(s_val) <= 32 or s_val[0:-32] == b'\x00'
|
||||
|
||||
# ensure r and s are always 32 chars long by 0padding
|
||||
r_val = ((b'\x00' * 32) + r_val)[-32:]
|
||||
s_val = ((b'\x00' * 32) + s_val)[-32:]
|
||||
|
||||
# tmp pubkey of self, but always compressed
|
||||
pubkey = CECKey()
|
||||
pubkey.set_pubkey(self.get_pubkey())
|
||||
pubkey.set_compressed(True)
|
||||
|
||||
# bitcoin core does <4, but I've seen other places do <2 and I've never seen a i > 1 so far
|
||||
for i in range(0, 4):
|
||||
cec_key = CECKey()
|
||||
cec_key.set_compressed(True)
|
||||
|
||||
result = cec_key.recover(r_val, s_val, hash, len(hash), i, 1)
|
||||
if result == 1:
|
||||
if cec_key.get_pubkey() == pubkey.get_pubkey():
|
||||
return r_val + s_val, i
|
||||
|
||||
raise ValueError
|
||||
|
||||
def signature_to_low_s(self, sig):
|
||||
der_sig = ECDSA_SIG_st()
|
||||
_ssl.d2i_ECDSA_SIG(ctypes.byref(ctypes.pointer(der_sig)), ctypes.byref(ctypes.c_char_p(sig)), len(sig))
|
||||
group = _ssl.EC_KEY_get0_group(self.k)
|
||||
order = _ssl.BN_new()
|
||||
halforder = _ssl.BN_new()
|
||||
ctx = _ssl.BN_CTX_new()
|
||||
_ssl.EC_GROUP_get_order(group, order, ctx)
|
||||
_ssl.BN_rshift1(halforder, order)
|
||||
|
||||
# Verify that s is over half the order of the curve before we actually subtract anything from it
|
||||
if _ssl.BN_cmp(der_sig.s, halforder) > 0:
|
||||
_ssl.BN_sub(der_sig.s, order, der_sig.s)
|
||||
|
||||
_ssl.BN_free(halforder)
|
||||
_ssl.BN_free(order)
|
||||
_ssl.BN_CTX_free(ctx)
|
||||
|
||||
derlen = _ssl.i2d_ECDSA_SIG(ctypes.pointer(der_sig), 0)
|
||||
if derlen == 0:
|
||||
_ssl.ECDSA_SIG_free(der_sig)
|
||||
return None
|
||||
new_sig = ctypes.create_string_buffer(derlen)
|
||||
_ssl.i2d_ECDSA_SIG(ctypes.pointer(der_sig), ctypes.byref(ctypes.pointer(new_sig)))
|
||||
_ssl.BN_free(der_sig.r)
|
||||
_ssl.BN_free(der_sig.s)
|
||||
|
||||
return new_sig.raw
|
||||
|
||||
def verify(self, hash, sig):
|
||||
"""Verify a DER signature"""
|
||||
if not sig:
|
||||
return false
|
||||
|
||||
# New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
|
||||
norm_sig = ctypes.c_void_p(0)
|
||||
_ssl.d2i_ECDSA_SIG(ctypes.byref(norm_sig), ctypes.byref(ctypes.c_char_p(sig)), len(sig))
|
||||
|
||||
derlen = _ssl.i2d_ECDSA_SIG(norm_sig, 0)
|
||||
if derlen == 0:
|
||||
_ssl.ECDSA_SIG_free(norm_sig)
|
||||
return false
|
||||
|
||||
norm_der = ctypes.create_string_buffer(derlen)
|
||||
_ssl.i2d_ECDSA_SIG(norm_sig, ctypes.byref(ctypes.pointer(norm_der)))
|
||||
_ssl.ECDSA_SIG_free(norm_sig)
|
||||
|
||||
# -1 = error, 0 = bad sig, 1 = good
|
||||
return _ssl.ECDSA_verify(0, hash, len(hash), norm_der, derlen, self.k) == 1
|
||||
|
||||
def set_compressed(self, compressed):
|
||||
if compressed:
|
||||
form = self.POINT_CONVERSION_COMPRESSED
|
||||
else:
|
||||
form = self.POINT_CONVERSION_UNCOMPRESSED
|
||||
_ssl.EC_KEY_set_conv_form(self.k, form)
|
||||
|
||||
def recover(self, sigR, sigS, msg, msglen, recid, check):
|
||||
"""
|
||||
Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
|
||||
recid selects which key is recovered
|
||||
if check is non-zero, additional checks are performed
|
||||
"""
|
||||
i = int(recid / 2)
|
||||
|
||||
r = None
|
||||
s = None
|
||||
ctx = None
|
||||
R = None
|
||||
O = None
|
||||
Q = None
|
||||
|
||||
assert len(sigR) == 32, len(sigR)
|
||||
assert len(sigS) == 32, len(sigS)
|
||||
|
||||
try:
|
||||
r = _ssl.BN_bin2bn(bytes(sigR), len(sigR), _ssl.BN_new())
|
||||
s = _ssl.BN_bin2bn(bytes(sigS), len(sigS), _ssl.BN_new())
|
||||
|
||||
group = _ssl.EC_KEY_get0_group(self.k)
|
||||
ctx = _ssl.BN_CTX_new()
|
||||
order = _ssl.BN_CTX_get(ctx)
|
||||
ctx = _ssl.BN_CTX_new()
|
||||
|
||||
if not _ssl.EC_GROUP_get_order(group, order, ctx):
|
||||
return -2
|
||||
|
||||
x = _ssl.BN_CTX_get(ctx)
|
||||
if not _ssl.BN_copy(x, order):
|
||||
return -1
|
||||
if not _ssl.BN_mul_word(x, i):
|
||||
return -1
|
||||
if not _ssl.BN_add(x, x, r):
|
||||
return -1
|
||||
|
||||
field = _ssl.BN_CTX_get(ctx)
|
||||
if not _ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx):
|
||||
return -2
|
||||
|
||||
if _ssl.BN_cmp(x, field) >= 0:
|
||||
return 0
|
||||
|
||||
R = _ssl.EC_POINT_new(group)
|
||||
if R is None:
|
||||
return -2
|
||||
if not _ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx):
|
||||
return 0
|
||||
|
||||
if check:
|
||||
O = _ssl.EC_POINT_new(group)
|
||||
if O is None:
|
||||
return -2
|
||||
if not _ssl.EC_POINT_mul(group, O, None, R, order, ctx):
|
||||
return -2
|
||||
if not _ssl.EC_POINT_is_at_infinity(group, O):
|
||||
return 0
|
||||
|
||||
Q = _ssl.EC_POINT_new(group)
|
||||
if Q is None:
|
||||
return -2
|
||||
|
||||
n = _ssl.EC_GROUP_get_degree(group)
|
||||
e = _ssl.BN_CTX_get(ctx)
|
||||
if not _ssl.BN_bin2bn(msg, msglen, e):
|
||||
return -1
|
||||
|
||||
if 8 * msglen > n:
|
||||
_ssl.BN_rshift(e, e, 8 - (n & 7))
|
||||
|
||||
zero = _ssl.BN_CTX_get(ctx)
|
||||
# if not _ssl.BN_zero(zero):
|
||||
# return -1
|
||||
if not _ssl.BN_mod_sub(e, zero, e, order, ctx):
|
||||
return -1
|
||||
rr = _ssl.BN_CTX_get(ctx)
|
||||
if not _ssl.BN_mod_inverse(rr, r, order, ctx):
|
||||
return -1
|
||||
sor = _ssl.BN_CTX_get(ctx)
|
||||
if not _ssl.BN_mod_mul(sor, s, rr, order, ctx):
|
||||
return -1
|
||||
eor = _ssl.BN_CTX_get(ctx)
|
||||
if not _ssl.BN_mod_mul(eor, e, rr, order, ctx):
|
||||
return -1
|
||||
if not _ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx):
|
||||
return -2
|
||||
|
||||
if not _ssl.EC_KEY_set_public_key(self.k, Q):
|
||||
return -2
|
||||
|
||||
return 1
|
||||
finally:
|
||||
if r: _ssl.BN_free(r)
|
||||
if s: _ssl.BN_free(s)
|
||||
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 recover_compact(hash, sig):
|
||||
"""Recover a public key from a compact signature."""
|
||||
if len(sig) != 65:
|
||||
raise ValueError("Signature should be 65 characters, not [%d]" % (len(sig), ))
|
||||
|
||||
recid = (_bord(sig[0]) - 27) & 3
|
||||
compressed = (_bord(sig[0]) - 27) & 4 != 0
|
||||
|
||||
cec_key = CECKey()
|
||||
cec_key.set_compressed(compressed)
|
||||
|
||||
sigR = sig[1:33]
|
||||
sigS = sig[33:65]
|
||||
|
||||
result = cec_key.recover(sigR, sigS, hash, len(hash), recid, 0)
|
||||
|
||||
if result < 1:
|
||||
return False
|
||||
|
||||
pubkey = cec_key.get_pubkey()
|
||||
|
||||
return pubkey
|
||||
|
||||
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" + num_to_var_int( len(message) ) + message
|
||||
|
||||
|
||||
def getMessagePubkey(message, sig):
|
||||
message = msg_magic(message)
|
||||
hash = hashlib.sha256(hashlib.sha256(message).digest()).digest()
|
||||
sig = base64.b64decode(sig)
|
||||
|
||||
pubkey = recover_compact(hash, sig)
|
||||
return pubkey
|
||||
|
||||
def test():
|
||||
sign = "HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ="
|
||||
pubkey = "044827c756561b8ef6b28b5e53a000805adbf4938ab82e1c2b7f7ea16a0d6face9a509a0a13e794d742210b00581f3e249ebcc705240af2540ea19591091ac1d41"
|
||||
assert getMessagePubkey("hello", sign).encode("hex") == pubkey
|
||||
|
||||
test() # Make sure it working right
|
||||
|
||||
if __name__ == "__main__":
|
||||
import time
|
||||
from pybitcointools import bitcoin as btctools
|
||||
priv = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk"
|
||||
address = "1N2XWu5soeppX2qUjvrf81rpdbShKJrjTr"
|
||||
sign = btctools.ecdsa_sign("hello", priv) # HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ=
|
||||
|
||||
s = time.time()
|
||||
for i in range(100):
|
||||
pubkey = getMessagePubkey("hello", sign)
|
||||
verified = btctools.pubkey_to_address(pubkey) == address
|
||||
print "100x Verified", verified, time.time()-s
|
|
@ -124,7 +124,9 @@ class Actions:
|
|||
|
||||
|
||||
def siteVerify(self, address):
|
||||
import time
|
||||
from Site import Site
|
||||
s = time.time()
|
||||
logging.info("Verifing site: %s..." % address)
|
||||
site = Site(address)
|
||||
|
||||
|
@ -138,7 +140,7 @@ class Actions:
|
|||
logging.info("Verifying site files...")
|
||||
bad_files = site.storage.verifyFiles()
|
||||
if not bad_files:
|
||||
logging.info("[OK] All file sha512sum matches!")
|
||||
logging.info("[OK] All file sha512sum matches! (%.3fs)" % (time.time()-s))
|
||||
else:
|
||||
logging.error("[ERROR] Error during verifying site files!")
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
def main():
|
||||
print " - Starting ZeroNet..."
|
||||
print "- Starting ZeroNet..."
|
||||
import sys, os
|
||||
try:
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) # Imports relative to src
|
||||
|
|
Loading…
Reference in a new issue