Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ package-lock.json
# Architecture department for architecture content
docs/architecture @bitwarden/dept-architecture

# Key management and Architecture for crypto concepts
docs/architecture/crypto @bitwarden/team-key-management-dev @bitwarden/dept-architecture

# Architecture and AppSec for security concepts
docs/architecture/security @bitwarden/team-appsec @bitwarden/dept-architecture

Expand Down
14 changes: 12 additions & 2 deletions custom-words.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Custom dictionary for spellchecking. Before adding a word here, consider whether you can put
# it in a single (`) or multiline (```) code snippet instead, as they are automatically ignored
# by the spellchecker. Please keep the list sorted alphabetically.

AndroidX
AOSP
Bitwarden
Expand All @@ -17,8 +16,8 @@ deinitializer
deinitializers
dockerized
dotfile
frontmatter
F-Droid
frontmatter
Gitter
HKDF
hotfix
Expand Down Expand Up @@ -97,3 +96,14 @@ YubiKeys
# Forbidden words
!auto-fill
!auto-filled
CBOR
ciphertext
Cose
CTXT
HMAC
kibibytes
namespacing
PKCS
plaintexts
unpadded
unsynchronized
106 changes: 106 additions & 0 deletions docs/architecture/cryptography/crypto-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: How to use Cryptography in Bitwarden
sidebar_label: Cryptography Guide
description: A
---

# How to use cryptography in Bitwarden

This guide is aimed at non-cryptography teams that want to consume cryptographic APIs in order to
build features that need end-to-end encryption.

## Rules

The primary rule here is: don't roll your own crypto. Where possible, high level safe, tested and
analyzed protocols and primitives need to be used. The higher level the primitive, the less likely
that security bugs get introduced, and the less complexity for you to maintain and keep track of.
Only where not otherwise possible low level primitives can be used, and this should be done with
extreme caution and external analysis.

Encryption in the typescript clients for new cases is deprecated. Any new cryptographic code must be
written in the SDK if possible. Existing use-cases can be continued in the typescript clients for
now, but eventually will have to be migrated too. There are several reasons behind this. On the one
hand the SDK has better memory safety guarantees and prevents key material from being left behind in
memory. On the other hand, newer, safer APIs are not exposed outside of the SDK.

## How do I use cryptography?

To use cryptographic primitives, you can decompose your feature into a chain of simpler use-cases.
Which cryptographic primitive you use depends on what you want to do. The following, is a list of
use-cases, and the corresponding construction that is currently supported for use. Most features can
be built out of a combination of the below constructs. If you believe your feature cannot be
constructed out of a combination of these, please reach out!

### I want to protect a document / struct

