Backup and Recovery
Overview
As outlined in the Backup and Recovery Overview, the backup and recovery features enable the creation of an encrypted copy of the end-user key share, which is then sent to Fireblocks for safekeeping. This process becomes essential when a user may lose access to their device or need to transition to a new one.
The application or the user must generate the recovery passphrase for AES encryption of the end-user key share. The end user must securely preserve this passphrase. This precaution ensures that the private key share can be decrypted in a recovery situation, granting the user access to their key and enabling them to operate as usual.
Backing up the passphrase can be accomplished through various methods, and Fireblocks does not mandate any specific approach. For example, the end user can store the recovery passphrase in their iCloud account or Google Drive, or they may download and keep it locally on their device.
Terms to know
passphrase
: The chosen passphrase for the backup. MPC key share #2 is encrypted using this passphrase and saved/encrypted along with thepassphraseId
from the Fireblocks cloud servers.passphraseId
: The UUID created by the application.passphraseResolver
: A callback that knows how to fetch the passphrase from its saved location when given apassphraseId
value. For example, if you saved the passphrase on the end user's iCloud account, then when given thepassphraseId
value, thepassphraseResolver
callback fetches the passphrase from the iCloud account so that therecoverKeys
function can decrypt the MPC key share.
Backup procedure
Prerequisites
Before running a backup procedure, you will need to have an MPC key share on the device.
This can be obtained by either:
- Generating an MPC key share (new wallet scenarios) as shown here.
- Running a recovery flow, as later described in this article.
await fireblocksNCW.backupKeys(passphrase, passphraseId);
// create a symmetric key for the encryption of the backup
var backupEncryptionKey = fireblocksSdk.generateRandomPassPhrase();
// store the backupEncryptionKey somewhere (user’s iCloud/Google, d/l, convert to seed phrase or other)
// backup the keys (including encryption)
fireblocks.backupKeys(passphrase, passphraseId) {
Timber.d("Backup keys result: $it")
callback.invoke(it)
}
let passphrase = Fireblocks.generateRandomPassPhrase()
// using concurrency
let result = await instance.backupKeys(passphrase: passphrase)
<--- OR --->
// using callback
try instance?.backupKeys(passphrase: passphrase, callback: { [weak self] result in
//handle result
})
Please note that steps 1 and 2 are under your implementation, while step 3 calls the Fireblocks SDK backup.
- Save the
passphrase
and thepassphraseId
on your preferred user cloud, such as iCloud or Google Drive. Note thatpassphraseId
should be a UUID (enforced by Fireblocks). - In your backend proxy database, save the
passphraseId
and the path to thepassphrase
. This data should indicate which user cloud you used and the path to the passphrase. - Call the Fireblocks implementation for backup together with the
passphrase
and thepassphraseId
.
Backing up your keys post extension
In case you have extended your key set, as elaborated here, you must repeat the above steps again, in order to back up your new, extended key set, as well.
Recovery procedure
await fireblocksNCW.recoverKeys(passphraseResolver);
// recover the backed up keys. We will use the given backupEncryptionKey to decrypt the keys
Fireblocks.getInstance(deviceId).recoverKeys(passphraseResolver = passphraseResolver) {
Timber.d("Recover keys result: $it")
callback.invoke(it)
}
// using concurrency
let result = await instance.recoverKeys(passphrase: passphrase)
<--- OR --->
// using callback
try instance.recoverKeys(passphrase: passphrase, callback: { [weak self] result in
//handle result
})
- Call the Fireblocks SDK's
recoverKeys
function with a callback that implements a function that, when given apassphraseId
, will fetch the associated passphrase for the user. - The Fireblocks SDK fetches the last encrypted key share with the associated
passphraseId
and then uses your callback to decrypt the private key share locally.
Additional recovery info
The encrypted backup is associated with the end user's deviceId
. Therefore, to recover and decrypt the key share saved on the Fireblocks cloud servers, the NCW SDK must initialize with the same deviceId
that created the backup. The NCW SDK cannot recover a key share of a different deviceId
.
If you want to let your end users go into recovery mode, you need to determine the deviceId
that will run the recovery procedure. To support this, Fireblocks has provided a function within the Fireblocks SDK that fetches the latest details about the backup of the specified walletId
. You call this function from your backend implementation.
await signer.NCW.getLatestBackup(walletId);
curl --request GET \
--url https://sandbox-api.fireblocks.io/v1/ncw/wallets/walletId/backup/latest \
--header 'accept: application/json'
After Recovering
After a successful recovery, the device with the
deviceId
used to decrypt the backup will have its certificate with Fireblocks disabled, and it will be unable to perform any MPC-related operations, such as signing transactions, creating backups, adding devices, or takeovers. Because of this, you should only consider performing a recovery when you have lost access to all of the devices associated with a wallet. If you still have access to one of the devices, you should add the device, as shown in the Multiple Devices article.
Updated about 1 month ago