Merge pull request #4 from cslashm/py3

Python 3 port with keeping Python 2 compliance
This commit is contained in:
Nicolas Bacca 2016-10-11 12:50:37 +02:00 committed by GitHub
commit cf74f4836c
12 changed files with 132 additions and 101 deletions

View File

@ -57,7 +57,7 @@ class BLEDongle(Dongle):
def exchange(self, apdu, timeout=20000): def exchange(self, apdu, timeout=20000):
if self.debug: if self.debug:
print "=> %s" % hexlify(apdu) print("=> %s" % hexlify(apdu))
apdu = wrapCommandAPDU(0, apdu, DEFAULT_BLE_CHUNK, True) apdu = wrapCommandAPDU(0, apdu, DEFAULT_BLE_CHUNK, True)
offset = 0 offset = 0
while(offset < len(apdu)): while(offset < len(apdu)):
@ -78,7 +78,7 @@ class BLEDongle(Dongle):
sw = (result[swOffset] << 8) + result[swOffset + 1] sw = (result[swOffset] << 8) + result[swOffset + 1]
response = result[dataStart : dataLength + dataStart] response = result[dataStart : dataLength + dataStart]
if self.debug: if self.debug:
print "<= %s%.2x" % (hexlify(response), sw) print("<= %s%.2x" % (hexlify(response), sw))
if sw <> 0x9000: if sw <> 0x9000:
raise CommException("Invalid status %04x" % sw, sw) raise CommException("Invalid status %04x" % sw, sw)
return response return response

View File

@ -23,6 +23,7 @@ from .ledgerWrapper import wrapCommandAPDU, unwrapResponseAPDU
from binascii import hexlify from binascii import hexlify
import hid import hid
import time import time
import sys
try: try:
from smartcard.Exceptions import NoCardException from smartcard.Exceptions import NoCardException
@ -32,6 +33,14 @@ try:
except ImportError: except ImportError:
SCARD = False SCARD = False
def hexstr(bstr):
if (sys.version_info.major == 3):
return hexlify(bstr).decode()
if (sys.version_info.major == 2):
return hexlify(bstr)
return "<undecoded APDU<"
class DongleWait(object): class DongleWait(object):
__metaclass__ = ABCMeta __metaclass__ = ABCMeta
@ -64,15 +73,15 @@ class HIDDongleHIDAPI(Dongle, DongleWait):
def exchange(self, apdu, timeout=20): def exchange(self, apdu, timeout=20):
if self.debug: if self.debug:
print "=> %s" % hexlify(apdu) print("=> %s" % hexstr(apdu))
if self.ledger: if self.ledger:
apdu = wrapCommandAPDU(0x0101, apdu, 64) apdu = wrapCommandAPDU(0x0101, apdu, 64)
padSize = len(apdu) % 64 padSize = len(apdu) % 64
tmp = apdu tmp = apdu
if padSize <> 0: if padSize != 0:
tmp.extend([0] * (64 - padSize)) tmp.extend([0] * (64 - padSize))
offset = 0 offset = 0
while(offset <> len(tmp)): while(offset != len(tmp)):
data = tmp[offset:offset + 64] data = tmp[offset:offset + 64]
data = bytearray([0]) + data data = bytearray([0]) + data
self.device.write(data) self.device.write(data)
@ -114,8 +123,8 @@ class HIDDongleHIDAPI(Dongle, DongleWait):
sw = (result[swOffset] << 8) + result[swOffset + 1] sw = (result[swOffset] << 8) + result[swOffset + 1]
response = result[dataStart : dataLength + dataStart] response = result[dataStart : dataLength + dataStart]
if self.debug: if self.debug:
print "<= %s%.2x" % (hexlify(response), sw) print("<= %s%.2x" % (hexstr(response), sw))
if sw <> 0x9000: if sw != 0x9000:
raise CommException("Invalid status %04x" % sw, sw) raise CommException("Invalid status %04x" % sw, sw)
return response return response
@ -148,12 +157,12 @@ class DongleSmartcard(Dongle):
def exchange(self, apdu, timeout=20): def exchange(self, apdu, timeout=20):
if self.debug: if self.debug:
print "=> %s" % hexlify(apdu) print("=> %s" % hexstr(apdu))
response, sw1, sw2 = self.device.transmit(toBytes(hexlify(apdu))) response, sw1, sw2 = self.device.transmit(toBytes(hexlify(apdu)))
sw = (sw1 << 8) | sw2 sw = (sw1 << 8) | sw2
if self.debug: if self.debug:
print "<= %s%.2x" % (toHexString(response).replace(" ", ""), sw) print("<= %s%.2x" % (hexstr(response).replace(" ", ""), sw))
if sw <> 0x9000: if sw != 0x9000:
raise CommException("Invalid status %04x" % sw, sw) raise CommException("Invalid status %04x" % sw, sw)
return bytearray(response) return bytearray(response)
@ -183,7 +192,7 @@ def getDongle(debug=False, selectCommand=None):
try: try:
connection = reader.createConnection() connection = reader.createConnection()
connection.connect() connection.connect()
if selectCommand <> None: if selectCommand != None:
response, sw1, sw2 = connection.transmit(toBytes("00A4040010FF4C4547522E57414C5430312E493031")) response, sw1, sw2 = connection.transmit(toBytes("00A4040010FF4C4547522E57414C5430312E493031"))
sw = (sw1 << 8) | sw2 sw = (sw1 << 8) | sw2
if sw == 0x9000: if sw == 0x9000:

