Fix eddsa, SSH optimization with signature + key, cleanup

nistp521
BTChip 8 years ago
parent 8fe16d24c2
commit bc1d7a5448

@ -1,4 +1,4 @@
"""Thin wrapper around trezor/keepkey libraries."""
"""Thin wrapper around trezor/keepkey/ledger libraries."""
import binascii
import collections
import logging
@ -82,114 +82,127 @@ def _load_ledger():
def __init__(self, dongle):
self.dongle = dongle
def expand_path(self, path):
@staticmethod
def expand_path(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):
@staticmethod
def convert_public_key(ecdsa_curve_name, result):
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):
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]
result = result[1:]
keyX = bytearray(result[0:32])
keyY = bytearray(result[32:][::-1])
if (keyX[31] & 1) <> 0:
keyY[31] |= 0x80
result = chr(0) + str(keyY)
publicKey = PublicKey()
publicKey.node.public_key = str(result)
return publicKey
def sign_identity(self, identity, challenge_hidden, challenge_visual, ecdsa_curve_name="secp256k1"):
# pylint: disable=unused-argument
def get_public_node(self, n, ecdsa_curve_name="secp256k1", show_display=False):
donglePath = LedgerClientConnection.expand_path(n)
if ecdsa_curve_name == "nist256p1":
p2 = "01"
else:
p2 = "02"
apdu = "800200" + p2
apdu = apdu.decode('hex')
apdu += chr(len(donglePath) + 1) + chr(len(donglePath) / 4)
apdu += donglePath
result = bytearray(self.dongle.exchange(bytes(apdu)))[1:]
return LedgerClientConnection.convert_public_key(ecdsa_curve_name, result)
# pylint: disable=too-many-locals
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)
donglePath = LedgerClientConnection.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"
p1 = "00"
if ecdsa_curve_name == "nist256p1":
p2 = "01"
p2 = "81" if identity.proto == 'ssh' else "01"
else:
p2 = "02"
p2 = "82" if identity.proto == 'ssh' else "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
apdu = apdu.decode('hex')
apdu += chr(len(challenge_hidden) + len(donglePath) + 1)
apdu += chr(len(donglePath) / 4) + donglePath
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]
length = result[offset]
r = result[offset + 1 : offset + 1 + length]
if r[0] == 0:
r = r[1:]
offset = offset + 1 + rLength + 1
sLength = result[offset]
s = result[offset + 1 : offset + 1 + sLength]
offset = offset + 1 + length + 1
length = result[offset]
s = result[offset + 1 : offset + 1 + length]
if s[0] == 0:
s = s[1:]
offset = offset + 1 + length
signature = SignedIdentity()
signature.signature = chr(0) + str(r) + str(s)
if identity.proto == 'ssh':
signature.public_key = publicKey.node.public_key
keyData = result[offset:]
pk = LedgerClientConnection.convert_public_key(ecdsa_curve_name, keyData)
signature.public_key = pk.node.public_key
return signature
else:
signature = SignedIdentity()
signature.signature = chr(0) + str(result)
signature.signature = chr(0) + str(result[0:64])
if identity.proto == 'ssh':
signature.public_key = publicKey.node.public_key
return signature
pass
keyData = result[64:]
pk = LedgerClientConnection.convert_public_key(ecdsa_curve_name, keyData)
signature.public_key = pk.node.public_key
return signature
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)
donglePath = LedgerClientConnection.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
apdu = apdu.decode('hex')
apdu += chr(len(peer_public_key) + len(donglePath) + 1)
apdu += chr(len(donglePath) / 4) + donglePath
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
sessionKey = ECDHSessionKey()
sessionKey.session_key = str(result)
return sessionKey
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):
# pylint: disable=unused-argument
# pylint: disable=no-self-use
def ping(self, msg, button_protection=False, pin_protection=False,
passphrase_protection=False):
return msg
class CallException(Exception):
@ -198,9 +211,9 @@ def _load_ledger():
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"')
# pylint: disable=bare-except
try:
from trezorlib.types_pb2 import IdentityType
dongle = getDongle(True)

Loading…
Cancel
Save