Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Satochip hardware wallet #8453

Closed
wants to merge 78 commits into from

Conversation

Toporin
Copy link
Contributor

@Toporin Toporin commented May 24, 2023

This is a pull request to add support for the Satochip hardware wallet.

The Satochip hardware wallet is based on a jacavard smartcard and is fully open-source.
The wallet is composed of a javacard applet that is to be loaded on the smartcard, and an Electrum client plugin that acts as the interface between the card and the network. An optional 2FA setting allows to confirm transaction requests on a second android device before signing them (iOS version coming soon).

This pull request updates and supersedes #7690, #7518 and #6520.

Changes compared to previous PR:
*Based on latest release Electrum v4.4.3
*Use pysatochip v0.12.3
*Suport for Satochip applet up to v0.12 (instead of v0.11)

New functionalities in Satochip applet v0.12:
*Card authenticity verification based on device certificate & PKI
*Reset to factory option (e.g. if user forget his PIN code or 2FA device)
*Support for importing encrypted seed from a SeedKeeper

More info:
https://github.com/Toporin/ (official repository)
https://pypi.org/project/pysatochip/ (pysatochip library)
https://prezi.com/p/mpq-xhh3mxjl/satochip-gent-meetup/ (Slides from previous meetups in Belgium)
https://t.me/Satochip (Telegram support)

Alcofribas4 and others added 30 commits December 18, 2018 12:17
Basic Satochip plugin functionnal
No SegWit support yet
- parse segwit tx
- sign tx

Electrum-Satochip integration:
- store authentikey in (encrypted) storage
- Device setup: prompt for PIN & Seed
Check Satochip version for support via card_get_status()
* Refactor card_bip32_import_seed() and card_bip32_get_authentikey(): return authentikey instead of (response, sw1, sw2)
* New class UninitializedSeedError(Exception) thrown when device has no seed
…e) directly

remove debug comments and clean code a bit
# Conflicts:
#	contrib/build-osx/make_osx
#	contrib/build-osx/osx.spec
#	contrib/build-osx/package.sh
#	contrib/build-wine/build-electrum-git.sh
#	contrib/build-wine/build-secp256k1.sh
#	contrib/build-wine/build.sh
#	contrib/build-wine/deterministic.spec
#	contrib/build-wine/prepare-wine.sh
#	contrib/build-wine/sign.sh
#	contrib/build-wine/unsign.sh
#	contrib/deterministic-build/check_submodules.sh
#	contrib/deterministic-build/find_restricted_dependencies.py
#	contrib/freeze_packages.sh
#	contrib/make_apk
#	contrib/make_download
#	contrib/make_locale
#	contrib/make_packages
#	contrib/make_tgz
#	contrib/sign_packages
#	contrib/upload
#	electrum
#	electrum-env
#	gui/kivy/data/fonts/tron/License.txt
#	gui/kivy/data/fonts/tron/Readme.txt
#	lib/base_wizard.py
#	lib/crypto.py
#	lib/plugins.py
#	lib/ripemd.py
#	lib/wordlist/portuguese.txt
#	plugins/trezor/trezor.py
#	scripts/bip70
#	scripts/block_headers
#	scripts/estimate_fee
#	scripts/get_history
#	scripts/peers
#	scripts/servers
#	scripts/txradar
#	scripts/watch_address
#	setup.py

Signed-off-by: Baudoin <bcollard@gmail.com>
various code cleaning,
set random PIN for unused pin/puk code
* card_get_status() returns number of pin/puk tries remaining
* PIN verification is refactored in card_verify_PIN()
Merge commit '87c596fa1d685b9365c26b9dfabe9c566f806ea0' into satochip

# Conflicts:
#	.gitignore
#	README.rst
#	contrib/build-linux/appimage/apprun.sh
#	contrib/build-linux/appimage/build.sh
#	contrib/build-osx/osx.spec
#	contrib/build-wine/build-electrum-git.sh
#	contrib/build-wine/deterministic.spec
#	contrib/build-wine/prepare-wine.sh
#	contrib/build_tools_util.sh
#	contrib/osx/make_osx
#	contrib/sign_version
#	electrum/base_wizard.py
#	electrum/plugin.py
#	icons.qrc
#	lib/crypto.py
In CardConnector.py:
- Encrypt/decrypt 2FA challenge/response for privacy
- erase PIN when card is removed

In Satochip.py:
- pairing with 2FA device using QR code
- if 2FA is enabled, tx signing requires response to challenge using hmac-sha1

New plugin in satochip_2FA folder: exchange challenge-response with 2FA device

Minor changes in TxParser.py, plugin.py
Merge remote-tracking branch 'upstream/master' into satochip

# Conflicts:
#	.gitignore
#	README.rst
#	contrib/build-wine/build-electrum-git.sh
#	contrib/build-wine/prepare-wine.sh
#	electrum/base_wizard.py
#	electrum/plugin.py
- contrib/build-wine/LICENCE
- contrib/build-wine/tmp/electrum/
- contrib/osx/package.sh~HEAD
- removed README-electrum.rst
- undo changes to README.rst
- removed debug traces in contrib/build-wine/deterministic.spec
- add pyscard in contrib/requirements/requirements-hw.txt
Merge branch 'Electrum-Satochip-v3.3.8-0.7' into satochip:
    - removed README-electrum.rst
    - undo changes to README.rst
    - removed debug traces in contrib/build-wine/deterministic.spec
    - add pyscard in contrib/requirements/requirements-hw.txt
Support for Satochip v0.8 (improved 2-Factor-Authentication support):
* A new setting menu is available when clicking on the satochip logo in the low right corner of the window.
* Add support for PIN change and seed reset
* In addition to transactions, 2FA is now required to sign messages, import eckey and reset seed/eckey/2FA.
* 2FA can be disabled, only when the seed and all private keys are cleared.

Added support for Satochip in AppImage.
To run the AppImage on Linux:
$ chmod a+x electrum*.AppImage
$ ./electrum*.AppImage
Support for Satochip v0.8 (improved 2-Factor-Authentication support):
  * A new setting menu is available when clicking on the satochip logo in the low right corner of the window.
  * Add support for PIN change and seed reset
  * In addition to transactions, 2FA is now required to sign messages, import eckey and reset seed/eckey/2FA.
  * 2FA can be disabled, only when the seed and all private keys are cleared.

Added support for Satochip in AppImage.
To run the AppImage on Linux:
  $ chmod a+x electrum*.AppImage
  $ ./electrum*.AppImage

Merge branch 'electrum-satochip-v3.3.8-0.8' into satochip
Only BIP39 seedd import (from existing seed) is currently supported.
Changes in pysatochip: drop pyaes and pyopenssl dependencies
brew install autoconf automake libtool gettext coreutils pkgconfig


info "Building PyInstaller."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this whole block is duplicated from above?
see line 123

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry, the MacOS build is still a work in progress, I pushed the changes I made so far to the Satochip repo in order to work on the mac build from my mac...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this PR is still in progress better to change it into a draft

@Toporin Toporin marked this pull request as draft June 22, 2023 15:13
@Toporin Toporin marked this pull request as ready for review June 23, 2023 08:39
@Toporin
Copy link
Contributor Author

Toporin commented Jun 23, 2023

The PR is ready for review.

Latest changes:

  • upgraded pysatochip to v0.12.5, removing pyopenssl and pyaes dependencies
  • on Satochip wallet setup, if the wallet is not seeded, allows to import an existing BIP39 seed, but not generating a new one from Electrum
  • Simplify MacOS build (only swig is needed to build pyscard from sources)
  • Added a 'cancel' option to QRDialog init method, the default behavior is unchanged.

Note that I have not been able to build the windows build yet due to #8496

@gruve-p
Copy link
Contributor

gruve-p commented Jun 23, 2023

Note that I have not been able to build the windows build yet due to #8496

You can turn off the snapshot archive (comment these 2 lines for windows: https://github.com/spesmilo/electrum/blob/master/contrib/build-wine/Dockerfile#L8-L9)

@@ -256,4 +255,4 @@ DoCodeSignMaybe ".DMG" "dist/electrum-${VERSION}.dmg"
if [ -z "$CODESIGN_CERT" ]; then
warn "App was built successfully but was not code signed. Users may get security warnings from macOS."
warn "Specify a valid code signing identity to enable code signing."
fi
fi
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please fix the code formatting issues so that the flake8 tests pass
https://cirrus-ci.com/task/4585331354238976

for example, "no newline at end of file"

@Toporin Toporin marked this pull request as draft June 23, 2023 18:38
Download the binary wheel from Satochip repo and install it.
We use a slightly modified version of 'requirements-hw' with pyscard package removed, otherwise pip install fails since no wheels are supported for windows.
For windows build, use pyscard binary wheels for win32.
    Aucun périphérique matériel détecté.
    Pour déclencher un nouveau scan, pressez 'Suivant'.

    Sur Linux, vous pouvez avoir à ajouter une nouvelle permission à vos règles udev.


    Message de débogage
      bitbox02: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading bitbox02 plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      coldcard: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading coldcard plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      digitalbitbox: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading digitalbitbox plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      jade: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading jade plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      keepkey: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading keepkey plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      ledger: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading ledger plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      safe_t: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading safe_t plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      satochip: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading satochip plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
      trezor: (error during plugin init)
        Vous avez peut-être une bibliothèque incompatible.
        Error loading trezor plugin: ImportError("cannot import name 'parse_URI' from 'electrum.util' (/Users/satochip/Documents/github/electrum-satochip/dist/Electrum.app/Contents/MacOS/electrum/util.pyc)")
@Toporin Toporin marked this pull request as ready for review July 10, 2023 13:17
@Toporin
Copy link
Contributor Author

Toporin commented Jul 10, 2023

This PR is now ready for review!

Main changes:

  • upgraded pysatochip to v0.12.5, removing pyopenssl and pyaes dependencies
  • upgraded pyscard to latest version v2.0.7, using binary wheels for Windows only
  • on Satochip wallet setup, if the wallet is not seeded, allows to import an existing BIP39 seed, but not generating a new one from Electrum
  • Simplify MacOS build (only swig is needed to build pyscard from sources)
  • Added a 'cancel' option to QRDialog init method, the default behavior is unchanged.
  • Fix code format using Flake8 and Autopep8

@@ -220,6 +220,22 @@ pyaes==1.6.1 \
pycparser==2.21 \
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
pysatochip==0.12.5 \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is 0.14.1 and 0.14.2 marked as latest on pypi (but has a date of 2021)? That confused me.

Comment on lines +1 to +83
Satochip plugin for electrum
=================================================================================

::

Licence: MIT Licence
Author: Toporin
Language: Python (>= 3.6)
Homepage: https://github.com/Toporin/electrum-satochip

Introduction
============

This plugin allows to integrate the Satochip Hardware Wallet with Electrum. To use it, you need a device with the Satochip javacard applet installed (see https://github.com/Toporin/SatochipApplet).
If the wallet is not intialized yet, Electrum will perform the setup (you only need to do this once). During setup, a seed is created: this seed allows you to recover your wallet at anytime, so make sure to BACKUP THE SEED SECURELY! During setup, a PIN code is also created: this PIN allows to unlock th device to access your funds. If you try too many wrong PIN, your device will be locked indefinitely (it is 'bricked'). If you loose your PIN or brick your device, you can only recover your funds with the seed backup.

The Satochip wallet is currently in Beta, use with caution!You can use the software on the Bitcoin testnet using the --testnet option.
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Rem: Electrum uses Python 3.x. In case of error, check first that you are not trying to run Electrum with Python 2.x or with Python 2.x libraries.

Development version (Windows 64bits)
=====================================

Install the latest python 3.6 release from https://www.python.org (https://www.python.org/downloads/release/python-368/)
(Caution: installing another release than 3.6 may cause incompatibility issues with pyscard)

Clone or download the code from GitHub.

Open a PowerShell command line in the electrum folder

In PowerShell, install the electrum dependencies::

python -m pip install .

You may also ned to install Python3-pyqt5::

python -m pip install pyqt5

Install pyscard from https://pyscard.sourceforge.io/
Pyscard is required to connect to the smartcard::

python -m pip install pyscard


In PowerShell, run electrum on the testnet (-v allows for verbose output)::

python .\run_electrum -v --testnet


Development version (Ubuntu)
==============================
(Electrum requires Python 3.6, which should be installed by default on Ubuntu)
(If necessary, install pip: sudo apt-get install python3-pip)

Electrum is a pure python application. To use the
Qt interface, install the Qt dependencies::

sudo apt-get install python3-pyqt5

Check out the code from GitHub::

git clone git://github.com/Toporin/electrum.git
cd electrum

In the electrum folder:

Run install (this should install dependencies)::

python3 -m pip install .

Install pyscard (https://pyscard.sourceforge.io/)
Pyscard is required to connect to the smartcard::
sudo apt-get install pcscd
sudo apt-get install python3-pyscard
(For alternatives, see https://github.com/LudovicRousseau/pyscard/blob/master/INSTALL.md for more detailed installation instructions)


To run Electrum use::
python3 electrum -v --testnet



Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this README is included? I do not see other hardware plugins having such a README.

Comment on lines +605 to +645
# def choose_seed_legacy(self, wizard):
# title = _('Create or restore')
# message = _('Do you want to create a new seed, or to restore a wallet using an existing seed?')
# choices = [
# #('create_seed', _('Create a new BIP39 seed')),
# ('restore_from_seed', _('I already have a BIP39 seed')),
# ]
# wizard.choice_dialog(title=title, message=message, choices=choices, run_next=wizard.run)

# #create seed
# def create_seed(self, wizard):
# wizard.seed_type = 'bip39'
# wizard.opt_bip39 = True
# wizard.opt_slip39 = False
# #seed = mnemonic.Mnemonic('en').make_seed(wizard.seed_type) # Electrum seed
# seed= self.to_bip39_mnemonic(128)
# f = lambda x: self.request_passphrase(wizard, seed, x)
# wizard.show_seed_dialog(run_next=f, seed_text=seed)

# def request_passphrase(self, wizard, seed, opt_passphrase):
# if opt_passphrase:
# f = lambda x: self.confirm_seed(wizard, seed, x)
# wizard.passphrase_dialog(run_next=f)
# else:
# wizard.run('confirm_seed', seed, '')

# def confirm_seed(self, wizard, seed, passphrase):
# f = lambda x: self.confirm_passphrase(wizard, seed, passphrase)
# wizard.confirm_seed_dialog(run_next=f, seed='', test=lambda x: x==seed)

# def confirm_passphrase(self, wizard, seed, passphrase):
# f = lambda x: self.derive_bip39_seed(seed, x) #f = lambda x: self.derive_bip32_seed(seed, x)
# if passphrase:
# title = _('Confirm Seed Extension')
# message = '\n'.join([
# _('Your seed extension must be saved together with your seed.'),
# _('Please type it here.'),
# ])
# wizard.line_dialog(run_next=f, title=title, message=message, default='', test=lambda x: x==passphrase)
# else:
# f('')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to keep this in?

Comment on lines +692 to +711
# # based on https://github.com/trezor/python-mnemonic/blob/master/mnemonic/mnemonic.py
# def to_bip39_mnemonic(self, strength: int) -> str:
# wordlist = mnemonic.Wordlist.from_file("english.txt")
# data= urandom(strength // 8)
# if len(data) not in [16, 20, 24, 28, 32]:
# raise ValueError(
# "Data length should be one of the following: [16, 20, 24, 28, 32], but it is not (%d)."
# % len(data)
# )
# h = hashlib.sha256(data).hexdigest()
# b = (
# bin(int.from_bytes(data, byteorder="big"))[2:].zfill(len(data) * 8)
# + bin(int(h, 16))[2:].zfill(256)[: len(data) * 8 // 32]
# )
# result = []
# for i in range(len(b) // 11):
# idx = int(b[i * 11 : (i + 1) * 11], 2)
# result.append(wordlist[idx])
# result_phrase = " ".join(result)
# return result_phrase
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to keep this in?

@accumulator
Copy link
Member

Note: this PR still uses the old wizard integration. See #8560 for the new wizard branch. You can check other hardware wallets to get a sense of the changes involved. Let me know if you need some pointers.

@Toporin
Copy link
Contributor Author

Toporin commented Sep 22, 2023

Thanks for the feedback @accumulator @gruve-p , I will update the PR accordingly!

@Toporin
Copy link
Contributor Author

Toporin commented Mar 21, 2024

Superseded by new pull request: #8967

@Toporin Toporin closed this Mar 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants