Skip to content

Repository files navigation

ucryptography

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.)

Namespace Implemented Not yet
hashes SHA1, SHA256, SHA384, SHA512, BLAKE2s, Hash —
hmac HMAC —
ciphers Cipher; algorithms AES, TripleDES; modes CBC, ECB, GCM; AESGCM ChaCha20Poly1305, AESCCM, AESSIV, AESOCB3, AESGCMSIV
serialization load/dump public+private (DER, PEM); Encoding (DER, PEM, X962, Raw); Public/PrivateFormat; NoEncryption; BestAvailableEncryption encrypted PKCS#8 write
rsa public/private keys + numbers, generate_private_key, sign/verify, rsa_crt_iqmp/dmp1/dmq1, rsa_recover_prime_factors —
ec ECDH, ECDSA, SECP256R1/384R1/521R1, public/private keys + numbers, generate/derive, from_encoded_point curves beyond NIST P-256/384/521
ed25519 Ed25519PrivateKey, Ed25519PublicKey —
padding PKCS1v15, PSS, OAEP, MGF1, calculate_max_pss_salt_length —
utils Prehashed, constant_time_bytes_eq, encode/decode_dss_signature, bit_length, rsa_deduce_private_exponent, RFC6979 —
twofactor HOTP, TOTP —
x509 load 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_number chain verification (PolicyBuilder / Store / Verifier), CRL, OCSP
exceptions InvalidSignature, AlreadyFinalized, UnsupportedAlgorithm, InvalidKey, InvalidToken —
dsa, dh, x25519, x448, ed448 — whole module
KDFs (hkdf, pbkdf2hmac, scrypt, concatkdf, x963kdf) — whole module
fernet — whole 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 suffix Python API disabled when 0
SHA1 / SHA256 / SHA384 / SHA512 hashes.SHA1 … hashes.SHA512
BLAKE2S hashes.BLAKE2s
HASH hashes.Hash
HMAC hmac.HMAC
AES ciphers.algorithms.AES
AESGCM ciphers.AESGCM
TRIPLEDES ciphers.algorithms.TripleDES
PKCS1V15 padding.PKCS1v15
MGF1 padding.MGF1
OAEP padding.OAEP
PSS padding.PSS
RSA rsa.* (keys, sign, verify)
EC ec.* (keys, ECDH, ECDSA)
ED25519 ed25519.*
X509 x509 reading (load_*, Certificate)
X509_CREATE x509.CertificateBuilder
X509_CSR x509 CSR read/write (load_*_x509_csr, CertificateSigningRequestBuilder)
TWOFACTOR twofactor.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 ⭐ this project and why not ... Buy me a coffee 😄

About

Lightweight porting of pyca/cryptography to Micropython based on ARM Mbed TLS

Resources

Stars

11 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages