Browse Source

passgen: passwd length sanity checks

- forbid attempts to generate passwords with bit length greater than seed
MMGen 5 years ago
parent
commit
fefea42b9c
2 changed files with 32 additions and 6 deletions
  1. 26 1
      mmgen/addr.py
  2. 6 5
      test/test_py_d/ts_ref_3seed.py

+ 26 - 1
mmgen/addr.py

@@ -835,6 +835,7 @@ Record this checksum: it will be used to verify the password file in the future
 			self.set_pw_len(pw_len)
 			if chk_params_only:
 				return
+			self.set_pw_len_vs_seed_len(pw_len,seed)
 			self.al_id = AddrListID(seed.sid,MMGenPasswordType('P'))
 			self.data = self.generate(seed,pw_idxs)
 
@@ -882,6 +883,30 @@ Record this checksum: it will be used to verify the password file in the future
 		self.pw_len = int(pw_len)
 		self.chk_pw_len()
 
+	def set_pw_len_vs_seed_len(self,pw_len,seed):
+		pf = self.pw_fmt
+		if pf == 'hex':
+			pw_bytes = self.pw_len // 2
+			good_pw_len = seed.byte_len * 2
+		elif pf in ('b32','b58'):
+			pw_int = (32 if pf == 'b32' else 58) ** self.pw_len
+			pw_bytes = pw_int.bit_length() // 8
+			good_pw_len = len(baseconv.fromhex('ff'*seed.byte_len,wl_id=pf))
+		else:
+			raise NotImplementedError('{!r}: unknown password format'.format(pf))
+
+		if pw_bytes > seed.byte_len:
+			m1 = 'Cannot generate passwords with more entropy than underlying seed! ({} bits)'
+			m2 = 'Re-run the command with --passwd-len={}' if pf == 'hex' else \
+				 'Re-run the command, specifying a password length of {} or less'
+			die(1,(m1+'\n'+m2).format(len(seed.data) * 8,good_pw_len))
+
+		if pf == 'hex' and pw_bytes < seed.byte_len:
+			m1 = 'WARNING: requested {} length has less entropy than underlying seed!'
+			m2 = 'Is this what you want?'
+			if not keypress_confirm((m1+'\n'+m2).format(self.pw_info[pf].desc),default_yes=True):
+				die(1,'Exiting at user request')
+
 	def make_passwd(self,hex_sec):
 		assert self.pw_fmt in self.pw_info
 		if self.pw_fmt == 'hex':
@@ -894,7 +919,7 @@ Record this checksum: it will be used to verify the password file in the future
 	def check_format(self,pw):
 		if not self.pw_info[self.pw_fmt].chk_func(pw):
 			raise ValueError('Password is not valid {} data'.format(self.pw_info[self.pw_fmt].desc))
-		pwlen = len(pw.split()) if self.pw_fmt == 'bip39' else len(pw)
+		pwlen = len(pw)
 		if pwlen != self.pw_len:
 			raise ValueError('Password has incorrect length ({} != {})'.format(pwlen,self.pw_len))
 		return True

+ 6 - 5
test/test_py_d/ts_ref_3seed.py

@@ -75,7 +75,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
 		'refpasswdgen_1':     'EB29 DC4F 924B 289F',
 		'refpasswdgen_half_1':'D310 2593 B5D9 2E88',
 		'ref_b32passwdgen_1': '37B6 C218 2ABC 7508',
-		'ref_hexpasswdgen_1': '523A F547 0E69 8323',
+		'ref_hexpasswdgen_1': '8E99 E696 84CE E7D5',
 		'ref_hexpasswdgen_half_1': '8E99 E696 84CE E7D5',
 		'refaddrgen_legacy_2': {
 			'btc': ('8C17 A5FA 0470 6E89','764C 66F9 7502 AAEA'),
@@ -112,7 +112,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
 		'refpasswdgen_2':     'ADEA 0083 094D 489A',
 		'refpasswdgen_half_2':'12B3 4929 9506 76E0',
 		'ref_b32passwdgen_2': '2A28 C5C7 36EC 217A',
-		'ref_hexpasswdgen_2': 'B11C AC6A 1464 608D',
+		'ref_hexpasswdgen_2': '88F9 0D48 3A7E 7CC2',
 		'ref_hexpasswdgen_half_2': '59F3 8F48 861E 1186',
 		'refaddrgen_legacy_3': {
 			'btc': ('6FEF 6FB9 7B13 5D91','424E 4326 CFFE 5F51'),
@@ -332,9 +332,10 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
 		return self.addrgen(wf,pf,check_ref=True,ftype='pass32',id_str='фубар@crypto.org',extra_args=ea)
 
 	def ref_hexpasswdgen(self,wf,pf):
-		ea = ['--passwd-fmt=hex']
+		pw_len = {'1':32,'2':48,'3':64}[self.test_name[-1]]
+		ea = ['--passwd-fmt=hex','--passwd-len={}'.format(pw_len)]
 		return self.addrgen(wf,pf,check_ref=True,ftype='passhex',id_str='фубар@crypto.org',extra_args=ea)
 
 	def ref_hexpasswdgen_half(self,wf,pf):
-		ea = ['--passwd-fmt=hex','--passwd-len=h']
-		return self.addrgen(wf,pf,check_ref=True,ftype='passhex',id_str='фубар@crypto.org',extra_args=ea)
+		ea = ['--passwd-fmt=hex','--passwd-len=h','--accept-defaults']
+		return self.addrgen(wf,pf,check_ref=True,ftype='passhex',id_str='фубар@crypto.org',extra_args=ea,stdout=1)