Skip to content

Commit

Permalink
Python 3 support WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
BTChip github committed Aug 12, 2017
1 parent a08f018 commit 6d82fba
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 92 deletions.
4 changes: 2 additions & 2 deletions btchip/bitcoinTransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
********************************************************************************
"""

from bitcoinVarint import *
from .bitcoinVarint import *
from binascii import hexlify

class bitcoinInput:
Expand Down Expand Up @@ -95,7 +95,7 @@ def __init__(self, data=None):
offset = 0
self.version = data[offset:offset + 4]
offset += 4
if (data[offset] == 0) and (data[offset + 1] <> 0):
if (data[offset] == 0) and (data[offset + 1] != 0):
offset += 2
self.witness = True
inputSize = readVarint(data, offset)
Expand Down
2 changes: 1 addition & 1 deletion btchip/bitcoinVarint.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
********************************************************************************
"""

from btchipException import BTChipException
from .btchipException import BTChipException

def readVarint(buffer, offset):
varintSize = 0
Expand Down
72 changes: 41 additions & 31 deletions btchip/btchip.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
********************************************************************************
"""

from btchipComm import *
from bitcoinTransaction import *
from bitcoinVarint import *
from btchipException import *
from btchipHelpers import *
from btchipKeyRecovery import *
from binascii import hexlify
from .btchipComm import *
from .bitcoinTransaction import *
from .bitcoinVarint import *
from .btchipException import *
from .btchipHelpers import *
from .btchipKeyRecovery import *
from binascii import hexlify, unhexlify

class btchip:
BTCHIP_CLA = 0xe0
Expand Down Expand Up @@ -71,9 +71,9 @@ class btchip:
FEATURE_FREE_SIGHASHTYPE = 0x04
FEATURE_NO_2FA_P2SH = 0x08

QWERTY_KEYMAP = bytearray("000000000000000000000000760f00d4ffffffc7000000782c1e3420212224342627252e362d3738271e1f202122232425263333362e37381f0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2f3130232d350405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2f313035".decode('hex'))
QWERTZ_KEYMAP = bytearray("000000000000000000000000760f00d4ffffffc7000000782c1e3420212224342627252e362d3738271e1f202122232425263333362e37381f0405060708090a0b0c0d0e0f101112131415161718191a1b1d1c2f3130232d350405060708090a0b0c0d0e0f101112131415161718191a1b1d1c2f313035".decode('hex'))
AZERTY_KEYMAP = bytearray("08000000010000200100007820c8ffc3feffff07000000002c38202030341e21222d352e102e3637271e1f202122232425263736362e37101f1405060708090a0b0c0d0e0f331112130415161718191d1b1c1a2f64302f2d351405060708090a0b0c0d0e0f331112130415161718191d1b1c1a2f643035".decode('hex'))
QWERTY_KEYMAP = bytearray(unhexlify("000000000000000000000000760f00d4ffffffc7000000782c1e3420212224342627252e362d3738271e1f202122232425263333362e37381f0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2f3130232d350405060708090a0b0c0d0e0f101112131415161718191a1b1c1d2f313035"))
QWERTZ_KEYMAP = bytearray(unhexlify("000000000000000000000000760f00d4ffffffc7000000782c1e3420212224342627252e362d3738271e1f202122232425263333362e37381f0405060708090a0b0c0d0e0f101112131415161718191a1b1d1c2f3130232d350405060708090a0b0c0d0e0f101112131415161718191a1b1d1c2f313035"))
AZERTY_KEYMAP = bytearray(unhexlify("08000000010000200100007820c8ffc3feffff07000000002c38202030341e21222d352e102e3637271e1f202122232425263736362e37101f1405060708090a0b0c0d0e0f331112130415161718191d1b1c1a2f64302f2d351405060708090a0b0c0d0e0f331112130415161718191d1b1c1a2f643035"))

def __init__(self, dongle):
self.dongle = dongle
Expand All @@ -98,6 +98,8 @@ def setAlternateCoinVersion(self, versionRegular, versionP2SH):
self.dongle.exchange(bytearray(apdu))

def verifyPin(self, pin):
if isinstance(pin, str):
pin = pin.encode('utf-8')
apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_VERIFY_PIN, 0x00, 0x00, len(pin) ]
apdu.extend(bytearray(pin))
self.dongle.exchange(bytearray(apdu))
Expand All @@ -107,7 +109,7 @@ def getVerifyPinRemainingAttempts(self):
apdu.extend(bytearray("0"))
try:
self.dongle.exchange(bytearray(apdu))
except BTChipException, e:
except BTChipException as e:
if ((e.sw & 0xfff0) == 0x63c0):
return e.sw - 0x63c0
raise e
Expand Down Expand Up @@ -235,7 +237,7 @@ def startUntrustedTransaction(self, newTransaction, inputIndex, outputList, rede
if ('trustedInput' in passedOutput) and passedOutput['trustedInput']:
params.append(len(passedOutput['value']))
params.extend(passedOutput['value'])
if currentIndex <> inputIndex:
if currentIndex != inputIndex:
script = bytearray()
writeVarint(len(script), params)
if len(script) == 0:
Expand Down Expand Up @@ -270,7 +272,7 @@ def finalizeInput(self, outputAddress, amount, fees, changePath, rawTx=None):
try:
fullTx = bitcoinTransaction(bytearray(rawTx))
outputs = fullTx.serializeOutputs()
if len(donglePath) <> 0:
if len(donglePath) != 0:
apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_HASH_INPUT_FINALIZE_FULL, 0xFF, 0x00 ]
params = []
params.extend(donglePath)
Expand Down Expand Up @@ -305,7 +307,7 @@ def finalizeInput(self, outputAddress, amount, fees, changePath, rawTx=None):
apdu.append(len(params))
apdu.extend(params)
response = self.dongle.exchange(bytearray(apdu))
result['confirmationNeeded'] = response[1 + response[0]] <> 0x00
result['confirmationNeeded'] = response[1 + response[0]] != 0x00
result['confirmationType'] = response[1 + response[0]]
if result['confirmationType'] == 0x02:
result['keycardData'] = response[1 + response[0] + 1:]
Expand All @@ -329,7 +331,7 @@ def finalizeInput(self, outputAddress, amount, fees, changePath, rawTx=None):
def finalizeInputFull(self, outputData):
result = {}
offset = 0
encryptedOutputData = ""
encryptedOutputData = b""
while (offset < len(outputData)):
blockLength = self.scriptBlockLength
if ((offset + blockLength) < len(outputData)):
Expand All @@ -345,11 +347,11 @@ def finalizeInputFull(self, outputData):
encryptedOutputData = encryptedOutputData + response[1 : 1 + response[0]]
offset += dataLength
if len(response) > 1:
result['confirmationNeeded'] = response[1 + response[0]] <> 0x00
result['confirmationNeeded'] = response[1 + response[0]] != 0x00
result['confirmationType'] = response[1 + response[0]]
else:
# Support for old style API before 1.0.2
result['confirmationNeeded'] = response[0] <> 0x00
result['confirmationNeeded'] = response[0] != 0x00
result['confirmationType'] = response[0]
if result['confirmationType'] == 0x02:
result['keycardData'] = response[1 + response[0] + 1:] # legacy
Expand All @@ -368,6 +370,8 @@ def finalizeInputFull(self, outputData):
return result

def untrustedHashSign(self, path, pin="", lockTime=0, sighashType=0x01):
if isinstance(pin, str):
pin = pin.encode('utf-8')
donglePath = parse_bip32_path(path)
if self.needKeyCache:
self.resolvePublicKeysInPath(path)
Expand Down Expand Up @@ -397,7 +401,7 @@ def signMessagePrepareV1(self, path, message):
apdu.append(len(params))
apdu.extend(params)
response = self.dongle.exchange(bytearray(apdu))
result['confirmationNeeded'] = response[0] <> 0x00
result['confirmationNeeded'] = response[0] != 0x00
result['confirmationType'] = response[0]
if result['confirmationType'] == 0x02:
result['keycardData'] = response[1:]
Expand Down Expand Up @@ -433,7 +437,7 @@ def signMessagePrepareV2(self, path, message):
response = self.dongle.exchange(bytearray(apdu))
encryptedOutputData = encryptedOutputData + response[1 : 1 + response[0]]
offset += blockLength
result['confirmationNeeded'] = response[1 + response[0]] <> 0x00
result['confirmationNeeded'] = response[1 + response[0]] != 0x00
result['confirmationType'] = response[1 + response[0]]
if result['confirmationType'] == 0x03:
offset = 1 + response[0] + 1
Expand All @@ -453,6 +457,8 @@ def signMessagePrepare(self, path, message):
return result

def signMessageSign(self, pin=""):
if isinstance(pin, str):
pin = pin.encode('utf-8')
apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_SIGN_MESSAGE, 0x80, 0x00 ]
params = []
if pin is not None:
Expand All @@ -466,12 +472,16 @@ def signMessageSign(self, pin=""):
return response

def setup(self, operationModeFlags, featuresFlag, keyVersion, keyVersionP2SH, userPin, wipePin, keymapEncoding, seed=None, developerKey=None):
if isinstance(userPin, str):
userPin = userPin.encode('utf-8')
result = {}
apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_SETUP, 0x00, 0x00 ]
params = [ operationModeFlags, featuresFlag, keyVersion, keyVersionP2SH ]
params.append(len(userPin))
params.extend(bytearray(userPin))
if wipePin is not None:
if isinstance(wipePin, str):
wipePin = wipePin.encode('utf-8')
params.append(len(wipePin))
params.extend(bytearray(wipePin))
else:
Expand Down Expand Up @@ -526,10 +536,10 @@ def getOperationMode(self):
return response[0]

def setOperationMode(self, operationMode):
if operationMode <> btchip.OPERATION_MODE_WALLET \
and operationMode <> btchip.OPERATION_MODE_RELAXED_WALLET \
and operationMode <> btchip.OPERATION_MODE_SERVER \
and operationMode <> btchip.OPERATION_MODE_DEVELOPER:
if operationMode != btchip.OPERATION_MODE_WALLET \
and operationMode != btchip.OPERATION_MODE_RELAXED_WALLET \
and operationMode != btchip.OPERATION_MODE_SERVER \
and operationMode != btchip.OPERATION_MODE_DEVELOPER:
raise BTChipException("Invalid operation mode")
apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_SET_OPERATION_MODE, 0x00, 0x00, 0x01, operationMode ]
self.dongle.exchange(bytearray(apdu))
Expand Down Expand Up @@ -576,9 +586,9 @@ def getPOSEncryptedSeed(self):

def importPrivateKey(self, data, isSeed=False):
apdu = [ self.BTCHIP_CLA, self.BTCHIP_INS_IMPORT_PRIVATE_KEY, (0x02 if isSeed else 0x01), 0x00 ]
apdu.append(len(data))
apdu.extend(data)
return self.dongle.exchange(bytearray(apdu))
apdu.append(len(data))
apdu.extend(data)
return self.dongle.exchange(bytearray(apdu))

def getPublicKey(self, encodedPrivateKey):
result = {}
Expand All @@ -587,9 +597,9 @@ def getPublicKey(self, encodedPrivateKey):
apdu.append(len(encodedPrivateKey))
apdu.extend(encodedPrivateKey)
response = self.dongle.exchange(bytearray(apdu))
offset = 1
result['publicKey'] = response[offset + 1 : offset + 1 + response[offset]]
offset = offset + 1 + response[offset]
offset = 1
result['publicKey'] = response[offset + 1 : offset + 1 + response[offset]]
offset = offset + 1 + response[offset]
if response[0] == 0x02:
result['chainCode'] = response[offset : offset + 32]
offset = offset + 32
Expand Down Expand Up @@ -678,7 +688,7 @@ def resolvePublicKeysInPath(self, path):
startOffset = offset
break
offset = offset + 1
if startOffset <> 0:
if startOffset != 0:
searchPath = splitPath[0:startOffset - 1]
offset = startOffset - 1
while(offset < len(splitPath)):
Expand All @@ -691,5 +701,5 @@ def getJCExtendedFeatures(self):
result = {}
apdu = [ self.BTCHIP_JC_EXT_CLA, self.BTCHIP_INS_EXT_CACHE_GET_FEATURES, 0x00, 0x00, 0x00 ]
response = self.dongle.exchange(bytearray(apdu))
result['proprietaryApi'] = ((response[0] & 0x01) <> 0)
result['proprietaryApi'] = ((response[0] & 0x01) != 0)
return result
20 changes: 10 additions & 10 deletions btchip/btchipComm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"""