Use [DataEnvelope](https://github.com/bitwarden/sdk-internal/pull/336). This handles encryption and
versioning, and hides exact sizes of the encrypted contents. You can follow the existing
[example](https://github.com/bitwarden/sdk-internal/blob/cbc84a33f3cbb59806a472459226150b86cc06e7/crates/bitwarden-crypto/examples/seal_struct.rs).

#### Historical: EncStrings

Historically, EncStrings have been used for this process. These are no longer recommended for new
use-cases.

### I want to protect a file

Existing attachments are protected using an EncArrayBuffer. This is just an EncString, but encoded
slightly differently.

#### Future outlook: FileEnvelope

In the future, a higher-level abstraction will be provided that supports streaming / random access
decryption securely. This is yet to be designed / specified. If you need this, please reach out.

### I want to protect a key with another key

Currently, you have to use EncStrings for this. The SDK contains high-level functions for doing this
as shown in this
[example](https://github.com/bitwarden/sdk-internal/blob/03646591c366a5568b0f8062a0cb3b4745bcbd93/crates/bitwarden-crypto/src/store/context.rs#L154).

#### Future outlook: KeyEnvelope

In the future, a CoseEncrypt0 message with more context will be provided that supports advertising
the contained key id, so that the server can validate key relationships. Further, strong context
binding / namespacing will be provided.

### I want to protect a key with a password

Use
[PasswordProtectedKeyEnvelope](https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs)
as described in
[example](https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-crypto/examples/protect_key_with_password.rs).
This allows you to store a key with a low-entropy password or PIN. The envelope handles brute-force
protection.

#### Historical: MasterPasswordUnlockData

MasterPasswordUnlockData is a struct that encapsulates the data needed to unlock a vault using a
master password. It contains the protected symmetric key that is encrypted with the stretched master
key, along with the KDF settings and salt used. The cryptography used is the same as for using the
master key directly, but the abstraction is safer and prevents decryption issues resulting from
unsynchronized state.

#### Historical: MasterKey

Historically, the master-key was used to protect keys with passwords. The master key is derived from
the user's master password using PBKDF2 or Argon2id user's email address as salt and the
synchronized account KDF parameters, producing a 256-bit key. This master key is then expanded using
HKDF into a 512-bit stretched master key, 256-bit of which are used as an aes256-cbc key, and
256-bit of which are used as an HMAC key. The stretched master key is used to encrypt the user's
symmetric key.

New usage of MasterKey is not supported.

### I want to authenticate with a password

Use MasterPasswordAuthenticationData. It encapsulates the data needed to unlock a vault using a
master password. It contains the serverAuthorizationMasterKeyHash, the KDF settings and salt used.
The cryptography is the same as for MasterKey based authentication, but the abstraction prevents
authentication issues resulting from unsynchronized state.

#### Historical: MasterKey

The master-key used for unlock is also re-used for authentication. The
severAuthorizationMasterKeyHash is derived from the master-key using pbkdf2, with the password as a
salt and 1 iteration applied. This hash is then sent to the server for authentication.
16 changes: 16 additions & 0 deletions docs/architecture/cryptography/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
sidebar_position: 7
---

# Cryptography

This document in detail describes how cryptography in Bitwarden should be used, and serves as a
reference of how it is implemented.

Currently, there is a set of low-level APIs (EncString, UnsignedSharedKey, MasterKey) that have been
historically used to build most features, with each team owning the cryptographic constructions
created. Increasingly, high-level safe primitives are introduced that move the complexity out of
each teams ownership. These are not yet complete, and if your use-case is not covered by them,
please reach out! The goal of these is to have most teams never have to think about cryptography, or
having to do safety analysis. These abstract away all complex details and give teams a
low-complexity, easy to use and hard to mis-use interface to work with.
89 changes: 89 additions & 0 deletions docs/architecture/cryptography/specification/data-envelope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
sidebar_position: 3
---

# Data Envelope

Data envelope is a cryptographic format for encrypting structured data (documents). It addresses the
problem of: "I have a struct of related data that I want to protect from tampering and unauthorized
access.". It can be used for encrypting structured data such as vault items, reports, or user
settings, that are stored long-term. To solve existing usability goals, it includes versioning and
makes key-rotation and key-sharing simple by enforcing the use of per-document content-encryption
keys.

Data envelope is **not** designed for:

1. Encrypting cryptographic keys
2. Encrypting large binary blobs like such as file attachments

## Security

Data envelope fulfills three core security goals that formalize what end-to-end encryption means:

1. **SG1: Integrity (INT-CTXT security)** - The ciphertext must not be malleable. An attacker with
full control over the encrypted data cannot modify it in ways that result in different but valid
plaintexts.
2. **SG2: Confidentiality (IND-CCA security)** - The attacker cannot infer information about the
plaintext contents beyond approximate length. The format uses padding to minimize length leakage.
3. **SG3: Context binding** - Data can only be decrypted in the correct context. For example, an
encrypted vault item cannot be swapped into a user settings slot, preventing undefined behavior
and security bugs.

### Attacker model

The attacker has complete control over the server and all data in transit (fully compromised server
model per P01 - Servers are zero knowledge). The attacker can:

1. Read all encrypted data
2. Modify or replace encrypted data
3. Replay old versions of encrypted data

## Format specification

A data envelope is a COSE_Encrypt0 structure with the following components:

### Protected header

The protected header contains:

1. **Algorithm (alg)**: Set to XChaCha20-Poly1305 (`-70000`)
2. **Key ID (kid)**: Identifier of the content encryption key used
3. **Content type**: Set to `"application/x.bitwarden.cbor-padded"`
4. **Namespace**: Custom header field containing an integer identifying the document type

### Unprotected header

The unprotected header contains:

1. **Initialization vector (iv)**: The nonce used for XChaCha20-Poly1305 encryption

### Serialization format

1. **Document encoding**: The plaintext document is serialized using CBOR
2. **Padding**: PKCS#5-style padding to 64-byte blocks is applied to hide the exact size

### Namespaces

Each document type is assigned a unique integer namespace identifier. The namespace is stored in the
protected header and validated during decryption. Examples:

```
VaultItem = 1
UserSettings = 2
Report = 3
```

Namespaces prevent documents from being decrypted in the wrong context, even if an attacker attempts
to substitute one encrypted document for another.

### Versioning

Documents support internal versioning. The direct inner contents of the unpadded payload are
(represented as json, but in reality encoded as CBOR):

```
{
version: "1",
content: {...}
}
```
9 changes: 9 additions & 0 deletions docs/architecture/cryptography/specification/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
sidebar_position: 0
---

# Specification

Specification covers the design of the various cryptographic constructs used in Bitwarden, and
explains the rationale behind them. _This is section is not meant for consumers of the APIs, but for
developers working on the cryptography and for security researches verifying the designs._
Loading
Loading