Skip to main content

Export

Export produces an encrypted blob containing the user's full reconstructed private key — not just the device's share. Anyone holding the matching decryption key can re-import the wallet on a fresh device. The blob is encrypted to a host-side keypair that the example generates per export.

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 combines both encrypted shares into a single export blob.
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)
val keyshare = dao.currentKeyshare ?: throw Exception("No active keyshare")
return sessionFor(dao.keyType).export(
hostKeyshare = keyshare,
otherEncryptedKeyshare = serverEncShare,
hostEncryptionKey = hostEncryptionKey,
otherDecryptionKey = serverPublicKey
).getOrThrow()
}

What the export blob becomes

The example wraps each wallet's export blob 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