HSM Key Classes

The hsmkey.keys module provides HSM-backed key classes that implement the Python cryptography library interfaces. These classes allow cryptographic operations to be performed on the HSM while maintaining API compatibility with standard cryptography library keys.

Key Architecture

All private key classes inherit from PKCS11PrivateKeyMixin which provides:

  • Lazy loading of PKCS#11 key objects

  • Session management

  • Key lookup by ID or label

  • Protection against private key extraction

from hsmkey import hsm_session
from hsmkey.keys import PKCS11RSAPrivateKey

with hsm_session("/usr/lib/softhsm/libsofthsm2.so", "my-token", "1234") as session:
    # Load key by label
    key = PKCS11RSAPrivateKey(session, key_label="my-rsa-key")

    # Or by ID
    key = PKCS11RSAPrivateKey(session, key_id=b'\x01')

Key Types

RSA Keys

PKCS11RSAPrivateKey

RSA private key backed by HSM. Implements cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.

from hsmkey.keys import PKCS11RSAPrivateKey
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# Create RSA private key reference
rsa_key = PKCS11RSAPrivateKey(session, key_label="rsa-2048")

# Get key size
print(f"Key size: {rsa_key.key_size} bits")

# Sign data
signature = rsa_key.sign(
    b"data to sign",
    padding.PKCS1v15(),
    hashes.SHA256()
)

# Decrypt data
plaintext = rsa_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Get public key
public_key = rsa_key.public_key()

Supported Operations:

  • sign(data, padding, algorithm) - Sign data with PKCS#1 v1.5 or PSS padding

  • decrypt(ciphertext, padding) - Decrypt with PKCS#1 v1.5 or OAEP padding

  • public_key() - Extract the public key

  • key_size - Get key size in bits

Unsupported Operations (private key never leaves HSM):

  • private_numbers() - Raises HSMUnsupportedError

  • private_bytes() - Raises HSMUnsupportedError

  • private_bytes_raw() - Raises HSMUnsupportedError

PKCS11RSAPublicKey

RSA public key extracted from HSM. Implements cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.

# Get public key from private key
public_key = rsa_key.public_key()

# Verify signature
public_key.verify(signature, data, padding.PKCS1v15(), hashes.SHA256())

# Encrypt data
ciphertext = public_key.encrypt(plaintext, padding.OAEP(...))

# Serialize public key
pem = public_key.public_bytes(
    serialization.Encoding.PEM,
    serialization.PublicFormat.SubjectPublicKeyInfo
)

Elliptic Curve Keys

PKCS11EllipticCurvePrivateKey

EC private key backed by HSM. Implements cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey.

Supported curves:

  • P-256 (secp256r1)

  • P-384 (secp384r1)

  • P-521 (secp521r1)

  • secp256k1

  • Brainpool curves (P256r1, P384r1, P512r1)

from hsmkey.keys import PKCS11EllipticCurvePrivateKey
from cryptography.hazmat.primitives.asymmetric import ec

# Create EC private key reference
ec_key = PKCS11EllipticCurvePrivateKey(session, key_label="ec-p256")

# Get curve information
print(f"Curve: {ec_key.curve.name}")
print(f"Key size: {ec_key.key_size} bits")

# Sign data with ECDSA
signature = ec_key.sign(
    b"data to sign",
    ec.ECDSA(hashes.SHA256())
)

# ECDH key exchange
shared_secret = ec_key.exchange(ec.ECDH(), peer_public_key)

# Get public key
public_key = ec_key.public_key()

Supported Operations:

  • sign(data, signature_algorithm) - ECDSA signing (returns DER-encoded signature)

  • exchange(algorithm, peer_public_key) - ECDH key exchange

  • public_key() - Extract the public key

  • curve - Get the elliptic curve

  • key_size - Get key size in bits

PKCS11EllipticCurvePublicKey

EC public key extracted from HSM. Implements cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.

# Get public key
public_key = ec_key.public_key()

# Verify signature
public_key.verify(signature, data, ec.ECDSA(hashes.SHA256()))

# Get public numbers (x, y coordinates)
numbers = public_key.public_numbers()
print(f"X: {numbers.x}")
print(f"Y: {numbers.y}")

# Serialize
pem = public_key.public_bytes(
    serialization.Encoding.PEM,
    serialization.PublicFormat.SubjectPublicKeyInfo
)

Ed25519 Keys

