From 0a9a9b5a575db6b30c279393f92c508e29d761db Mon Sep 17 00:00:00 2001 From: Ivanq Date: Mon, 30 Mar 2020 09:16:12 +0300 Subject: [PATCH] Support compressed keys --- plugins/CryptMessage/CryptMessage.py | 2 +- plugins/CryptMessage/CryptMessagePlugin.py | 6 ++--- src/Crypt/CryptBitcoin.py | 3 +-- src/lib/sslcrypto/_ecc.py | 31 +++++++++++++++++----- src/lib/sslcrypto/openssl/ecc.py | 2 +- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/plugins/CryptMessage/CryptMessage.py b/plugins/CryptMessage/CryptMessage.py index 74659404..8349809c 100644 --- a/plugins/CryptMessage/CryptMessage.py +++ b/plugins/CryptMessage/CryptMessage.py @@ -32,7 +32,7 @@ def eciesDecryptMulti(encrypted_datas, privatekey): def eciesDecrypt(ciphertext, privatekey): - return curve.decrypt(base64.b64decode(ciphertext), curve.wif_to_private(privatekey), derivation="sha512") + return curve.decrypt(base64.b64decode(ciphertext), curve.wif_to_private(privatekey.encode()), derivation="sha512") def decodePubkey(pubkey): diff --git a/plugins/CryptMessage/CryptMessagePlugin.py b/plugins/CryptMessage/CryptMessagePlugin.py index 150bf8be..7c24f730 100644 --- a/plugins/CryptMessage/CryptMessagePlugin.py +++ b/plugins/CryptMessage/CryptMessagePlugin.py @@ -110,7 +110,7 @@ class UiWebsocketPlugin(object): # Gets the publickey of a given privatekey def actionEccPrivToPub(self, to, privatekey): - self.response(to, curve.private_to_public(curve.wif_to_private(privatekey))) + self.response(to, curve.private_to_public(curve.wif_to_private(privatekey.encode()))) # Gets the address of a given publickey def actionEccPubToAddr(self, to, publickey): @@ -149,8 +149,8 @@ class UserPlugin(object): index = param_index if "encrypt_publickey_%s" % index not in site_data: - privatekey = self.getEncryptPrivatekey(address, param_index) - publickey = curve.private_to_public(curve.wif_to_private(privatekey)) + privatekey = self.getEncryptPrivatekey(address, param_index).encode() + publickey = curve.private_to_public(curve.wif_to_private(privatekey) + b"\x01") site_data["encrypt_publickey_%s" % index] = base64.b64encode(publickey).decode("utf8") return site_data["encrypt_publickey_%s" % index] diff --git a/src/Crypt/CryptBitcoin.py b/src/Crypt/CryptBitcoin.py index ae34141f..c81999dd 100644 --- a/src/Crypt/CryptBitcoin.py +++ b/src/Crypt/CryptBitcoin.py @@ -60,7 +60,7 @@ def privatekeyToAddress(privatekey): # Return address from private key privatekey_bin = bytes.fromhex(privatekey) else: privatekey_bin = sslcurve.wif_to_private(privatekey.encode()) - return sslcurve.private_to_address(privatekey_bin, is_compressed=False).decode() + return sslcurve.private_to_address(privatekey_bin).decode() except Exception: # Invalid privatekey return False @@ -71,7 +71,6 @@ def sign(data, privatekey): # Return sign to data using private key return base64.b64encode(sslcurve.sign( data.encode(), sslcurve.wif_to_private(privatekey.encode()), - is_compressed=False, recoverable=True, hash=dbl_format )).decode() diff --git a/src/lib/sslcrypto/_ecc.py b/src/lib/sslcrypto/_ecc.py index 3dbc56cd..88e04576 100644 --- a/src/lib/sslcrypto/_ecc.py +++ b/src/lib/sslcrypto/_ecc.py @@ -296,11 +296,18 @@ class EllipticCurve: return x, y - def new_private_key(self): - return self._backend.new_private_key() + def new_private_key(self, is_compressed=False): + return self._backend.new_private_key() + (b"\x01" if is_compressed else b"") - def private_to_public(self, private_key, is_compressed=True): + def private_to_public(self, private_key): + if len(private_key) == self._backend.public_key_length: + is_compressed = False + elif len(private_key) == self._backend.public_key_length + 1 and private_key[-1] == 1: + is_compressed = True + private_key = private_key[:-1] + else: + raise ValueError("Private key has invalid length") x, y = self._backend.private_to_public(private_key) return self._encode_public_key(x, y, is_compressed=is_compressed) @@ -322,12 +329,16 @@ class EllipticCurve: return base58.b58encode_check(b"\x00" + hash160) - def private_to_address(self, private_key, is_compressed=True): + def private_to_address(self, private_key): # Kinda useless but left for quick migration from pybitcointools - return self.public_to_address(self.private_to_public(private_key, is_compressed=is_compressed)) + return self.public_to_address(self.private_to_public(private_key)) def derive(self, private_key, public_key): + if len(private_key) == self._backend.public_key_length + 1 and private_key[-1] == 1: + private_key = private_key[:-1] + if len(private_key) != self._backend.public_key_length: + raise ValueError("Private key has invalid length") if not isinstance(public_key, tuple): public_key = self._decode_public_key(public_key) return self._backend.ecdh(private_key, public_key) @@ -447,7 +458,15 @@ class EllipticCurve: return self._aes.decrypt(ciphertext, iv, k_enc, algo=algo) - def sign(self, data, private_key, hash="sha256", recoverable=False, is_compressed=True, entropy=None): + def sign(self, data, private_key, hash="sha256", recoverable=False, entropy=None): + if len(private_key) == self._backend.public_key_length: + is_compressed = False + elif len(private_key) == self._backend.public_key_length + 1 and private_key[-1] == 1: + is_compressed = True + private_key = private_key[:-1] + else: + raise ValueError("Private key has invalid length") + data = self._digest(data, hash) if not entropy: v = b"\x01" * len(data) diff --git a/src/lib/sslcrypto/openssl/ecc.py b/src/lib/sslcrypto/openssl/ecc.py index f9271e43..c667be8a 100644 --- a/src/lib/sslcrypto/openssl/ecc.py +++ b/src/lib/sslcrypto/openssl/ecc.py @@ -311,7 +311,7 @@ class EllipticCurveBackend: # To big integer private_key = BN(lib.EC_KEY_get0_private_key(eckey), link_only=True) # To binary - private_key_buf = private_key.bytes() + private_key_buf = private_key.bytes(self.public_key_length) # Cleanup lib.EC_KEY_free(eckey) return private_key_buf