ucryptography

August 6, 2026 · View on GitHub

Lightweight porting of cryptography to Micropython based on ARM Mbed TLS

  • Drop-in PyCA cryptography import paths — the same nested imports run on MicroPython and CPython + PyCA.
  • Wraps ARM Mbed TLS; no extra native dependency.
  • Portable across MicroPython ports: unix, esp32, stm32, rp2, …
  • Compile-time feature toggles to stub unused APIs and shrink the build (see How to build).

Supported API

The API mirrors PyCA cryptography at the same import paths (cryptography.hazmat.primitives[.asymmetric].*, plus cryptography.exceptions and cryptography.x509[.oid]), so the same nested imports run unchanged on both MicroPython (this module) and CPython + PyCA. (utils.RFC6979 is a ucryptography-only extension, not part of PyCA.)

NamespaceImplementedNot yet
hashesSHA1, SHA256, SHA384, SHA512, BLAKE2s, Hash
hmacHMAC
ciphersCipher; algorithms AES, TripleDES; modes CBC, ECB, GCM; AESGCMChaCha20Poly1305, AESCCM, AESSIV, AESOCB3, AESGCMSIV
serializationload/dump public+private (DER, PEM); Encoding (DER, PEM, X962, Raw); Public/PrivateFormat; NoEncryption; BestAvailableEncryptionencrypted PKCS#8 write
rsapublic/private keys + numbers, generate_private_key, sign/verify, rsa_crt_iqmp/dmp1/dmq1, rsa_recover_prime_factors
ecECDH, ECDSA, SECP256R1/384R1/521R1, public/private keys + numbers, generate/derive, from_encoded_pointcurves beyond NIST P-256/384/521
ed25519Ed25519PrivateKey, Ed25519PublicKey
paddingPKCS1v15, PSS, OAEP, MGF1, calculate_max_pss_salt_length
utilsPrehashed, constant_time_bytes_eq, encode/decode_dss_signature, bit_length, rsa_deduce_private_exponent, RFC6979
twofactorHOTP, TOTP
x509load cert & CSR (DER, PEM); Certificate; CertificateBuilder; CSR + builder; Name, NameAttribute, ObjectIdentifier, NameOID; extensions (BasicConstraints, KeyUsage, ExtendedKeyUsage + OID, SubjectAlternativeName, DNSName, IPAddress, SubjectKeyIdentifier, AuthorityKeyIdentifier, UnrecognizedExtension); random_serial_numberchain verification (PolicyBuilder / Store / Verifier), CRL, OCSP
exceptionsInvalidSignature, AlreadyFinalized, UnsupportedAlgorithm, InvalidKey, InvalidToken
dsa, dh, x25519, x448, ed448whole module
KDFs (hkdf, pbkdf2hmac, scrypt, concatkdf, x963kdf)whole module
fernetwhole module

Basic usage

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa

message = b"A message I want to sign"
chosen_hash = hashes.SHA256()

private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
signature = private_key.sign(
    message,
    padding.PSS(
        mgf=padding.MGF1(chosen_hash), salt_length=chosen_hash.digest_size
    ),
    chosen_hash,
)
public_key = private_key.public_key()
public_key.verify(
    signature,
    message,
    padding.PSS(
        mgf=padding.MGF1(chosen_hash), salt_length=chosen_hash.digest_size
    ),
    chosen_hash,
)

More examples

How to build

UNIX port (standard)

$ git clone https://github.com/micropython/micropython.git
$ cd micropython
micropython$ git submodule update --init --depth 1
micropython$ git clone https://github.com/dmazzella/ucryptography.git usercmodule/ucryptography
micropython$ cd usercmodule/ucryptography
ucryptography$ git submodule update --init --depth 1
ucryptography$ cd ../../
micropython$ make -j2 -C mpy-cross/
micropython$ make -j2 -C ports/unix/ VARIANT="standard" MICROPY_SSL_AXTLS=0 MICROPY_SSL_MBEDTLS=1 USER_C_MODULES="$(pwd)/usercmodule"

ESP32 port (ESP32_GENERIC_C3)

$ git clone https://github.com/micropython/micropython.git
$ cd micropython
micropython$ git submodule update --init --depth 1
micropython$ git clone https://github.com/dmazzella/ucryptography.git usercmodule/ucryptography
micropython$ cd usercmodule/ucryptography
ucryptography$ git submodule update --init --depth 1
ucryptography$ cd ../../
micropython$ make -j2 -C mpy-cross/
micropython$ make -C ports/esp32 BOARD=ESP32_GENERIC_C3 USER_C_MODULES="$(pwd)/usercmodule/ucryptography/micropython.cmake"

STM32 port (ARDUINO_PORTENTA_H7)

$ git clone https://github.com/micropython/micropython.git
$ cd micropython
micropython$ git submodule update --init --depth 1
micropython$ git clone https://github.com/dmazzella/ucryptography.git usercmodule/ucryptography
micropython$ cd usercmodule/ucryptography
ucryptography$ git submodule update --init --depth 1
ucryptography$ cd ../../
micropython$ make -j2 -C mpy-cross/
micropython$ make -C ports/stm32 BOARD=ARDUINO_PORTENTA_H7 USER_C_MODULES="$(pwd)/usercmodule"

Feature toggles (optional)

Every ucryptography feature is compiled in by default. Each is guarded by a MICROPY_PY_UCRYPTOGRAPHY_* flag (all default 1) declared in modcryptography_features.h. Set a flag to 0 to compile the feature out: its type stays registered (no AttributeError) but constructing it raises NotImplementedError naming the flag to re-enable.

Override a flag either by editing modcryptography_features.h, or — on the make-based ports (unix, stm32) — by passing -D<FLAG>=0 through CFLAGS_EXTRA:

micropython$ make -j2 -C ports/unix/ VARIANT="standard" MICROPY_SSL_AXTLS=0 MICROPY_SSL_MBEDTLS=1 \
    CFLAGS_EXTRA="-DMICROPY_PY_UCRYPTOGRAPHY_TRIPLEDES=0 -DMICROPY_PY_UCRYPTOGRAPHY_OAEP=0 -DMICROPY_PY_UCRYPTOGRAPHY_PSS=0" \
    USER_C_MODULES="$(pwd)/usercmodule"

Flags (prefix MICROPY_PY_UCRYPTOGRAPHY_, all default 1):

Flag suffixPython API disabled when 0
SHA1 / SHA256 / SHA384 / SHA512hashes.SHA1hashes.SHA512
BLAKE2Shashes.BLAKE2s
HASHhashes.Hash
HMAChmac.HMAC
AESciphers.algorithms.AES
AESGCMciphers.AESGCM
TRIPLEDESciphers.algorithms.TripleDES
PKCS1V15padding.PKCS1v15
MGF1padding.MGF1
OAEPpadding.OAEP
PSSpadding.PSS
RSArsa.* (keys, sign, verify)
ECec.* (keys, ECDH, ECDSA)
ED25519ed25519.*
X509x509 reading (load_*, Certificate)
X509_CREATEx509.CertificateBuilder
X509_CSRx509 CSR read/write (load_*_x509_csr, CertificateSigningRequestBuilder)
TWOFACTORtwofactor.HOTP / twofactor.TOTP

Dependencies are enforced automatically: MGF1=0 also disables OAEP and PSS; X509=0 also disables X509_CREATE and X509_CSR. The CSR builder additionally needs X509_CREATE (they share the mbedtls certificate-writing stack).

Most toggles only stub the Python API — the underlying mbedtls primitive stays because the port's TLS stack shares it. A few settings additionally shrink the mbedtls library (they gate modules exclusive to ucryptography): TRIPLEDES=0 drops MBEDTLS_DES_C; OAEP=0 and PSS=0 drop MBEDTLS_PKCS1_V21; X509_CREATE=0 drops MBEDTLS_X509_CREATE_C + MBEDTLS_X509_CRT_WRITE_C; X509_CSR=0 drops MBEDTLS_X509_CSR_PARSE_C + MBEDTLS_X509_CSR_WRITE_C.

CSR read note: mbedtls natively parses only KeyUsage and SubjectAlternativeName from a CSR; BasicConstraints and ExtendedKeyUsage are recovered from the raw request, and any other requested extension is exposed as an UnrecognizedExtension. A requested BasicConstraints/ExtendedKeyUsage marked critical is rejected by mbedtls, so keep those non-critical in a CSR.

Support

Development help is welcome: issues, pull requests and discussions are all appreciated.

Tip

If you find ucryptography useful, consider :star: this project and why not ... Buy me a coffee :smile: