Browse Source

keygen.py: forbid use of non-safe public key generation backends

While the default generation backends for all public key types are timing
safe, a non-safe implementation could be selected manually by the user or
automatically as a fallback in the case of a broken installation (e.g.
missing libsecp256k1).

This patch prevents the use of non-timing-safe backends altogether except
when testing.
The MMGen Project 11 months ago
parent
commit
a49aa2ba53
4 changed files with 21 additions and 2 deletions
  1. 7 0
      mmgen/keygen.py
  2. 6 0
      mmgen/proto/secp256k1/keygen.py
  3. 5 2
      mmgen/proto/xmr/keygen.py
  4. 3 0
      mmgen/proto/zec/keygen.py

+ 7 - 0
mmgen/keygen.py

@@ -32,6 +32,13 @@ keygen_public_data = namedtuple(
 
 
 class keygen_base:
 class keygen_base:
 
 
+	def __init__(self,cfg):
+		if not (self.production_safe or cfg.test_suite):
+			from .util import die
+			die(2,
+				f'Public key generator {type(self).__name__!r} is not safe from timing attacks '
+				'and may only be used in a testing environment')
+
 	def gen_data(self,privkey):
 	def gen_data(self,privkey):
 		assert isinstance(privkey,PrivKey)
 		assert isinstance(privkey,PrivKey)
 		return keygen_public_data(
 		return keygen_public_data(

+ 6 - 0
mmgen/proto/secp256k1/keygen.py

@@ -19,7 +19,10 @@ class backend:
 
 
 	class libsecp256k1(keygen_base):
 	class libsecp256k1(keygen_base):
 
 
+		production_safe = True
+
 		def __init__(self,cfg):
 		def __init__(self,cfg):
+			super().__init__(cfg)
 			# catch ImportError to satisfy pylint when testing repo with unbuilt secp256k1 extension mod:
 			# catch ImportError to satisfy pylint when testing repo with unbuilt secp256k1 extension mod:
 			try:
 			try:
 				from .secp256k1 import priv2pub
 				from .secp256k1 import priv2pub
@@ -51,7 +54,10 @@ class backend:
 
 
 	class python_ecdsa(keygen_base):
 	class python_ecdsa(keygen_base):
 
 
+		production_safe = False
+
 		def __init__(self,cfg):
 		def __init__(self,cfg):
+			super().__init__(cfg)
 			import ecdsa
 			import ecdsa
 			self.ecdsa = ecdsa
 			self.ecdsa = ecdsa
 
 

+ 5 - 2
mmgen/proto/xmr/keygen.py

@@ -20,10 +20,9 @@ class backend:
 	class base(keygen_base):
 	class base(keygen_base):
 
 
 		def __init__(self,cfg):
 		def __init__(self,cfg):
-
+			super().__init__(cfg)
 			from ...proto.xmr.params import mainnet
 			from ...proto.xmr.params import mainnet
 			self.proto_cls = mainnet
 			self.proto_cls = mainnet
-
 			from ...util2 import get_keccak
 			from ...util2 import get_keccak
 			self.keccak_256 = get_keccak(cfg)
 			self.keccak_256 = get_keccak(cfg)
 
 
@@ -35,6 +34,8 @@ class backend:
 
 
 	class nacl(base):
 	class nacl(base):
 
 
+		production_safe = True
+
 		def __init__(self,cfg):
 		def __init__(self,cfg):
 			super().__init__(cfg)
 			super().__init__(cfg)
 			from nacl.bindings import crypto_scalarmult_ed25519_base_noclamp
 			from nacl.bindings import crypto_scalarmult_ed25519_base_noclamp
@@ -49,6 +50,8 @@ class backend:
 
 
 	class ed25519(base):
 	class ed25519(base):
 
 
+		production_safe = False
+
 		def __init__(self,cfg):
 		def __init__(self,cfg):
 			super().__init__(cfg)
 			super().__init__(cfg)
 			from ...contrib.ed25519 import edwards,encodepoint,B,scalarmult
 			from ...contrib.ed25519 import edwards,encodepoint,B,scalarmult

+ 3 - 0
mmgen/proto/zec/keygen.py

@@ -19,7 +19,10 @@ class backend:
 
 
 	class nacl(keygen_base):
 	class nacl(keygen_base):
 
 
+		production_safe = True
+
 		def __init__(self,cfg):
 		def __init__(self,cfg):
+			super().__init__(cfg)
 			from nacl.bindings import crypto_scalarmult_base
 			from nacl.bindings import crypto_scalarmult_base
 			self.crypto_scalarmult_base = crypto_scalarmult_base
 			self.crypto_scalarmult_base = crypto_scalarmult_base
 			from ...sha2 import Sha256
 			from ...sha2 import Sha256