View File

@ -22,6 +22,8 @@ from .comm import getDongle
from .deployed import getDeployedSecretV1, getDeployedSecretV2 from .deployed import getDeployedSecretV1, getDeployedSecretV2
from .hexLoader import HexLoader from .hexLoader import HexLoader
import argparse import argparse
import binascii
import sys
def auto_int(x): def auto_int(x):
return int(x, 0) return int(x, 0)
@ -37,13 +39,19 @@ args = parser.parse_args()
if args.appName == None: if args.appName == None:
raise Exception("Missing appName") raise Exception("Missing appName")
if (sys.version_info.major == 3):
args.appName = bytes(args.appName,'ascii')
if (sys.version_info.major == 2):
args.appName = bytes(args.appName)
if args.targetId == None: if args.targetId == None:
args.targetId = 0x31000002 args.targetId = 0x31000002
if args.rootPrivateKey == None: if args.rootPrivateKey == None:
privateKey = PrivateKey() privateKey = PrivateKey()
publicKey = str(privateKey.pubkey.serialize(compressed=False)).encode('hex') publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
print "Generated random root public key : " + publicKey print("Generated random root public key : %s" % publicKey)
args.rootPrivateKey = privateKey.serialize().encode('ascii') args.rootPrivateKey = privateKey.serialize()
dongle = getDongle(args.apdu) dongle = getDongle(args.apdu)

View File

