Skip to content

Commit 616e2d1

Browse files
Merge branch 'master' into remove-unicode-prefix
2 parents 993241e + 23e9a7c commit 616e2d1

14 files changed

Lines changed: 483 additions & 120 deletions

File tree

ChangeLog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
wolfCrypt-py Release NEXT (TBD, 2026)
2+
==========================================
3+
4+
* Add extra nonce parameter to Random generator
5+
6+
17
wolfCrypt-py Release 5.8.4 (Jan 7, 2026)
28
==========================================
39

requirements/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
-r prod.txt
22
tox
33
pytest
4+
types-cffi

scripts/build_ffi.py

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ def wolfssl_lib_dir(local_wolfssl=None, fips=False):
101101
return lib_dir
102102

103103
def call(cmd):
104-
print("Calling: '{}' from working directory {}".format(cmd, os.getcwd()))
104+
print(f"Calling: '{cmd}' from working directory {os.getcwd()}")
105105

106106
old_env = os.environ["PATH"]
107-
os.environ["PATH"] = "{}:{}".format(WOLFSSL_SRC_PATH, old_env)
107+
os.environ["PATH"] = f"{WOLFSSL_SRC_PATH}:{old_env}"
108108
subprocess.check_call(cmd, shell=True, env=os.environ)
109109
os.environ["PATH"] = old_env
110110

@@ -133,7 +133,7 @@ def checkout_version(version):
133133
current = subprocess.check_output(
134134
["git", "describe", "--all", "--exact-match"]
135135
).strip().decode().split('/')[-1]
136-
except:
136+
except subprocess.CalledProcessError:
137137
pass
138138

139139
if current != version:
@@ -142,9 +142,9 @@ def checkout_version(version):
142142
).strip().decode().split("\n")
143143

144144
if version != "master" and version not in tags:
145-
call("git fetch --depth=1 origin tag {}".format(version))
145+
call(f"git fetch --depth=1 origin tag {version}")
146146

147-
call("git checkout --force {}".format(version))
147+
call(f"git checkout --force {version}")
148148

149149
return True # rebuild needed
150150

@@ -171,7 +171,7 @@ def make_flags(prefix, fips):
171171
"""
172172
if sys.platform == "win32":
173173
flags = []
174-
flags.append("-DCMAKE_INSTALL_PREFIX={}".format(prefix))
174+
flags.append(f"-DCMAKE_INSTALL_PREFIX={prefix}")
175175
flags.append("-DWOLFSSL_CRYPT_TESTS=no")
176176
flags.append("-DWOLFSSL_EXAMPLES=no")
177177
flags.append("-DBUILD_SHARED_LIBS=no")
@@ -188,7 +188,7 @@ def make_flags(prefix, fips):
188188
flags.append("CFLAGS=-fPIC")
189189

190190
# install location
191-
flags.append("--prefix={}".format(prefix))
191+
flags.append(f"--prefix={prefix}")
192192

193193
# crypt only, lib only
194194
flags.append("--enable-cryptonly")
@@ -261,7 +261,7 @@ def make(configure_flags, fips=False):
261261
raise Exception("Cannot build wolfSSL FIPS from git repo.")
262262

263263
with chdir(build_path):
264-
call("cmake {} ..".format(configure_flags))
264+
call(f"cmake {configure_flags} ..")
265265
call("cmake --build . --config Release")
266266
call("cmake --install . --config Release")
267267
else:
@@ -274,7 +274,7 @@ def make(configure_flags, fips=False):
274274
call("libtoolize")
275275
call("./autogen.sh")
276276

277-
call("./configure {}".format(configure_flags))
277+
call(f"./configure {configure_flags}")
278278
call("make")
279279
call("make install")
280280

@@ -458,45 +458,45 @@ def build_ffi(local_wolfssl, features):
458458
#include <wolfssl/wolfcrypt/dilithium.h>
459459
"""
460460

461-
init_source_string = """
461+
init_source_string = f"""
462462
#ifdef __cplusplus
463-
extern "C" {
463+
extern "C" {{
464464
#endif
465-
""" + includes_string + """
465+
{includes_string}
466466
#ifdef __cplusplus
467-
}
467+
}}
468468
#endif
469469
470-
int ERROR_STRINGS_ENABLED = """ + str(features["ERROR_STRINGS"]) + """;
471-
int MPAPI_ENABLED = """ + str(features["MPAPI"]) + """;
472-
int SHA_ENABLED = """ + str(features["SHA"]) + """;
473-
int SHA256_ENABLED = """ + str(features["SHA256"]) + """;
474-
int SHA384_ENABLED = """ + str(features["SHA384"]) + """;
475-
int SHA512_ENABLED = """ + str(features["SHA512"]) + """;
476-
int SHA3_ENABLED = """ + str(features["SHA3"]) + """;
477-
int DES3_ENABLED = """ + str(features["DES3"]) + """;
478-
int AES_ENABLED = """ + str(features["AES"]) + """;
479-
int AES_SIV_ENABLED = """ + str(features["AES_SIV"]) + """;
480-
int CHACHA_ENABLED = """ + str(features["CHACHA"]) + """;
481-
int HMAC_ENABLED = """ + str(features["HMAC"]) + """;
482-
int RSA_ENABLED = """ + str(features["RSA"]) + """;
483-
int RSA_BLINDING_ENABLED = """ + str(features["RSA_BLINDING"]) + """;
484-
int ECC_TIMING_RESISTANCE_ENABLED = """ + str(features["ECC_TIMING_RESISTANCE"]) + """;
485-
int ECC_ENABLED = """ + str(features["ECC"]) + """;
486-
int ED25519_ENABLED = """ + str(features["ED25519"]) + """;
487-
int ED448_ENABLED = """ + str(features["ED448"]) + """;
488-
int KEYGEN_ENABLED = """ + str(features["KEYGEN"]) + """;
489-
int PWDBASED_ENABLED = """ + str(features["PWDBASED"]) + """;
490-
int FIPS_ENABLED = """ + str(features["FIPS"]) + """;
491-
int FIPS_VERSION = """ + str(features["FIPS_VERSION"]) + """;
492-
int ASN_ENABLED = """ + str(features["ASN"]) + """;
493-
int WC_RNG_SEED_CB_ENABLED = """ + str(features["WC_RNG_SEED_CB"]) + """;
494-
int AESGCM_STREAM_ENABLED = """ + str(features["AESGCM_STREAM"]) + """;
495-
int RSA_PSS_ENABLED = """ + str(features["RSA_PSS"]) + """;
496-
int CHACHA20_POLY1305_ENABLED = """ + str(features["CHACHA20_POLY1305"]) + """;
497-
int ML_KEM_ENABLED = """ + str(features["ML_KEM"]) + """;
498-
int ML_DSA_ENABLED = """ + str(features["ML_DSA"]) + """;
499-
int HKDF_ENABLED = """ + str(features["HKDF"]) + """;
470+
int ERROR_STRINGS_ENABLED = {features["ERROR_STRINGS"]};
471+
int MPAPI_ENABLED = {features["MPAPI"]};
472+
int SHA_ENABLED = {features["SHA"]};
473+
int SHA256_ENABLED = {features["SHA256"]};
474+
int SHA384_ENABLED = {features["SHA384"]};
475+
int SHA512_ENABLED = {features["SHA512"]};
476+
int SHA3_ENABLED = {features["SHA3"]};
477+
int DES3_ENABLED = {features["DES3"]};
478+
int AES_ENABLED = {features["AES"]};
479+
int AES_SIV_ENABLED = {features["AES_SIV"]};
480+
int CHACHA_ENABLED = {features["CHACHA"]};
481+
int HMAC_ENABLED = {features["HMAC"]};
482+
int RSA_ENABLED = {features["RSA"]};
483+
int RSA_BLINDING_ENABLED = {features["RSA_BLINDING"]};
484+
int ECC_TIMING_RESISTANCE_ENABLED = {features["ECC_TIMING_RESISTANCE"]};
485+
int ECC_ENABLED = {features["ECC"]};
486+
int ED25519_ENABLED = {features["ED25519"]};
487+
int ED448_ENABLED = {features["ED448"]};
488+
int KEYGEN_ENABLED = {features["KEYGEN"]};
489+
int PWDBASED_ENABLED = {features["PWDBASED"]};
490+
int FIPS_ENABLED = {features["FIPS"]};
491+
int FIPS_VERSION = {features["FIPS_VERSION"]};
492+
int ASN_ENABLED = {features["ASN"]};
493+
int WC_RNG_SEED_CB_ENABLED = {features["WC_RNG_SEED_CB"]};
494+
int AESGCM_STREAM_ENABLED = {features["AESGCM_STREAM"]};
495+
int RSA_PSS_ENABLED = {features["RSA_PSS"]};
496+
int CHACHA20_POLY1305_ENABLED = {features["CHACHA20_POLY1305"]};
497+
int ML_KEM_ENABLED = {features["ML_KEM"]};
498+
int ML_DSA_ENABLED = {features["ML_DSA"]};
499+
int HKDF_ENABLED = {features["HKDF"]};
500500
"""
501501

502502
ffibuilder.set_source( "wolfcrypt._ffi", init_source_string,
@@ -1306,6 +1306,7 @@ def build_ffi(local_wolfssl, features):
13061306

13071307
if features["ML_DSA"]:
13081308
cdef += """
1309+
static const int DILITHIUM_SEED_SZ;
13091310
static const int WC_ML_DSA_44;
13101311
static const int WC_ML_DSA_65;
13111312
static const int WC_ML_DSA_87;
@@ -1375,9 +1376,9 @@ def main(ffibuilder):
13751376