PKCS11Ed25519PrivateKey

Ed25519 private key backed by HSM. Implements cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey.

Ed25519 is a modern elliptic curve signature scheme known for:

  • Fast signature generation and verification

  • Small signatures (64 bytes)

  • Strong security with 128-bit security level

  • Deterministic signatures (no random number needed)

from hsmkey.keys import PKCS11Ed25519PrivateKey

# Create Ed25519 private key reference
ed_key = PKCS11Ed25519PrivateKey(session, key_label="ed25519")

# Sign data (Ed25519 handles hashing internally)
signature = ed_key.sign(b"data to sign")
assert len(signature) == 64  # Ed25519 signatures are 64 bytes

# Get public key
public_key = ed_key.public_key()

PKCS11Ed25519PublicKey

Ed25519 public key extracted from HSM. Implements cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey.

# Get public key
public_key = ed_key.public_key()

# Verify signature
public_key.verify(signature, data)

# Get raw public key bytes (32 bytes)
raw_bytes = public_key.public_bytes_raw()

Ed448 Keys

PKCS11Ed448PrivateKey

Ed448 private key backed by HSM. Implements cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey.

Ed448 provides stronger security than Ed25519:

  • 224-bit security level

  • Larger signatures (114 bytes)

  • 57-byte public keys

from hsmkey.keys import PKCS11Ed448PrivateKey

# Create Ed448 private key reference
ed_key = PKCS11Ed448PrivateKey(session, key_label="ed448")

# Sign data
signature = ed_key.sign(b"data to sign")
assert len(signature) == 114  # Ed448 signatures are 114 bytes

# Get public key
public_key = ed_key.public_key()

PKCS11Ed448PublicKey

Ed448 public key extracted from HSM. Implements cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey.

# Get public key
public_key = ed_key.public_key()

# Verify signature
public_key.verify(signature, data)

# Get raw public key bytes (57 bytes)
raw_bytes = public_key.public_bytes_raw()

Base Class

PKCS11PrivateKeyMixin

Base mixin class providing common functionality for all HSM-backed private keys.

from hsmkey.keys import PKCS11PrivateKeyMixin

Key features:

  • Lazy loading: PKCS#11 key objects are loaded on first use

  • Key lookup: Find keys by ID (CKA_ID) or label (CKA_LABEL)

  • Session management: Maintains reference to PKCS#11 session

  • Private key protection: Operations that would export private key material raise HSMUnsupportedError

Properties:

  • pkcs11_private_key - Get the underlying PKCS#11 private key object

  • pkcs11_public_key - Get the underlying PKCS#11 public key object

Using Keys with JWCrypto

For JWCrypto integration, use the HSMJWK class instead of raw key classes:

from hsmkey import HSMJWK, hsm_session
from jwcrypto.jws import JWS

with hsm_session("/usr/lib/softhsm/libsofthsm2.so", "my-token", "1234") as session:
    # HSMJWK wraps the key classes for JWCrypto compatibility
    jwk = HSMJWK.from_hsm(session, key_label="rsa-2048")

    # Use with JWS
    jws = JWS(b"payload")
    jws.add_signature(jwk, alg="RS256", protected='{"alg":"RS256"}')

See JWCrypto Integration for complete JWCrypto integration documentation.

Error Handling

Key operations may raise the following exceptions:

from hsmkey.exceptions import (
    HSMKeyNotFoundError,
    HSMOperationError,
    HSMUnsupportedError,
)

try:
    key = PKCS11RSAPrivateKey(session, key_label="nonexistent")
    key.sign(data, padding, algorithm)
except HSMKeyNotFoundError:
    print("Key not found in HSM")
except HSMOperationError as e:
    print(f"HSM operation failed: {e}")

try:
    # Attempting to extract private key material
    key.private_bytes(...)
except HSMUnsupportedError:
    print("Private key cannot be extracted from HSM")

Algorithm Support

The following table summarizes algorithm support for each key type:

Key Type

Signing Algorithms

Encryption/Key Exchange

RSA

PKCS#1 v1.5, PSS (SHA-256, SHA-384, SHA-512)

PKCS#1 v1.5, OAEP

EC (P-256, P-384, P-521)

ECDSA (SHA-256, SHA-384, SHA-512)

ECDH

Ed25519

EdDSA (built-in hashing)

N/A

Ed448

EdDSA (built-in hashing)

N/A