from abc import ABCMeta, abstractmethod
from btchipException import *
from ledgerWrapper import wrapCommandAPDU, unwrapResponseAPDU
from .btchipException import *
from .ledgerWrapper import wrapCommandAPDU, unwrapResponseAPDU
from binascii import hexlify
import hid
import time
Expand Down Expand Up @@ -64,15 +64,15 @@ def __init__(self, device, ledger=False, debug=False):

def exchange(self, apdu, timeout=20000):
if self.debug:
print "=> %s" % hexlify(apdu)
print("=> %s" % hexlify(apdu))
if self.ledger:
apdu = wrapCommandAPDU(0x0101, apdu, 64)
padSize = len(apdu) % 64
tmp = apdu
if padSize <> 0:
if padSize != 0:
tmp.extend([0] * (64 - padSize))
offset = 0
while(offset <> len(tmp)):
while(offset != len(tmp)):
data = tmp[offset:offset + 64]
data = bytearray([0]) + data
self.device.write(data)
Expand Down Expand Up @@ -114,8 +114,8 @@ def exchange(self, apdu, timeout=20000):
sw = (result[swOffset] << 8) + result[swOffset + 1]
response = result[dataStart : dataLength + dataStart]
if self.debug:
print "<= %s%.2x" % (hexlify(response), sw)
if sw <> 0x9000:
print("<= %s%.2x" % (hexlify(response), sw))
if sw != 0x9000:
raise BTChipException("Invalid status %04x" % sw, sw)
return response

Expand Down Expand Up @@ -148,12 +148,12 @@ def __init__(self, device, debug=False):

def exchange(self, apdu, timeout=20000):
if self.debug:
print "=> %s" % hexlify(apdu)
print("=> %s" % hexlify(apdu))
response, sw1, sw2 = self.device.transmit(toBytes(hexlify(apdu)))
sw = (sw1 << 8) | sw2
if self.debug:
print "<= %s%.2x" % (toHexString(response).replace(" ", ""), sw)
if sw <> 0x9000:
print("<= %s%.2x" % (toHexString(response).replace(" ", ""), sw))
if sw != 0x9000:
raise BTChipException("Invalid status %04x" % sw, sw)
return bytearray(response)

Expand Down
Loading

0 comments on commit 6d82fba

Please sign in to comment.