protocol.py: check that private key is within allowable range

- if pk == 0 or pk == secp256k1_ge: FAIL
- if pk > secp256k1_ge: pk = pk % secp256k1_ge
This commit is contained in:
The MMGen Project 2018-09-29 14:38:49 +00:00
commit 0d77a78a4c
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
2 changed files with 24 additions and 7 deletions

View file

@ -657,12 +657,14 @@ class PrivKey(str,Hilite,InitErrors,MMGenObject):
try:
assert s and type(compressed) == bool and pubkey_type,'Incorrect args for PrivKey()'
assert len(s) == cls.width / 2,'Key length must be {}'.format(cls.width/2)
me = str.__new__(cls,g.proto.preprocess_key(s.encode('hex'),pubkey_type))
me.orig_hex = s.encode('hex') # save the non-preprocessed key
if pubkey_type == 'password': # skip WIF creation and pre-processing for passwds
me = str.__new__(cls,s.encode('hex'))
else:
me = str.__new__(cls,g.proto.preprocess_key(s.encode('hex'),pubkey_type))
me.wif = WifKey(g.proto.hex2wif(me,pubkey_type,compressed),on_fail='raise')
me.compressed = compressed
me.pubkey_type = pubkey_type
if pubkey_type != 'password': # skip WIF creation for passwds
me.wif = WifKey(g.proto.hex2wif(me,pubkey_type,compressed),on_fail='raise')
me.orig_hex = s.encode('hex') # save the non-preprocessed key
return me
except Exception as e:
fs = "Key={!r}\nCompressed={}\nValue pair cannot be converted to PrivKey\n({})"

View file

@ -22,7 +22,7 @@ protocol.py: Coin protocol functions, classes and methods
import sys,os,hashlib
from binascii import unhexlify
from mmgen.util import msg,pmsg,Msg,pdie
from mmgen.util import msg,pmsg,ymsg,Msg,pdie,ydie
from mmgen.obj import MMGenObject,BTCAmt,LTCAmt,BCHAmt,B2XAmt,ETHAmt
from mmgen.globalvars import g
import mmgen.bech32 as bech32
@ -93,6 +93,7 @@ class BitcoinProtocol(MMGenObject):
witness_vernum = int(witness_vernum_hex,16)
bech32_hrp = 'bc'
sign_mode = 'daemon'
secp256k1_ge = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
@classmethod
def is_testnet(cls):
@ -110,7 +111,19 @@ class BitcoinProtocol(MMGenObject):
def cap(cls,s): return s in cls.caps
@classmethod
def preprocess_key(cls,hexpriv,pubkey_type): return hexpriv
def preprocess_key(cls,hexpriv,pubkey_type):
# Key must be non-zero and less than group order of secp256k1 curve
if 0 < int(hexpriv,16) < cls.secp256k1_ge:
return hexpriv
else: # chance of this is less than 1 in 2^127
pk = int(hexpriv,16)
if pk == 0: # chance of this is 1 in 2^256
ydie(3,'Private key is zero!')
elif pk == cls.secp256k1_ge: # ditto
ydie(3,'Private key == secp256k1_ge!')
else:
ymsg('Warning: private key is greater than secp256k1 group order!:\n {}'.format(hexpriv))
return '{:064x}'.format(pk % cls.secp256k1_ge)
@classmethod
def hex2wif(cls,hexpriv,pubkey_type,compressed):
@ -131,6 +144,8 @@ class BitcoinProtocol(MMGenObject):
else:
assert len(key) == 64,'invalid key length'
compressed = False
assert 0 < int(key[:64],16) < cls.secp256k1_ge,(
"'{}': invalid WIF (produces key outside allowable range)".format(wif))
return { 'hex':key[:64], 'pubkey_type':pubkey_type, 'compressed':compressed }
@classmethod
@ -292,7 +307,7 @@ class DummyWIF(object):
def wif2hex(cls,wif):
return { 'hex':str(wif), 'pubkey_type':cls.pubkey_type, 'compressed':False }
class EthereumProtocol(DummyWIF,BitcoinProtocolAddrgen):
class EthereumProtocol(DummyWIF,BitcoinProtocol):
addr_width = 40
mmtypes = ('E',)