13761377
local_wolfssl = os.environ.get("USE_LOCAL_WOLFSSL")
13771378
if local_wolfssl:
1378-
print("Using local wolfSSL at {}.".format(local_wolfssl))
1379+
print(f"Using local wolfSSL at {local_wolfssl}.")
13791380
if not os.path.exists(local_wolfssl):
1380-
e = "Local wolfssl installation path {} doesn't exist.".format(local_wolfssl)
1381+
e = f"Local wolfssl installation path {local_wolfssl} doesn't exist."
13811382
raise FileNotFoundError(e)
13821383

13831384
if not local_wolfssl:

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"Programming Language :: Python :: 3.7",
7575
"Programming Language :: Python :: 3.8",
7676
"Programming Language :: Python :: 3.9",
77+
"Programming Language :: Python :: 3.10",
7778
"Topic :: Security",
7879
"Topic :: Security :: Cryptography",
7980
"Topic :: Software Development"
@@ -83,5 +84,5 @@
8384
install_requires=["cffi>=1.0.0"],
8485
cffi_modules=["./scripts/build_ffi.py:ffibuilder"],
8586

86-
package_data={"wolfcrypt": ["*.dll"]}
87+
package_data={"wolfcrypt": ["*.dll", "**/*.pyi"]}
8788
)

tests/test_ciphers.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import pytest
2626
from wolfcrypt._ffi import lib as _lib
2727
from wolfcrypt.ciphers import MODE_CTR, MODE_ECB, MODE_CBC, WolfCryptError
28+
from wolfcrypt.random import Random
2829
from wolfcrypt.utils import t2b, h2b
30+
from wolfcrypt.random import Random
2931
import os
3032

3133
certs_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "certs")
@@ -325,10 +327,18 @@ def test_chacha_enc_dec(chacha_obj):
325327
assert plaintext == dec
326328

327329
if _lib.RSA_ENABLED:
330+
@pytest.fixture
331+
def rng():
332+
return Random()
333+
328334
@pytest.fixture
329335
def rsa_private(vectors):
330336
return RsaPrivate(vectors[RsaPrivate].key)
331337

338+
@pytest.fixture
339+
def rsa_private_rng(vectors, rng):
340+
return RsaPrivate(vectors[RsaPrivate].key, rng=rng)
341+
332342
@pytest.fixture
333343
def rsa_private_oaep(vectors):
334344
return RsaPrivate(vectors[RsaPrivate].key, hash_type=HASH_TYPE_SHA)
@@ -345,6 +355,10 @@ def rsa_private_pkcs8(vectors):
345355
def rsa_public(vectors):
346356
return RsaPublic(vectors[RsaPublic].key)
347357

358+
@pytest.fixture
359+
def rsa_public_rng(vectors, rng):
360+
return RsaPublic(vectors[RsaPublic].key, rng=rng)
361+
348362
@pytest.fixture
349363
def rsa_public_oaep(vectors):
350364
return RsaPublic(vectors[RsaPublic].key, hash_type=HASH_TYPE_SHA)
@@ -365,6 +379,17 @@ def rsa_public_pem(vectors):
365379
pem = f.read()
366380
return RsaPublic.from_pem(pem)
367381

