ARC-35: Algorand Offline Wallet Backup Protocol
Wallet-agnostic backup protocol for multiple accounts
Author | Yigit Guler |
---|---|
Discussions-To | https://github.com/algorandfoundation/ARCs/issues/156 |
Status | Final |
Type | Standards Track |
Category | Interface |
Created | 2023-01-03 |
Table of Contents
Algorand Secure 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.
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:
- The wallet generates a random 16-byte string S (using a cryptographically secure random number generator)
- 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,crypto_auth_hmacsha256_init
/crypto_auth_hmacsha256_update
/crypto_auth_hmacsha256_final
- The wallet encrypts the input JSON using
crypto_secretbox_easy
from libsodium (https://libsodium.gitbook.io/doc/secret-key_cryptography/secretbox) - 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.
- 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.
Citation
Please cite this document as:
Yigit Guler, "ARC-35: Algorand Offline Wallet Backup Protocol," Algorand Requests for Comments, no. 35, January 2023. [Online serial]. Available: https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0035.md.