Permalink
Cannot retrieve contributors at this time
| """ | |
| 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. <https://github.com/Bitmessage/PyBitmessage/issues/953>`_ | |
| `More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_ | |
| """ | |
| from binascii import hexlify | |
| import pyelliptic | |
| from bmconfigparser import BMConfigParser | |
| from pyelliptic import OpenSSL | |
| from pyelliptic import arithmetic as a | |
| def makeCryptor(privkey): | |
| """Return a private `.pyelliptic.ECC` instance""" | |
| private_key = a.changebase(privkey, 16, 256, minlen=32) | |
| public_key = pointMult(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:] | |
| cryptor = pyelliptic.ECC( | |
| curve='secp256k1', privkey=privkey_bin, pubkey=pubkey_bin) | |
| return cryptor | |
| def hexToPubkey(pubkey): | |
| """Convert a pubkey from hex to binary""" | |
| pubkey_raw = a.changebase(pubkey[2:], 16, 256, minlen=64) | |
| pubkey_bin = '\x02\xca\x00 ' + pubkey_raw[:32] + '\x00 ' + pubkey_raw[32:] | |
| return pubkey_bin | |
| def makePubCryptor(pubkey): | |
| """Return a public `.pyelliptic.ECC` instance""" | |
| pubkey_bin = hexToPubkey(pubkey) | |
| return pyelliptic.ECC(curve='secp256k1', pubkey=pubkey_bin) | |
| def privToPub(privkey): | |
| """Converts hex private key into hex public key""" | |
| private_key = a.changebase(privkey, 16, 256, minlen=32) | |
| public_key = pointMult(private_key) | |
| return hexlify(public_key) | |
| def encrypt(msg, hexPubkey): | |
| """Encrypts message with hex public key""" | |
| return pyelliptic.ECC(curve='secp256k1').encrypt( | |
| msg, hexToPubkey(hexPubkey)) | |
| def decrypt(msg, hexPrivkey): | |
| """Decrypts message with hex private key""" | |
| return makeCryptor(hexPrivkey).decrypt(msg) | |
| def decryptFast(msg, cryptor): | |
| """Decrypts message with an existing `.pyelliptic.ECC` object""" | |
| return cryptor.decrypt(msg) | |
| def sign(msg, hexPrivkey): | |
| """ | |
| Signs with hex private key using SHA1 or SHA256 depending on | |
| "digestalg" setting | |
| """ | |
| digestAlg = BMConfigParser().safeGet( | |
| 'bitmessagesettings', 'digestalg', 'sha256') | |
| if digestAlg == "sha1": | |
| # SHA1, this will eventually be deprecated | |
| return makeCryptor(hexPrivkey).sign( | |
| msg, digest_alg=OpenSSL.digest_ecdsa_sha1) | |
| elif digestAlg == "sha256": | |
| # SHA256. Eventually this will become the default | |
| return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) | |
| else: | |
| raise ValueError("Unknown digest algorithm %s" % digestAlg) | |
| def verify(msg, sig, hexPubkey): | |
| """Verifies with hex public key using SHA1 or SHA256""" | |
| # As mentioned above, we must upgrade gracefully to use SHA256. So | |
| # let us check the signature using both SHA1 and SHA256 and if one | |
| # of them passes then we will be satisfied. Eventually this can | |
| # be simplified and we'll only check with SHA256. | |
| try: | |
| # old SHA1 algorithm. | |
| sigVerifyPassed = makePubCryptor(hexPubkey).verify( | |
| sig, msg, digest_alg=OpenSSL.digest_ecdsa_sha1) | |
| except: | |
| sigVerifyPassed = False | |
| if sigVerifyPassed: | |
| # The signature check passed using SHA1 | |
| return True | |
| # The signature check using SHA1 failed. Let us try it with SHA256. | |
| try: | |
| return makePubCryptor(hexPubkey).verify( | |
| sig, msg, digest_alg=OpenSSL.EVP_sha256) | |
| except: | |
| return False | |
| def pointMult(secret): | |
| """ | |
| Does an EC point multiplication; turns a private key into a public key. | |
| Evidently, this type of error can occur very rarely: | |
| >>> File "highlevelcrypto.py", line 54, in pointMult | |
| >>> group = OpenSSL.EC_KEY_get0_group(k) | |
| >>> WindowsError: exception: access violation reading 0x0000000000000008 | |
| """ | |
| while True: | |
| try: | |
| k = OpenSSL.EC_KEY_new_by_curve_name( | |
| OpenSSL.get_curve('secp256k1')) | |
| priv_key = OpenSSL.BN_bin2bn(secret, 32, None) | |
| group = OpenSSL.EC_KEY_get0_group(k) | |
| pub_key = OpenSSL.EC_POINT_new(group) | |
| OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) | |
| OpenSSL.EC_KEY_set_private_key(k, priv_key) | |
| OpenSSL.EC_KEY_set_public_key(k, pub_key) | |
| size = OpenSSL.i2o_ECPublicKey(k, None) | |
| mb = OpenSSL.create_string_buffer(size) | |
| OpenSSL.i2o_ECPublicKey(k, OpenSSL.byref(OpenSSL.pointer(mb))) | |
| OpenSSL.EC_POINT_free(pub_key) | |
| OpenSSL.BN_free(priv_key) | |
| OpenSSL.EC_KEY_free(k) | |
| return mb.raw | |
| except Exception: | |
| import traceback | |
| import time | |
| traceback.print_exc() | |
| time.sleep(0.2) |