1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! AES-128-CBC cookie decryption and PBKDF2 key derivation for Chromium browsers.
//!
//! # macOS Cookie Decryption
//!
//! Brave and Chrome encrypt cookies with AES-128-CBC:
//! - Key: PBKDF2-SHA1(`keychain_password`, salt=`"saltysalt"`, iterations=1003, 16 bytes)
//! - IV: 16 **space** bytes (`0x20 * 16`) — NOT zero bytes
//! - Ciphertext: `encrypted_value[3..]` (first 3 bytes are the `"v10"` prefix)
//! - Padding: PKCS7
//!
//! ## Schema v24+ domain-integrity prefix
//!
//! Starting with Chromium cookie DB schema version 24 (Chrome 130+, Brave 1.70+),
//! the first 32 bytes of every decrypted plaintext are `SHA-256(host_key)`.
//! These bytes must be stripped to recover the actual cookie value.
//! See: <https://issues.chromium.org/issues/40185252>
//!
//! # Security Notice — Post-Quantum Cryptography (PQC)
//!
//! **This entire module implements a read-only compatibility shim for Chromium's
//! on-disk cookie format. nab does not choose these algorithms — Chromium does.**
//!
//! The algorithms used here are NOT post-quantum safe:
//! - `PBKDF2-HMAC-SHA1` — classical KDF, no quantum resistance
//! - `AES-128-CBC` — 128-bit key provides only ~64 bits of security against
//! Grover's algorithm on a large-scale quantum computer
//! - Static IV (`0x20 * 16`) — hardcoded by Chromium; CBC with a fixed IV is
//! additionally vulnerable to chosen-plaintext attacks
//!
//! **These weaknesses cannot be fixed here.** The format is owned by the Chromium
//! project. Any PQC upgrade must originate in Chromium's `os_crypt` component.
//! Track upstream progress at: <https://issues.chromium.org/issues/40185252>
//!
//! nab-owned session persistence is handled separately in [`crate::session`] and
//! uses Argon2id-derived AES-256-GCM. This module remains strictly for Chromium
//! compatibility.
use ;
// ─── Constants ────────────────────────────────────────────────────────────────
// LEGACY: Chromium compatibility constants — these values are dictated by the Chromium
// on-disk cookie format and CANNOT be changed by nab.
// AES-128-CBC + PBKDF2-SHA1 are NOT post-quantum safe. See module-level doc for details.
/// PBKDF2 salt used by Chromium for cookie key derivation.
// LEGACY: Chromium compatibility — "saltysalt" is hard-coded in Chromium's os_crypt_mac.mm.
pub const CHROME_PBKDF2_SALT: & = b"saltysalt";
/// PBKDF2 iteration count (1003 for macOS Chromium builds).
// LEGACY: Chromium compatibility — 1003 iterations of PBKDF2-HMAC-SHA1 is NOT
// post-quantum safe and is well below NIST SP 800-132 recommendations (≥210,000 for SHA-256).
pub const CHROME_PBKDF2_ITERATIONS: u32 = 1003;
/// Derived key length in bytes (AES-128 = 16 bytes).
// LEGACY: Chromium compatibility — AES-128 provides only ~64 bits of post-quantum security
// (Grover's algorithm). AES-256 would be required for PQC readiness.
pub const CHROME_KEY_LEN: usize = 16;
/// Prefix on every v10 encrypted cookie value (ASCII "v10").
pub const V10_PREFIX: & = b"v10";
/// AES-CBC IV: 16 **space** bytes (0x20). Chromium hard-codes this — NOT zero bytes.
/// Reference: `chromium/components/os_crypt/os_crypt_mac.mm`, `OSCryptImpl::DecryptString`.
// LEGACY: Chromium compatibility — a static, non-random IV is a known weakness of CBC mode.
// This makes the scheme additionally vulnerable to chosen-plaintext attacks beyond the
// baseline PQC concerns. Fixing this requires a Chromium format change.
pub const AES_CBC_IV: = ;
/// Domain-integrity prefix length added in DB schema v24+.
/// First 32 bytes of every decrypted value are `SHA-256(host_key)`.
pub const DOMAIN_SHA256_LEN: usize = 32;
/// Minimum Chromium cookie DB schema version that prepends a SHA-256 domain tag.
pub const SCHEMA_VERSION_WITH_DOMAIN_TAG: u32 = 24;
// ─── Key derivation ───────────────────────────────────────────────────────────
/// Derive the 16-byte AES key from the raw Keychain password using PBKDF2-SHA1.
///
/// This is the exact derivation used by all Chromium-based browsers on macOS:
/// `PBKDF2(password, salt="saltysalt", iterations=1003, key_len=16, prf=HMAC-SHA1)`
///
/// # Security Notice — Post-Quantum Cryptography (PQC)
///
/// **LEGACY: Chromium compatibility — AES-128-CBC is NOT post-quantum safe.**
///
/// This function implements the key derivation step of Chromium's cookie encryption
/// scheme. The parameters — PBKDF2-HMAC-SHA1, 1003 iterations, 16-byte key — are
/// fixed by the Chromium on-disk format and cannot be changed here.
///
/// For PQC-safe key derivation in new nab-native code, use Argon2id with a 256-bit
/// output key, or PBKDF2-HMAC-SHA256 with ≥210,000 iterations (NIST SP 800-132).
// ─── Decryption ───────────────────────────────────────────────────────────────
/// Decrypt a single AES-128-CBC encrypted cookie blob.
///
/// # Format (macOS Chromium v10 cookies)
/// ```text
/// [ 'v' | '1' | '0' | ciphertext... ]
/// 3 bytes prefix N bytes (must be a nonzero multiple of 16)
/// ```
///
/// After PKCS7 unpadding the plaintext layout depends on the DB schema version:
/// - **Schema < 24**: `[actual_cookie_value]`
/// - **Schema ≥ 24**: `[SHA-256(host_key) 32 bytes][actual_cookie_value]`
///
/// Pass `has_domain_tag = true` for schema v24+ databases.
///
/// # Security Notice — Post-Quantum Cryptography (PQC)
///
/// **LEGACY: Chromium compatibility — AES-128-CBC is NOT post-quantum safe.**
///
/// This function decrypts cookies using Chromium's on-disk format. The algorithm
/// (AES-128-CBC, static IV, PKCS7 padding) is owned by the Chromium project.
/// nab cannot change these without breaking cookie extraction entirely.
///
/// Do NOT use this function or copy its algorithm for any nab-native data storage.
/// For nab-native encryption, use the AES-256-GCM session storage in
/// [`crate::session`] with a random 96-bit nonce.
///
/// # Errors
/// Returns an error if the blob is too short, the prefix is wrong, AES
/// decryption/unpadding fails, or the result is not valid UTF-8.