Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions wolfcrypt/ciphers.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,13 +650,13 @@ class _Rsa(object): # pylint: disable=too-few-public-methods
_mgf = None
_hash_type = None

def __init__(self):
def __init__(self, rng=Random()):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [High] Mutable default argument rng=Random() in _Rsa.__init__
🚫 BLOCK bug

The default argument rng=Random() is a classic Python mutable-default-argument bug. Random() is evaluated once at class definition time, and the same object is reused for every call that omits rng. This means all RsaPrivate instances (whose __init__ calls _Rsa.__init__(self) without providing rng on line 851) will share the exact same Random object. If one instance is garbage-collected and its Random object cleaned up, every other instance sharing that default will hold a dangling reference. Even without cleanup issues, sharing a single RNG across independent key objects is a correctness and isolation problem. Ironically, the RsaPublic subclass does this correctly with the rng=None / if rng is None: rng = Random() pattern — the base class should use the same approach.

Suggestion:

Suggested change
def __init__(self, rng=Random()):
def __init__(self, rng=None):
self.native_object = _ffi.new("RsaKey *")
ret = _lib.wc_InitRsaKey(self.native_object, _ffi.NULL)
if ret < 0: # pragma: no cover
raise WolfCryptError("Invalid key error (%d)" % ret)
if rng is None:
rng = Random()
self._random = rng

self.native_object = _ffi.new("RsaKey *")
ret = _lib.wc_InitRsaKey(self.native_object, _ffi.NULL)
if ret < 0: # pragma: no cover
raise WolfCryptError("Invalid key error (%d)" % ret)

self._random = Random()
self._random = rng
if _lib.RSA_BLINDING_ENABLED:
ret = _lib.wc_RsaSetRNG(self.native_object,
self._random.native_object)
Expand Down Expand Up @@ -690,12 +690,14 @@ def _get_mgf(self):


class RsaPublic(_Rsa):
def __init__(self, key=None, hash_type=None):
def __init__(self, key=None, hash_type=None, rng=None):
if key is not None:
key = t2b(key)
self._hash_type = hash_type
if rng is None:
rng = Random()

_Rsa.__init__(self)
_Rsa.__init__(self, rng)

idx = _ffi.new("word32*")
idx[0] = 0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [Medium] RsaPrivate.__init__ not updated to accept/forward rng parameter
💡 SUGGEST api

The PR's stated goal is to make the random generator of _Rsa and RsaPublic configurable. However, RsaPrivate.__init__ (line 849) was not updated to accept an rng parameter, and its call to _Rsa.__init__(self) on line 851 still relies on the default. Since RsaPrivate extends RsaPublic, users would reasonably expect RsaPrivate to also support a configurable RNG. Additionally, RsaPrivate.make_key (line 829) and RsaPublic.from_pem (line 718) also don't forward an rng parameter, leaving the configurability incomplete.

Suggestion:

Suggested change
idx[0] = 0
def __init__(self, key=None, hash_type=None, rng=None): # pylint: disable=super-init-not-called
if rng is None:
rng = Random()
_Rsa.__init__(self, rng) # pylint: disable=non-parent-init-called

Expand Down
Loading