Skip to main content

Export

Export reconstructs the user's full private key — not just the device's share — and returns it as raw bytes; the example saves it hex-encoded in a plaintext JSON file. Anyone holding that file can re-import the wallet on a fresh device. The host-side keypair the example generates per export only protects the server's share as it travels back to the device — the exported key itself is returned in the clear.

For the SDK contract see Export Key (Kotlin) and Export Key (Swift).

Duo's 3-step protocol

Duo export requires coordination with the server over HTTP:

  1. prepareExport(keyId) — generates a fresh host encryption/decryption keypair locally.
  2. HTTP fetch — the example posts the host public key to the server's /v3/{algorithm}/export endpoint and gets back the server's encrypted share + the server's public key.
  3. exportKeyshare(...) — the SDK decrypts the server's share with the host keypair, combines it with the device's share, and reconstructs the raw private key.
vault/.../session/VaultSessionManager.kt
suspend fun prepareExport(keyId: String): Triple<ByteArray, String, String> {
val keyType = readDao(keyId).keyType
val (hostEncryptionKey, hostDecryptionKey) =
keyType.silentShard.generateEncryptionDecryptionKeyPair()
return Triple(hostEncryptionKey, hostDecryptionKey.toHex(), keyType.algorithmName)
}

suspend fun exportKeyshare(
keyId: String,
hostEncryptionKey: ByteArray,
serverEncShare: ByteArray,
serverPublicKey: ByteArray,
): ByteArray {
val dao = readDao(keyId)
return sessionFor(dao.keyType).export(
keyId,
otherEncryptedKeyshare = serverEncShare,
hostEncryptionKey = hostEncryptionKey,
otherDecryptionKey = serverPublicKey
).getOrThrow()
}

What the exported key becomes

The example wraps each wallet's exported key (hex-encoded) into a JSON entry and writes the result to a user-chosen file:

{ "keyType": "ECDSA", "chain": "ETHEREUM_SEPOLIA", "exportDataHex": "abc123..." }

The vault never persists exports — the file is purely for the user to store.

Export screen