Skip to content

Master Key Export

← Back to KMD Client

This example demonstrates how to export the master derivation key (MDK) for wallet backup using the KMD export_master_key() method. Key concepts:

  • The master derivation key (MDK) is the root key used to deterministically generate all keys in the wallet
  • With the MDK, you can recreate a wallet and regenerate all derived keys
  • Imported keys CANNOT be recovered from the MDK
  • The MDK should be stored securely as it can regenerate all wallet keys Prerequisites: Covered operations:
  • export_master_key() - Export the master derivation key from a wallet
  • LocalNet running (via algokit localnet start)

From the repository’s examples directory:

Terminal window
cd examples
uv run python kmd_client/07_master_key_export.py

View source on GitHub

07_master_key_export.py
# ruff: noqa: N999, C901, PLR0912, PLR0915
"""
Example: Master Key Export
This example demonstrates how to export the master derivation key (MDK)
for wallet backup using the KMD export_master_key() method.
Key concepts:
- The master derivation key (MDK) is the root key used to deterministically
generate all keys in the wallet
- With the MDK, you can recreate a wallet and regenerate all derived keys
- Imported keys CANNOT be recovered from the MDK
- The MDK should be stored securely as it can regenerate all wallet keys
Prerequisites:
- LocalNet running (via `algokit localnet start`)
Covered operations:
- export_master_key() - Export the master derivation key from a wallet
"""
import sys
from shared import (
cleanup_test_wallet,
create_kmd_client,
create_test_wallet,
print_error,
print_header,
print_info,
print_step,
print_success,
)
from algokit_kmd_client.models import ExportMasterKeyRequest, GenerateKeyRequest, ListKeysRequest
def format_bytes_for_display(data: bytes, show_first: int = 4, show_last: int = 4) -> str:
"""Format a byte array for display, showing first and last few bytes for security."""
hex_str = data.hex()
if len(data) <= show_first + show_last:
return hex_str
first_bytes = hex_str[: show_first * 2]
last_bytes = hex_str[-(show_last * 2) :]
return f"{first_bytes}...{last_bytes}"
def main() -> None:
print_header("KMD Master Key Export Example")
kmd = create_kmd_client()
wallet_handle_token = ""
wallet_password = "test-password"
try:
# =========================================================================
# Step 1: Create a Test Wallet
# =========================================================================
print_step(1, "Creating a test wallet")
test_wallet = create_test_wallet(kmd, wallet_password)
wallet_handle_token = test_wallet["wallet_handle_token"]
print_success(f"Test wallet created: {test_wallet['wallet_name']}")
print_info(f"Wallet ID: {test_wallet['wallet_id']}")
# =========================================================================
# Step 2: Generate Several Keys in the Wallet
# =========================================================================
print_step(2, "Generating several keys in the wallet")
generated_addresses: list[str] = []
num_keys = 3
for i in range(1, num_keys + 1):
address = kmd.generate_key(GenerateKeyRequest(wallet_handle_token=wallet_handle_token)).address
generated_addresses.append(address)
print_info(f"Key {i}: {address}")
print_success(f"Generated {num_keys} keys in the wallet")
print_info("")
print_info("These keys are deterministically derived from the master derivation key.")
print_info("They can be regenerated by creating a new wallet with the same MDK.")
# =========================================================================
# Step 3: Export the Master Derivation Key
# =========================================================================
print_step(3, "Exporting the master derivation key with export_master_key()")
master_key = kmd.export_master_key(
ExportMasterKeyRequest(wallet_handle_token=wallet_handle_token, wallet_password=wallet_password)
).master_derivation_key
print_success("Master derivation key exported successfully!")
print_info("")
print_info("export_master_key() response:")
key_display = format_bytes_for_display(master_key)
print_info(f" master_derivation_key ({len(master_key)} bytes): {key_display}")
print_info("")
print_info("Note: The wallet password is required to export the master key for security.")
# =========================================================================
# Step 4: Explain What the Master Key Is
# =========================================================================
print_step(4, "Understanding the master derivation key")
print_info("")
print_info("What is the Master Derivation Key (MDK)?")
print_info("-" * 40)
print_info("")
print_info("The MDK is the cryptographic root of your wallet. It is used to:")
print_info("")
print_info(" 1. BACKUP/RECOVERY: Store this key to recover your wallet")
print_info(" - Create a new wallet with the MDK to restore it")
print_info(" - Call generate_key() the same number of times to recover keys")
print_info(f" - In this example, calling generate_key() {num_keys} times would")
print_info(" regenerate the exact same addresses")
print_info("")
print_info(" 2. DETERMINISTIC DERIVATION: Keys are derived in sequence")
print_info(" - First generate_key() call always produces the same address")
print_info(" - Second call produces the same second address, etc.")
print_info(" - This sequence is reproducible with the same MDK")
# =========================================================================
# Step 5: Important Limitations
# =========================================================================
print_step(5, "Important limitations - Imported keys")
print_info("")
print_info("IMPORTANT: Imported keys CANNOT be recovered from the MDK!")
print_info("-" * 40)
print_info("")
print_info("The MDK only protects keys generated with generate_key().")
print_info("")
print_info("Keys imported with import_key():")
print_info(" - Are stored in the wallet database")
print_info(" - Can be used for transactions while the wallet exists")
print_info(" - CANNOT be regenerated from the MDK")
print_info(" - Must be backed up separately using export_key()")
print_info("")
print_info("To fully backup a wallet with imported keys:")
print_info(" 1. Export and store the MDK (for generated keys)")
print_info(" 2. Export and store each imported key separately")
print_info(" 3. Or backup the entire wallet database file")
# =========================================================================
# Step 6: Security Implications
# =========================================================================
print_step(6, "Security implications")
print_info("")
print_info("SECURITY WARNING: Handle the MDK with extreme care!")
print_info("-" * 40)
print_info("")
print_info("Anyone with access to your MDK can:")
print_info(" - Recreate your entire wallet")
print_info(" - Generate all your derived keys")
print_info(" - Sign transactions and move your funds")
print_info("")
print_info("Best practices for MDK storage:")
print_info(" - Never store it in plain text on your computer")
print_info(" - Use hardware security modules (HSM) for production")
print_info(" - Consider splitting the key using Shamir Secret Sharing")
print_info(" - Store backups in secure, offline locations")
print_info(" - Never transmit the MDK over insecure channels")
print_info("")
print_info("The MDK in this example is for demonstration only.")
print_info("In production, implement proper key management practices.")
# =========================================================================
# Step 7: Verify Keys Can Be Listed
# =========================================================================
print_step(7, "Verifying wallet state")
list_result = kmd.list_keys_in_wallet(ListKeysRequest(wallet_handle_token=wallet_handle_token)).addresses
print_success(f"Wallet contains {len(list_result)} key(s)")
print_info("")
print_info("Generated addresses (would be recoverable from MDK):")
for i, addr in enumerate(list_result):
print_info(f" {i + 1}. {addr}")
# =========================================================================
# Cleanup
# =========================================================================
print_step(8, "Cleaning up test wallet")
cleanup_test_wallet(kmd, wallet_handle_token)
wallet_handle_token = "" # Mark as cleaned up
print_success("Test wallet handle released")
# =========================================================================
# Summary
# =========================================================================
print_header("Summary")
print_info("This example demonstrated master key export in KMD:")
print_info("")
print_info(" export_master_key()")
print_info(" Parameters: wallet_handle_token, wallet_password")
print_info(f" Returns: master_derivation_key ({len(master_key)}-byte bytes)")
print_info("")
print_info("Key takeaways:")
print_info(" - The MDK is the root key for deterministic key derivation")
print_info(f" - MDK is {len(master_key)} bytes (256 bits) for ed25519")
print_info(" - Wallet password is required to export the MDK")
print_info(" - Generated keys can be recovered with the MDK")
print_info(" - Imported keys CANNOT be recovered with the MDK")
print_info(" - The MDK must be stored securely - it controls all funds!")
print_info("")
print_info("Note: The test wallet remains in KMD (wallets cannot be deleted via API).")
except Exception as e:
print_error(f"Error: {e}")
print_info("")
print_info("Troubleshooting:")
print_info(" - Ensure LocalNet is running: algokit localnet start")
print_info(" - If LocalNet issues occur: algokit localnet reset")
print_info(" - Check that KMD is accessible on port 4002")
# Cleanup on error
if wallet_handle_token:
cleanup_test_wallet(kmd, wallet_handle_token)
sys.exit(1)
if __name__ == "__main__":
main()