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