Skip to content

Commit 889dc50

Browse files
committed
v7.0.1; use pycryptodome's scrypt, for working pyinstaller macOS app
o Remove dependency on scrypt o Detect Paper Wallet capability, en/disable controls in GUI
1 parent 5b41ec4 commit 889dc50

File tree

8 files changed

+41
-20
lines changed

8 files changed

+41
-20
lines changed

SLIP39.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ coll = COLLECT(exe,
4949
app = BUNDLE(coll,
5050
name='SLIP39.app',
5151
icon='images/SLIP39.icns',
52-
version='7.0.0',
52+
version='7.0.1',
5353
info_plist={
54-
'CFBundleVersion':'7.0.0',
54+
'CFBundleVersion':'7.0.1',
5555
'CFBundlePackageType':'APPL',
5656
'LSApplicationCategoryType':'public.app-category.finance',
5757
'LSMinimumSystemVersion':'10.15.0',

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pip
44
pytest
55
setuptools
66
wheel
7+
pyinstaller >= 4.9

requirements-wallet.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
eth-account >=0.6.0, <1
2-
scrypt >=0.8.17
32
pycryptodome >=3.10.1

slip39/api.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
# Support for private key encryption via BIP-38 and Ethereum JSON wallet is optional; pip install slip39[wallet]
1919
try:
2020
from Crypto.Cipher import AES
21+
from Crypto.Protocol.KDF import scrypt
2122
except ImportError:
2223
AES = None
23-
try:
24-
import scrypt
25-
except ImportError:
2624
scrypt = None
2725
try:
2826
import eth_account
@@ -38,6 +36,11 @@
3836
log = logging.getLogger( __package__ )
3937

4038

39+
def paper_wallet_available():
40+
"""Determine if encrypted BIP-38 and Ethereum JSON Paper Wallets are available."""
41+
return AES and scrypt and eth_account
42+
43+
4144
def path_edit(
4245
path: str,
4346
edit: str,
@@ -256,17 +259,17 @@ def bip38( self, passphrase, flagbyte=b'\xe0' ):
256259
raise NotImplementedError( f"{self.crypto} does not support BIP-38 private key encryption" )
257260
private_hex = self.key
258261
addr = self.legacy_address().encode( 'UTF-8' ) # Eg. b"184xW5g..."
259-
addrhash = hashlib.sha256( hashlib.sha256( addr ).digest() ).digest()[0:4]
262+
ahash = hashlib.sha256( hashlib.sha256( addr ).digest() ).digest()[0:4]
260263
if isinstance( passphrase, str ):
261264
passphrase = passphrase.encode( 'UTF-8' )
262-
key = scrypt.hash( passphrase, addrhash, 16384, 8, 8, 64 )
265+
key = scrypt( passphrase, salt=ahash, key_len=64, N=16384, r=8, p=8 )
263266
derivedhalf1 = key[0:32]
264267
derivedhalf2 = key[32:64]
265268
aes = AES.new( derivedhalf2, AES.MODE_ECB )
266269
enchalf1 = aes.encrypt( ( int( private_hex[ 0:32], 16 ) ^ int.from_bytes( derivedhalf1[ 0:16], 'big' )).to_bytes( 16, 'big' ))
267270
enchalf2 = aes.encrypt( ( int( private_hex[32:64], 16 ) ^ int.from_bytes( derivedhalf1[16:32], 'big' )).to_bytes( 16, 'big' ))
268271
prefix = b'\x01\x42'
269-
encrypted_privkey = prefix + flagbyte + addrhash + enchalf1 + enchalf2
272+
encrypted_privkey = prefix + flagbyte + ahash + enchalf1 + enchalf2
270273
# Encode the encrypted private key to base58, adding the 4-byte base58 check suffix
271274
return base58.b58encode_check( encrypted_privkey ).decode( 'UTF-8' )
272275

@@ -287,7 +290,7 @@ def from_bip38( self, encrypted_privkey, passphrase, strict=True ):
287290
f"Unrecognized BIP-38 flagbyte: {flag!r}"
288291
if isinstance( passphrase, str ):
289292
passphrase = passphrase.encode( 'UTF-8' )
290-
key = scrypt.hash( passphrase, ahash, 16384, 8, 8, 64 )
293+
key = scrypt( passphrase, salt=ahash, key_len=64, N=16384, r=8, p=8 )
291294
derivedhalf1 = key[0:32]
292295
derivedhalf2 = key[32:64]
293296
aes = AES.new( derivedhalf2, AES.MODE_ECB )

slip39/api_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
except ImportError:
88
eth_account = None
99
try:
10-
import scrypt
10+
from Crypto.Cipher import AES
11+
from Crypto.Protocol.KDF import scrypt
1112
except ImportError:
13+
AES = None
1214
scrypt = None
1315

1416
import shamir_mnemonic

slip39/gui/main.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import PySimpleGUI as sg
1111

12-
from .. import Account, create, group_parser, random_secret, cryptopaths_parser
12+
from ..api import Account, create, group_parser, random_secret, cryptopaths_parser, paper_wallet_available
1313
from ..recovery import recover, recover_bip39
1414
from ..util import log_level, log_cfg, ordinal, chunker
1515
from ..layout import write_pdfs
@@ -48,6 +48,7 @@ def groups_layout(
4848
groups,
4949
passphrase = None,
5050
cryptocurrency = None,
51+
paper_wallet = True, # Should we include Paper Wallet config in layout?
5152
):
5253
"""Return a layout for the specified number of SLIP-39 groups.
5354
@@ -80,6 +81,9 @@ def groups_layout(
8081
),
8182
]
8283

84+
if not paper_wallet:
85+
log.warning( "Disabling Paper Wallets capability: API unavailable" )
86+
8387
layout = [
8488
[
8589
sg.Frame( '1. Location for output PDF File(s) (Preferably removable media, such as a USB drive)', [
@@ -229,7 +233,7 @@ def groups_layout(
229233
],
230234
], **F_kwds ),
231235
],
232-
], key='-WALLET-F-', visible=True, **F_kwds ),
236+
], key='-WALLET-F-', visible=paper_wallet, **F_kwds ), # noqa: E126
233237
],
234238
] + [
235239
[
@@ -535,13 +539,16 @@ def app(
535539

536540
sg.user_settings_set_entry( '-target folder-', os.getcwd() )
537541

542+
paper_wallet = paper_wallet_available()
543+
538544
# Compute initial App window layout, from the supplied groups.
539545
layout = groups_layout(
540546
names = names,
541547
group_threshold = group_threshold,
542548
groups = groups,
543549
passphrase = passphrase,
544550
cryptocurrency = cryptocurrency,
551+
paper_wallet = paper_wallet,
545552
)
546553

547554
window = None
@@ -563,7 +570,8 @@ def app(
563570
window['-SE-SEED-F-'].expand( expand_x=True )
564571
window['-SEED-F-'].expand( expand_x=True )
565572
window['-OUTPUT-F-'].expand( expand_x=True )
566-
window['-WALLET-F-'].expand( expand_x=True )
573+
if paper_wallet:
574+
window['-WALLET-F-'].expand( expand_x=True )
567575
window['-SUMMARY-F-'].expand( expand_x=True )
568576
window['-STATUS-F-'].expand( expand_x=True )
569577
window['-RECOVERED-F-'].expand( expand_x=True )
@@ -756,6 +764,7 @@ def app(
756764
# time we recompute -- even without any changes -- the SLIP-39 Mnemonics will change, due to the use
757765
# of entropy in the SLIP-39 process.
758766
if slip39_update or not details:
767+
log.info( f"SLIP39 details for {names}..." )
759768
try:
760769
details = {}
761770
for n,name in enumerate( names ):
@@ -779,8 +788,15 @@ def app(
779788
continue
780789

781790
# Display the computed SLIP-39 Mnemonics for the first name.
782-
if status := update_seed_recovered( window, values, details[names[0]], passphrase=passphrase ):
783-
groups_recovered = {}
791+
try:
792+
if status := update_seed_recovered( window, values, details[names[0]], passphrase=passphrase ):
793+
groups_recovered = {}
794+
continue
795+
except Exception as exc:
796+
status = f"Error recovering: {exc}"
797+
logging.exception( f"{status}" )
798+
update_seed_recovered( window, values, None )
799+
groups_recovered = {}
784800
continue
785801

786802
# If all has gone well -- display the resultant <name>/<filename>, and some derived account details
@@ -795,10 +811,10 @@ def app(
795811
# details is now { "<filename>": <details> })
796812
if event == '-SAVE-':
797813
try:
798-
card = next( c for c in CARD_SIZES if values[f"-CS-{c}"] )
814+
card_format = next( c for c in CARD_SIZES if values[f"-CS-{c}"] )
799815
details = write_pdfs(
800816
names = details,
801-
card = card,
817+
card_format = card_format,
802818
cryptocurrency = cryptocurrency,
803819
edit = edit,
804820
wallet_pwd = values['-WALLET-PASS-'], # Produces Paper Wallet(s) iff set

slip39/layout/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ def write_pdfs(
733733
wall_tpl['wallet-bg'] = os.path.join( images, 'paper-wallet-background.png' )
734734
wall_tpl[f"crypto-f{c_n}"] = account.crypto
735735
wall_tpl[f"crypto-b{c_n}"] = account.crypto
736-
736+
737737
wall_tpl['center'] = os.path.join( images, account.crypto + '.png' )
738738

739739
wall_tpl['name-label'] = "Wallet name:"

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, 0, 0 )
1+
__version_info__ = ( 7, 0, 1 )
22
__version__ = '.'.join( map( str, __version_info__ ))

0 commit comments

Comments
 (0)