Skip to content
Algorand Developer Portal

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);
});