Skip to content

Commit 8b3acfc

Browse files
authored
Merge pull request #119 from LinuxJedi/f-fixes2
Address Fenrir findings
2 parents c6d23d3 + ef4195f commit 8b3acfc

8 files changed

Lines changed: 49 additions & 15 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ classifiers = [
2323
]
2424
dynamic = ["version"]
2525
dependencies = [
26-
"cffi>=1.0.0",
26+
"cffi>=1.0.0,<2",
2727
]
2828

2929
[project.urls]

requirements/docs.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
-r prod.txt
2-
Sphinx
3-
sphinx_rtd_theme
2+
Sphinx>=7,<9
3+
sphinx_rtd_theme>=2,<4

requirements/prod.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
cffi
1+
cffi>=1.17,<2

requirements/test.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
-r prod.txt
2-
tox
3-
pytest
4-
types-cffi
2+
tox>=4,<5
3+
pytest>=8,<9
4+
types-cffi>=1.16,<2

scripts/build_ffi.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,8 @@ def build_ffi(local_wolfssl, features):
545545
typedef struct { ...; } OS_Seed;
546546
547547
int wc_InitRng(WC_RNG*);
548-
int wc_InitRngNonce(WC_RNG*, byte*, word32);
549-
int wc_InitRngNonce_ex(WC_RNG*, byte*, word32, void*, int);
548+
int wc_InitRngNonce(WC_RNG*, const byte*, word32);
549+
int wc_InitRngNonce_ex(WC_RNG*, const byte*, word32, void*, int);
550550
int wc_RNG_GenerateBlock(WC_RNG*, byte*, word32);
551551
int wc_RNG_GenerateByte(WC_RNG*, byte*);
552552
int wc_FreeRng(WC_RNG*);
@@ -1039,10 +1039,12 @@ def build_ffi(local_wolfssl, features):
10391039
RsaKey*, WC_RNG*);
10401040
int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out,
10411041
word32 outLen, RsaKey* key, WC_RNG* rng, int type,
1042-
enum wc_HashType hash, int mgf, byte* label, word32 labelSz);
1042+
enum wc_HashType hash, int mgf, const byte* label,
1043+
word32 labelSz);
10431044
int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen,
10441045
byte* out, word32 outLen, RsaKey* key, int type,
1045-
enum wc_HashType hash, int mgf, byte* label, word32 labelSz);
1046+
enum wc_HashType hash, int mgf, const byte* label,
1047+
word32 labelSz);
10461048
int wc_RsaSSL_Sign(const byte*, word32, byte*, word32, RsaKey*, WC_RNG*);
10471049
int wc_RsaSSL_Verify(const byte*, word32, byte*, word32, RsaKey*);
10481050
"""

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@
6060

6161
packages=find_packages(),
6262

63-
setup_requires=["cffi>=1.0.0"],
64-
install_requires=["cffi>=1.0.0"],
63+
setup_requires=["cffi>=1.0.0,<2"],
64+
install_requires=["cffi>=1.0.0,<2"],
6565
cffi_modules=["./scripts/build_ffi.py:ffibuilder"],
6666

6767
package_data={"wolfcrypt": ["*.dll", "**/*.pyi"]}

tests/test_aesgcmstream.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def test_encrypt_short_tag():
5050
authTag = gcm.final()
5151
assert b2h(authTag) == bytes('ac8fcee96dc6ef8e5236da19', 'utf-8')
5252
assert b2h(buf) == bytes('5ba7d42e1bf01d7998e932', "utf-8")
53-
gcmdec = AesGcmStream(key, iv)
53+
gcmdec = AesGcmStream(key, iv, 12)
5454
bufdec = gcmdec.decrypt(buf)
5555
gcmdec.final(authTag)
5656
assert bufdec == t2b("hello world")
@@ -144,6 +144,33 @@ def test_invalid_tag_bytes():
144144
tag = gcm.final()
145145
assert len(tag) == good
146146

147+
def test_decrypt_rejects_wrong_tag_length():
148+
key = "fedcba9876543210"
149+
iv = "0123456789abcdef"
150+
gcm = AesGcmStream(key, iv, tag_bytes=16)
151+
buf = gcm.encrypt("hello world")
152+
authTag = gcm.final()
153+
assert len(authTag) == 16
154+
155+
# Truncated tag: would silently lower the verification window to
156+
# 32-bit forgery probability without this check.
157+
gcmdec = AesGcmStream(key, iv, tag_bytes=16)
158+
gcmdec.decrypt(buf)
159+
with pytest.raises(ValueError, match="authTag must be 16 bytes"):
160+
gcmdec.final(authTag[:4])
161+
162+
# Over-long tag is also rejected.
163+
gcmdec2 = AesGcmStream(key, iv, tag_bytes=16)
164+
gcmdec2.decrypt(buf)
165+
with pytest.raises(ValueError, match="authTag must be 16 bytes"):
166+
gcmdec2.final(authTag + b"\x00")
167+
168+
# Happy path with the configured length still verifies.
169+
gcmdec3 = AesGcmStream(key, iv, tag_bytes=16)
170+
plain = gcmdec3.decrypt(buf)
171+
gcmdec3.final(authTag)
172+
assert plain == t2b("hello world")
173+
147174
def test_repeated_construction_destruction():
148175
import gc
149176
key = "fedcba9876543210"

wolfcrypt/ciphers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,12 @@ def final(self, authTag=None):
496496
if authTag is None:
497497
raise WolfCryptError("authTag parameter required")
498498
authTag = t2b(authTag)
499-
ret = _lib.wc_AesGcmDecryptFinal(self._native_object, authTag, len(authTag))
499+
if len(authTag) != self._tag_bytes:
500+
raise ValueError(
501+
"authTag must be %d bytes, got %d" %
502+
(self._tag_bytes, len(authTag)))
503+
ret = _lib.wc_AesGcmDecryptFinal(
504+
self._native_object, authTag, self._tag_bytes)
500505
if ret < 0:
501506
raise WolfCryptApiError("Decryption error", ret)
502507

0 commit comments

Comments
 (0)