Skip to content
Open
Show file tree
Hide file tree
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
40 changes: 30 additions & 10 deletions scripts/build_ffi.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,14 @@ def generate_libwolfssl(fips):

def get_features(local_wolfssl, features):
fips = False
fips_file = None

if sys.platform == "win32":
if local_wolfssl and sys.platform == "win32":
# On Windows, we assume the local_wolfssl path is to a wolfSSL source
# directory where the library has been built.
fips_file = os.path.join(local_wolfssl, "wolfssl", "wolfcrypt",
"fips.h")
else:
elif local_wolfssl:
# On non-Windows platforms, first assume local_wolfssl is an
# installation directory with an include subdirectory.
fips_file = os.path.join(local_wolfssl, "include", "wolfssl",
Expand All @@ -321,7 +322,7 @@ def get_features(local_wolfssl, features):
fips_file = os.path.join(local_wolfssl, "wolfssl", "wolfcrypt",
"fips.h")

if os.path.exists(fips_file):
if fips_file and os.path.exists(fips_file):
with open(fips_file, "r") as f:
contents = f.read()
if not contents.isspace():
Expand All @@ -332,7 +333,7 @@ def get_features(local_wolfssl, features):

for d in include_dirs:
if not os.path.exists(d):
e = "Invalid wolfSSL include dir: .".format(d)
e = "Invalid wolfSSL include dir: {}.".format(d)
raise FileNotFoundError(e)

options = os.path.join(d, "wolfssl", "options.h")
Expand Down Expand Up @@ -496,6 +497,7 @@ def build_ffi(local_wolfssl, features):
int ML_KEM_ENABLED = """ + str(features["ML_KEM"]) + """;
int ML_DSA_ENABLED = """ + str(features["ML_DSA"]) + """;
int HKDF_ENABLED = """ + str(features["HKDF"]) + """;
int ERROR_STRINGS_ENABLED = """ + str(features["ERROR_STRINGS"]) + """;
"""

ffibuilder.set_source( "wolfcrypt._ffi", init_source_string,
Expand Down Expand Up @@ -535,6 +537,7 @@ def build_ffi(local_wolfssl, features):
extern int ML_KEM_ENABLED;
extern int ML_DSA_ENABLED;
extern int HKDF_ENABLED;
extern int ERROR_STRINGS_ENABLED;

typedef unsigned char byte;
typedef unsigned int word32;
Expand All @@ -558,6 +561,7 @@ def build_ffi(local_wolfssl, features):
typedef struct { ...; } mp_int;

int mp_init (mp_int * a);
void mp_clear (mp_int * a);
int mp_to_unsigned_bin (mp_int * a, unsigned char *b);
int mp_to_unsigned_bin_len (mp_int * a, unsigned char *b, int c);
int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
Expand All @@ -569,6 +573,7 @@ def build_ffi(local_wolfssl, features):
int wc_InitSha(wc_Sha*);
int wc_ShaUpdate(wc_Sha*, const byte*, word32);
int wc_ShaFinal(wc_Sha*, byte*);
void wc_ShaFree(wc_Sha*);
"""

if features["SHA256"]:
Expand All @@ -577,6 +582,7 @@ def build_ffi(local_wolfssl, features):
int wc_InitSha256(wc_Sha256*);
int wc_Sha256Update(wc_Sha256*, const byte*, word32);
int wc_Sha256Final(wc_Sha256*, byte*);
void wc_Sha256Free(wc_Sha256*);
"""

if features["SHA384"]:
Expand All @@ -585,6 +591,7 @@ def build_ffi(local_wolfssl, features):
int wc_InitSha384(wc_Sha384*);
int wc_Sha384Update(wc_Sha384*, const byte*, word32);
int wc_Sha384Final(wc_Sha384*, byte*);
void wc_Sha384Free(wc_Sha384*);
"""

if features["SHA512"]:
Expand All @@ -594,6 +601,7 @@ def build_ffi(local_wolfssl, features):
int wc_InitSha512(wc_Sha512*);
int wc_Sha512Update(wc_Sha512*, const byte*, word32);
int wc_Sha512Final(wc_Sha512*, byte*);
void wc_Sha512Free(wc_Sha512*);
"""
if features["SHA3"]:
cdef += """
Expand All @@ -610,6 +618,10 @@ def build_ffi(local_wolfssl, features):
int wc_Sha3_256_Final(wc_Sha3*, byte*);
int wc_Sha3_384_Final(wc_Sha3*, byte*);
int wc_Sha3_512_Final(wc_Sha3*, byte*);
void wc_Sha3_224_Free(wc_Sha3*);
void wc_Sha3_256_Free(wc_Sha3*);
void wc_Sha3_384_Free(wc_Sha3*);
void wc_Sha3_512_Free(wc_Sha3*);
"""

if features["DES3"]:
Expand Down Expand Up @@ -649,6 +661,7 @@ def build_ffi(local_wolfssl, features):
word32 sz, const byte* authIn, word32 authInSz);
int wc_AesGcmDecryptFinal(Aes* aes, const byte* authTag,
word32 authTagSz);
void wc_AesFree(Aes* aes);
"""

if features["AES"] and features["AES_SIV"]:
Expand Down Expand Up @@ -705,6 +718,7 @@ def build_ffi(local_wolfssl, features):
int wc_HmacSetKey(Hmac*, int, const byte*, word32);
int wc_HmacUpdate(Hmac*, const byte*, word32);
int wc_HmacFinal(Hmac*, byte*);
void wc_HmacFree(Hmac*);
"""

if features["RSA"]:
Expand Down Expand Up @@ -961,6 +975,7 @@ def build_ffi(local_wolfssl, features):
int wc_PemToDer(const unsigned char* buff, long longSz, int type,
DerBuffer** pDer, void* heap, EncryptedInfo* info,
int* keyFormat);
void wc_FreeDer(DerBuffer** pDer);
int wc_DerToPemEx(const byte* der, word32 derSz, byte* output, word32 outSz,
byte *cipher_info, int type);
"""
Expand Down Expand Up @@ -988,6 +1003,11 @@ def build_ffi(local_wolfssl, features):
int wolfCrypt_GetPrivateKeyReadEnable_fips(enum wc_KeyType);
"""

if features["ERROR_STRINGS"]:
cdef += """
const char* wc_GetErrorString(int error);
"""

if features["ML_KEM"] or features["ML_DSA"]:
cdef += """
static const int INVALID_DEVID;
Expand Down Expand Up @@ -1087,17 +1107,17 @@ def main(ffibuilder):
e = "Local wolfssl installation path {} doesn't exist.".format(local_wolfssl)
raise FileNotFoundError(e)

get_features(local_wolfssl, features)

if features["RSA_BLINDING"] and features["FIPS"]:
# These settings can't coexist. See settings.h.
features["RSA_BLINDING"] = 0

if not local_wolfssl:
print("Building wolfSSL...")
if not get_libwolfssl():
generate_libwolfssl(features["FIPS"])

get_features(local_wolfssl, features)

if features["RSA_BLINDING"] and features["FIPS"]:
# These settings can't coexist. See settings.h.
features["RSA_BLINDING"] = 0

build_ffi(local_wolfssl, features)


Expand Down
13 changes: 13 additions & 0 deletions tests/test_aesgcmstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,16 @@ def test_encrypt_aad_bad():
gcmdec.decrypt(buf)
with pytest.raises(WolfCryptError):
gcmdec.final(authTag)

def test_invalid_tag_bytes():
key = "fedcba9876543210"
iv = "0123456789abcdef"
with pytest.raises(ValueError, match="tag_bytes must be between 4 and 16"):
AesGcmStream(key, iv, tag_bytes=0)
with pytest.raises(ValueError, match="tag_bytes must be between 4 and 16"):
AesGcmStream(key, iv, tag_bytes=3)
with pytest.raises(ValueError, match="tag_bytes must be between 4 and 16"):
AesGcmStream(key, iv, tag_bytes=17)
# valid edge cases
AesGcmStream(key, iv, tag_bytes=4)
AesGcmStream(key, iv, tag_bytes=16)
26 changes: 26 additions & 0 deletions tests/test_ciphers.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,3 +876,29 @@ def test_aessiv_decrypt_kat_openssl():
TEST_VECTOR_CIPHERTEXT_OPENSSL
)
assert plaintext == TEST_VECTOR_PLAINTEXT_OPENSSL


