From d45e13553a8c442765c2336a93eafadcac722faa Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sun, 29 Oct 2017 15:49:29 +0100 Subject: [PATCH 1/2] old seeds: normalize, and stricter is_old_seed() --- lib/bitcoin.py | 11 +++++++---- lib/keystore.py | 4 ++-- lib/tests/test_bitcoin.py | 27 ++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/bitcoin.py b/lib/bitcoin.py index 36cbc753..7df4df27 100644 --- a/lib/bitcoin.py +++ b/lib/bitcoin.py @@ -260,11 +260,14 @@ def is_new_seed(x, prefix=version.SEED_PREFIX): def is_old_seed(seed): - from . import old_mnemonic - words = seed.strip().split() + from . import old_mnemonic, mnemonic + seed = mnemonic.normalize_text(seed) + words = seed.split() try: - old_mnemonic.mn_decode(words) - uses_electrum_words = True + hex_seed = old_mnemonic.mn_decode(words) + words2 = old_mnemonic.mn_encode(hex_seed) + seed2 = ' '.join(words2) + uses_electrum_words = seed == seed2 except Exception: uses_electrum_words = False try: diff --git a/lib/keystore.py b/lib/keystore.py index d1921aa6..ab127530 100644 --- a/lib/keystore.py +++ b/lib/keystore.py @@ -355,9 +355,9 @@ class Old_KeyStore(Deterministic_KeyStore): self.mpk = mpk def format_seed(self, seed): - from . import old_mnemonic + from . import old_mnemonic, mnemonic + seed = mnemonic.normalize_text(seed) # see if seed was entered as hex - seed = seed.strip() if seed: try: bfh(seed) diff --git a/lib/tests/test_bitcoin.py b/lib/tests/test_bitcoin.py index 2bce9212..7732b7b4 100644 --- a/lib/tests/test_bitcoin.py +++ b/lib/tests/test_bitcoin.py @@ -11,7 +11,7 @@ from lib.bitcoin import ( var_int, op_push, address_to_script, regenerate_key, verify_message, deserialize_privkey, serialize_privkey, is_segwit_address, is_b58_address, address_to_scripthash, is_minikey, is_compressed, is_xpub, - xpub_type, is_xprv, is_bip32_derivation) + xpub_type, is_xprv, is_bip32_derivation, seed_type) from lib.util import bfh try: @@ -348,6 +348,27 @@ class Test_keyImport(unittest.TestCase): class Test_seeds(unittest.TestCase): """ Test old and new seeds. """ + + mnemonics = { + ('cell dumb heartbeat north boom tease ship baby bright kingdom rare squeeze', 'old'), + ('cell dumb heartbeat north boom tease ' * 4, 'old'), + ('cell dumb heartbeat north boom tease ship baby bright kingdom rare badword', ''), + ('cElL DuMb hEaRtBeAt nOrTh bOoM TeAsE ShIp bAbY BrIgHt kInGdOm rArE SqUeEzE', 'old'), + (' cElL DuMb hEaRtBeAt nOrTh bOoM TeAsE ShIp bAbY BrIgHt kInGdOm rArE SqUeEzE ', 'old'), + ('hurry idiot prefer sunset mention mist jaw inhale impossible kingdom rare squeeze', ''), # almost 'old' but maps to 33 hex chars + ('cram swing cover prefer miss modify ritual silly deliver chunk behind inform able', 'standard'), + ('cram swing cover prefer miss modify ritual silly deliver chunk behind inform', ''), + ('ostrich security deer aunt climb inner alpha arm mutual marble solid task', 'standard'), + ('OSTRICH SECURITY DEER AUNT CLIMB INNER ALPHA ARM MUTUAL MARBLE SOLID TASK', 'standard'), + (' oStRiCh sEcUrItY DeEr aUnT ClImB InNeR AlPhA ArM MuTuAl mArBlE SoLiD TaSk ', 'standard'), + ('x8', 'standard'), + ('science dawn member doll dutch real can brick knife deny drive list', '2fa'), + ('science dawn member doll dutch real ca brick knife deny drive list', ''), + (' sCience dawn member doll Dutch rEAl can brick knife deny drive lisT', '2fa'), + ('frost pig brisk excite novel report camera enlist axis nation novel desert', 'segwit'), + (' fRoSt pig brisk excIte novel rePort CamEra enlist axis nation nOVeL dEsert ', 'segwit'), + ('9dk', 'segwit'), + } def test_new_seed(self): seed = "cram swing cover prefer miss modify ritual silly deliver chunk behind inform able" @@ -364,3 +385,7 @@ class Test_seeds(unittest.TestCase): self.assertTrue(is_old_seed("0123456789ABCDEF" * 2)) self.assertTrue(is_old_seed("0123456789ABCDEF" * 4)) + + def test_seed_type(self): + for seed_words, _type in self.mnemonics: + self.assertEqual(_type, seed_type(seed_words), msg=seed_words) From c05549c8cd7b2d324fd280f8b7b537b3fbf60f5c Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sun, 29 Oct 2017 20:04:31 +0100 Subject: [PATCH 2/2] follow-up prev commit: revert "strict checks" for old seeds --- lib/bitcoin.py | 7 +++---- lib/tests/test_bitcoin.py | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/bitcoin.py b/lib/bitcoin.py index 7df4df27..4d75d0a5 100644 --- a/lib/bitcoin.py +++ b/lib/bitcoin.py @@ -264,10 +264,9 @@ def is_old_seed(seed): seed = mnemonic.normalize_text(seed) words = seed.split() try: - hex_seed = old_mnemonic.mn_decode(words) - words2 = old_mnemonic.mn_encode(hex_seed) - seed2 = ' '.join(words2) - uses_electrum_words = seed == seed2 + # checks here are deliberately left weak for legacy reasons, see #3149 + old_mnemonic.mn_decode(words) + uses_electrum_words = True except Exception: uses_electrum_words = False try: diff --git a/lib/tests/test_bitcoin.py b/lib/tests/test_bitcoin.py index 7732b7b4..94741ead 100644 --- a/lib/tests/test_bitcoin.py +++ b/lib/tests/test_bitcoin.py @@ -355,7 +355,8 @@ class Test_seeds(unittest.TestCase): ('cell dumb heartbeat north boom tease ship baby bright kingdom rare badword', ''), ('cElL DuMb hEaRtBeAt nOrTh bOoM TeAsE ShIp bAbY BrIgHt kInGdOm rArE SqUeEzE', 'old'), (' cElL DuMb hEaRtBeAt nOrTh bOoM TeAsE ShIp bAbY BrIgHt kInGdOm rArE SqUeEzE ', 'old'), - ('hurry idiot prefer sunset mention mist jaw inhale impossible kingdom rare squeeze', ''), # almost 'old' but maps to 33 hex chars + # below seed is actually 'invalid old' as it maps to 33 hex chars + ('hurry idiot prefer sunset mention mist jaw inhale impossible kingdom rare squeeze', 'old'), ('cram swing cover prefer miss modify ritual silly deliver chunk behind inform able', 'standard'), ('cram swing cover prefer miss modify ritual silly deliver chunk behind inform', ''), ('ostrich security deer aunt climb inner alpha arm mutual marble solid task', 'standard'),