Add scripts related to Nano S 1.3
This commit is contained in:
parent
310442593d
commit
09ad4fd1e2
|
@ -25,6 +25,8 @@ import hid
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
TIMEOUT=20000
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from smartcard.Exceptions import NoCardException
|
from smartcard.Exceptions import NoCardException
|
||||||
from smartcard.System import readers
|
from smartcard.System import readers
|
||||||
|
@ -52,7 +54,7 @@ class Dongle(object):
|
||||||
__metaclass__ = ABCMeta
|
__metaclass__ = ABCMeta
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def exchange(self, apdu, timeout=20):
|
def exchange(self, apdu, timeout=TIMEOUT):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
@ -71,7 +73,7 @@ class HIDDongleHIDAPI(Dongle, DongleWait):
|
||||||
self.waitImpl = self
|
self.waitImpl = self
|
||||||
self.opened = True
|
self.opened = True
|
||||||
|
|
||||||
def exchange(self, apdu, timeout=20):
|
def exchange(self, apdu, timeout=TIMEOUT):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("=> %s" % hexstr(apdu))
|
print("=> %s" % hexstr(apdu))
|
||||||
if self.ledger:
|
if self.ledger:
|
||||||
|
@ -155,7 +157,7 @@ class DongleSmartcard(Dongle):
|
||||||
self.waitImpl = self
|
self.waitImpl = self
|
||||||
self.opened = True
|
self.opened = True
|
||||||
|
|
||||||
def exchange(self, apdu, timeout=20):
|
def exchange(self, apdu, timeout=TIMEOUT):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("=> %s" % hexstr(apdu))
|
print("=> %s" % hexstr(apdu))
|
||||||
response, sw1, sw2 = self.device.transmit(toBytes(hexlify(apdu)))
|
response, sw1, sw2 = self.device.transmit(toBytes(hexlify(apdu)))
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
"""
|
||||||
|
*******************************************************************************
|
||||||
|
* Ledger Blue
|
||||||
|
* (c) 2016 Ledger
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEFAULT_ALIGNMENT = 1024
|
||||||
|
|
||||||
|
from .ecWrapper import PrivateKey
|
||||||
|
from .comm import getDongle
|
||||||
|
from .hexParser import IntelHexParser, IntelHexPrinter
|
||||||
|
from .hexLoader import HexLoader
|
||||||
|
from .deployed import getDeployedSecretV1, getDeployedSecretV2
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
|
||||||
|
privateKey = PrivateKey()
|
||||||
|
publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
|
||||||
|
print("Public key : %s" % publicKey)
|
||||||
|
print("Private key: %s" % privateKey.serialize())
|
|
@ -226,3 +226,12 @@ class HexLoader:
|
||||||
initialAddress = hexFile.minAddr()
|
initialAddress = hexFile.minAddr()
|
||||||
self.boot(bootaddr - initialAddress, signature)
|
self.boot(bootaddr - initialAddress, signature)
|
||||||
|
|
||||||
|
def resetCustomCA(self):
|
||||||
|
data = b'\x13'
|
||||||
|
data = self.encryptAES(data)
|
||||||
|
self.exchange(self.cla, 0x00, 0x00, 0x00, data)
|
||||||
|
|
||||||
|
def setupCustomCA(self, name, public):
|
||||||
|
data = b'\x12' + struct.pack('>B',len(name)) + name + struct.pack('>B',len(public)) + public
|
||||||
|
data = self.encryptAES(data)
|
||||||
|
self.exchange(self.cla, 0x00, 0x00, 0x00, data)
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
"""
|
||||||
|
*******************************************************************************
|
||||||
|
* Ledger Blue
|
||||||
|
* (c) 2016 Ledger
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEFAULT_ALIGNMENT = 1024
|
||||||
|
|
||||||
|
from .ecWrapper import PrivateKey
|
||||||
|
from .comm import getDongle
|
||||||
|
from .hexParser import IntelHexParser, IntelHexPrinter
|
||||||
|
from .hexLoader import HexLoader
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
import getpass
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
def auto_int(x):
|
||||||
|
return int(x, 0)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--apdu", help="Display APDU log", action='store_true')
|
||||||
|
parser.add_argument("--id", help="Identity to initialize", type=auto_int)
|
||||||
|
parser.add_argument("--pin", help="Set a PINs to backup the seed for future use")
|
||||||
|
parser.add_argument("--prefix", help="Derivation prefix")
|
||||||
|
parser.add_argument("--passphrase", help="Derivation passphrase")
|
||||||
|
parser.add_argument("--words", help="Derivation phrase")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if (args.id is None) or args.id > 2:
|
||||||
|
raise Exception("Missing identity number [0-2]")
|
||||||
|
|
||||||
|
dongle = getDongle(args.apdu)
|
||||||
|
|
||||||
|
def enter_if_none_and_normalize(hint, strg):
|
||||||
|
if strg is None: # or len(string) == 0: len 0 is accepted, to specify without being bothered by a message
|
||||||
|
strg = getpass.getpass(hint)
|
||||||
|
if len(strg) != 0 :
|
||||||
|
strg = unicodedata.normalize('NFKD', u''+strg)
|
||||||
|
return strg
|
||||||
|
|
||||||
|
if (args.id < 2):
|
||||||
|
args.pin = enter_if_none_and_normalize("PIN: ", args.pin)
|
||||||
|
if args.pin is None or len(args.pin) == 0:
|
||||||
|
raise Exception("Missing PIN for persistent identity")
|
||||||
|
elif not args.pin is None:
|
||||||
|
raise Exception("Can't set a PIN for the temporary identity")
|
||||||
|
|
||||||
|
args.prefix = enter_if_none_and_normalize("Derivation prefix: ", args.prefix)
|
||||||
|
args.passphrase = enter_if_none_and_normalize("Derivation passphrase: ", args.passphrase)
|
||||||
|
args.words = enter_if_none_and_normalize("Derivation phrase: ", args.words)
|
||||||
|
|
||||||
|
if args.pin:
|
||||||
|
apdudata = bytearray([len(args.pin)]) + bytearray(args.pin, 'utf8')
|
||||||
|
else:
|
||||||
|
apdudata = bytearray([0])
|
||||||
|
|
||||||
|
if args.prefix:
|
||||||
|
apdudata += bytearray([len(args.prefix)]) + bytearray(args.prefix, 'utf8')
|
||||||
|
else:
|
||||||
|
apdudata += bytearray([0])
|
||||||
|
|
||||||
|
if args.passphrase:
|
||||||
|
apdudata += bytearray([len(args.passphrase)]) + bytearray(args.passphrase, 'utf8')
|
||||||
|
else:
|
||||||
|
apdudata += bytearray([0])
|
||||||
|
|
||||||
|
if args.words:
|
||||||
|
apdudata += bytearray([len(args.words)]) + bytearray(args.words, 'utf8')
|
||||||
|
else:
|
||||||
|
apdudata += bytearray([0])
|
||||||
|
|
||||||
|
apdu = bytearray([0xE0, 0xD0, args.id, 0x00, len(apdudata)]) + apdudata
|
||||||
|
dongle.exchange(apdu, timeout=3000)
|
|
@ -0,0 +1,50 @@
|
||||||
|
"""
|
||||||
|
*******************************************************************************
|
||||||
|
* Ledger Blue
|
||||||
|
* (c) 2016 Ledger
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .ecWrapper import PrivateKey
|
||||||
|
from .comm import getDongle
|
||||||
|
from .deployed import getDeployedSecretV1, getDeployedSecretV2
|
||||||
|
from .hexLoader import HexLoader
|
||||||
|
import argparse
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def auto_int(x):
|
||||||
|
return int(x, 0)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--targetId", help="Set the chip target ID", type=auto_int)
|
||||||
|
parser.add_argument("--rootPrivateKey", help="Set the root private key")
|
||||||
|
parser.add_argument("--apdu", help="Display APDU log", action='store_true')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.targetId == None:
|
||||||
|
args.targetId = 0x31000002
|
||||||
|
if args.rootPrivateKey == None:
|
||||||
|
privateKey = PrivateKey()
|
||||||
|
publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
|
||||||
|
print("Generated random root public key : %s" % publicKey)
|
||||||
|
args.rootPrivateKey = privateKey.serialize()
|
||||||
|
|
||||||
|
dongle = getDongle(args.apdu)
|
||||||
|
|
||||||
|
secret = getDeployedSecretV2(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
|
||||||
|
loader = HexLoader(dongle, 0xe0, True, secret)
|
||||||
|
loader.exchange(0xE0, 0, 0, 0, loader.encryptAES(b'\xB0'));
|
|
@ -0,0 +1,57 @@
|
||||||
|
"""
|
||||||
|
*******************************************************************************
|
||||||
|
* Ledger Blue
|
||||||
|
* (c) 2016 Ledger
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEFAULT_ALIGNMENT = 1024
|
||||||
|
|
||||||
|
from .ecWrapper import PrivateKey
|
||||||
|
from .comm import getDongle
|
||||||
|
from .hexParser import IntelHexParser, IntelHexPrinter
|
||||||
|
from .hexLoader import HexLoader
|
||||||
|
from .deployed import getDeployedSecretV1, getDeployedSecretV2
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def auto_int(x):
|
||||||
|
return int(x, 0)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--targetId", help="Set the chip target ID", type=auto_int)
|
||||||
|
parser.add_argument("--apdu", help="Display APDU log", action='store_true')
|
||||||
|
parser.add_argument("--rootPrivateKey", help="Set the root private key")
|
||||||
|
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.targetId is None:
|
||||||
|
args.targetId = 0x31000002
|
||||||
|
if args.rootPrivateKey is None:
|
||||||
|
privateKey = PrivateKey()
|
||||||
|
publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
|
||||||
|
print("Generated random root public key : %s" % publicKey)
|
||||||
|
args.rootPrivateKey = privateKey.serialize()
|
||||||
|
|
||||||
|
|
||||||
|
dongle = getDongle(args.apdu)
|
||||||
|
|
||||||
|
secret = getDeployedSecretV2(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
|
||||||
|
loader = HexLoader(dongle, 0xe0, True, secret)
|
||||||
|
|
||||||
|
loader.resetCustomCA()
|
|
@ -0,0 +1,65 @@
|
||||||
|
"""
|
||||||
|
*******************************************************************************
|
||||||
|
* Ledger Blue
|
||||||
|
* (c) 2016 Ledger
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEFAULT_ALIGNMENT = 1024
|
||||||
|
|
||||||
|
from .ecWrapper import PrivateKey
|
||||||
|
from .comm import getDongle
|
||||||
|
from .hexParser import IntelHexParser, IntelHexPrinter
|
||||||
|
from .hexLoader import HexLoader
|
||||||
|
from .deployed import getDeployedSecretV1, getDeployedSecretV2
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def auto_int(x):
|
||||||
|
return int(x, 0)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--targetId", help="Set the chip target ID", type=auto_int)
|
||||||
|
parser.add_argument("--apdu", help="Display APDU log", action='store_true')
|
||||||
|
parser.add_argument("--rootPrivateKey", help="Set the root private key")
|
||||||
|
parser.add_argument("--public", help="Custom CA public key to setup (hex encoded)")
|
||||||
|
parser.add_argument("--name", help="Name of the Custom CA (to be displayed on screen upon auth requests)")
|
||||||
|
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.targetId is None:
|
||||||
|
args.targetId = 0x31000002
|
||||||
|
if args.rootPrivateKey is None:
|
||||||
|
privateKey = PrivateKey()
|
||||||
|
publicKey = binascii.hexlify(privateKey.pubkey.serialize(compressed=False))
|
||||||
|
print("Generated random root public key : %s" % publicKey)
|
||||||
|
args.rootPrivateKey = privateKey.serialize()
|
||||||
|
if args.public is None:
|
||||||
|
raise Exception("Missing public key")
|
||||||
|
if args.name is None:
|
||||||
|
raise Exception("Missing certificate name")
|
||||||
|
|
||||||
|
public = bytearray.fromhex(args.public)
|
||||||
|
|
||||||
|
|
||||||
|
dongle = getDongle(args.apdu)
|
||||||
|
|
||||||
|
secret = getDeployedSecretV2(dongle, bytearray.fromhex(args.rootPrivateKey), args.targetId)
|
||||||
|
loader = HexLoader(dongle, 0xe0, True, secret)
|
||||||
|
|
||||||
|
loader.setupCustomCA(args.name, public)
|
|
@ -57,4 +57,4 @@ 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(str(testMaster.ecdsa_serialize(signature)).encode('hex'))
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -8,7 +8,7 @@ import os
|
||||||
here = dirname(__file__)
|
here = dirname(__file__)
|
||||||
setup(
|
setup(
|
||||||
name='ledgerblue',
|
name='ledgerblue',
|
||||||
version='0.1.11',
|
version='0.1.12',
|
||||||
author='Ledger',
|
author='Ledger',
|
||||||
author_email='hello@ledger.fr',
|
author_email='hello@ledger.fr',
|
||||||
description='Python library to communicate with Ledger Blue/Nano S',
|
description='Python library to communicate with Ledger Blue/Nano S',
|
||||||
|
|
Loading…
Reference in New Issue