API reference

Algorithm constants

class Algorithm

Static class containing W3C XML Security algorithm URI strings. Use these instead of hardcoding URI strings in your code.

from pybergshamra import Algorithm

print(Algorithm.RSA_SHA256)
# "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"

Canonicalization

C14N: str

Inclusive C14N (http://www.w3.org/TR/2001/REC-xml-c14n-20010315)

C14N_WITH_COMMENTS: str

Inclusive C14N with comments

C14N11: str

Inclusive C14N 1.1 (http://www.w3.org/2006/12/xml-c14n11)

C14N11_WITH_COMMENTS: str

Inclusive C14N 1.1 with comments

EXC_C14N: str

Exclusive C14N (http://www.w3.org/2001/10/xml-exc-c14n#)

EXC_C14N_WITH_COMMENTS: str

Exclusive C14N with comments

Digest

SHA1: str

SHA-1 digest

SHA224: str

SHA-224 digest

SHA256: str

SHA-256 digest

SHA384: str

SHA-384 digest

SHA512: str

SHA-512 digest

SHA3_224: str

SHA3-224 digest

SHA3_256: str

SHA3-256 digest

SHA3_384: str

SHA3-384 digest

SHA3_512: str

SHA3-512 digest

MD5: str

MD5 digest (legacy, not recommended)

RIPEMD160: str

RIPEMD-160 digest (legacy)

RSA Signature

RSA_SHA1: str

RSA with SHA-1

RSA_SHA224: str

RSA with SHA-224

RSA_SHA256: str

RSA with SHA-256

RSA_SHA384: str

RSA with SHA-384

RSA_SHA512: str

RSA with SHA-512

RSA_MD5: str

RSA with MD5 (legacy, not recommended)

RSA_RIPEMD160: str

RSA with RIPEMD-160 (legacy)

RSA-PSS Signature

RSA_PSS_SHA1: str

RSA-PSS with SHA-1

RSA_PSS_SHA224: str

RSA-PSS with SHA-224

RSA_PSS_SHA256: str

RSA-PSS with SHA-256

RSA_PSS_SHA384: str

RSA-PSS with SHA-384

RSA_PSS_SHA512: str

RSA-PSS with SHA-512

RSA_PSS_SHA3_224: str

RSA-PSS with SHA3-224

RSA_PSS_SHA3_256: str

RSA-PSS with SHA3-256

RSA_PSS_SHA3_384: str

RSA-PSS with SHA3-384

RSA_PSS_SHA3_512: str

RSA-PSS with SHA3-512

DSA Signature

DSA_SHA1: str

DSA with SHA-1

DSA_SHA256: str

DSA with SHA-256

ECDSA Signature

ECDSA_SHA1: str

ECDSA with SHA-1

ECDSA_SHA224: str

ECDSA with SHA-224

ECDSA_SHA256: str

ECDSA with SHA-256

ECDSA_SHA384: str

ECDSA with SHA-384

ECDSA_SHA512: str

ECDSA with SHA-512

ECDSA_SHA3_224: str

ECDSA with SHA3-224

ECDSA_SHA3_256: str

ECDSA with SHA3-256

ECDSA_SHA3_384: str

ECDSA with SHA3-384

ECDSA_SHA3_512: str

ECDSA with SHA3-512

ECDSA_RIPEMD160: str

ECDSA with RIPEMD-160 (legacy)

EdDSA Signature

EDDSA_ED25519: str

Ed25519 signature

HMAC Signature

HMAC_SHA1: str

HMAC with SHA-1

HMAC_SHA224: str

HMAC with SHA-224

HMAC_SHA256: str

HMAC with SHA-256

HMAC_SHA384: str

HMAC with SHA-384

HMAC_SHA512: str

HMAC with SHA-512

HMAC_MD5: str

HMAC with MD5 (legacy, not recommended)

HMAC_RIPEMD160: str

HMAC with RIPEMD-160 (legacy)

ML-DSA Post-Quantum

ML_DSA_44: str

ML-DSA-44 (FIPS 204)

ML_DSA_65: str

ML-DSA-65 (FIPS 204)

ML_DSA_87: str

ML-DSA-87 (FIPS 204)

SLH-DSA Post-Quantum

SLH_DSA_SHA2_128F: str

SLH-DSA-SHA2-128f (FIPS 205)

SLH_DSA_SHA2_128S: str

SLH-DSA-SHA2-128s (FIPS 205)

SLH_DSA_SHA2_192F: str

SLH-DSA-SHA2-192f (FIPS 205)

SLH_DSA_SHA2_192S: str

SLH-DSA-SHA2-192s (FIPS 205)

SLH_DSA_SHA2_256F: str

SLH-DSA-SHA2-256f (FIPS 205)

SLH_DSA_SHA2_256S: str

SLH-DSA-SHA2-256s (FIPS 205)

Block Cipher

AES128_CBC: str

AES-128 in CBC mode

AES192_CBC: str

AES-192 in CBC mode

AES256_CBC: str

AES-256 in CBC mode

AES128_GCM: str

AES-128 in GCM mode

AES192_GCM: str

AES-192 in GCM mode

AES256_GCM: str

AES-256 in GCM mode

TRIPLEDES_CBC: str

Triple DES in CBC mode (legacy)

Key Wrap

KW_AES128: str

AES-128 key wrap

KW_AES192: str

AES-192 key wrap

KW_AES256: str

AES-256 key wrap

KW_TRIPLEDES: str

Triple DES key wrap (legacy)

Key Transport

RSA_PKCS1: str

RSA PKCS#1 v1.5 key transport (legacy)

RSA_OAEP: str

RSA-OAEP key transport

RSA_OAEP_ENC11: str

RSA-OAEP (XML Encryption 1.1)

Mask Generation Function (MGF)

MGF1_SHA1: str

MGF1 with SHA-1

MGF1_SHA224: str

MGF1 with SHA-224

MGF1_SHA256: str

MGF1 with SHA-256

MGF1_SHA384: str

MGF1 with SHA-384

MGF1_SHA512: str

MGF1 with SHA-512

Key Agreement

DH_ES: str

Diffie-Hellman ephemeral-static

ECDH_ES: str

ECDH ephemeral-static

X25519: str

X25519 key agreement

Key Derivation

PBKDF2: str

PBKDF2 key derivation

CONCAT_KDF: str

ConcatKDF key derivation

HKDF: str

HKDF key derivation

Transform

BASE64: str

Base64 transform

ENVELOPED_SIGNATURE: str

Enveloped signature transform

XPATH: str

XPath transform

XPATH2: str

XPath 2.0 filter transform

XSLT: str

XSLT transform

XPOINTER: str

XPointer transform

RELATIONSHIP: str

Relationship transform

KeyValue Type

RSA_KEY_VALUE: str

RSA KeyValue

DSA_KEY_VALUE: str

DSA KeyValue

EC_KEY_VALUE: str

EC KeyValue

DH_KEY_VALUE: str

DH KeyValue

DER_ENCODED_KEY_VALUE: str

DER-encoded KeyValue

X509

X509_DATA: str

X509Data key data

RAW_X509_CERT: str

Raw X.509 certificate

Encrypted/Derived Key

ENCRYPTED_KEY: str

EncryptedKey

DERIVED_KEY: str

DerivedKey

Key management

KeyUsage

class KeyUsage

Key usage mode enumeration. Pass these values to Key.usage() or KeysManager.find_by_usage().

Sign

Key is used for signing.

Verify

Key is used for signature verification.

Encrypt

Key is used for encryption.

Decrypt

Key is used for decryption.

Any

Key can be used for any purpose (default).

import pybergshamra
from pybergshamra import KeyUsage

key = pybergshamra.load_rsa_private_pem(pem_data)
key.usage = KeyUsage.Sign

manager = pybergshamra.KeysManager()
manager.add_key(key)
found = manager.find_by_usage(KeyUsage.Sign)

Key

class Key

A cryptographic key (RSA, EC, HMAC, AES, Ed25519, X25519, PQ, etc.). Keys are created through the key loader functions, not constructed directly.

name: str | None

The key name, or None. Readable and writable.

key = pybergshamra.load_rsa_private_pem(pem_data)
key.name = "my-signing-key"
print(key.name)  # "my-signing-key"
usage: KeyUsage

The key usage mode. Readable and writable.

algorithm_name: str

The algorithm name (read-only). Examples: "RSA", "EC-P256", "HMAC", "AES", "3DES", "Ed25519", "X25519".

key = pybergshamra.load_rsa_private_pem(pem_data)
print(key.algorithm_name)  # "RSA"
has_private_key: bool

Whether this key contains private key material (read-only).

x509_chain: list[bytes]

The DER-encoded X.509 certificate chain, if present (read-only).

to_spki_der() bytes | None

Return the SPKI DER encoding of the public key, or None if not available.

symmetric_key_bytes() bytes | None

Return the raw symmetric key bytes (HMAC/AES/DES3), or None.

ec_public_key_bytes() bytes | None

Return the uncompressed EC public key bytes, or None.

x25519_public_key_bytes() bytes | None

Return the X25519 public key bytes (32 bytes), or None.

x25519_private_key_bytes() bytes | None

Return the X25519 private key bytes (32 bytes), or None.

to_key_value_xml(prefix: str = 'ds') str | None

Return the KeyValue XML fragment, or None. The returned XML uses the given namespace prefix.

key = pybergshamra.load_rsa_private_pem(pem_data)
xml_fragment = key.to_key_value_xml()
# Returns e.g. "<ds:RSAKeyValue>...</ds:RSAKeyValue>"

KeysManager

class KeysManager

Key store for managing cryptographic keys and certificates.

import pybergshamra

manager = pybergshamra.KeysManager()
key = pybergshamra.load_rsa_private_pem(pem_data)
manager.add_key(key)

print(len(manager))  # 1
print(bool(manager))  # True
add_key(key: Key) None

Add a key to the manager.

insert_key_first(key: Key) None

Insert a key at the front (becomes the first key).

first_key() Key | None

Return the first key, or None if the manager is empty.

keys() list[Key]

Return all keys as a list.

find_by_name(name: str) Key | None

Find a key by name.

key = pybergshamra.load_hmac_key(b"secret")
key.name = "my-hmac"
manager.add_key(key)
found = manager.find_by_name("my-hmac")
find_by_usage(usage: KeyUsage) Key | None

Find a key by usage mode.

find_rsa() Key | None

Find the first RSA key.

find_rsa_private() Key | None

Find the first RSA key with private material.

find_hmac() Key | None

Find the first HMAC key.

find_aes() Key | None

Find the first AES key.

find_aes_by_size(size_bytes: int) Key | None

Find the first AES key matching the given size in bytes (16, 24, or 32).

find_des3() Key | None

Find the first 3DES key.

find_ec_p256() Key | None

Find the first EC P-256 key.

find_ec_p384() Key | None

Find the first EC P-384 key.

find_ec_p521() Key | None

Find the first EC P-521 key.

find_ed25519() Key | None

Find the first Ed25519 key.

find_x25519() Key | None

Find the first X25519 key.

find_pq() Key | None

Find the first post-quantum key.

find_dh() Key | None

Find the first DH key.

add_trusted_cert(der: bytes) None

Add a trusted DER-encoded X.509 certificate.

add_untrusted_cert(der: bytes) None

Add an untrusted DER-encoded X.509 certificate.

add_crl(der: bytes) None

Add a DER-encoded CRL.

trusted_certs() list[bytes]

Return the trusted certificates as a list of DER bytes.

untrusted_certs() list[bytes]

Return the untrusted certificates as a list of DER bytes.

crls() list[bytes]

Return the CRLs as a list of DER bytes.

has_trusted_certs() bool

Whether the manager has any trusted certificates.

Key loaders

File-based loaders

load_key_file(path: str) Key

Load a key from a file, auto-detecting the format by extension (.pem, .der, .cer, .p12, etc.).

Raises:

KeyLoadError – If the file cannot be read or parsed.

key = pybergshamra.load_key_file("rsakey.pem")
load_key_file_with_password(path: str, password: str) Key

Load a key from a password-protected file.

Raises:

KeyLoadError – If the file cannot be read, the password is wrong, or the format is unsupported.

key = pybergshamra.load_key_file_with_password("cakey.pem", "secret123")
load_pkcs12(data: bytes, password: str) Key

Load a key from PKCS#12 (PFX) data with a password.

Parameters:
  • data – Raw PKCS#12 bytes.

  • password – The password protecting the PKCS#12 file.

Raises:

KeyLoadError – If the data is invalid or the password is wrong.

p12_data = open("key.p12", "rb").read()
key = pybergshamra.load_pkcs12(p12_data, "secret123")
load_keys_file(path: str) list[Key]

Load keys from an xmlsec keys.xml file.

Raises:

KeyLoadError – If the file cannot be read or parsed.

keys = pybergshamra.load_keys_file("keys.xml")
for key in keys:
    print(key.name, key.algorithm_name)

RSA loaders

load_rsa_private_pem(pem_data: bytes) Key

Load an RSA private key from PEM data.

Raises:

KeyLoadError – If the PEM data is not a valid RSA private key.

load_rsa_public_pem(pem_data: bytes) Key

Load an RSA public key from PEM data.

Raises:

KeyLoadError – If the PEM data is not a valid RSA public key.

EC loaders

load_ec_p256_private_pem(pem_data: bytes) Key

Load an EC P-256 (secp256r1) private key from PEM data.

Raises:

KeyLoadError – If the PEM data is not a valid EC P-256 key.

load_ec_p384_private_pem(pem_data: bytes) Key

Load an EC P-384 (secp384r1) private key from PEM data.

Raises:

KeyLoadError – If the PEM data is not a valid EC P-384 key.

load_ec_p521_private_pem(pem_data: bytes) Key

Load an EC P-521 (secp521r1) private key from PEM data.

Raises:

KeyLoadError – If the PEM data is not a valid EC P-521 key.

X.509 loaders

load_x509_cert_pem(pem_data: bytes) Key

Load an X.509 certificate from PEM data. The returned key contains the certificate’s public key and the certificate chain.

Raises:

KeyLoadError – If the PEM data is not a valid certificate.

cert_pem = open("cert.pem", "rb").read()
key = pybergshamra.load_x509_cert_pem(cert_pem)
print(key.algorithm_name)  # e.g. "RSA"
print(len(key.x509_chain))  # 1
load_x509_cert_der(data: bytes) Key

Load an X.509 certificate from DER data.

Raises:

KeyLoadError – If the data is not a valid DER certificate.

Symmetric key loaders

load_hmac_key(data: bytes) Key

Create an HMAC key from raw bytes. This function never fails.

key = pybergshamra.load_hmac_key(b"my-secret-key")
print(key.algorithm_name)  # "HMAC"
load_aes_key(data: bytes) Key

Create an AES key from raw bytes. The data length must be 16 (AES-128), 24 (AES-192), or 32 (AES-256) bytes.

Raises:

KeyLoadError – If the data length is invalid.

import os
key = pybergshamra.load_aes_key(os.urandom(32))  # AES-256
load_des3_key(data: bytes) Key

Create a 3DES key from raw bytes. The data must be 24 bytes.

Raises:

KeyLoadError – If the data length is not 24.

Auto-detect loaders

load_pem_auto(pem_data: bytes, password: str | None = None) Key

Auto-detect the PEM type and load the key. Handles RSA, EC, Ed25519, X.509 certificates, PKCS#8, and encrypted PEM.

Parameters:
  • pem_data – PEM-encoded key or certificate bytes.

  • password – Optional password for encrypted PEM files.

Raises:

KeyLoadError – If the PEM type cannot be determined or loaded.

# Works with any PEM type
key = pybergshamra.load_pem_auto(open("some-key.pem", "rb").read())

# With password for encrypted PEM
key = pybergshamra.load_pem_auto(open("cakey.pem", "rb").read(), password="secret123")

SPKI loaders

load_spki_pem(pem_data: bytes) Key

Load a public key from SPKI (Subject Public Key Info) PEM data.

Raises:

KeyLoadError – If the PEM data is not valid SPKI.

load_spki_der(data: bytes) Key

Load a public key from SPKI DER data.

Raises:

KeyLoadError – If the data is not valid SPKI DER.

Ed25519 loaders

load_ed25519_private_pkcs8_der(data: bytes) Key

Load an Ed25519 private key from PKCS#8 DER data.

Raises:

KeyLoadError – If the data is not a valid Ed25519 PKCS#8 key.

load_ed25519_public_spki_der(data: bytes) Key

Load an Ed25519 public key from SPKI DER data.

Raises:

KeyLoadError – If the data is not a valid Ed25519 SPKI key.

X25519 loaders

load_x25519_private_raw(data: bytes) Key

Load an X25519 private key from raw 32-byte data.

Raises:

KeyLoadError – If the data is not exactly 32 bytes.

load_x25519_public_raw(data: bytes) Key

Load an X25519 public key from raw 32-byte data.

Raises:

KeyLoadError – If the data is not exactly 32 bytes.

Keys XML

parse_keys_xml(xml: str) list[Key]

Parse keys from an xmlsec keys.xml string.

Raises:

KeyLoadError – If the XML is not a valid keys document.

xml = open("keys.xml").read()
keys = pybergshamra.parse_keys_xml(xml)
for k in keys:
    print(k.name, k.algorithm_name)

X509 KeyInfo builders

build_x509_key_info(certs_b64: list[str]) str

Build a <ds:KeyInfo><ds:X509Data> XML fragment from base64-encoded certificates.

Parameters:

certs_b64 – List of base64-encoded certificate strings.

Returns:

XML string with ds: namespace prefix.

import base64
cert_der = open("cert.der", "rb").read()
cert_b64 = base64.b64encode(cert_der).decode()
xml = pybergshamra.build_x509_key_info([cert_b64])
# '<ds:KeyInfo><ds:X509Data><ds:X509Certificate>...</ds:X509Certificate></ds:X509Data></ds:KeyInfo>'
build_x509_key_info_from_der(certs_der: list[bytes]) str

Build a <ds:KeyInfo><ds:X509Data> XML fragment from DER-encoded certificates.

Parameters:

certs_der – List of DER-encoded certificate bytes.

Returns:

XML string with ds: namespace prefix.

cert_der = open("cert.der", "rb").read()
xml = pybergshamra.build_x509_key_info_from_der([cert_der])

Digital signatures

DsigContext

class DsigContext(keys_manager: KeysManager)

Context for XML Digital Signature operations. Holds configuration and a KeysManager. Build one, set properties, then call verify() or sign().

Parameters:

keys_manager – The key store to use for sign/verify operations.

manager = pybergshamra.KeysManager()
manager.add_key(key)
ctx = pybergshamra.DsigContext(manager)
debug: bool

Debug mode: print pre-digest and pre-signature data to stderr. Default: False.

insecure: bool

Insecure mode: skip certificate validation. Default: False.

verify_keys: bool

Whether to validate certificates for keys loaded from files. Default: False.

verification_time: str | None

Verification time override. Format: "YYYY-MM-DD+HH:MM:SS". Default: None (use current time).

skip_time_checks: bool

Skip X.509 NotBefore/NotAfter validation. Default: False.

enabled_key_data_x509: bool

Whether enabled key data includes X.509. Default: False.

trusted_keys_only: bool

Only use pre-configured keys, skip inline KeyInfo extraction. Default: False.

strict_verification: bool

Enforce strict reference target validation (anti-XSW protection). Default: False.

ctx = pybergshamra.DsigContext(manager)
ctx.strict_verification = True
result = pybergshamra.verify(ctx, xml)
hmac_min_out_len: int

Minimum HMAC output length in bits. 0 means use the spec default.

base_dir: str | None

Base directory for resolving relative external URIs.

add_id_attr(name: str) None

Register an additional ID attribute name. Required for SAML and other XML formats that use custom ID attributes (e.g. "ID").

ctx = pybergshamra.DsigContext(manager)
ctx.add_id_attr("ID")  # needed for SAML
result = pybergshamra.verify(ctx, saml_xml)
add_url_map(url: str, file_path: str) None

Map a URL to a local file path for external URI resolution.

ctx.add_url_map("http://example.com/schema.xsd", "/local/schema.xsd")

VerifyResult

class VerifyResult

Result of signature verification. Use bool(result) to check validity.

is_valid: bool

Whether the signature is valid.

reason: str | None

The reason for invalidity, or None if valid.

references: list[VerifiedReference] | None

The verified references, or None if invalid.

key_info: VerifiedKeyInfo | None

Information about the verification key, or None if invalid.

signature_node_id: int | None

The node ID of the <Signature> element, or None if invalid.

result = pybergshamra.verify(ctx, xml)
if result:
    print("Valid!")
    for ref in result.references:
        print(f"  Reference URI: {ref.uri}")
    print(f"  Key algorithm: {result.key_info.algorithm}")
else:
    print(f"Invalid: {result.reason}")

VerifiedReference

class VerifiedReference

Metadata about a single verified <Reference> element.

uri: str

The URI attribute from the <Reference> element.

resolved_node_id: int | None

The resolved target node ID (if a same-document reference).

VerifiedKeyInfo

class VerifiedKeyInfo

Information about the key used for verification.

algorithm: str

Algorithm name (e.g. "RSA", "EC-P256", "HMAC").

key_name: str | None

Key name (if resolved by name from KeysManager).

x509_chain: list[bytes]

DER-encoded X.509 certificate chain (leaf first).

verify and sign

verify(ctx: DsigContext, xml: str) VerifyResult

Verify a signed XML document. Returns a VerifyResult – use bool(result) to check validity.

Parameters:
  • ctx – A configured DsigContext.

  • xml – The signed XML string.

Raises:

XmlError – If the XML cannot be parsed.

result = pybergshamra.verify(ctx, xml)
if result:
    print("Signature valid")
sign(ctx: DsigContext, template_xml: str) str

Sign an XML template and return the signed XML string. The template must contain a <Signature> skeleton with <SignedInfo>, <Reference>, etc.

Parameters:
  • ctx – A configured DsigContext.

  • template_xml – The XML template string.

Raises:
signed_xml = pybergshamra.sign(ctx, template)
print(signed_xml)

XML encryption

EncContext

class EncContext(keys_manager: KeysManager)

Context for XML Encryption operations. Holds configuration and a KeysManager.

Parameters:

keys_manager – The key store to use for encrypt/decrypt operations.

disable_cipher_reference: bool

Whether CipherReference resolution is disabled. Default: False.

add_id_attr(name: str) None

Register an additional ID attribute name.

encrypt, decrypt, decrypt_to_bytes

encrypt(ctx: EncContext, template_xml: str, data: bytes) str

Encrypt data using an XML template. The template must contain an <EncryptedData> element with an empty <CipherValue>.

Parameters:
  • ctx – A configured EncContext.

  • template_xml – The XML encryption template.

  • data – The plaintext bytes to encrypt.

Returns:

XML string with encrypted content.

Raises:

EncryptionError – If encryption fails.

decrypt(ctx: EncContext, xml: str) str

Decrypt an XML document containing <EncryptedData>. Returns the decrypted XML as a string.

Parameters:
  • ctx – A configured EncContext.

  • xml – The XML string containing encrypted data.

Raises:
decrypt_to_bytes(ctx: EncContext, xml: str) bytes

Decrypt an XML document containing <EncryptedData>. Returns the raw decrypted bytes (supports non-UTF-8 content).

Parameters:
  • ctx – A configured EncContext.

  • xml – The XML string containing encrypted data.

Raises:

Canonicalization

C14nMode

class C14nMode

XML Canonicalization mode enumeration.

Inclusive

Inclusive C14N (http://www.w3.org/TR/2001/REC-xml-c14n-20010315)

InclusiveWithComments

Inclusive C14N with comments

Inclusive11

Inclusive C14N 1.1

Inclusive11WithComments

Inclusive C14N 1.1 with comments

Exclusive

Exclusive C14N (http://www.w3.org/2001/10/xml-exc-c14n#)

ExclusiveWithComments

Exclusive C14N with comments

Properties

uri: str

The W3C algorithm URI for this mode.

with_comments: bool

Whether this mode includes comments.

is_exclusive: bool

Whether this mode uses exclusive canonicalization.

Methods

static from_uri(uri: str) C14nMode | None

Look up a C14nMode from its W3C algorithm URI. Returns None if the URI is not recognized.

from pybergshamra import C14nMode

mode = C14nMode.from_uri("http://www.w3.org/2001/10/xml-exc-c14n#")
assert mode == C14nMode.Exclusive

canonicalize and canonicalize_subtree

canonicalize(xml: str, mode: C14nMode, inclusive_prefixes: list[str] | None = None) bytes

Canonicalize an XML document.

Parameters:
  • xml – The XML string.

  • mode – The canonicalization mode.

  • inclusive_prefixes – Optional namespace prefixes to force visibly-utilized in exclusive C14N.

Returns:

The canonicalized XML as bytes.

Raises:

XmlError – If the XML cannot be parsed.

from pybergshamra import canonicalize, C14nMode

result = canonicalize("<b/><a/>", C14nMode.Exclusive)
canonicalize_subtree(xml: str, element_id: str, mode: C14nMode, inclusive_prefixes: list[str] | None = None) bytes

Canonicalize a subtree identified by an element ID.

Parameters:
  • xml – The XML string.

  • element_id – The ID attribute value of the target element.

  • mode – The canonicalization mode.

  • inclusive_prefixes – Optional namespace prefixes.

Returns:

The canonicalized subtree as bytes.

Raises:

XmlError – If the XML cannot be parsed or the element is not found.

from pybergshamra import canonicalize_subtree, C14nMode

xml = '<root><item Id="x1">hello</item></root>'
result = canonicalize_subtree(xml, "x1", C14nMode.Exclusive)

Cryptographic primitives

digest(algorithm_uri: str, data: bytes) bytes

Compute a one-shot message digest.

Parameters:
  • algorithm_uri – A W3C algorithm URI (e.g. Algorithm.SHA256).

  • data – The data to digest.

Returns:

The digest bytes.

Raises:

AlgorithmError – If the algorithm is unsupported.

from pybergshamra import digest, Algorithm

h = digest(Algorithm.SHA256, b"hello world")
print(h.hex())
pbkdf2_derive(password: bytes, salt: bytes, iteration_count: int, key_length: int, prf_uri: str) bytes

Derive a key using PBKDF2 (RFC 8018).

Parameters:
  • password – The password/secret bytes.

  • salt – Salt bytes.

  • iteration_count – Number of iterations.

  • key_length – Desired output key length in bytes.

  • prf_uri – PRF algorithm URI (e.g. Algorithm.HMAC_SHA256).

Returns:

The derived key bytes.

from pybergshamra import pbkdf2_derive, Algorithm

key = pbkdf2_derive(
    b"password", b"salt", 100_000, 32, Algorithm.HMAC_SHA256
)
hkdf_derive(shared_secret: bytes, key_length: int, prf_uri: str | None = None, salt: bytes | None = None, info: bytes | None = None) bytes

Derive a key using HKDF (RFC 5869).

Parameters:
  • shared_secret – Input keying material (IKM).

  • key_length – Desired output key length in bytes.

  • prf_uri – PRF algorithm URI (default: HMAC-SHA256).

  • salt – Optional salt bytes.

  • info – Optional context/info bytes.

Returns:

The derived key bytes.

from pybergshamra import hkdf_derive

key = hkdf_derive(b"shared-secret", 32, salt=b"salt", info=b"context")
concat_kdf(shared_secret: bytes, key_length: int, digest_uri: str | None = None, algorithm_id: bytes | None = None, party_u_info: bytes | None = None, party_v_info: bytes | None = None) bytes

Derive a key using ConcatKDF (NIST SP 800-56A).

Parameters:
  • shared_secret – The shared secret bytes (Z).

  • key_length – Desired output key length in bytes.

  • digest_uri – Digest algorithm URI (default: SHA-256).

  • algorithm_id – Optional AlgorithmID bytes.

  • party_u_info – Optional PartyUInfo bytes.

  • party_v_info – Optional PartyVInfo bytes.

Returns:

The derived key bytes.

from pybergshamra import concat_kdf

key = concat_kdf(b"shared-secret", 32)

Certificate validation

validate_cert_chain(leaf_der: bytes, additional_certs: list[bytes] = [], trusted_certs: list[bytes] = [], untrusted_certs: list[bytes] = [], crls: list[bytes] = [], verification_time: str | None = None, skip_time_checks: bool = False) None

Validate an X.509 certificate chain. Verifies that the leaf certificate chains to a trusted root, optionally checking time validity and CRLs.

Parameters:
  • leaf_der – DER-encoded leaf certificate.

  • additional_certs – Extra certificates from XML (DER-encoded).

  • trusted_certs – Trusted CA certificates (DER-encoded).

  • untrusted_certs – Untrusted intermediate certificates (DER-encoded).

  • crls – Certificate Revocation Lists (DER-encoded).

  • verification_time – Time override (format: "YYYY-MM-DD+HH:MM:SS").

  • skip_time_checks – Skip NotBefore/NotAfter validation.

Raises:

CertificateError – If validation fails.

Returns None on success.

import pybergshamra

leaf_der = open("leaf.der", "rb").read()
ca_der = open("ca.der", "rb").read()

# Raises CertificateError on failure
pybergshamra.validate_cert_chain(
    leaf_der,
    trusted_certs=[ca_der],
    skip_time_checks=True,
)