Optional libsecp256k1 dependency, default to pure Python cryptographic API to help Windows users
This commit is contained in:
parent
4eefb8a7f7
commit
b56ff7cbe1
|
@ -2,7 +2,7 @@
|
|||
|
||||
This package contains Python tools to communicate with Ledger Blue and Nano S and manage applications life cycle
|
||||
|
||||
The life cycle management requires [libsecp256k1](https://github.com/ludbb/secp256k1-py) Python bindings compiled with ECDH support. It is recommended to install this package in a [Virtual Environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/) in your native environment (not a Docker image) through
|
||||
It is recommended to install this package in a [Virtual Environment](http://docs.python-guide.org/en/latest/dev/virtualenvs/) in your native environment (not a Docker image) to avoid hidapi issues.
|
||||
|
||||
```
|
||||
virtualenv ledger
|
||||
|
@ -10,3 +10,9 @@ source ledger/bin/activate
|
|||
pip install ledgerblue
|
||||
```
|
||||
|
||||
This package can optionally work with [libsecp256k1](https://github.com/ludbb/secp256k1-py) Python bindings compiled with ECDH support. If you wish to enable libsecp256k1 bindings, make sure to install libsecp256k1 as follows
|
||||
|
||||
```
|
||||
SECP_BUNDLED_EXPERIMENTAL=1 pip --no-cache-dir install secp256k1
|
||||
```
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
********************************************************************************
|
||||
"""
|
||||
|
||||
from secp256k1 import PrivateKey
|
||||
from .ecWrapper import PrivateKey
|
||||
from .comm import getDongle
|
||||
from .deployed import getDeployedSecretV1, getDeployedSecretV2
|
||||
from .hexLoader import HexLoader
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
********************************************************************************
|
||||
"""
|
||||
|
||||
from secp256k1 import PrivateKey, PublicKey
|
||||
from .ecWrapper import PrivateKey, PublicKey
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
"""
|
||||
*******************************************************************************
|
||||
* 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.
|
||||
********************************************************************************
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
try:
|
||||
import secp256k1
|
||||
USE_SECP = secp256k1.HAS_ECDH
|
||||
except ImportError:
|
||||
USE_SECP = False
|
||||
|
||||
if not USE_SECP:
|
||||
import ecpy
|
||||
from builtins import int
|
||||
from ecpy.curves import Curve, Point
|
||||
from ecpy.keys import ECPublicKey, ECPrivateKey
|
||||
from ecpy.ecdsa import ECDSA
|
||||
CURVE_SECP256K1 = Curve.get_curve('secp256k1')
|
||||
SIGNER = ECDSA()
|
||||
|
||||
class PublicKey(object):
|
||||
def __init__(self, pubkey=None, raw=False, flags=None, ctx=None):
|
||||
if USE_SECP:
|
||||
if flags == None:
|
||||
flags = secp256k1.FLAG_VERIFY
|
||||
self.obj = secp256k1.PublicKey(pubkey, raw, flags, ctx)
|
||||
else:
|
||||
if not raw:
|
||||
raise Exception("Non raw init unsupported")
|
||||
pubkey = pubkey[1:]
|
||||
x = int.from_bytes(pubkey[0:32], 'big')
|
||||
y = int.from_bytes(pubkey[32:], 'big')
|
||||
self.obj = ECPublicKey(Point(x, y, CURVE_SECP256K1))
|
||||
|
||||
def ecdsa_deserialize(self, ser_sig):
|
||||
if USE_SECP:
|
||||
return self.obj.ecdsa_deserialize(ser_sig)
|
||||
else:
|
||||
return ser_sig
|
||||
|
||||
def serialize(self, compressed=True):
|
||||
if USE_SECP:
|
||||
return self.obj.serialize(compressed)
|
||||
else:
|
||||
if not compressed:
|
||||
out = "\x04"
|
||||
out += str(bytearray(self.obj.W.x.to_bytes(32, 'big')))
|
||||
out += str(bytearray(self.obj.W.y.to_bytes(32, 'big')))
|
||||
else:
|
||||
out = "\x03" if ((self.obj.W.y & 1) <> 0) else "\x02"
|
||||
out += str(bytearray(self.obj.W.x.to_bytes(32, 'big')))
|
||||
return out
|
||||
|
||||
def ecdh(self, scalar):
|
||||
if USE_SECP:
|
||||
return self.obj.ecdh(scalar)
|
||||
else:
|
||||
scalar = int.from_bytes(scalar)
|
||||
point = self.obj.W * scalar
|
||||
# libsecp256k1 style secret
|
||||
out = "\x03" if ((point.y & 1) <> 0) else "\x02"
|
||||
out += str(bytearray(point.x.to_bytes(32, 'big')))
|
||||
hash = hashlib.sha256()
|
||||
hash.update(out)
|
||||
return hash.digest()
|
||||
|
||||
def ecdsa_verify(self, msg, raw_sig, raw=False, digest=hashlib.sha256):
|
||||
if USE_SECP:
|
||||
return self.obj.ecdsa_verify(msg, raw_sig, raw, digest)
|
||||
else:
|
||||
if not raw:
|
||||
h = digest()
|
||||
h.update(msg)
|
||||
msg = h.digest()
|
||||
raw_sig = bytearray(raw_sig)
|
||||
return SIGNER.verify(msg, raw_sig, self.obj)
|
||||
|
||||
class PrivateKey(object):
|
||||
|
||||
def __init__(self, privkey=None, raw=True, flags=None, ctx=None):
|
||||
if USE_SECP:
|
||||
if flags == None:
|
||||
flags = secp256k1.ALL_FLAGS
|
||||
self.obj = secp256k1.PrivateKey(privkey, raw, flags, ctx)
|
||||
self.pubkey = self.obj.pubkey
|
||||
else:
|
||||
if not raw:
|
||||
raise Exception("Non raw init unsupported")
|
||||
if privkey == None:
|
||||
privkey = ecpy.ecrand.rnd(CURVE_SECP256K1.order)
|
||||
else:
|
||||
privkey = int.from_bytes(privkey)
|
||||
self.obj = ECPrivateKey(privkey, CURVE_SECP256K1)
|
||||
pubkey = self.obj.get_public_key().W
|
||||
out = "\x04"
|
||||
out += str(bytearray(pubkey.x.to_bytes(32, 'big')))
|
||||
out += str(bytearray(pubkey.y.to_bytes(32, 'big')))
|
||||
self.pubkey = PublicKey(out, raw=True)
|
||||
|
||||
def serialize(self):
|
||||
if USE_SECP:
|
||||
return self.obj.serialize()
|
||||
else:
|
||||
return str(bytearray(self.obj.d.to_bytes(32, 'big'))).encode('hex')
|
||||
|
||||
def ecdsa_serialize(self, raw_sig):
|
||||
if USE_SECP:
|
||||
return self.obj.ecdsa_serialize(raw_sig)
|
||||
else:
|
||||
return raw_sig
|
||||
|
||||
def ecdsa_sign(self, msg, raw=False, digest=hashlib.sha256):
|
||||
if USE_SECP:
|
||||
return self.obj.ecdsa_sign(msg, raw, digest)
|
||||
else:
|
||||
if not raw:
|
||||
h = digest()
|
||||
h.update(msg)
|
||||
msg = h.digest()
|
||||
signature = SIGNER.sign(msg, self.obj)
|
||||
return bytearray(signature)
|
|
@ -17,7 +17,7 @@
|
|||
********************************************************************************
|
||||
"""
|
||||
|
||||
from secp256k1 import PrivateKey
|
||||
from .ecWrapper import PrivateKey
|
||||
from .comm import getDongle
|
||||
from .hexParser import IntelHexParser
|
||||
from .hexLoader import HexLoader
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
from .comm import getDongle
|
||||
from .deployed import getDeployedSecretV2
|
||||
from secp256k1 import PrivateKey
|
||||
from .ecWrapper import PrivateKey
|
||||
from Crypto.Cipher import AES
|
||||
import argparse
|
||||
import sys
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
from .hexParser import IntelHexParser
|
||||
from .hexParser import IntelHexPrinter
|
||||
from secp256k1 import PrivateKey
|
||||
from .ecWrapper import PrivateKey
|
||||
import hashlib
|
||||
import binascii
|
||||
import argparse
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
from .hexParser import IntelHexParser
|
||||
from .hexParser import IntelHexPrinter
|
||||
from secp256k1 import PublicKey
|
||||
from .ecWrapper import PublicKey
|
||||
import hashlib
|
||||
import binascii
|
||||
import argparse
|
||||
|
|
6
setup.py
6
setup.py
|
@ -5,19 +5,17 @@ from setuptools import setup, find_packages
|
|||
from os.path import dirname, join
|
||||
import os
|
||||
|
||||
os.environ['SECP_BUNDLED_EXPERIMENTAL'] = "1"
|
||||
|
||||
here = dirname(__file__)
|
||||
setup(
|
||||
name='ledgerblue',
|
||||
version='0.1.6',
|
||||
version='0.1.7',
|
||||
author='Ledger',
|
||||
author_email='hello@ledger.fr',
|
||||
description='Python library to communicate with Ledger Blue/Nano S',
|
||||
long_description=open(join(here, 'README.md')).read(),
|
||||
url='https://github.com/LedgerHQ/blue-loader-python',
|
||||
packages=find_packages(),
|
||||
install_requires=['hidapi>=0.7.99', 'secp256k1>=0.12.1', 'pycrypto>=2.6.1'],
|
||||
install_requires=['hidapi>=0.7.99', 'pycrypto>=2.6.1', 'future', 'ecpy>=0.8.1'],
|
||||
extras_require = {
|
||||
'smartcard': [ 'python-pyscard>=1.6.12-4build1' ]
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue