Skip to content

Commit b073e59

Browse files
committed
Correct SLIP-39 passphrase handling, work toward Windows support
1 parent c4a630a commit b073e59

File tree

4 files changed

+45
-20
lines changed

4 files changed

+45
-20
lines changed

README.org

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,24 @@ by entering the mnemonics right on the device.
12401240
: $ git clone [email protected]:pjkundert/python-slip39.git
12411241
: $ make -C python-slip39 app
12421242

1243+
*** The Windows 10 =SLIP-39= GUI
1244+
1245+
Install Python from https://python.org/downloads, and the [[https://visualstudio.microsoft.com/visual-cpp-build-tools][Microsoft C++ Build Tools]] via the
1246+
Visual Studio Installer (required for installing some =slip39= package dependencies).
1247+
1248+
To run the GUI, just install =slip39= package from Pypi using pip, including the =gui= and
1249+
=wallet= options. Building the Windows =SLIP-39= executable GUI application requires the =dev=
1250+
option.
1251+
: PS C:\Users\IEUser> pip install slip39[gui,wallet,dev]
1252+
1253+
To work with the [[https://github.com/pjkundert/python-slip39.git][python-slip39 Git repo on Github]], you'll also need to install [[https://git-scm.com/download/win][Git from
1254+
git-scm.com]]. Once installed, run "Git bash", and
1255+
: $ ssh-keygen.exe -t ed25519
1256+
to create an =id_ed25519.pub= SSH identity, and import it into your Git Settings SSH keys. Then,
1257+
: $ mkdir src
1258+
: $ cd src
1259+
: $ git clone [email protected]:pjkundert/python-slip39.git
1260+
12431261
* Dependencies
12441262

12451263
Internally, python-slip39 project uses Trezor's [[https://gihub.com/trezor/python-shamir-mnemonic.git][python-shamir-mnemonic]] to encode the seed data to

SLIP-39.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ coll = COLLECT(exe,
5050
app = BUNDLE(coll,
5151
name='SLIP-39.app',
5252
icon='images/SLIP-39.icns',
53-
version='7.1.0',
53+
version='7.2.1',
5454
info_plist={
55-
'CFBundleVersion':'7.1.0',
55+
'CFBundleVersion':'7.2.1',
5656
'CFBundlePackageType':'APPL',
5757
'LSApplicationCategoryType':'public.app-category.finance',
5858
'LSMinimumSystemVersion':'10.15.0',

slip39/gui/main.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import math
66
import os
77
import re
8+
import sys
89
import subprocess
910

1011
from itertools import islice
@@ -415,24 +416,26 @@ def update_seed_data( event, window, values ):
415416
if 'BIP' in update_seed_data.src:
416417
bits = 512
417418
try:
419+
passphrase = pwd.strip().encode( 'UTF-8' )
418420
seed_data = recover_bip39(
419421
mnemonic = dat.strip(),
420-
passphrase = pwd.strip().encode( 'UTF-8' )
422+
passphrase = passphrase,
421423
)
422424
except Exception as exc:
423-
log.exception( f"BIP-39 recovery failed w/ {dat!r} ({pwd!r}): {exc}" )
425+
log.exception( f"BIP-39 recovery failed w/ {dat!r} w/ passphrase: {pwd!r}: {exc}" )
424426
status = f"Invalid BIP-39 recovery mnemonic: {exc}"
425427
elif 'SLIP' in update_seed_data.src:
426428
bits = 128
427429
window['-SD-PASS-F-'].update( visible=values['-SD-PASS-C-'] )
428430
try:
431+
passphrase = pwd.strip().encode( 'UTF-8' )
429432
seed_data = recover(
430433
mnemonics = list( mnemonic_continuation( dat.strip().split( '\n' ))),
431-
passphrase = pwd.strip().encode( 'UTF-8' )
434+
passphrase = passphrase,
432435
)
433436
bits = len( seed_data ) * 4
434437
except Exception as exc:
435-
log.exception( f"SLIP-39 recovery failed w/ {dat!r} ({pwd!r}): {exc}" )
438+
log.exception( f"SLIP-39 recovery failed w/ {dat!r} w/ passphrase: {pwd!r}: {exc}" )
436439
status = f"Invalid SLIP-39 recovery mnemonics: {exc}"
437440
elif 'FIX' in update_seed_data.src:
438441
bits = int( update_seed_data.src.split( '-' )[2] )
@@ -674,7 +677,7 @@ def app(
674677
#
675678
# If no name(s) supplied, try to get the User's full name.
676679
#
677-
if not names:
680+
if not names and sys.platform == 'darwin':
678681
try:
679682
scutil = subprocess.run(
680683
[ '/usr/sbin/scutil' ],
@@ -735,7 +738,9 @@ def app(
735738
window['-MNEMONICS-F-'].expand( expand_x=True )
736739
window['-GROUPS-F-'].expand( expand_x=True )
737740
else:
738-
window = sg.Window( f"{', '.join( names or [ 'SLIP-39' ] )} Mnemonic Cards", layout )
741+
window = sg.Window(
742+
f"{', '.join( names or [ 'SLIP-39' ] )} Mnemonic Cards", layout, grab_anywhere=True,
743+
)
739744
timeout = 0 # First time through w/ new window, refresh immediately
740745

741746
# Block (except for first loop) and obtain current event and input values. Until we get a
@@ -898,17 +903,24 @@ def app(
898903
details = None
899904

900905
# Produce a summary of the SLIP-39 recovery groups, including any passphrase needed for
901-
# decryption, and how few/many cards will need to be collected to recover the Seed. If the
902-
# SLIP-39 passphrase has changed, force regeneration of SLIP-39. NOTE: this passphrase is
903-
# NOT Trezor-compatible; use the Trezor "hidden wallet" feature instead.
906+
# decryption of the SLIP-39 seed, and how few/many cards will need to be collected to
907+
# recover the Seed. If the SLIP-39 passphrase has changed, force regeneration of SLIP-39.
908+
# NOTE: this SLIP-39 standard passphrase is NOT Trezor-compatible; use the Trezor "hidden
909+
# wallet" feature instead.
904910
summary_groups = ', '.join( f"{n}({need}/{size})" for n,(need,size) in groups_recovered.items())
905911
summary = f"Requires collecting {group_threshold} of {len(groups_recovered)} the Groups: {summary_groups}"
912+
913+
tot_cards = sum( size for _,size in groups_recovered.values() )
914+
min_req = sum( islice( sorted( ( need for need,_ in groups_recovered.values() ), reverse=False ), group_threshold ))
915+
max_req = sum( islice( sorted( ( need for need,_ in groups_recovered.values() ), reverse=True ), group_threshold ))
916+
summary += f" (from {min_req}-{max_req} of {tot_cards} Mnemonic cards)"
917+
906918
if values['-PASSPHRASE-C-']:
907919
window['-PASSPHRASE-F-'].update( visible=True )
908920
passphrase_now = values['-PASSPHRASE-'].strip()
909921
if passphrase_now:
910-
summary += f", decrypted w/ passphrase {passphrase_now!r}"
911-
passphrase_now = passphrase.encode( 'utf-8' )
922+
summary += f", w/ passphrase: {passphrase_now!r})"
923+
passphrase_now = passphrase_now.encode( 'UTF-8' )
912924
if passphrase != passphrase_now:
913925
passphrase = passphrase_now
914926
details = None
@@ -918,11 +930,6 @@ def app(
918930
details = None
919931
passphrase = b''
920932

921-
tot_cards = sum( size for _,size in groups_recovered.values() )
922-
min_req = sum( islice( sorted( ( need for need,_ in groups_recovered.values() ), reverse=False ), group_threshold ))
923-
max_req = sum( islice( sorted( ( need for need,_ in groups_recovered.values() ), reverse=True ), group_threshold ))
924-
summary += f", and {min_req}-{max_req} of all {tot_cards} Mnemonics cards produced"
925-
926933
window['-SUMMARY-'].update( summary )
927934

928935
# Re-compute the SLIP39 Seed details. For multiple names, each subsequent slip39.create
@@ -943,7 +950,7 @@ def app(
943950
master_secret_n = compute_master_secret( window, values, n=n )
944951
assert n > 0 or codecs.encode( master_secret_n, 'hex_codec' ).decode( 'ascii' ) == master_secret, \
945952
"Computed Seed for 1st SLIP39 Mnemonics didn't match"
946-
log.info( f"SLIP39 for {name} from master_secret: {codecs.encode( master_secret_n, 'hex_codec' ).decode( 'ascii' )}" )
953+
log.info( f"SLIP39 for {name} from master_secret: {codecs.encode( master_secret_n, 'hex_codec' ).decode( 'ascii' )} (w/ passphrase: {passphrase!r}" )
947954
details[name] = create(
948955
name = name,
949956
group_threshold = group_threshold,

slip39/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version_info__ = ( 7, 2, 0 )
1+
__version_info__ = ( 7, 2, 1 )
22
__version__ = '.'.join( map( str, __version_info__ ))

0 commit comments

Comments
 (0)