382+
@pytest.fixture
383+
def rsa_private_pem_rng(vectors, rng):
384+
with open(vectors[RsaPrivate].pem, "rb") as f:
385+
pem = f.read()
386+
return RsaPrivate.from_pem(pem, rng=rng)
387+
388+
@pytest.fixture
389+
def rsa_public_pem_rng(vectors, rng):
390+
with open(vectors[RsaPublic].pem, "rb") as f:
391+
pem = f.read()
392+
return RsaPublic.from_pem(pem, rng=rng)
368393

369394
def test_new_rsa_raises(vectors):
370395
with pytest.raises(WolfCryptError):
@@ -394,6 +419,22 @@ def test_rsa_encrypt_decrypt(rsa_private, rsa_public):
394419
assert 1024 / 8 == len(ciphertext) == rsa_private.output_size
395420
assert plaintext == rsa_private.decrypt(ciphertext)
396421

422+
def test_rsa_encrypt_decrypt_rng(rsa_private_rng, rsa_public_rng):
423+
plaintext = t2b("Everyone gets Friday off.")
424+
425+
# normal usage, encrypt with public, decrypt with private
426+
ciphertext = rsa_public_rng.encrypt(plaintext)
427+
428+
assert 1024 / 8 == len(ciphertext) == rsa_public_rng.output_size
429+
assert plaintext == rsa_private_rng.decrypt(ciphertext)
430+
431+
# private object holds both private and public info, so it can also encrypt
432+
# using the known public key.
433+
ciphertext = rsa_private_rng.encrypt(plaintext)
434+
435+
assert 1024 / 8 == len(ciphertext) == rsa_private_rng.output_size
436+
assert plaintext == rsa_private_rng.decrypt(ciphertext)
437+
397438
def test_rsa_encrypt_decrypt_pad_oaep(rsa_private_oaep, rsa_public_oaep):
398439
plaintext = t2b("Everyone gets Friday off.")
399440

@@ -477,6 +518,22 @@ def test_rsa_sign_verify_pem(rsa_private_pem, rsa_public_pem):
477518
assert 256 == len(signature) == rsa_private_pem.output_size
478519
assert plaintext == rsa_private_pem.verify(signature)
479520

521+
def test_rsa_sign_verify_pem_rng(rsa_private_pem_rng, rsa_public_pem_rng):
522+
plaintext = t2b("Everyone gets Friday off.")
523+
524+
# normal usage, sign with private, verify with public
525+
signature = rsa_private_pem_rng.sign(plaintext)
526+
527+
assert 256 == len(signature) == rsa_private_pem_rng.output_size
528+
assert plaintext == rsa_public_pem_rng.verify(signature)
529+
530+
# private object holds both private and public info, so it can also verify
531+
# using the known public key.
532+
signature = rsa_private_pem_rng.sign(plaintext)
533+
534+
assert 256 == len(signature) == rsa_private_pem_rng.output_size
535+
assert plaintext == rsa_private_pem_rng.verify(signature)
536+
480537
def test_rsa_pkcs8_sign_verify(rsa_private_pkcs8, rsa_public):
481538
plaintext = t2b("Everyone gets Friday off.")
482539

@@ -613,11 +670,11 @@ def test_ecc_sign_verify_raw(ecc_private, ecc_public):
613670

614671

615672
def test_ecc_make_shared_secret():
616-
a = EccPrivate.make_key(32)
673+
a = EccPrivate.make_key(32, rng=Random())
617674
a_pub = EccPublic()
618675
a_pub.import_x963(a.export_x963())
619676

620-
b = EccPrivate.make_key(32)
677+
b = EccPrivate.make_key(32, rng=Random())
621678
b_pub = EccPublic()
622679
b_pub.import_x963(b.export_x963())
623680

@@ -626,6 +683,13 @@ def test_ecc_make_shared_secret():
626683
== a.shared_secret(b_pub) \
627684
== b.shared_secret(a_pub)
628685

686+
def test_ecc_make_key_no_rng():
687+
key = EccPrivate.make_key(32)
688+
pub_key = EccPublic()
689+
pub_key.import_x963(key.export_x963())
690+
691+
assert key.shared_secret(pub_key)
692+
629693
if _lib.ED25519_ENABLED:
630694
@pytest.fixture
631695
def ed25519_private(vectors):

0 commit comments

Comments
 (0)