More docstrings and formatting fixes in highlevelcrypto and shutdown

This commit is contained in:
Dmitri Bogomolov 2019-11-04 13:30:11 +02:00
parent a7da0c0eff
commit d9fa6a94f4
Signed by untrusted user: g1itch
GPG Key ID: 720A756F18DEED13
2 changed files with 37 additions and 23 deletions

View File

@ -1,6 +1,10 @@
""" """
src/highlevelcrypto.py High level cryptographic functions based on `.pyelliptic` OpenSSL bindings.
======================
.. note::
Upstream pyelliptic was upgraded from SHA1 to SHA256 for signing.
We must upgrade PyBitmessage gracefully.
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
""" """
from binascii import hexlify from binascii import hexlify
@ -12,12 +16,13 @@ from pyelliptic import arithmetic as a
def makeCryptor(privkey): def makeCryptor(privkey):
"""Return a private pyelliptic.ECC() instance""" """Return a private `.pyelliptic.ECC` instance"""
private_key = a.changebase(privkey, 16, 256, minlen=32) private_key = a.changebase(privkey, 16, 256, minlen=32)
public_key = pointMult(private_key) public_key = pointMult(private_key)
privkey_bin = '\x02\xca\x00\x20' + private_key privkey_bin = '\x02\xca\x00\x20' + private_key
pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + public_key[-32:] pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + public_key[-32:]
cryptor = pyelliptic.ECC(curve='secp256k1', privkey=privkey_bin, pubkey=pubkey_bin) cryptor = pyelliptic.ECC(
curve='secp256k1', privkey=privkey_bin, pubkey=pubkey_bin)
return cryptor return cryptor
@ -29,7 +34,7 @@ def hexToPubkey(pubkey):
def makePubCryptor(pubkey): def makePubCryptor(pubkey):
"""Return a public pyelliptic.ECC() instance""" """Return a public `.pyelliptic.ECC` instance"""
pubkey_bin = hexToPubkey(pubkey) pubkey_bin = hexToPubkey(pubkey)
return pyelliptic.ECC(curve='secp256k1', pubkey=pubkey_bin) return pyelliptic.ECC(curve='secp256k1', pubkey=pubkey_bin)
@ -43,7 +48,8 @@ def privToPub(privkey):
def encrypt(msg, hexPubkey): def encrypt(msg, hexPubkey):
"""Encrypts message with hex public key""" """Encrypts message with hex public key"""
return pyelliptic.ECC(curve='secp256k1').encrypt(msg, hexToPubkey(hexPubkey)) return pyelliptic.ECC(curve='secp256k1').encrypt(
msg, hexToPubkey(hexPubkey))
def decrypt(msg, hexPrivkey): def decrypt(msg, hexPrivkey):
@ -52,36 +58,38 @@ def decrypt(msg, hexPrivkey):
def decryptFast(msg, cryptor): def decryptFast(msg, cryptor):
"""Decrypts message with an existing pyelliptic.ECC.ECC object""" """Decrypts message with an existing `.pyelliptic.ECC` object"""
return cryptor.decrypt(msg) return cryptor.decrypt(msg)
def sign(msg, hexPrivkey): def sign(msg, hexPrivkey):
"""Signs with hex private key""" """
# pyelliptic is upgrading from SHA1 to SHA256 for signing. We must Signs with hex private key using SHA1 or SHA256 depending on
# upgrade PyBitmessage gracefully. "digestalg" setting
# https://github.com/yann2192/pyelliptic/pull/33 """
# More discussion: https://github.com/yann2192/pyelliptic/issues/32 digestAlg = BMConfigParser().safeGet(
digestAlg = BMConfigParser().safeGet('bitmessagesettings', 'digestalg', 'sha1') 'bitmessagesettings', 'digestalg', 'sha1')
if digestAlg == "sha1": if digestAlg == "sha1":
# SHA1, this will eventually be deprecated # SHA1, this will eventually be deprecated
return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) return makeCryptor(hexPrivkey).sign(
msg, digest_alg=OpenSSL.digest_ecdsa_sha1)
elif digestAlg == "sha256": elif digestAlg == "sha256":
# SHA256. Eventually this will become the default # SHA256. Eventually this will become the default
return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256)
else: else:
raise ValueError("Unknown digest algorithm %s" % (digestAlg)) raise ValueError("Unknown digest algorithm %s" % digestAlg)
def verify(msg, sig, hexPubkey): def verify(msg, sig, hexPubkey):
"""Verifies with hex public key""" """Verifies with hex public key using SHA1 or SHA256"""
# As mentioned above, we must upgrade gracefully to use SHA256. So # As mentioned above, we must upgrade gracefully to use SHA256. So
# let us check the signature using both SHA1 and SHA256 and if one # let us check the signature using both SHA1 and SHA256 and if one
# of them passes then we will be satisfied. Eventually this can # of them passes then we will be satisfied. Eventually this can
# be simplified and we'll only check with SHA256. # be simplified and we'll only check with SHA256.
try: try:
# old SHA1 algorithm. # old SHA1 algorithm.
sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig, msg, digest_alg=OpenSSL.digest_ecdsa_sha1) sigVerifyPassed = makePubCryptor(hexPubkey).verify(
sig, msg, digest_alg=OpenSSL.digest_ecdsa_sha1)
except: except:
sigVerifyPassed = False sigVerifyPassed = False
if sigVerifyPassed: if sigVerifyPassed:
@ -89,7 +97,8 @@ def verify(msg, sig, hexPubkey):
return True return True
# The signature check using SHA1 failed. Let us try it with SHA256. # The signature check using SHA1 failed. Let us try it with SHA256.
try: try:
return makePubCryptor(hexPubkey).verify(sig, msg, digest_alg=OpenSSL.EVP_sha256) return makePubCryptor(hexPubkey).verify(
sig, msg, digest_alg=OpenSSL.EVP_sha256)
except: except:
return False return False
@ -106,7 +115,8 @@ def pointMult(secret):
""" """
while True: while True:
try: try:
k = OpenSSL.EC_KEY_new_by_curve_name(OpenSSL.get_curve('secp256k1')) k = OpenSSL.EC_KEY_new_by_curve_name(
OpenSSL.get_curve('secp256k1'))
priv_key = OpenSSL.BN_bin2bn(secret, 32, None) priv_key = OpenSSL.BN_bin2bn(secret, 32, None)
group = OpenSSL.EC_KEY_get0_group(k) group = OpenSSL.EC_KEY_get0_group(k)
pub_key = OpenSSL.EC_POINT_new(group) pub_key = OpenSSL.EC_POINT_new(group)

View File

@ -16,7 +16,9 @@ from queues import (
def doCleanShutdown(): def doCleanShutdown():
"""Used to tell proof of work worker threads and the objectProcessorThread to exit.""" """
Used to tell all the treads to finish work and exit.
"""
state.shutdown = 1 state.shutdown = 1
objectProcessorQueue.put(('checkShutdownVariable', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data'))
@ -52,9 +54,11 @@ def doCleanShutdown():
time.sleep(.25) time.sleep(.25)
for thread in threading.enumerate(): for thread in threading.enumerate():
if (thread is not threading.currentThread() and if (
isinstance(thread, StoppableThread) and thread is not threading.currentThread()
thread.name != 'SQL'): and isinstance(thread, StoppableThread)
and thread.name != 'SQL'
):
logger.debug("Waiting for thread %s", thread.name) logger.debug("Waiting for thread %s", thread.name)
thread.join() thread.join()