if _lib.DES3_ENABLED:
def test_des3_rejects_mode_ctr():
key = b"\x01\x23\x45\x67\x89\xab\xcd\xef" * 3
iv = b"\xfe\xdc\xba\x98\x76\x54\x32\x10"
with pytest.raises(ValueError, match="Des3 only supports MODE_CBC"):
Des3(key, MODE_CTR, iv)


if _lib.CHACHA_ENABLED:
def test_chacha_non_block_aligned():
key = b"\x00" * 32
chacha = ChaCha(key)
chacha.set_iv(b"\x00" * 12)
plaintext = b"This is 25 bytes of text!"
assert len(plaintext) == 25
ciphertext = chacha.encrypt(plaintext)
assert len(ciphertext) == 25
chacha2 = ChaCha(key)
chacha2.set_iv(b"\x00" * 12)
assert chacha2.decrypt(ciphertext) == plaintext

def test_chacha_invalid_key_length():
with pytest.raises(ValueError, match="key must be"):
ChaCha(b"\x00" * 20)
1 change: 1 addition & 0 deletions wolfcrypt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
if top_level_py not in ["setup.py", "build_ffi.py"]:
from wolfcrypt._ffi import ffi as _ffi
from wolfcrypt._ffi import lib as _lib
from wolfcrypt.exceptions import WolfCryptError

