From adb09cd8ca79d1906843c915bb48cfde978c266c Mon Sep 17 00:00:00 2001 From: BTChip Date: Sun, 31 Jul 2016 10:00:46 +0200 Subject: [PATCH] Ledger integration --- trezor_agent/factory.py | 137 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/trezor_agent/factory.py b/trezor_agent/factory.py index 43536b8..422db2c 100644 --- a/trezor_agent/factory.py +++ b/trezor_agent/factory.py @@ -76,10 +76,145 @@ def _load_keepkey(): except ImportError: log.exception('Missing module: install via "pip install keepkey"') +def _load_ledger(): + import struct + class LedgerClientConnection(object): + def __init__(self, dongle): + self.dongle = dongle + + def expand_path(self, path): + result = "" + for pathElement in path: + result = result + struct.pack(">I", pathElement) + return result + + def get_public_node(self, n, ecdsa_curve_name="secp256k1", show_display=False): + from trezorlib.messages_pb2 import PublicKey + donglePath = self.expand_path(n) + if ecdsa_curve_name == "nist256p1": + p2 = "01" + else: + p2 = "02" + apdu = "800200" + p2 + apdu = apdu.decode('hex') + chr(len(donglePath) + 1) + chr(len(donglePath) / 4) + donglePath + result = bytearray(self.dongle.exchange(bytes(apdu)))[1:] + if ecdsa_curve_name == "nist256p1": + if ((result[64] & 1) <> 0): + result = bytearray([0x03]) + result[1:33] + else: + result = bytearray([0x02]) + result[1:33] + else: + #TODO + #result = result[1:] + #keyY = bytearray(result[32:][::-1]) + #keyY = bytearray(result[32:]) + #if ((keyX[31] & 1)<>0): + # keyY[31] |= 0x80 + #result = chr(0) + str(keyY) + result = chr(0) + result[1:33] + publicKey = PublicKey() + publicKey.node.public_key = str(result) + return publicKey + + def sign_identity(self, identity, challenge_hidden, challenge_visual, ecdsa_curve_name="secp256k1"): + from trezor_agent import client + from trezorlib.messages_pb2 import SignedIdentity + import hashlib + n = client.get_address(identity) + donglePath = self.expand_path(n) + if identity.proto == 'ssh': + ins = "04" + p1 = "00" + publicKey = self.get_public_node(n, ecdsa_curve_name) + else: + ins = "08" + p1 = "00" + if ecdsa_curve_name == "nist256p1": + p2 = "01" + else: + p2 = "02" + apdu = "80" + ins + p1 + p2 + apdu = apdu.decode('hex') + chr(len(challenge_hidden) + len(donglePath) + 1) + apdu = apdu + chr(len(donglePath) / 4) + donglePath + apdu = apdu + challenge_hidden + result = bytearray(self.dongle.exchange(bytes(apdu))) + if ecdsa_curve_name == "nist256p1": + offset = 3 + rLength = result[offset] + r = result[offset + 1 : offset + 1 + rLength] + if r[0] == 0: + r = r[1:] + offset = offset + 1 + rLength + 1 + sLength = result[offset] + s = result[offset + 1 : offset + 1 + sLength] + if s[0] == 0: + s = s[1:] + signature = SignedIdentity() + signature.signature = chr(0) + str(r) + str(s) + if identity.proto == 'ssh': + signature.public_key = publicKey.node.public_key + return signature + else: + signature = SignedIdentity() + signature.signature = chr(0) + str(result) + if identity.proto == 'ssh': + signature.public_key = publicKey.node.public_key + return signature + pass + + def get_ecdh_session_key(self, identity, peer_public_key, ecdsa_curve_name="secp256k1"): + from trezor_agent import client + from trezorlib.messages_pb2 import ECDHSessionKey + n = client.get_address(identity, True) + donglePath = self.expand_path(n) + if ecdsa_curve_name == "nist256p1": + p2 = "01" + else: + p2 = "02" + apdu = "800a00" + p2 + apdu = apdu.decode('hex') + chr(len(peer_public_key) + len(donglePath) + 1) + apdu = apdu + chr(len(donglePath) / 4) + donglePath + apdu = apdu + peer_public_key + result = bytearray(self.dongle.exchange(bytes(apdu))) + if ecdsa_curve_name == "nist256p1": + sessionKey = ECDHSessionKey() + sessionKey.session_key = str(result) + return sessionKey + pass + + def clear_session(self): + pass + + def close(self): + self.dongle.close() + pass + + def ping(self, msg, button_protection=False, pin_protection=False, passphrase_protection=False): + return msg + + class CallException(Exception): + def __init__(self, code, message): + super(CallException, self).__init__() + self.args = [code, message] + try: + from ledgerblue.comm import getDongle + from ledgerblue.commException import CommException + except ImportError: + log.exception('Missing module: install via "pip install ledgerblue"') + try: + from trezorlib.types_pb2 import IdentityType + dongle = getDongle(True) + except: + return + yield ClientWrapper(connection=LedgerClientConnection(dongle), + identity_type=IdentityType, + device_name="ledger", + call_exception=CallException) LOADERS = [ _load_trezor, - _load_keepkey + _load_keepkey, + _load_ledger ]