@ -23,6 +23,7 @@ import sys
import struct import struct
from .hexParser import IntelHexParser from .hexParser import IntelHexParser
from .hexLoader import HexLoader from .hexLoader import HexLoader
import binascii
def getDeployedSecretV1(dongle, masterPrivate, targetid): def getDeployedSecretV1(dongle, masterPrivate, targetid):
testMaster = PrivateKey(bytes(masterPrivate)) testMaster = PrivateKey(bytes(masterPrivate))
@ -38,13 +39,13 @@ def getDeployedSecretV1(dongle, masterPrivate, targetid):
cardKey = batch_info[5:5 + batch_info[4]] cardKey = batch_info[5:5 + batch_info[4]]
# if not found, get another pair # if not found, get another pair
#if cardKey <> testMasterPublic: #if cardKey != testMasterPublic:
# raise Exception("Invalid batch public key") # raise Exception("Invalid batch public key")
# provide the ephemeral certificate # provide the ephemeral certificate
ephemeralPrivate = PrivateKey() ephemeralPrivate = PrivateKey()
ephemeralPublic = bytearray(ephemeralPrivate.pubkey.serialize(compressed=False)) ephemeralPublic = bytearray(ephemeralPrivate.pubkey.serialize(compressed=False))
print "Using ephemeral key " + str(ephemeralPublic).encode('hex') print("Using ephemeral key %s" %binascii.hexlify(ephemeralPublic))
signature = testMaster.ecdsa_sign(bytes(ephemeralPublic)) signature = testMaster.ecdsa_sign(bytes(ephemeralPublic))
signature = testMaster.ecdsa_serialize(signature) signature = testMaster.ecdsa_serialize(signature)
certificate = bytearray([len(ephemeralPublic)]) + ephemeralPublic + bytearray([len(signature)]) + signature certificate = bytearray([len(ephemeralPublic)]) + ephemeralPublic + bytearray([len(signature)]) + signature
@ -63,7 +64,7 @@ def getDeployedSecretV1(dongle, masterPrivate, targetid):
if not last_pub_key.ecdsa_verify(bytes(certificatePublic), certificateSignature): if not last_pub_key.ecdsa_verify(bytes(certificatePublic), certificateSignature):
if index == 0: if index == 0:
# Not an error if loading from user key # Not an error if loading from user key
print "Broken certificate chain - loading from user key" print("Broken certificate chain - loading from user key")
else: else:
raise Exception("Broken certificate chain") raise Exception("Broken certificate chain")
last_pub_key = PublicKey(bytes(certificatePublic), raw=True) last_pub_key = PublicKey(bytes(certificatePublic), raw=True)
@ -72,7 +73,7 @@ def getDeployedSecretV1(dongle, masterPrivate, targetid):
# Commit device ECDH channel # Commit device ECDH channel
dongle.exchange(bytearray.fromhex('E053000000')) dongle.exchange(bytearray.fromhex('E053000000'))
secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex'))) secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex')))
return str(secret[0:16]) return secret[0:16]
def getDeployedSecretV2(dongle, masterPrivate, targetid): def getDeployedSecretV2(dongle, masterPrivate, targetid):
testMaster = PrivateKey(bytes(masterPrivate)) testMaster = PrivateKey(bytes(masterPrivate))
@ -91,10 +92,10 @@ def getDeployedSecretV2(dongle, masterPrivate, targetid):
deviceNonce = auth_info[4:12] deviceNonce = auth_info[4:12]
# if not found, get another pair # if not found, get another pair
#if cardKey <> testMasterPublic: #if cardKey != testMasterPublic:
# raise Exception("Invalid batch public key") # raise Exception("Invalid batch public key")
print "Using test master key " + str(testMasterPublic).encode('hex') print("Using test master key %s " % binascii.hexlify(testMasterPublic))
dataToSign = bytes(bytearray([0x01]) + testMasterPublic) dataToSign = bytes(bytearray([0x01]) + testMasterPublic)
signature = testMaster.ecdsa_sign(bytes(dataToSign)) signature = testMaster.ecdsa_sign(bytes(dataToSign))
signature = testMaster.ecdsa_serialize(signature) signature = testMaster.ecdsa_serialize(signature)
@ -105,7 +106,7 @@ def getDeployedSecretV2(dongle, masterPrivate, targetid):
# provide the ephemeral certificate # provide the ephemeral certificate
ephemeralPrivate = PrivateKey() ephemeralPrivate = PrivateKey()
ephemeralPublic = bytearray(ephemeralPrivate.pubkey.serialize(compressed=False)) ephemeralPublic = bytearray(ephemeralPrivate.pubkey.serialize(compressed=False))
print "Using ephemeral key " + str(ephemeralPublic).encode('hex') print("Using ephemeral key %s" %binascii.hexlify(ephemeralPublic))
dataToSign = bytes(bytearray([0x11]) + nonce + deviceNonce + ephemeralPublic) dataToSign = bytes(bytearray([0x11]) + nonce + deviceNonce + ephemeralPublic)
signature = testMaster.ecdsa_sign(bytes(dataToSign)) signature = testMaster.ecdsa_sign(bytes(dataToSign))
signature = testMaster.ecdsa_serialize(signature) signature = testMaster.ecdsa_serialize(signature)
@ -122,10 +123,10 @@ def getDeployedSecretV2(dongle, masterPrivate, targetid):
elif index == 1: elif index == 1:
certificate = bytearray(dongle.exchange(bytearray.fromhex('E052800000'))) certificate = bytearray(dongle.exchange(bytearray.fromhex('E052800000')))
else: else:
break break
if len(certificate) == 0: if len(certificate) == 0:
break break
offset = 1 offset = 1
certificateHeader = certificate[offset : offset + certificate[offset-1]] certificateHeader = certificate[offset : offset + certificate[offset-1]]
offset += certificate[offset-1] + 1 offset += certificate[offset-1] + 1
certificatePublicKey = certificate[offset : offset + certificate[offset-1]] certificatePublicKey = certificate[offset : offset + certificate[offset-1]]
@ -142,7 +143,7 @@ def getDeployedSecretV2(dongle, masterPrivate, targetid):
if not last_pub_key.ecdsa_verify(bytes(certificateSignedData), certificateSignature): if not last_pub_key.ecdsa_verify(bytes(certificateSignedData), certificateSignature):
if index == 0: if index == 0:
# Not an error if loading from user key # Not an error if loading from user key
print "Broken certificate chain - loading from user key" print("Broken certificate chain - loading from user key")
else: else:
raise Exception("Broken certificate chain") raise Exception("Broken certificate chain")
last_pub_key = PublicKey(bytes(certificatePublicKey), raw=True) last_pub_key = PublicKey(bytes(certificatePublicKey), raw=True)
@ -150,5 +151,5 @@ def getDeployedSecretV2(dongle, masterPrivate, targetid):
# Commit device ECDH channel # Commit device ECDH channel
dongle.exchange(bytearray.fromhex('E053000000')) dongle.exchange(bytearray.fromhex('E053000000'))
secret = last_pub_key.ecdh(bytes(ephemeralPrivate.serialize().decode('hex'))) secret = last_pub_key.ecdh(binascii.unhexlify(ephemeralPrivate.serialize()))
return str(secret[0:16]) return secret[0:16]

