bitwarden/server
Key management & rotation
Active contributors: key management team.
Purpose
The Key Management feature owns the user encryption key lifecycle: how it is derived, stored, wrapped, rotated, and recovered. The actual cryptography is split between client and (in newer code) the Bitwarden Rust SDK; the server's job is to enforce that key changes are atomic and that every dependent piece of data is re-wrapped at the same time.
Where the code lives
src/Core/KeyManagement/
├── Authorization/
├── Commands/
├── Constants.cs
├── Entities/
├── Enums/
├── Kdf/ # PBKDF2 / Argon2id parameters and migration helpers
├── KeyManagementServiceCollectionExtensions.cs
├── Models/
├── Queries/
├── Repositories/
├── Sends/ # Send-key migration helpers
├── UserKey/ # User-key rotation commands
└── Utilities/
src/Api/KeyManagement/
├── Validators/ # IRotationValidator<T> — one per dependent data type
└── Controllers/
util/RustSdk/ # The Rust SDK consumed by parts of the cipher domainKey abstractions
| Type | Path | Description |
|---|---|---|
User columns |
src/Core/Entities/User.cs |
Key (master-password-sealed user key), PublicKey, PrivateKey (user-key-wrapped), SignedPublicKey, Kdf, KdfIterations, KdfMemory, KdfParallelism. |
IUserKeyCommand family |
src/Core/KeyManagement/UserKey/Commands/ |
Atomic key rotation; wraps every dependent record together. |
IRotationValidator<TIn,TOut> |
src/Api/KeyManagement/Validators/ |
Each implementation validates that a particular set of records (ciphers, folders, sends, emergency access, organization-user resets, WebAuthn keys, device keys) has been re-wrapped under the new user key. The set is exhaustive: rotation cannot proceed unless every validator passes. |
IKdfMigrator |
src/Core/KeyManagement/Kdf/ |
Migrates a user from PBKDF2 to Argon2id (or up-iterates PBKDF2). |
IUserService.RotateUserKey |
src/Core/Services/Implementations/UserService.cs |
The orchestration point — loops over all rotation validators and persists. |
How it works
sequenceDiagram
participant Client
participant Api
participant Validators as IRotationValidator implementations
participant DB
Client->>Client: derive new master key, new user key
Client->>Client: re-wrap every cipher, folder, send, etc.
Client->>Api: POST /accounts/key (new payload)
Api->>Validators: for each (Ciphers, Folders, Sends, EmergencyAccess, OrgUsers, WebAuthn, Devices)
Validators->>DB: ensure exact 1-to-1 mapping<br/>between current rows and submitted re-wrapped versions
Api->>DB: persist wrapped Key, PrivateKey, etc. + each dependent row
Api-->>Client: 200 okThe strictness is intentional: if rotation persisted only the new user key but missed re-wrapping a single cipher, that cipher would become unreadable. IRotationValidator ensures every dependent row is accounted for before any write happens.
KDF migrations
The default for new users since 2023 has been Argon2id (3 iterations, 64 MB memory, 4 parallelism). PBKDF2 (600k iterations) remains supported for legacy users. Migrations happen at password-change time — the client computes the new master-password hash with the new KDF parameters and submits both the old and new wrapped user keys.
Master-password reset (Org-level)
If an organization enables the Account Recovery policy (PolicyType.ResetPassword), administrators can reset member passwords. Each member's OrganizationUser.ResetPasswordKey holds their user key wrapped under the org public key; admins decrypt with the org private key, derive a new wrapped user key, and update the user.
SDK port
util/RustSdk/ exists so that encryption and decryption logic can be shared between the Bitwarden client SDK (which talks to all Bitwarden front-ends) and the server. The cipher domain has been incrementally migrated to call SDK functions for the parts of cipher creation that benefit (PR #7457 "PM-19944 Remove feature flag pm-19941-migrate-cipher-domain-to-sdk", 2026-04-13). The plan is to extend SDK use into other domains over time.
Integration points
- Auth — master-password change and KDF migration are entry points to key rotation.
- Vault, Tools, AdminConsole, Auth — every dependent record lives here; rotation validators ensure they all migrate together.
- Emergency Access — the grantee's wrapped user key has to be updated whenever the grantor rotates.
- Devices — TDE devices hold device-specific wrapped user keys that must also be rotated.
Entry points for modification
- Add a new entity holding a wrapped key → write an
IRotationValidator<TIn,TOut>, register inservices.AddUserKeyCommands, ensure the rotation API accepts the new request shape. - Update default KDF parameters → edit
KdfMigratorOptions(src/Core/KeyManagement/Kdf/). - Add a new key-management endpoint →
src/Api/KeyManagement/Controllers/and a domain command insrc/Core/KeyManagement/Commands/.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.