Recovery codes
Ce contenu n’est pas encore disponible dans votre langue.
When you enable E2EE, Pia generates a single recovery code. It is the only way to recover access to your encrypted data if you lose every active device.
What the recovery code is
Section titled “What the recovery code is”A 26-character Base32 code, shown in groups of four, carrying 128 bits of entropy. It’s never transmitted to the server in cleartext. Internally it’s used to derive a Key Encryption Key (KEK) via Argon2id, which then unwraps your User Master Key (UMK).
Recovery code ──Argon2id(salt, m, t, p)──► KEK ──AES-GCM-decrypt──► UMKThe Argon2id parameters (salt, memory cost, time cost, parallelism) are stored on the server alongside the wrapped UMK so any new device can reproduce the derivation.
When to use it
Section titled “When to use it”You need the recovery code when:
- You’ve lost or wiped all active devices.
- A new device can’t be approved by an existing one (because you have none).
You do not need the recovery code for:
- Routine sign-in (your active devices keep working).
- Adding a device when another device is online and reachable — that flow uses the device-to-device approval, not recovery.
Activation flow
Section titled “Activation flow”- On a fresh device, sign in with your account credentials.
- When prompted, choose “Use recovery code”.
- Paste the code. The client derives the KEK via Argon2id.
- The client downloads the recovery-wrapped UMK from
/api/e2ee/recovery/wrapped-umkand decrypts it locally. - The client computes a proof of possession from the UMK and POSTs it, with the UMK wrapped for this device, to
/api/e2ee/recovery/activate. - From server 1.4, the server checks that proof against the account’s proof key where one is on file, and refuses a wrong one before it writes anything. Then it upgrades this device to
Activeand the client self-wraps the UMK for ongoing use.
The server never sees the recovery code or the unwrapped UMK.
The proof key
Section titled “The proof key”The proof key is derived from the UMK with its own label, so it reveals neither the UMK nor any other key. A desktop client uploads it once, right after setting up encryption, or later from any active device that holds the UMK. The server keeps it write-only: no response, log line or data export contains it, and the account’s E2EE status says only whether one is on file.
Once a proof key is on file:
- a recovery activation needs the right code — someone holding only the account’s access token can no longer activate a device this way;
- the recovery copy of the UMK is locked and cannot be replaced, so nobody can point the next recovery at a key of their choosing.
An account whose devices have not uploaded a proof key yet behaves as before: the activation is accepted without the check. Older desktop clients keep working either way, because they already send the proof in the format the server checks.
The code is not rotated
Section titled “The code is not rotated”The desktop client generates the code once, when encryption is first set up, and offers no way to generate a new one; RecoveryWrapVersion stays at 1. Once a proof key is on file the server also refuses to replace the recovery copy. If the code may have been seen by someone else, the only way to retire it is to reset the account’s synced data, which removes the encryption, the proof key and everything synced.
Storage advice
Section titled “Storage advice”Treat the recovery code like a paper master key:
- Print it and store the paper somewhere secure (a safe, a sealed envelope in a filing cabinet).
- Or save it in a password manager whose own master password isn’t stored on a Pia-synced device.
- Never email it to yourself or paste it into a chat — those services have copies.
What recovery does not restore
Section titled “What recovery does not restore”The recovery code restores access to the encrypted records the server holds for you. It does not restore:
- Local-only state on a wiped device (DPAPI-encrypted client cache).
- Plaintext data that was never synced.
- Account-level settings that are stored client-side.