View File

@ -58,23 +58,23 @@ class PublicKey(object):
return self.obj.serialize(compressed) return self.obj.serialize(compressed)
else: else:
if not compressed: if not compressed:
out = "\x04" out = b"\x04"
out += str(bytearray(self.obj.W.x.to_bytes(32, 'big'))) out += self.obj.W.x.to_bytes(32, 'big')
out += str(bytearray(self.obj.W.y.to_bytes(32, 'big'))) out += self.obj.W.y.to_bytes(32, 'big')
else: else:
out = "\x03" if ((self.obj.W.y & 1) <> 0) else "\x02" out = b"\x03" if ((self.obj.W.y & 1) != 0) else "\x02"
out += str(bytearray(self.obj.W.x.to_bytes(32, 'big'))) out += self.obj.W.x.to_bytes(32, 'big')
return out return out
def ecdh(self, scalar): def ecdh(self, scalar):
if USE_SECP: if USE_SECP:
return self.obj.ecdh(scalar) return self.obj.ecdh(scalar)
else: else:
scalar = int.from_bytes(scalar) scalar = int.from_bytes(scalar, 'big')
point = self.obj.W * scalar point = self.obj.W * scalar
# libsecp256k1 style secret # libsecp256k1 style secret
out = "\x03" if ((point.y & 1) <> 0) else "\x02" out = b"\x03" if ((point.y & 1) != 0) else b"\x02"
out += str(bytearray(point.x.to_bytes(32, 'big'))) out += point.x.to_bytes(32, 'big')
hash = hashlib.sha256() hash = hashlib.sha256()
hash.update(out) hash.update(out)
return hash.digest() return hash.digest()
@ -104,19 +104,19 @@ class PrivateKey(object):
if privkey == None: if privkey == None:
privkey = ecpy.ecrand.rnd(CURVE_SECP256K1.order) privkey = ecpy.ecrand.rnd(CURVE_SECP256K1.order)
else: else:
privkey = int.from_bytes(privkey) privkey = int.from_bytes(privkey,'big')
self.obj = ECPrivateKey(privkey, CURVE_SECP256K1) self.obj = ECPrivateKey(privkey, CURVE_SECP256K1)
pubkey = self.obj.get_public_key().W pubkey = self.obj.get_public_key().W
out = "\x04" out = b"\x04"
out += str(bytearray(pubkey.x.to_bytes(32, 'big'))) out += pubkey.x.to_bytes(32, 'big')
out += str(bytearray(pubkey.y.to_bytes(32, 'big'))) out += pubkey.y.to_bytes(32, 'big')
self.pubkey = PublicKey(out, raw=True) self.pubkey = PublicKey(out, raw=True)
def serialize(self): def serialize(self):
if USE_SECP: if USE_SECP:
return self.obj.serialize() return self.obj.serialize()
else: else:
return str(bytearray(self.obj.d.to_bytes(32, 'big'))).encode('hex') return "%.64x"%self.obj.d
def ecdsa_serialize(self, raw_sig): def ecdsa_serialize(self, raw_sig):
if USE_SECP: if USE_SECP:

View File

