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 exportMasterKey() 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
  • LocalNet running (via algokit localnet start)
  • Covered operations:
  • exportMasterKey() - Export the master derivation key from a wallet

From the repository root:

Terminal window
cd examples
npm run example kmd_client/07-master-key-export.ts

View source on GitHub

07-master-key-export.ts
/**
* Example: Master Key Export
*
* This example demonstrates how to export the master derivation key (MDK)
* for wallet backup using the KMD `exportMasterKey()` 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:
* - exportMasterKey() - Export the master derivation key from a wallet
*/
import {
cleanupTestWallet,
createKmdClient,
createTestWallet,
printError,
printHeader,
printInfo,
printStep,
printSuccess,
} from '../shared/utils.js'
/**
* Format a byte array for display, showing first and last few bytes for security
*/
function formatBytesForDisplay(bytes: Uint8Array, showFirst = 4, showLast = 4): string {
const hex = Buffer.from(bytes).toString('hex')
if (bytes.length <= showFirst + showLast) {
return hex
}
const firstBytes = hex.slice(0, showFirst * 2)
const lastBytes = hex.slice(-(showLast * 2))
return `${firstBytes}...${lastBytes}`
}
async function main() {
printHeader('KMD Master Key Export Example')
const kmd = createKmdClient()
let walletHandleToken = ''
const walletPassword = 'test-password'
try {
// =========================================================================
// Step 1: Create a Test Wallet
// =========================================================================
printStep(1, 'Creating a test wallet')
const testWallet = await createTestWallet(kmd, walletPassword)
walletHandleToken = testWallet.walletHandleToken
printSuccess(`Test wallet created: ${testWallet.walletName}`)
printInfo(`Wallet ID: ${testWallet.walletId}`)
// =========================================================================
// Step 2: Generate Several Keys in the Wallet
// =========================================================================
printStep(2, 'Generating several keys in the wallet')
const generatedAddresses: string[] = []
const numKeys = 3
for (let i = 1; i <= numKeys; i++) {
const result = await kmd.generateKey({ walletHandleToken })
generatedAddresses.push(result.address.toString())
printInfo(`Key ${i}: ${result.address}`)
}
printSuccess(`Generated ${numKeys} keys in the wallet`)
printInfo('')
printInfo('These keys are deterministically derived from the master derivation key.')
printInfo('They can be regenerated by creating a new wallet with the same MDK.')
// =========================================================================
// Step 3: Export the Master Derivation Key
// =========================================================================
printStep(3, 'Exporting the master derivation key with exportMasterKey()')
const exportResult = await kmd.exportMasterKey({
walletHandleToken,
walletPassword,
})
const masterKey = exportResult.masterDerivationKey
printSuccess('Master derivation key exported successfully!')
printInfo('')
printInfo('ExportMasterKeyResponse fields:')
printInfo(` masterDerivationKey (${masterKey.length} bytes): ${formatBytesForDisplay(masterKey)}`)
printInfo('')
printInfo('Note: The wallet password is required to export the master key for security.')
// =========================================================================
// Step 4: Explain What the Master Key Is
// =========================================================================
printStep(4, 'Understanding the master derivation key')
printInfo('')
printInfo('What is the Master Derivation Key (MDK)?')
printInfo('-'.repeat(40))
printInfo('')
printInfo('The MDK is the cryptographic root of your wallet. It is used to:')
printInfo('')
printInfo(' 1. BACKUP/RECOVERY: Store this key to recover your wallet')
printInfo(' - Create a new wallet with the MDK to restore it')
printInfo(' - Call generateKey() the same number of times to recover keys')
printInfo(` - In this example, calling generateKey() ${numKeys} times would`)
printInfo(' regenerate the exact same addresses')
printInfo('')
printInfo(' 2. DETERMINISTIC DERIVATION: Keys are derived in sequence')
printInfo(' - First generateKey() call always produces the same address')
printInfo(' - Second call produces the same second address, etc.')
printInfo(' - This sequence is reproducible with the same MDK')
// =========================================================================
// Step 5: Important Limitations
// =========================================================================
printStep(5, 'Important limitations - Imported keys')
printInfo('')
printInfo('IMPORTANT: Imported keys CANNOT be recovered from the MDK!')
printInfo('-'.repeat(40))
printInfo('')
printInfo('The MDK only protects keys generated with generateKey().')
printInfo('')
printInfo('Keys imported with importKey():')
printInfo(' - Are stored in the wallet database')
printInfo(' - Can be used for transactions while the wallet exists')
printInfo(' - CANNOT be regenerated from the MDK')
printInfo(' - Must be backed up separately using exportKey()')
printInfo('')
printInfo('To fully backup a wallet with imported keys:')
printInfo(' 1. Export and store the MDK (for generated keys)')
printInfo(' 2. Export and store each imported key separately')
printInfo(' 3. Or backup the entire wallet database file')
// =========================================================================
// Step 6: Security Implications
// =========================================================================
printStep(6, 'Security implications')
printInfo('')
printInfo('⚠️ SECURITY WARNING: Handle the MDK with extreme care!')
printInfo('-'.repeat(40))
printInfo('')
printInfo('Anyone with access to your MDK can:')
printInfo(' - Recreate your entire wallet')
printInfo(' - Generate all your derived keys')
printInfo(' - Sign transactions and move your funds')
printInfo('')
printInfo('Best practices for MDK storage:')
printInfo(' - Never store it in plain text on your computer')
printInfo(' - Use hardware security modules (HSM) for production')
printInfo(' - Consider splitting the key using Shamir Secret Sharing')
printInfo(' - Store backups in secure, offline locations')
printInfo(' - Never transmit the MDK over insecure channels')
printInfo('')
printInfo('The MDK in this example is for demonstration only.')
printInfo('In production, implement proper key management practices.')
// =========================================================================
// Step 7: Verify Keys Can Be Listed
// =========================================================================
printStep(7, 'Verifying wallet state')
const listResult = await kmd.listKeysInWallet({ walletHandleToken })
printSuccess(`Wallet contains ${listResult.addresses.length} key(s)`)
printInfo('')
printInfo('Generated addresses (would be recoverable from MDK):')
listResult.addresses.forEach((addr, i) => {
printInfo(` ${i + 1}. ${addr}`)
})
// =========================================================================
// Cleanup
// =========================================================================
printStep(8, 'Cleaning up test wallet')
await cleanupTestWallet(kmd, walletHandleToken)
walletHandleToken = '' // Mark as cleaned up
printSuccess('Test wallet handle released')
// =========================================================================
// Summary
// =========================================================================
printHeader('Summary')
printInfo('This example demonstrated master key export in KMD:')
printInfo('')
printInfo(' exportMasterKey()')
printInfo(' Parameters: walletHandleToken, walletPassword')
printInfo(` Returns: masterDerivationKey (${masterKey.length}-byte Uint8Array)`)
printInfo('')
printInfo('Key takeaways:')
printInfo(' - The MDK is the root key for deterministic key derivation')
printInfo(` - MDK is ${masterKey.length} bytes (256 bits) for ed25519`)
printInfo(' - Wallet password is required to export the MDK')
printInfo(' - Generated keys can be recovered with the MDK')
printInfo(' - Imported keys CANNOT be recovered with the MDK')
printInfo(' - The MDK must be stored securely - it controls all funds!')
printInfo('')
printInfo('Note: The test wallet remains in KMD (wallets cannot be deleted via API).')
} catch (error) {
printError(`Error: ${error instanceof Error ? error.message : String(error)}`)
printInfo('')
printInfo('Troubleshooting:')
printInfo(' - Ensure LocalNet is running: algokit localnet start')
printInfo(' - If LocalNet issues occur: algokit localnet reset')
printInfo(' - Check that KMD is accessible on port 4002')
// Cleanup on error
if (walletHandleToken) {
await cleanupTestWallet(kmd, walletHandleToken)
}
process.exit(1)
}
}
main().catch((error) => {
console.error('Fatal error:', error)
process.exit(1)
})