# Algorand Offline Wallet Backup Protocol

## Abstract

This document outlines the high-level requirements for a wallet-agnostic backup protocol that can be used across all wallets on the Algorand ecosystem.

## Specification

The key words “ **MUST**”, “ **MUST NOT**”, “ **REQUIRED**”, “ **SHALL**”, “ **SHALL NOT**”, “ **SHOULD**”, “ **SHOULD NOT**”, “ **RECOMMENDED**”, “ **MAY**”, and “ **OPTIONAL**” in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt).

### Requirements

At a high-level, offline wallet backup protocol has the following requirements:

- Wallet applications should allow backing up and storing multiple accounts at the same time.
Account information should be encrypted with a user-defined secret key, utilizing NaCl SecretBox method (audited and endorsed by Algorand).

- Encrypted final string should be easily copyable to be stored digitally.
When importing, wallet applications should be able to detect already imported accounts and gracefully ignore them.

### Format

Before encryption, account information should be converted to the following JSON format:

```
{

"device_id": "UNIQUE IDENTIFIER FOR DEVICE (OPTIONAL)",

"provider_name": "PROVIDER NAME (OPTIONAL, i.e. Pera Wallet)",

"accounts": [\
\
    {\
\
      "address": "ACCOUNT PUBLIC ADDRESS (REQUIRED)",\
\
      "name": "USER DEFINED ACCOUNT NAME (OPTIONAL)",\
\
      "account_type": "TYPE OF ACCOUNT: single, multisig, watch, contact, ledger (REQUIRED)",\
\
    "private_key": "PRIVATE KEY AS BASE64 ENCODING OF 64 BYTE ALGORAND PRIVATE KEY as encoded by algosdk (NOT PASSPHRASE, REQUIRED for user-owned accounts, can be omitted in case of watch, contact, multisig, ledger accounts)",\
\
      "metadata": "ANY ADDITIONAL CONTENT (OPTIONAL)",\
\
      "multisig": "Multisig information (only required if the account_type is multisig)",\
\
      "ledger": {\
\
        "device_id": "device id",\
\
        "index": <index of the account on device, integer>,\
\
        "connection_type": "bluetooth|usb"\
\
      },\
\
    },\
\
    ...\
\
  ]

}
```

_Clients must accept additional fields in the JSON document._

Here is an example with a single account:

```
{

"device_id": "2498232091970170817",

"provider_name": "Pera Wallet",

"accounts": [\
\
    {\
\
      "address": "ELWRE6HZ7KIUT46EQ6PBISGD3ND6QSCBVWICYR2QR2Y7LOBRZRCAIKLWDE",\
\
      "name": "My NFT Account",\
\
      "account_type": "single",\
\
      "private_key": "w0HG2VH7tAYz9PD4SYX0flC4CKh1OONCB6U5bP7cXGci7RJ4+fqRSfPEh54USMPbR+hIQa2QLEdQjrH1uDHMRA=="\
\
    }\
\
  ],

}
```

Here is an example with a single multi-sig account:

```
{

"device_id": "2498232091970170817",

"provider_name": "Pera Wallet",

"accounts": [\
\
    {\
\
      "address": "ELWRE6HZ7KIUT46EQ6PBISGD3ND6QSCBVWICYR2QR2Y7LOBRZRCAIKLWDE",\
\
      "name": "Our Multisig Account",\
\
      "account_type": "multisig",\
\
      "multisig": {\
\
        version: 1,\
\
        threshold: 2,\
\
        addrs: [\
\
            account1.addr,\
\
            account2.addr,\
\
            account3.addr,\
\
            ],\
\
     },\
\
    }\
\
  ],

}
```

### Encryption

Once the input JSON is ready, as specified above, it needs to be encrypted. Even if it is assumed that the user is going to store this information in a secure location, copy-pasting it without encryption is not secure since multiple applications can access the clipboard.

The information needs to be encrypted using a very long passphrase. 12 words mnemonic will be used as the key. 12-word mnemonic is secure and it will not create confusion with the 25-word mnemonics that are used to encrypt accounts.

The wallet applications should not allow users to copy the 12-word mnemonic nor allow taking screenshots. The users should note it visually.

The encryption should be made as follows:

1. The wallet generates a random 16-byte string S (using a cryptographically secure random number generator)
2. The wallet derives a 32-byte key: `key = HMAC-SHA256(key="Algorand export 1.0", input=S)`
On libsodium, use [https://libsodium.gitbook.io/doc/advanced/hmac-sha2#hmac-sha-256](https://libsodium.gitbook.io/doc/advanced/hmac-sha2#hmac-sha-256),
`crypto_auth_hmacsha256_init` / `crypto_auth_hmacsha256_update` / `crypto_auth_hmacsha256_final`
3. The wallet encrypts the input JSON using `crypto_secretbox_easy` from libsodium ( [https://libsodium.gitbook.io/doc/secret-key\_cryptography/secretbox](https://libsodium.gitbook.io/doc/secret-key_cryptography/secretbox))
4. The wallet outputs the following output JSON:

```
{

"version": "1.0",

"suite": "HMAC-SHA256:sodium_secretbox_easy",

"ciphertext": <base64 of the ciphertext>
}
```

This JSON document (will be referred as ciphertext envelope JSON) needs to be encoded with base64 again in order to make it easier to copy-paste & store.

5. S is encoded as a 12-word mnemonic (according to BIP-39) and displayed to the user.

The user will be responsible for keeping the 12-word mnemonic and the base64 output of the ciphertext envelope JSON in safe locations. Note that step 5 is the default approach, however, the wallets can support other methods other than mnemonics as well, as long as they are secure.

### Importing

When importing, wallet applications should ask the user for the base64 output of the envelope JSON and the 12-word mnemonic. After getting these values, it should attempt to decrypt the encrypted string using the 12-word mnemonic. On successful decryption, accounts that can be imported can be processed.

## Rationale

There are many benefits to having an openly documented format:

- Better interoperability across wallets, allowing users to use multiple wallets easily by importing all of their accounts using a single format.

- Easy and secure backup of all wallet data at a user-defined location, including secure storage in digital environments.

- Ability to transfer data from device to device securely, such as when moving data from one mobile device to another.

## Security Considerations

Tbd

## Copyright

Copyright and related rights waived via [CCO](https://creativecommons.org/publicdomain/zero/1.0/).