@ -20,6 +20,7 @@
from Crypto.Cipher import AES from Crypto.Cipher import AES
import struct import struct
import hashlib import hashlib
import binascii
class HexLoader: class HexLoader:
def __init__(self, card, cla=0xF0, secure=False, key=None, relative=True): def __init__(self, card, cla=0xF0, secure=False, key=None, relative=True):
@ -27,9 +28,11 @@ class HexLoader:
self.cla = cla self.cla = cla
self.secure = secure self.secure = secure
self.key = key self.key = key
self.iv = "\x00" * 16 self.iv = b"\x00" * 16
self.relative = relative self.relative = relative
def crc16(self, data): def crc16(self, data):
TABLE_CRC16_CCITT = [ TABLE_CRC16_CCITT = [
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
@ -73,40 +76,40 @@ class HexLoader:
return crc return crc
def exchange(self, cla, ins, p1, p2, data): def exchange(self, cla, ins, p1, p2, data):
apdu = bytearray(chr(cla) + chr(ins) + chr(p1) + chr(p2) + chr(len(data))) + bytearray(data) apdu = bytearray([cla, ins, p1, p2, len(data)]) + bytearray(data)
if self.card == None: if self.card == None:
print str(apdu).encode('hex') print("%s" % binascii.hexlify(apdu))
else: else:
self.card.exchange(apdu) self.card.exchange(apdu)
def encryptAES(self, data): def encryptAES(self, data):
if not self.secure: if not self.secure:
return data return data
paddedData = data + '\x80' paddedData = data + b'\x80'
while (len(paddedData) % 16) <> 0: while (len(paddedData) % 16) != 0:
paddedData += '\x00' paddedData += b'\x00'
cipher = AES.new(self.key, AES.MODE_CBC, self.iv) cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
encryptedData = cipher.encrypt(str(paddedData)) encryptedData = cipher.encrypt(paddedData)
self.iv = encryptedData[len(encryptedData) - 16:] self.iv = encryptedData[len(encryptedData) - 16:]
return encryptedData return encryptedData
def selectSegment(self, baseAddress): def selectSegment(self, baseAddress):
data = '\x05' + struct.pack('>I', baseAddress) data = b'\x05' + struct.pack('>I', baseAddress)
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
def loadSegmentChunk(self, offset, chunk): def loadSegmentChunk(self, offset, chunk):
data = '\x06' + struct.pack('>H', offset) + chunk data = b'\x06' + struct.pack('>H', offset) + chunk
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
def flushSegment(self): def flushSegment(self):
data = '\x07' data = b'\x07'
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
def crcSegment(self, offsetSegment, lengthSegment, crcExpected): def crcSegment(self, offsetSegment, lengthSegment, crcExpected):
data = '\x08' + struct.pack('>H', offsetSegment) + struct.pack('>I', lengthSegment) + struct.pack('>H', crcExpected) data = b'\x08' + struct.pack('>H', offsetSegment) + struct.pack('>I', lengthSegment) + struct.pack('>H', crcExpected)
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
@ -117,29 +120,30 @@ class HexLoader:
def boot(self, bootadr, signature=None): def boot(self, bootadr, signature=None):
# Force jump into Thumb mode # Force jump into Thumb mode
bootadr |= 1 bootadr |= 1
data = '\x09' + struct.pack('>I', bootadr) data = b'\x09' + struct.pack('>I', bootadr)
if (signature != None): if (signature != None):
data += chr(len(signature)) + signature data += chr(len(signature)) + signature
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
def createApp(self, appflags, applength, appname, icon=None, path=None): def createApp(self, appflags, applength, appname, icon=None, path=None):
data = '\x0B' + struct.pack('>I', applength) + struct.pack('>I', appflags) + chr(len(appname)) + appname data = b'\x0B' + struct.pack('>I', applength) + struct.pack('>I', appflags) + struct.pack('>B', len(appname)) + appname
if (icon != None): if (icon != None):
data += chr(len(icon)) + icon data += struct.pack('>B', len(icon))+ icon
if (path != None): if (path != None):
data += chr(len(path)) + path data += struct.pack('>B', len(path)) + path
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
def deleteApp(self, appname): def deleteApp(self, appname):
data = '\x0C' + chr(len(appname)) + appname data = b'\x0C' + struct.pack('>B',len(appname)) + appname
data = self.encryptAES(data) data = self.encryptAES(data)
self.exchange(self.cla, 0x00, 0x00, 0x00, data) self.exchange(self.cla, 0x00, 0x00, 0x00, data)
def load(self, erase_u8, max_length_per_apdu, hexAreas, bootaddr): def load(self, erase_u8, max_length_per_apdu, hexAreas, bootaddr):
initialAddress = 0 initialAddress = 0
if (len(hexAreas) <> 0) and self.relative: if (len(hexAreas) != 0) and self.relative:
initialAddress = hexAreas[0].getStart() initialAddress = hexAreas[0].getStart()
sha256 = hashlib.new('sha256') sha256 = hashlib.new('sha256')
for area in hexAreas: for area in hexAreas:
@ -160,7 +164,7 @@ class HexLoader:
chunkLen = length chunkLen = length
chunk = data[offset : offset + chunkLen] chunk = data[offset : offset + chunkLen]
sha256.update(chunk) sha256.update(chunk)
self.loadSegmentChunk(offset, chunk) self.loadSegmentChunk(offset, bytes(chunk))
offset += chunkLen offset += chunkLen
length -= chunkLen length -= chunkLen
self.flushSegment() self.flushSegment()
@ -169,7 +173,7 @@ class HexLoader:
def run(self, hexAreas, bootaddr, signature=None): def run(self, hexAreas, bootaddr, signature=None):
initialAddress = 0 initialAddress = 0
if (len(hexAreas) <> 0) and self.relative: if (len(hexAreas) != 0) and self.relative:
initialAddress = hexAreas[0].getStart() initialAddress = hexAreas[0].getStart()
self.boot(bootaddr - initialAddress, signature) self.boot(bootaddr - initialAddress, signature)

View File

@ -36,16 +36,16 @@ class IntelHexParser:
startZone = None startZone = None
startFirst = None startFirst = None
current = None current = None
zoneData = "" zoneData = b''
file = open(fileName, "r") file = open(fileName, "r")
for data in file: for data in file:
lineNumber += 1 lineNumber += 1
data = data.rstrip('\r\n') data = data.rstrip('\r\n')
if len(data) == 0: if len(data) == 0:
continue continue
if data[0] <> ':': if data[0] != ':':
raise Exception("Invalid data at line " + str(lineNumber)) raise Exception("Invalid data at line %d" % lineNumber)
data = bytearray(data[1:].decode('hex')) data = bytearray.fromhex(data[1:]) #binascii.unhexlify(data[1:])
count = data[0] count = data[0]
address = (data[1] << 8) + data[2] address = (data[1] << 8) + data[2]
recordType = data[3] recordType = data[3]
@ -55,7 +55,7 @@ class IntelHexParser:
if startFirst == None: if startFirst == None:
startFirst = address startFirst = address
current = startFirst current = startFirst
if address <> current: if address != current:
self.areas.append(IntelHexArea((startZone << 16) + startFirst, zoneData)) self.areas.append(IntelHexArea((startZone << 16) + startFirst, zoneData))
zoneData = "" zoneData = ""
startFirst = address startFirst = address
@ -63,7 +63,7 @@ class IntelHexParser:
zoneData += data[4:4 + count] zoneData += data[4:4 + count]
current += count current += count
if recordType == 0x01: if recordType == 0x01:
if len(zoneData) <> 0: if len(zoneData) != 0:
self.areas.append(IntelHexArea((startZone << 16) + startFirst, zoneData)) self.areas.append(IntelHexArea((startZone << 16) + startFirst, zoneData))
zoneData = "" zoneData = ""
startZone = None startZone = None
@ -74,7 +74,7 @@ class IntelHexParser:
if recordType == 0x03: if recordType == 0x03:
raise Exception("Unsupported record 03") raise Exception("Unsupported record 03")
if recordType == 0x04: if recordType == 0x04:
if len(zoneData) <> 0: if len(zoneData) != 0:
self.areas.append(IntelHexArea((startZone << 16) + startFirst, zoneData)) self.areas.append(IntelHexArea((startZone << 16) + startFirst, zoneData))
zoneData = "" zoneData = ""
startZone = None startZone = None

View File

@ -39,7 +39,7 @@ def wrapCommandAPDU(channel, command, packetSize, ble=False):
blockSize = len(command) blockSize = len(command)
result += command[offset : offset + blockSize] result += command[offset : offset + blockSize]
offset = offset + blockSize offset = offset + blockSize
while offset <> len(command): while offset != len(command):
if not ble: if not ble:
result += struct.pack(">H", channel) result += struct.pack(">H", channel)
result += struct.pack(">BH", 0x05, sequenceIdx) result += struct.pack(">BH", 0x05, sequenceIdx)
@ -51,8 +51,8 @@ def wrapCommandAPDU(channel, command, packetSize, ble=False):
result += command[offset : offset + blockSize] result += command[offset : offset + blockSize]
offset = offset + blockSize offset = offset + blockSize
if not ble: if not ble:
while (len(result) % packetSize) <> 0: while (len(result) % packetSize) != 0:
result += "\x00" result += b"\x00"
return bytearray(result) return bytearray(result)
def unwrapResponseAPDU(channel, data, packetSize, ble=False): def unwrapResponseAPDU(channel, data, packetSize, ble=False):
@ -65,16 +65,16 @@ def unwrapResponseAPDU(channel, data, packetSize, ble=False):
if ((data is None) or (len(data) < 5 + extraHeaderSize + 5)): if ((data is None) or (len(data) < 5 + extraHeaderSize + 5)):
return None return None
if not ble: if not ble:
if struct.unpack(">H", str(data[offset : offset + 2]))[0] <> channel: if struct.unpack(">H", data[offset : offset + 2])[0] != channel:
raise CommException("Invalid channel") raise CommException("Invalid channel")
offset += 2 offset += 2
if data[offset] <> 0x05: if data[offset] != 0x05:
raise CommException("Invalid tag") raise CommException("Invalid tag")
offset += 1 offset += 1
if struct.unpack(">H", str(data[offset : offset + 2]))[0] <> sequenceIdx: if struct.unpack(">H", data[offset : offset + 2])[0] != sequenceIdx:
raise CommException("Invalid sequence") raise CommException("Invalid sequence")
offset += 2 offset += 2
responseLength = struct.unpack(">H", str(data[offset : offset + 2]))[0] responseLength = struct.unpack(">H", data[offset : offset + 2])[0]
offset += 2 offset += 2
if len(data) < 5 + extraHeaderSize + responseLength: if len(data) < 5 + extraHeaderSize + responseLength:
return None return None
@ -84,18 +84,18 @@ def unwrapResponseAPDU(channel, data, packetSize, ble=False):
blockSize = responseLength blockSize = responseLength
result = data[offset : offset + blockSize] result = data[offset : offset + blockSize]
offset += blockSize offset += blockSize
while (len(result) <> responseLength): while (len(result) != responseLength):
sequenceIdx = sequenceIdx + 1 sequenceIdx = sequenceIdx + 1
if (offset == len(data)): if (offset == len(data)):
return None return None
if not ble: if not ble:
if struct.unpack(">H", str(data[offset : offset + 2]))[0] <> channel: if struct.unpack(">H", data[offset : offset + 2])[0] != channel:
raise CommException("Invalid channel") raise CommException("Invalid channel")
offset += 2 offset += 2
if data[offset] <> 0x05: if data[offset] != 0x05:
raise CommException("Invalid tag") raise CommException("Invalid tag")
offset += 1 offset += 1
if struct.unpack(">H", str(data[offset : offset + 2]))[0] <> sequenceIdx: if struct.unpack(">H", data[offset : offset + 2])[0] != sequenceIdx:
raise CommException("Invalid sequence") raise CommException("Invalid sequence")
offset += 2 offset += 2
if (responseLength - len(result)) > packetSize - 3 - extraHeaderSize: if (responseLength - len(result)) > packetSize - 3 - extraHeaderSize:

View File

@ -24,14 +24,16 @@ from .hexLoader import HexLoader
from .deployed import getDeployedSecretV1, getDeployedSecretV2 from .deployed import getDeployedSecretV1, getDeployedSecretV2
import argparse import argparse
import struct import struct
import binascii
import sys
def auto_int(x): def auto_int(x):
return int(x, 0) return int(x, 0)
def parse_bip32_path(path, apilevel): def parse_bip32_path(path, apilevel):
if len(path) == 0: if len(path) == 0:
return "" return b""
result = "" result = b""
elements = path.split('/') elements = path.split('/')
if apilevel >= 5: if apilevel >= 5:
result = result + chr(len(elements)) result = result + chr(len(elements))
@ -72,15 +74,21 @@ if args.appFlags == None:
args.appFlags = 0 args.appFlags = 0
if args.rootPrivateKey == None: if args.rootPrivateKey == None:
privateKey = PrivateKey() privateKey = PrivateKey()
publicKey = str(privateKey.pubkey.serialize(compressed=False)).encode('hex') publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
print "Generated random root public key : " + publicKey print("Generated random root public key : %s" % publicKey)
args.rootPrivateKey = privateKey.serialize().encode('ascii') args.rootPrivateKey = privateKey.serialize()
if (sys.version_info.major == 3):
args.appName = bytes(args.appName,'ascii')
if (sys.version_info.major == 2):
args.appName = bytes(args.appName)
parser = IntelHexParser(args.fileName) parser = IntelHexParser(args.fileName)
if args.bootAddr == None: if args.bootAddr == None:
args.bootAddr = parser.getBootAddr() args.bootAddr = parser.getBootAddr()
path = "" path = b""
curveMask = 0xff curveMask = 0xff
if args.curve != None: if args.curve != None:
curveMask = 0x00 curveMask = 0x00
@ -95,17 +103,17 @@ if args.curve != None:
raise Exception("Unknown curve " + curve) raise Exception("Unknown curve " + curve)
if args.apilevel >= 5: if args.apilevel >= 5:
path += chr(curveMask) path += struct.pack('>B',curveMask)
if args.path != None: if args.path != None:
for item in args.path: for item in args.path:
if len(item) <> 0: if len(item) != 0:
path += parse_bip32_path(item, args.apilevel) path += parse_bip32_path(item, args.apilevel)
else: else:
if args.curve != None: if args.curve != None:
print "Curve not supported using this API level, ignoring" print("Curve not supported using this API level, ignoring")
if args.path != None: if args.path != None:
if len(args.path) > 1: if len(args.path) > 1:
print "Multiple path levels not supported using this API level, ignoring" print("Multiple path levels not supported using this API level, ignoring")
else: else:
path = parse_bip32_path(args.path[0], args.apilevel) path = parse_bip32_path(args.path[0], args.apilevel)
@ -126,13 +134,14 @@ for area in parser.getAreas():
icon = None icon = None
if args.icon != None: if args.icon != None:
icon = bytearray.fromhex(args.icon) icon = bytes(bytearray.fromhex(args.icon))
signature = None signature = None
if args.signature != None: if args.signature != None:
signature = bytearray.fromhex(args.signature) signature = bytes(bytearray.fromhex(args.signature))
loader.createApp(args.appFlags, appLength, args.appName, icon, path) loader.createApp(args.appFlags, appLength, args.appName, icon, path)
hash = loader.load(0x0, 0xE0, parser.getAreas(), args.bootAddr) hash = loader.load(0x0, 0xE0, parser.getAreas(), args.bootAddr)
print "Application hash : " + hash print("Application hash : " + hash)
loader.run(parser.getAreas(), args.bootAddr, signature) loader.run(parser.getAreas(), args.bootAddr, signature)

View File

@ -48,14 +48,14 @@ else:
class SCP: class SCP:
def __init__(self, dongle, targetId, rootPrivateKey): def __init__(self, dongle, targetId, rootPrivateKey):
self.key = getDeployedSecretV2(dongle, rootPrivateKey, targetId) self.key = getDeployedSecretV2(dongle, rootPrivateKey, targetId)
self.iv = "\x00" * 16; self.iv = b'\x00' * 16;
def encryptAES(self, data): def encryptAES(self, data):
paddedData = data + '\x80' paddedData = data + b'\x80'
while (len(paddedData) % 16) <> 0: while (len(paddedData) % 16) != 0:
paddedData += '\x00' paddedData += b'\x00'
cipher = AES.new(self.key, AES.MODE_CBC, self.iv) cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
encryptedData = cipher.encrypt(str(paddedData)) encryptedData = cipher.encrypt(paddedData)
self.iv = encryptedData[len(encryptedData) - 16:] self.iv = encryptedData[len(encryptedData) - 16:]
return encryptedData return encryptedData
@ -64,9 +64,9 @@ dongle = getDongle(args.apdu)
if args.scp: if args.scp:
if args.rootPrivateKey == None: if args.rootPrivateKey == None:
privateKey = PrivateKey() privateKey = PrivateKey()
publicKey = str(privateKey.pubkey.serialize(compressed=False)).encode('hex') publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
print "Generated random root public key : " + publicKey print("Generated random root public key : %s" % publicKey)
args.rootPrivateKey = privateKey.serialize().encode('ascii') args.rootPrivateKey = privateKey.serialize()
scp = SCP(dongle, args.targetId, bytearray.fromhex(args.rootPrivateKey)) scp = SCP(dongle, args.targetId, bytearray.fromhex(args.rootPrivateKey))
for data in file: for data in file:

View File

@ -50,11 +50,11 @@ dataToSign = m.digest()
MASTER_PRIVATE = bytearray.fromhex(args.key) MASTER_PRIVATE = bytearray.fromhex(args.key)
testMaster = PrivateKey(bytes(MASTER_PRIVATE)) testMaster = PrivateKey(bytes(MASTER_PRIVATE))
testMasterPublic = bytearray(testMaster.pubkey.serialize(compressed=False)) #testMasterPublic = bytearray(testMaster.pubkey.serialize(compressed=False))
signature = testMaster.ecdsa_sign(bytes(dataToSign), raw=True) signature = testMaster.ecdsa_sign(bytes(dataToSign), raw=True)
# test signature before printing it # test signature before printing it
if testMaster.pubkey.ecdsa_verify(dataToSign, signature, raw=True): if testMaster.pubkey.ecdsa_verify(dataToSign, signature, raw=True):
#print "Signer's public: " + binascii.hexlify(testMasterPublic) #print("Signer's public: " + binascii.hexlify(testMasterPublic))
print testMaster.ecdsa_serialize(signature).encode('hex') print(testMaster.ecdsa_serialize(signature).encode('hex'))

View File

@ -56,4 +56,4 @@ signature = publicKey.ecdsa_deserialize(bytes(bytearray.fromhex(args.signature))
if not publicKey.ecdsa_verify(bytes(dataToSign), signature, raw=True): if not publicKey.ecdsa_verify(bytes(dataToSign), signature, raw=True):
raise Exception("Signature not verified") raise Exception("Signature not verified")
print "Signature verified" print("Signature verified")