Merge pull request #93 from roberthdevries/rsa-public-add-rng-param

Make the random generator of _Rsa and RsaPublic configurable.
pull/115/head^2
David Garske 2026-05-05 10:35:04 -07:00 committed by GitHub
commit b0708870ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 70 additions and 11 deletions

View File

@ -27,6 +27,7 @@ from wolfcrypt._ffi import lib as _lib
from wolfcrypt.ciphers import MODE_CTR, MODE_ECB, MODE_CBC, WolfCryptError
from wolfcrypt.random import Random
from wolfcrypt.utils import t2b, h2b
from wolfcrypt.random import Random
import os
certs_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "certs")
@ -326,10 +327,18 @@ if _lib.CHACHA_ENABLED:
assert plaintext == dec
if _lib.RSA_ENABLED:
@pytest.fixture
def rng():
return Random()
@pytest.fixture
def rsa_private(vectors):
return RsaPrivate(vectors[RsaPrivate].key)
@pytest.fixture
def rsa_private_rng(vectors, rng):
return RsaPrivate(vectors[RsaPrivate].key, rng=rng)
@pytest.fixture
def rsa_private_oaep(vectors):
return RsaPrivate(vectors[RsaPrivate].key, hash_type=HASH_TYPE_SHA)
@ -346,6 +355,10 @@ if _lib.RSA_ENABLED:
def rsa_public(vectors):
return RsaPublic(vectors[RsaPublic].key)
@pytest.fixture
def rsa_public_rng(vectors, rng):
return RsaPublic(vectors[RsaPublic].key, rng=rng)
@pytest.fixture
def rsa_public_oaep(vectors):
return RsaPublic(vectors[RsaPublic].key, hash_type=HASH_TYPE_SHA)
@ -366,6 +379,17 @@ if _lib.RSA_ENABLED:
pem = f.read()
return RsaPublic.from_pem(pem)
@pytest.fixture
def rsa_private_pem_rng(vectors, rng):
with open(vectors[RsaPrivate].pem, "rb") as f:
pem = f.read()
return RsaPrivate.from_pem(pem, rng=rng)
@pytest.fixture
def rsa_public_pem_rng(vectors, rng):
with open(vectors[RsaPublic].pem, "rb") as f:
pem = f.read()
return RsaPublic.from_pem(pem, rng=rng)
def test_new_rsa_raises(vectors):
with pytest.raises(WolfCryptError):
@ -395,6 +419,22 @@ if _lib.RSA_ENABLED:
assert 1024 / 8 == len(ciphertext) == rsa_private.output_size
assert plaintext == rsa_private.decrypt(ciphertext)
def test_rsa_encrypt_decrypt_rng(rsa_private_rng, rsa_public_rng):
plaintext = t2b("Everyone gets Friday off.")
# normal usage, encrypt with public, decrypt with private
ciphertext = rsa_public_rng.encrypt(plaintext)
assert 1024 / 8 == len(ciphertext) == rsa_public_rng.output_size
assert plaintext == rsa_private_rng.decrypt(ciphertext)
# private object holds both private and public info, so it can also encrypt
# using the known public key.
ciphertext = rsa_private_rng.encrypt(plaintext)
assert 1024 / 8 == len(ciphertext) == rsa_private_rng.output_size
assert plaintext == rsa_private_rng.decrypt(ciphertext)
def test_rsa_encrypt_decrypt_pad_oaep(rsa_private_oaep, rsa_public_oaep):
plaintext = t2b("Everyone gets Friday off.")
@ -478,6 +518,22 @@ if _lib.RSA_ENABLED:
assert 256 == len(signature) == rsa_private_pem.output_size
assert plaintext == rsa_private_pem.verify(signature)
def test_rsa_sign_verify_pem_rng(rsa_private_pem_rng, rsa_public_pem_rng):
plaintext = t2b("Everyone gets Friday off.")
# normal usage, sign with private, verify with public
signature = rsa_private_pem_rng.sign(plaintext)
assert 256 == len(signature) == rsa_private_pem_rng.output_size
assert plaintext == rsa_public_pem_rng.verify(signature)
# private object holds both private and public info, so it can also verify
# using the known public key.
signature = rsa_private_pem_rng.sign(plaintext)
assert 256 == len(signature) == rsa_private_pem_rng.output_size
assert plaintext == rsa_private_pem_rng.verify(signature)
def test_rsa_pkcs8_sign_verify(rsa_private_pkcs8, rsa_public):
plaintext = t2b("Everyone gets Friday off.")

View File

@ -684,13 +684,16 @@ if _lib.RSA_ENABLED:
_mgf = None
_hash_type = None
def __init__(self):
def __init__(self, rng=None):
if rng is None:
rng = Random()
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)
@ -724,13 +727,13 @@ if _lib.RSA_ENABLED:
class RsaPublic(_Rsa):
def __init__(self, key=None, hash_type=None):
def __init__(self, key=None, hash_type=None, rng=None):
super().__init__(rng)
if key is not None:
key = t2b(key)
self._hash_type = hash_type
_Rsa.__init__(self)
idx = _ffi.new("word32*")
idx[0] = 0
@ -747,9 +750,9 @@ if _lib.RSA_ENABLED:
if _lib.ASN_ENABLED:
@classmethod
def from_pem(cls, file, hash_type=None):
def from_pem(cls, file, hash_type=None, rng=None):
der = pem_to_der(file, _lib.PUBLICKEY_TYPE)
return cls(key=der, hash_type=hash_type)
return cls(key=der, hash_type=hash_type, rng=rng)
def encrypt(self, plaintext):
"""
@ -883,9 +886,9 @@ if _lib.RSA_ENABLED:
return rsa
def __init__(self, key=None, hash_type=None): # pylint: disable=super-init-not-called
def __init__(self, key=None, hash_type=None, rng=None): # pylint: disable=super-init-not-called
_Rsa.__init__(self) # pylint: disable=non-parent-init-called
_Rsa.__init__(self, rng) # pylint: disable=non-parent-init-called
self._hash_type = hash_type
idx = _ffi.new("word32*")
idx[0] = 0
@ -913,9 +916,9 @@ if _lib.RSA_ENABLED:
if _lib.ASN_ENABLED:
@classmethod
def from_pem(cls, file, hash_type=None):
def from_pem(cls, file, hash_type=None, rng=None):
der = pem_to_der(file, _lib.PRIVATEKEY_TYPE)
return cls(key=der, hash_type=hash_type)
return cls(key=der, hash_type=hash_type, rng=rng)
if _lib.KEYGEN_ENABLED:
def encode_key(self):