A secure key management system that generates and protects master private keys inside AWS Nitro Enclaves, leveraging Mysten's Seal protocol for distributed threshold encryption. The system provides secure key derivation services to other Nautilus enclaves, enabling them to obtain package-specific private keys through attestation-based authentication.
- Hardware-Isolated Key Generation: Master keys are generated inside AWS Nitro Enclaves
- Distributed Key Protection: Uses Mysten Seal's threshold cryptography (3-of-n)
- Zero-Trust Architecture: Keys are encrypted before leaving the enclave
- On-Chain Attestation: Sui blockchain verifies enclave integrity
- Double Encryption: Additional AES-256-GCM layer for on-chain storage
- Secure Key Derivation: Derives unique keys based on enclave type (not just package ID)
- Attestation-Based Authentication: Client enclaves prove their identity via attestation documents
The Seal KMS consists of these main components:
-
Enclave Server (Rust): Runs inside AWS Nitro Enclave (port 3000)
- Generates and protects the enclave's Ed25519 key pair
- Signs intents and attestation documents
- Provides low-level cryptographic operations
-
Application Server (Node.js): Runs on top of the enclave (port 8000)
- Implements KMS business logic
- Manages master key via Seal protocol
- Handles key derivation using HKDF
- Validates remote attestations
- Encrypts responses using ECDH
-
Client Nautilus Enclaves: Applications requesting derived keys
-
Sui Blockchain: On-chain storage for encrypted keys and attestation verification
-
Seal Key Servers: Distributed threshold encryption/decryption service
The system uses a two-tier architecture where both components run inside the AWS Nitro Enclave:
-
Tier 1 (Rust Enclave Server): The base enclave server that manages the Ed25519 signing key. It exposes a minimal API on localhost:3000 for internal use only. This server handles attestation generation and intent signing.
-
Tier 2 (Node.js App Server): Runs on top of the Rust enclave server inside the same enclave. It implements the KMS business logic including master key management, key derivation (HKDF), attestation validation, and ECDH encryption. It calls the Rust server's
/sign_intentendpoint via localhost:3000 to sign responses and certificates. The public API on port 8000 is exposed via vsock proxy to the host.
Both servers run inside the hardware enclave with full memory isolation from the host. The master key used for derivation and the Ed25519 signing key never leave the enclave's protected memory. Derived private keys are ephemeral - generated on demand and not persisted.
sequenceDiagram
participant Client as Client Enclave
participant App as App Server<br/>(Node.js :8000)
participant Enclave as Enclave Server<br/>(Rust :3000)
participant Sui as Sui Blockchain
participant Seal as Seal Key Servers
Note over App,Enclave: Initial Setup (One-time)
App->>App: Generate master key (32 bytes)
App->>Seal: Request threshold encryption (3-of-n)
Seal-->>App: Return encrypted key shares
App->>App: Additional AES-256-GCM encryption
App->>Sui: Store double-encrypted master key
App->>Enclave: Register enclave
Enclave->>Enclave: Generate Ed25519 keypair
Enclave-->>App: Return public key
Note over Client,Enclave: Key Request Flow
Client->>Client: Generate ephemeral ECDH keypair
Client->>Client: Create attestation document
Client->>Client: Sign request intent with enclave key
Client->>App: POST /api/request-enclave-key<br/>{ephemeral_public_key, attestation_doc,<br/>enclave_config_id, timestamp, signature}
App->>App: Validate timestamp (< 5 min)
App->>Sui: Fetch enclave config by ID
Sui-->>App: Return config with enclave type & PCRs
App->>App: Verify attestation document
App->>App: Compare PCRs with on-chain values
App->>App: Reconstruct & verify intent signature
alt If master key not in memory
App->>Sui: Fetch encrypted master key
Sui-->>App: Return encrypted key
App->>App: Decrypt AES layer
App->>Seal: Request threshold decryption
Seal-->>App: Return decrypted master key
end
App->>App: Derive key using HKDF-SHA256<br/>Context: enclave_type from config
App->>App: Derive public key for certificate
App->>App: ECDH key agreement with client
App->>App: Encrypt derived private key
App->>Enclave: POST /sign_intent<br/>(certificate data)
Enclave->>Enclave: Sign with Ed25519
Enclave-->>App: Return certificate signature
App->>Enclave: POST /sign_intent<br/>(response data)
Enclave->>Enclave: Sign with Ed25519
Enclave-->>App: Return response signature
App-->>Client: Return encrypted response<br/>{encrypted_key, iv, auth_tag,<br/>server_public_key, signature,<br/>public_key_certificate}
Client->>Client: ECDH key agreement with server
Client->>Client: Decrypt private key
Client->>Client: Verify certificate signature
Client->>Client: Use derived key for operations
The Seal KMS exposes two layers of APIs:
Client applications should use this API layer.
The Node.js application server implements the KMS logic and exposes these endpoints:
Main KMS endpoint for client enclaves to request derived private keys.
Request Body:
{
"ephemeral_public_key": "hex...", // Hex-encoded ECDH public key (prime256v1) for response encryption
"attestation_document": "hex...", // Hex-encoded attestation document from client enclave
"enclave_config_object_id": "0x...", // Sui object ID of client's enclave config (contains type info)
"timestamp_ms": 1234567890, // Request timestamp (must be within 5 minutes)
"signature": "hex..." // Ed25519 signature of the intent
}Response (Success):
{
"success": true,
"data": {
"encrypted_private_key": "hex...", // Private key encrypted with ECDH shared secret
"iv": "hex...", // Initialization vector for AES-256-GCM
"auth_tag": "hex...", // Authentication tag for AES-256-GCM
"server_public_key": "hex...", // Server's ephemeral ECDH public key
"derived_for": "0x123::module::EnclaveConfig<0x456::app::MyApp>", // Enclave type
"timestamp_ms": 1234567890, // Response timestamp
"signature": "hex...", // Ed25519 signature of the response
"enclave_object_id": "0x...", // KMS enclave object ID for validation
"public_key_certificate": { // Signed certificate for the derived public key
"derived_public_key": "hex...",
"kms_enclave_object_id": "0x...",
"kms_enclave_public_key": "hex...",
"target_enclave_config_id": "0x...",
"enclave_type": "0x123::module::EnclaveConfig<...>",
"issued_at_ms": 1234567890,
"signature": "hex..."
}
}
}Response (Error):
{
"success": false,
"error": "Attestation validation failed: PCR values do not match"
}Validation Process:
- Timestamp validation (within 5 minutes)
- Remote attestation validation against on-chain enclave config
- PCR values verification against registered values
- Extract enclave type from config object
- Intent signature verification using public key from attestation
- Authorization check (currently allows all valid enclaves)
- Key derivation using HKDF-SHA256 with enclave type as context
- Response encryption using ECDH key agreement (prime256v1)
- Response signing via enclave's
/sign_intentendpoint - Public key certificate creation and signing
Proxied to the enclave server. Returns the enclave's public key.
Response:
{
"pk": "hex..." // Hex-encoded Ed25519 public key
}Proxied to the enclave server. Returns an attestation document committed to the enclave's public key.
Response:
{
"attestation": "hex..." // Hex-encoded attestation document
}These endpoints are only available when sui_network is set to testnet in the enclave configuration. They are disabled in production environments.
GET /debug/master-key- Returns the master public key hashPOST /debug/master-key/encrypt- Encrypts data with the master keyPOST /debug/master-key/decrypt- Decrypts data with the master key
This API is used internally by the Application Server. Client applications typically don't need to call these endpoints directly.
The Rust enclave server runs inside the AWS Nitro Enclave and provides low-level signing:
Signs arbitrary data with the enclave's Ed25519 private key.
Request Body:
{
"payload": "hex..." // Hex-encoded data to sign
}Response:
{
"signature": "hex..." // Hex-encoded Ed25519 signature
}Returns the enclave's Ed25519 public key.
Response:
{
"public_key": "hex..." // Hex-encoded public key
}Loads configuration from the host via vsock.
Response:
{
// Configuration object from host
}Generates an attestation document containing the enclave's public key.
Response:
{
"attestation": "hex..." // Hex-encoded attestation document
}Health check endpoint.
Response:
{
"pk": "hex..." // Hex-encoded public key
}The production key management approach uses a persistent master key protected by Seal threshold encryption:
-
First boot (one-time setup): The enclave generates a master key, encrypts it with Seal (3-of-n threshold), applies an additional AES-256-GCM encryption layer, and stores the double-encrypted key on-chain as a shared
EncryptedMasterKeyobject. -
Subsequent boots: The enclave loads the encrypted master key from on-chain storage, decrypts the AES layer locally, then uses a Programmable Transaction Block (PTB) with fresh attestation to request Seal threshold decryption. Seal key servers verify the attestation matches the registered
EnclaveConfig(PCR values) before releasing their shares.
The Move contract provides a set_master_key function (intent type SET_MASTER_KEY_INTENT = 1) that allows the enclave to update the encrypted master key on-chain. This is used for:
- Seal server rotation: When key server configurations change, the master key is decrypted with the old servers and re-encrypted with the new servers automatically on startup.
- Key versioning: The
EncryptedMasterKeyobject tracks aversioncounter andupdated_attimestamp for auditability.
Both seal_approve and set_master_key require a valid enclave signature verified against the registered Enclave object's public key.
The on-chain logic is split into two packages:
move/enclave/— Generic enclave registration and verification framework. HandlesEnclaveConfig(PCR storage),Enclave(registered instance with public key),Cap(admin capability), andIntentMessagesignature verification. Reusable by any application.move/app/— KMS-specific logic. Definesseal_approve(Seal access control),set_master_key(key rotation), and theEncryptedMasterKeyshared object.
While the Seal SDK sends the same signed personal message to all key servers, responses from each server are encrypted to the requester's ephemeral session key. A compromised key server cannot decrypt responses from other servers, even if it replays the signed request. Threshold shares remain protected.
Debug endpoints (/debug/*) are gated by the sui_network configuration value. They are only registered when sui_network === 'testnet'. Production deployments must use a non-testnet network configuration to ensure these endpoints are not available.
Keys are derived using HKDF-SHA256 with the full enclave type string (e.g., 0x123::module::EnclaveConfig<0x456::app::MyApp>) as the context. Different enclave types always receive different derived keys, even from the same master key.
Contributions are welcome! Please read our contributing guidelines and submit pull requests to the main repository.
Apache 2.0 - See LICENSE file for details
Built on Mysten Nautilus framework for verifiable off-chain computation on Sui.
For questions about integration or security concerns, please open an issue or contact the maintainers.