From f8f96983e2a5c3db111d76356a0971a948b52941 Mon Sep 17 00:00:00 2001 From: JeremiahM37 Date: Wed, 18 Mar 2026 11:39:46 -0600 Subject: [PATCH 1/6] Fix Sha3.copy() losing digest_size for non-384 variants --- wolfcrypt/hashes.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/wolfcrypt/hashes.py b/wolfcrypt/hashes.py index 920305b..ef3989e 100644 --- a/wolfcrypt/hashes.py +++ b/wolfcrypt/hashes.py @@ -209,14 +209,7 @@ class Sha3(_Hash): SHA3_384_DIGEST_SIZE = 48 SHA3_512_DIGEST_SIZE = 64 - def __init__(self): # pylint: disable=W0231 - self._native_object = _ffi.new(self._native_type) - self.digest_size = SHA3_384_DIGEST_SIZE - ret = self._init() - if ret < 0: # pragma: no cover - raise WolfCryptError("Sha3 init error (%d)" % ret) - - def __init__(self, string, size=SHA3_384_DIGEST_SIZE): # pylint: disable=W0231 + def __init__(self, string=None, size=SHA3_384_DIGEST_SIZE): # pylint: disable=W0231 self._native_object = _ffi.new(self._native_type) self.digest_size = size ret = self._init() @@ -225,6 +218,15 @@ def __init__(self, string, size=SHA3_384_DIGEST_SIZE): # pylint: disable=W0231 if string: self.update(string) + @classmethod + def new(cls, string=None, size=SHA3_384_DIGEST_SIZE): + return cls(string, size) + + def copy(self): + c = Sha3(size=self.digest_size) + _ffi.memmove(c._native_object, self._native_object, self._native_size) + return c + def _init(self): if (self.digest_size != Sha3.SHA3_224_DIGEST_SIZE and self.digest_size != Sha3.SHA3_256_DIGEST_SIZE and From 476f6858bfecba377cba03723b270a513c8b9fd5 Mon Sep 17 00:00:00 2001 From: JeremiahM37 Date: Wed, 18 Mar 2026 11:41:51 -0600 Subject: [PATCH 2/6] Fix verify_pss returning raw C code instead of boolean --- tests/test_ciphers.py | 4 ++-- wolfcrypt/ciphers.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_ciphers.py b/tests/test_ciphers.py index ec1ed17..79092e2 100644 --- a/tests/test_ciphers.py +++ b/tests/test_ciphers.py @@ -456,14 +456,14 @@ def test_rsa_pss_sign_verify(rsa_private_pss, rsa_public_pss): signature = rsa_private_pss.sign_pss(plaintext) assert 1024 / 8 == len(signature) == rsa_private_pss.output_size - assert 0 == rsa_public_pss.verify_pss(plaintext, signature) + assert rsa_public_pss.verify_pss(plaintext, signature) is True # private object holds both private and public info, so it can also verify # using the known public key. signature = rsa_private_pss.sign_pss(plaintext) assert 1024 / 8 == len(signature) == rsa_private_pss.output_size - assert 0 == rsa_private_pss.verify_pss(plaintext, signature) + assert rsa_private_pss.verify_pss(plaintext, signature) is True def test_rsa_sign_verify_pem(rsa_private_pem, rsa_public_pem): plaintext = t2b("Everyone gets Friday off.") diff --git a/wolfcrypt/ciphers.py b/wolfcrypt/ciphers.py index 6da9f28..d34aef8 100644 --- a/wolfcrypt/ciphers.py +++ b/wolfcrypt/ciphers.py @@ -811,8 +811,10 @@ def verify_pss(self, plaintext, signature): ret = _lib.wc_RsaPSS_CheckPadding(digest, len(digest), verify, ret, self._hash_type) - return ret + if ret < 0: # pragma: no cover + raise WolfCryptError("PSS padding check error (%d)" % ret) + return ret == 0 class RsaPrivate(RsaPublic): From 6892321faf51d097385e0c322e7e78d70b67e1ae Mon Sep 17 00:00:00 2001 From: JeremiahM37 Date: Wed, 18 Mar 2026 11:43:50 -0600 Subject: [PATCH 3/6] Fix CHACHA20_POLY1305 feature check ignoring HAVE_CHACHA --- scripts/build_ffi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_ffi.py b/scripts/build_ffi.py index 18caa3a..3509c45 100644 --- a/scripts/build_ffi.py +++ b/scripts/build_ffi.py @@ -375,7 +375,7 @@ def get_features(local_wolfssl, features): features["WC_RNG_SEED_CB"] = 1 if '#define WC_RNG_SEED_CB' in defines else 0 features["AESGCM_STREAM"] = 1 if '#define WOLFSSL_AESGCM_STREAM' in defines else 0 features["RSA_PSS"] = 1 if '#define WC_RSA_PSS' in defines else 0 - features["CHACHA20_POLY1305"] = 1 if '#define HAVE_CHACHA' and '#define HAVE_POLY1305' in defines else 0 + features["CHACHA20_POLY1305"] = 1 if ('#define HAVE_CHACHA' in defines and '#define HAVE_POLY1305' in defines) else 0 features["ML_DSA"] = 1 if '#define HAVE_DILITHIUM' in defines else 0 features["ML_KEM"] = 1 if '#define WOLFSSL_HAVE_MLKEM' in defines else 0 features["HKDF"] = 1 if "#define HAVE_HKDF" in defines else 0 From 48fe5aefe0ff42dd4ed4ca556ce418f5728fbb0a Mon Sep 17 00:00:00 2001 From: JeremiahM37 Date: Wed, 18 Mar 2026 11:44:14 -0600 Subject: [PATCH 4/6] Fix re.search on list instead of string in FIPS version detection --- scripts/build_ffi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_ffi.py b/scripts/build_ffi.py index 3509c45..36a3e9d 100644 --- a/scripts/build_ffi.py +++ b/scripts/build_ffi.py @@ -386,7 +386,7 @@ def get_features(local_wolfssl, features): raise RuntimeError(e) features["FIPS"] = 1 - version_match = re.search(r'#define HAVE_FIPS_VERSION\s+(\d+)', defines) + version_match = re.search(r'#define HAVE_FIPS_VERSION\s+(\d+)', '\n'.join(defines)) if version_match is not None: features["FIPS_VERSION"] = int(version_match.group(1)) else: From 3ca2548ec5368470ee8439f1004d4d01dd3f2d9b Mon Sep 17 00:00:00 2001 From: JeremiahM37 Date: Wed, 18 Mar 2026 11:44:40 -0600 Subject: [PATCH 5/6] Move wc_RsaSSL_Sign/Verify declarations out of RSA_PSS block --- scripts/build_ffi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build_ffi.py b/scripts/build_ffi.py index 36a3e9d..4d5ad22 100644 --- a/scripts/build_ffi.py +++ b/scripts/build_ffi.py @@ -756,6 +756,8 @@ def build_ffi(local_wolfssl, features): int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, int type, enum wc_HashType hash, int mgf, byte* label, word32 labelSz); + int wc_RsaSSL_Sign(const byte*, word32, byte*, word32, RsaKey*, WC_RNG*); + int wc_RsaSSL_Verify(const byte*, word32, byte*, word32, RsaKey*); """ if features["RSA_PSS"]: @@ -766,8 +768,6 @@ def build_ffi(local_wolfssl, features): enum wc_HashType hash, int mgf, RsaKey* key); int wc_RsaPSS_CheckPadding(const byte* in, word32 inSz, byte* sig, word32 sigSz, enum wc_HashType hashType); - int wc_RsaSSL_Sign(const byte*, word32, byte*, word32, RsaKey*, WC_RNG*); - int wc_RsaSSL_Verify(const byte*, word32, byte*, word32, RsaKey*); """ if features["RSA_BLINDING"]: From 6e8c43bde4da9d7682277f890e27d0231f5acb93 Mon Sep 17 00:00:00 2001 From: JeremiahM37 Date: Wed, 18 Mar 2026 11:45:24 -0600 Subject: [PATCH 6/6] Add nonce length validation to ChaCha.set_iv --- wolfcrypt/ciphers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wolfcrypt/ciphers.py b/wolfcrypt/ciphers.py index d34aef8..105224e 100644 --- a/wolfcrypt/ciphers.py +++ b/wolfcrypt/ciphers.py @@ -530,8 +530,13 @@ def _decrypt(self, destination, source): return _lib.wc_Chacha_Process(self._dec, destination, source, len(source)) + _NONCE_SIZE = 12 + def set_iv(self, nonce, counter = 0): self._IV_nonce = t2b(nonce) + if len(self._IV_nonce) != self._NONCE_SIZE: + raise ValueError("nonce must be %d bytes, got %d" % + (self._NONCE_SIZE, len(self._IV_nonce))) self._IV_counter = counter self._set_key(0)