pypi312 / cryptography /Test_Cryptography.py
PythonSTB's picture
Upload cryptography/Test_Cryptography.py with huggingface_hub
b52906b verified
Raw
History Blame Contribute Delete
18.5 kB
"""
On-device verification for the cross-compiled cryptography + cffi wheels.
Run after installing:
pip install pycparser-2.22-py2.py3-none-any.whl
pip install cffi-2.1.1-cp312-cp312-android_24_<ABI>.whl
pip install cryptography-50.0.0-cp312-abi3-android_24_<ABI>.whl
Usage:
python test_crypto_on_device.py [--quick]
Exit code 0 = everything required PASSed.
Sections marked [SKIP] are features the bundled OpenSSL 3.2.1 does not
provide (e.g. post-quantum ML-KEM/ML-DSA) and are informational only.
Generated by RIMI
"""
import sys
import traceback
RESULTS = []
def test(name, fn):
try:
fn()
RESULTS.append((name, "PASS", None))
except NotImplementedError as exc:
RESULTS.append((name, "SKIP", str(exc)))
except Exception as exc:
RESULTS.append((name, "FAIL", "%s: %s" % (type(exc).__name__, exc)))
print(" ! %s -> %s: %s" % (name, type(exc).__name__, exc))
def section(title):
print("=" * 60)
print(title)
print("=" * 60)
# ---------------------------------------------------------------------------
# 1. cryptography import surface
# ---------------------------------------------------------------------------
def imports_core():
import cryptography
assert cryptography.__version__ == "50.0.0", cryptography.__version__
import cryptography.hazmat.bindings._rust # noqa: F401 (the .so extension)
import cryptography.exceptions # noqa: F401
import cryptography.utils # noqa: F401
import cryptography.fernet # noqa: F401
import cryptography.cobblestone # noqa: F401
def imports_bindings():
import cryptography.hazmat.backends.openssl.backend # noqa: F401
import cryptography.hazmat.bindings.openssl._conditional # noqa: F401
import cryptography.hazmat.bindings.openssl.binding # noqa: F401
import cryptography.hazmat.bindings._rust # noqa: F401
def imports_primitives():
import cryptography.hazmat.primitives.hashes # noqa: F401
import cryptography.hazmat.primitives.hmac # noqa: F401
import cryptography.hazmat.primitives.cmac # noqa: F401
import cryptography.hazmat.primitives.ciphers # noqa: F401
import cryptography.hazmat.primitives.ciphers.aead # noqa: F401
import cryptography.hazmat.primitives.padding # noqa: F401
import cryptography.hazmat.primitives.constant_time # noqa: F401
import cryptography.hazmat.primitives.keywrap # noqa: F401
import cryptography.hazmat.primitives.poly1305 # noqa: F401
import cryptography.hazmat.primitives.hpke # noqa: F401
import cryptography.hazmat.primitives.kdf.hkdf # noqa: F401
import cryptography.hazmat.primitives.kdf.pbkdf2 # noqa: F401
import cryptography.hazmat.primitives.kdf.scrypt # noqa: F401
import cryptography.hazmat.primitives.kdf.kbkdf # noqa: F401
import cryptography.hazmat.primitives.kdf.concatkdf # noqa: F401
import cryptography.hazmat.primitives.kdf.x963kdf # noqa: F401
import cryptography.hazmat.primitives.serialization # noqa: F401
import cryptography.hazmat.primitives.serialization.pkcs7 # noqa: F401
import cryptography.hazmat.primitives.serialization.pkcs12 # noqa: F401
import cryptography.hazmat.primitives.serialization.ssh # noqa: F401
import cryptography.hazmat.primitives.twofactor.hotp # noqa: F401
import cryptography.hazmat.primitives.twofactor.totp # noqa: F401
def imports_asymmetric():
import cryptography.hazmat.primitives.asymmetric.rsa # noqa: F401
import cryptography.hazmat.primitives.asymmetric.ec # noqa: F401
import cryptography.hazmat.primitives.asymmetric.dsa # noqa: F401
import cryptography.hazmat.primitives.asymmetric.dh # noqa: F401
import cryptography.hazmat.primitives.asymmetric.ed25519 # noqa: F401
import cryptography.hazmat.primitives.asymmetric.ed448 # noqa: F401
import cryptography.hazmat.primitives.asymmetric.x25519 # noqa: F401
import cryptography.hazmat.primitives.asymmetric.x448 # noqa: F401
import cryptography.hazmat.primitives.asymmetric.padding # noqa: F401
import cryptography.hazmat.primitives.asymmetric.utils # noqa: F401
def imports_x509():
import cryptography.x509 # noqa: F401
import cryptography.x509.base # noqa: F401
import cryptography.x509.extensions # noqa: F401
import cryptography.x509.general_name # noqa: F401
import cryptography.x509.name # noqa: F401
import cryptography.x509.ocsp # noqa: F401
import cryptography.x509.oid # noqa: F401
import cryptography.x509.verification # noqa: F401
import cryptography.x509.certificate_transparency # noqa: F401
# ---------------------------------------------------------------------------
# 2. hashes / hmac / cmac
# ---------------------------------------------------------------------------
def hashes():
from cryptography.hazmat.primitives import hashes
d = hashes.Hash(hashes.SHA256())
d.update(b"hello cryptography")
assert d.finalize().hex() == (
"a301dc0ba3af7e81df0d99b6b37c4ffca866cb2ee44058bb76158db3b59d02b9"
), "SHA256 mismatch"
def sha512():
from cryptography.hazmat.primitives import hashes
d = hashes.Hash(hashes.SHA512())
d.update(b"abc")
h = d.finalize().hex()
assert h.startswith("ddaf35a193617aba"), "SHA512 mismatch"
def sha3_and_blake2():
from cryptography.hazmat.primitives import hashes
for cls in (hashes.SHA3_256, hashes.SHA3_512):
d = hashes.Hash(cls())
d.update(b"data")
assert len(d.finalize()) == d.algorithm.digest_size
d = hashes.Hash(hashes.BLAKE2b(digest_size=64))
d.update(b"data")
assert len(d.finalize()) == 64
d = hashes.Hash(hashes.SHA256())
d.update(b"x")
assert len(d.finalize()) == 32
def hmac_():
from cryptography.hazmat.primitives import hashes, hmac
h = hmac.HMAC(b"key", hashes.SHA256())
h.update(b"message")
assert len(h.finalize()) == 32
def cmac():
from cryptography.hazmat.primitives import cmac
from cryptography.hazmat.primitives.ciphers import algorithms
c = cmac.CMAC(algorithms.AES(b"0" * 16))
c.update(b"msg")
assert len(c.finalize()) == 16
# ---------------------------------------------------------------------------
# 3. symmetric ciphers
# ---------------------------------------------------------------------------
def aes_gcm():
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = bytes(range(32))
nonce = b"123456789012"
ct = AESGCM(key).encrypt(nonce, b"secret message", b"aad")
pt = AESGCM(key).decrypt(nonce, ct, b"aad")
assert pt == b"secret message"
def aes_cbc():
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
cipher = Cipher(algorithms.AES(b"0" * 16), modes.CBC(b"0" * 16))
enc = cipher.encryptor()
ct = enc.update(b"0123456789abcdef") + enc.finalize()
cipher2 = Cipher(algorithms.AES(b"0" * 16), modes.CBC(b"0" * 16))
dec = cipher2.decryptor()
assert dec.update(ct) + dec.finalize() == b"0123456789abcdef"
def chacha20_poly1305():
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
key = bytes(range(32))
nonce = b"123456789012"
ct = ChaCha20Poly1305(key).encrypt(nonce, b"hello", None)
assert ChaCha20Poly1305(key).decrypt(nonce, ct, None) == b"hello"
def padding_():
from cryptography.hazmat.primitives import padding
p = padding.PKCS7(128).padder()
data = p.update(b"1234") + p.finalize()
u = padding.PKCS7(128).unpadder()
assert u.update(data) + u.finalize() == b"1234"
def keywrap_():
from cryptography.hazmat.primitives.keywrap import aes_key_wrap, aes_key_unwrap
kek = b"0" * 16
wrapped = aes_key_wrap(kek, b"1" * 24)
assert aes_key_unwrap(kek, wrapped) == b"1" * 24
# ---------------------------------------------------------------------------
# 4. asymmetric
# ---------------------------------------------------------------------------
def rsa_sign_verify():
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
sig = key.sign(b"data", padding.PKCS1v15(), hashes.SHA256())
key.public_key().verify(sig, b"data", padding.PKCS1v15(), hashes.SHA256())
pub_pem = key.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
)
loaded = serialization.load_pem_public_key(pub_pem)
loaded.verify(sig, b"data", padding.PKCS1v15(), hashes.SHA256())
priv_pem = key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
assert serialization.load_pem_private_key(priv_pem, None) is not None
def rsa_oaep():
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
ct = key.public_key().encrypt(
b"top secret", padding.OAEP(mgf=padding.MGF1(hashes.SHA256()),
algorithm=hashes.SHA256(), label=None)
)
assert key.decrypt(ct, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None)) == b"top secret"
def ec_():
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
key = ec.generate_private_key(ec.SECP256R1())
sig = key.sign(b"msg", ec.ECDSA(hashes.SHA256()))
key.public_key().verify(sig, b"msg", ec.ECDSA(hashes.SHA256()))
def ed25519_():
from cryptography.hazmat.primitives.asymmetric import ed25519
key = ed25519.Ed25519PrivateKey.generate()
sig = key.sign(b"msg")
key.public_key().verify(sig, b"msg")
def ed448_():
from cryptography.hazmat.primitives.asymmetric import ed448
key = ed448.Ed448PrivateKey.generate()
sig = key.sign(b"msg")
key.public_key().verify(sig, b"msg")
def x25519_():
from cryptography.hazmat.primitives.asymmetric import x25519
a = x25519.X25519PrivateKey.generate()
b = x25519.X25519PrivateKey.generate()
sa = a.exchange(b.public_key())
sb = b.exchange(a.public_key())
assert sa == sb
def x448_():
from cryptography.hazmat.primitives.asymmetric import x448
a = x448.X448PrivateKey.generate()
b = x448.X448PrivateKey.generate()
assert a.exchange(b.public_key()) == b.exchange(a.public_key())
def dh_():
from cryptography.hazmat.primitives.asymmetric import dh
params = dh.generate_parameters(generator=2, key_size=2048)
a = params.generate_private_key()
b = params.generate_private_key()
assert a.exchange(b.public_key()) == b.exchange(a.public_key())
def dsa_():
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import dsa
key = dsa.generate_private_key(key_size=2048)
sig = key.sign(b"m", hashes.SHA256())
key.public_key().verify(sig, b"m", hashes.SHA256())
# ---------------------------------------------------------------------------
# 5. KDF / password hashing
# ---------------------------------------------------------------------------
def hkdf_():
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
k = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b"i").derive(b"pw")
assert len(k) == 32
def pbkdf2_():
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
k = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b"s", iterations=1000).derive(b"pw")
assert len(k) == 32
def scrypt_():
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
k = Scrypt(salt=b"salt", length=32, n=2**14, r=8, p=1).derive(b"pw")
assert len(k) == 32
# ---------------------------------------------------------------------------
# 6. x509
# ---------------------------------------------------------------------------
def x509_selfsigned():
import datetime
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.x509.oid import NameOID
key = ec.generate_private_key(ec.SECP256R1())
name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "test")])
now = datetime.datetime.now(datetime.timezone.utc)
cert = (
x509.CertificateBuilder()
.subject_name(name)
.issuer_name(name)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - datetime.timedelta(days=1))
.not_valid_after(now + datetime.timedelta(days=1))
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.sign(key, hashes.SHA256())
)
pem = cert.public_bytes(serialization.Encoding.PEM)
loaded = x509.load_pem_x509_certificate(pem)
assert loaded.subject == name
loaded.public_key().verify(
cert.signature, cert.tbs_certificate_bytes,
ec.ECDSA(hashes.SHA256()),
)
# ---------------------------------------------------------------------------
# 7. fernet
# ---------------------------------------------------------------------------
def fernet_():
from cryptography.fernet import Fernet
f = Fernet(Fernet.generate_key())
t = f.encrypt(b"payload")
assert f.decrypt(t) == b"payload"
# ---------------------------------------------------------------------------
# 8. cffi
# ---------------------------------------------------------------------------
def cffi_import():
import _cffi_backend
import cffi
assert cffi.__version__ == "2.1.1", cffi.__version__
# backend version must match the cffi package version
assert getattr(_cffi_backend, "__version__", None) in (None, "2.1.1")
def _open_libc(ffi):
import ctypes.util
for name in ("libc.so", "libc.so.6", "c"):
try:
return ffi.dlopen(name)
except OSError:
continue
found = ctypes.util.find_library("c")
if found:
return ffi.dlopen(found)
raise NotImplementedError("no libc available on this platform")
def cffi_libc_call():
import cffi
ffi = cffi.FFI()
ffi.cdef("size_t strlen(const char *s);")
lib = _open_libc(ffi)
s = ffi.new("char[]", b"android-cffi")
n = lib.strlen(s)
assert n == 12, n
def cffi_abi_mode():
import cffi
ffi = cffi.FFI()
ffi.cdef("int abs(int x);")
lib = _open_libc(ffi)
assert lib.abs(-5) == 5
def cffi_struct():
import cffi
ffi = cffi.FFI()
ffi.cdef(
"typedef struct { int x; int y; } point_t; "
"point_t make_point(int x, int y);"
)
# use ABI mode call into a trivial function we link ourselves via ctypes-free
# path is not available, so just validate the type machinery and FFI().new()
p = ffi.new("point_t*")
p.x = 3
p.y = 4
assert p.x == 3 and p.y == 4
def cffi_callback():
import cffi
ffi = cffi.FFI()
ffi.cdef("typedef int (*cb_t)(int);")
calls = []
cb = ffi.callback("int(int)", lambda n: (calls.append(n), n + 1)[1])
assert cb(10) == 11
assert calls == [10]
# ---------------------------------------------------------------------------
def main():
quick = "--quick" in sys.argv
section("1. cryptography imports (full surface)")
test("import core (version + _rust.so + fernet)", imports_core)
test("import bindings/backends", imports_bindings)
test("import primitives", imports_primitives)
test("import asymmetric", imports_asymmetric)
test("import x509", imports_x509)
section("2. hashes / hmac / cmac")
test("SHA256", hashes)
test("SHA512", sha512)
test("SHA3 / BLAKE2", sha3_and_blake2)
test("HMAC", hmac_)
test("CMAC", cmac)
section("3. symmetric ciphers")
test("AES-GCM", aes_gcm)
test("AES-CBC", aes_cbc)
test("ChaCha20-Poly1305", chacha20_poly1305)
test("PKCS7 padding", padding_)
test("AES keywrap", keywrap_)
section("4. asymmetric")
test("RSA sign/verify + PEM roundtrip", rsa_sign_verify)
test("RSA-OAEP", rsa_oaep)
test("EC P-256", ec_)
test("Ed25519", ed25519_)
test("Ed448", ed448_)
test("X25519 key exchange", x25519_)
test("X448 key exchange", x448_)
test("DH", dh_)
test("DSA", dsa_)
section("5. KDF")
test("HKDF", hkdf_)
test("PBKDF2", pbkdf2_)
test("scrypt", scrypt_)
section("6. X.509")
test("self-signed cert build+parse+verify", x509_selfsigned)
section("7. Fernet")
test("Fernet encrypt/decrypt", fernet_)
section("8. cffi")
test("cffi import (backend version match)", cffi_import)
test("cffi dlopen libc + strlen", cffi_libc_call)
test("cffi ABI mode abs()", cffi_abi_mode)
test("cffi struct", cffi_struct)
test("cffi callback", cffi_callback)
print()
print("=" * 60)
print("SUMMARY")
print("=" * 60)
fails = 0
skips = 0
for name, status, why in RESULTS:
mark = " OK" if status == "PASS" else (" SKIP" if status == "SKIP" else "FAIL")
print("%s %s" % (mark, name))
if why:
print(" -> %s" % why)
if status == "FAIL":
fails += 1
elif status == "SKIP":
skips += 1
print()
passed = len(RESULTS) - fails - skips
print("passed=%d skipped=%d failed=%d" % (passed, skips, fails))
if fails:
print("RESULT: FAILED")
elif skips and not quick:
print("RESULT: PASSED (with informational skips)")
else:
print("RESULT: PASSED")
sys.exit(1 if fails else 0)
if __name__ == "__main__":
main()