The AES module is a single file (aes.py) with automatic backend dispatch: OpenSSL (via ctypes) is used by default when libcrypto is available; a pure-Python fallback activates otherwise.
OpenSSL ctypes is the default backend and consistently outperforms pycryptodome's C extension: 1.1--1.5x faster in ECB/CBC for small-to-medium data, scaling up to 6.9x faster for large CBC decryption. In GCM mode the advantage is most pronounced at 5.3--6.3x faster. All of this requires zero pip dependencies -- only a system-installed libcrypto.
Pure Python fallback is ~10x slower than pycryptodome for small messages and 300--500x slower for medium/large data. This is expected for interpreted Python vs compiled C and serves as a last-resort fallback when no native library is available.
GCM mode in pure Python includes GF(2^128) multiplication, making it the slowest pure-Python mode (~250 us for 13 bytes vs ~82--85 us for ECB/CBC). The OpenSSL backend shows no such penalty.
pycryptodome is fast (C extension) but requires a compiled dependency via pip. OpenSSL ctypes matches or beats it in every scenario tested.