if hasattr(_lib, 'WC_RNG_SEED_CB_ENABLED'):
if _lib.WC_RNG_SEED_CB_ENABLED:
Expand Down
16 changes: 10 additions & 6 deletions wolfcrypt/asn.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

# pylint: disable=no-member,no-name-in-module

import hmac as _hmac

from wolfcrypt._ffi import ffi as _ffi
from wolfcrypt._ffi import lib as _lib
from wolfcrypt.exceptions import WolfCryptError
Expand All @@ -42,7 +44,9 @@ def pem_to_der(pem, pem_type):
err = "Error converting from PEM to DER. ({})".format(ret)
raise WolfCryptError(err)

return _ffi.buffer(der[0][0].buffer, der[0][0].length)[:]
result = _ffi.buffer(der[0][0].buffer, der[0][0].length)[:]
_lib.wc_FreeDer(der)
return result

def der_to_pem(der, pem_type):
pem_length = _lib.wc_DerToPemEx(der, len(der), _ffi.NULL, 0, _ffi.NULL,
Expand All @@ -61,13 +65,13 @@ def der_to_pem(der, pem_type):
return _ffi.buffer(pem, pem_length)[:]

def hash_oid_from_class(hash_cls):
if hash_cls == Sha:
if _lib.SHA_ENABLED and hash_cls == Sha:
return _lib.SHAh
elif hash_cls == Sha256:
elif _lib.SHA256_ENABLED and hash_cls == Sha256:
return _lib.SHA256h
elif hash_cls == Sha384:
elif _lib.SHA384_ENABLED and hash_cls == Sha384:
return _lib.SHA384h
elif hash_cls == Sha512:
elif _lib.SHA512_ENABLED and hash_cls == Sha512:
return _lib.SHA512h
else:
err = "Unknown hash class {}.".format(hash_cls.__name__)
Expand Down Expand Up @@ -95,4 +99,4 @@ def make_signature(data, hash_cls, key=None):
def check_signature(signature, data, hash_cls, pub_key):
computed_signature = make_signature(data, hash_cls)
decrypted_signature = pub_key.verify(signature)
return computed_signature == decrypted_signature
return _hmac.compare_digest(computed_signature, decrypted_signature)
Loading
Loading