<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parag Mali - tag: dpapi</title><description>Posts tagged dpapi.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:11 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/dpapi/rss.xml" rel="self" type="application/rss+xml"/><item><title>Beyond BitLocker: The Three File-Level Encryption Layers Microsoft Hides in Plain Sight</title><link>https://paragmali.com/blog/beyond-bitlocker-the-three-file-level-encryption-layers-micr/</link><guid isPermaLink="true">https://paragmali.com/blog/beyond-bitlocker-the-three-file-level-encryption-layers-micr/</guid><description>BitLocker is one layer of four. EFS, Personal Data Encryption, and Purview sensitivity labels close gaps BitLocker structurally cannot -- three roots, three threat models, by design.</description><pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate><content:encoded>
**&quot;BitLocker is on&quot; is a misleading shorthand.** BitLocker encrypts the volume, but the volume is decrypted to the running OS the moment the TPM unseals -- which happens before any human authenticates. Three above-BitLocker layers close different gaps: the Encrypting File System (legacy per-user per-file, sealed by classic DPAPI), Personal Data Encryption (Hello-bound per-file, released through DPAPI-NG), and Microsoft Purview sensitivity labels (envelope encryption via Azure Rights Management, travels with the file across tenants). Three layers, three protection-key roots, three threat models -- by design, not by accident.
&lt;h2&gt;1. &quot;BitLocker Is On&quot;&lt;/h2&gt;
&lt;p&gt;A Windows 11 laptop sits on a desk at the user&apos;s lock screen. TPM-only &lt;a href=&quot;https://paragmali.com/blog/bitlocker-on-windows-architecture-attacks-and-the-limits-of-/&quot; rel=&quot;noopener&quot;&gt;BitLocker&lt;/a&gt;, secure boot clean, automatic login disabled. The owner stepped away to take a call.&lt;/p&gt;
&lt;p&gt;An attacker with physical access boots it normally. The &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM&lt;/a&gt; unseals the volume master key against PCR[7] and PCR[11].Microsoft Learn states the Secure Boot anchor verbatim: &lt;em&gt;&quot;By default, BitLocker provides integrity protection for Secure Boot by utilizing the TPM PCR[7] measurement&quot;&lt;/em&gt; [@ms-bitlocker-countermeasures]. PCR[11] is widely documented in TCG-aware BitLocker references as the boot-manager / BitLocker access-control measurement; the cited Wikipedia BitLocker article confirms TPM-PCR sealing in general terms [@wikipedia-bitlocker]. The point that matters is that TPM-only BitLocker seals against a subset of platform-state PCRs, and the unseal happens automatically when the boot chain has not been tampered with. NTFS mounts. The login prompt appears. The attacker now stands in front of a fully decrypted volume without having authenticated as any user.&lt;/p&gt;
&lt;p&gt;What is, and what is not, still protected at this exact instant?&lt;/p&gt;
&lt;p&gt;The expected reaction is &lt;em&gt;&quot;the data on disk is plaintext to whoever can read the running kernel; isn&apos;t that the whole point of why people add a PIN to BitLocker?&quot;&lt;/em&gt; That reaction is half right. The volume is plaintext, yes. But not every file on it is readable.&lt;/p&gt;
&lt;p&gt;Files marked with the EFS attribute are still encrypted. Files inside a Personal Data Encryption (PDE) protected folder are still encrypted. A DOCX labelled &quot;Confidential - All Employees&quot; by a Purview sensitivity label is still encrypted. Three different cryptographic mechanisms, three different protection-key roots, three different reasons the attacker is staring at ciphertext while the volume is mounted.&lt;/p&gt;
&lt;p&gt;This is the gap the rest of the article walks. It is the gap most security architects know exists in the abstract -- &quot;BitLocker is on&quot; does not mean &quot;every file is locked&quot; -- and which most do not know is closed by three structurally distinct technologies that have been hiding in plain sight since 2000.&lt;/p&gt;

Adding a pre-boot PIN closes part of this gap by requiring user input before the TPM releases the volume master key. That is genuinely useful. But TPM+PIN does not give per-user isolation on a shared device -- everyone with the PIN sees everyone else&apos;s files. It does not travel with the file when that file is emailed, copied to OneDrive, or saved on a USB stick. And it does not bind the on-disk key to any particular human identity. Pre-boot authentication and above-volume encryption solve different problems. The three layers in this article sit *on top* of TPM+PIN BitLocker, not in place of it.
&lt;p&gt;Three layers, three reasons, three different roots, three different attack surfaces. That is the article.&lt;/p&gt;

sequenceDiagram
    participant Hardware as TPM and PCRs
    participant Boot as Boot Manager
    participant OS as Windows Kernel
    participant User as Human at Keyboard
    Hardware-&amp;gt;&amp;gt;Boot: PCR[7], PCR[11] match
    Boot-&amp;gt;&amp;gt;OS: VMK released, NTFS mounts
    OS-&amp;gt;&amp;gt;OS: Volume now plaintext to kernel
    OS-&amp;gt;&amp;gt;User: Lock screen presented
    Note over OS,User: Attacker stands here, with a plaintext volume and no authenticated user
    User--&amp;gt;&amp;gt;OS: Hello PIN or biometric (eventually)
    OS-&amp;gt;&amp;gt;OS: Per-user secrets unseal
&lt;h2&gt;2. Historical Origins: Windows 2000 and the Birth of EFS&lt;/h2&gt;
&lt;p&gt;It is 1999. Laptops are appearing on every executive&apos;s desk. Theft is rising. The only protection NTFS offers against an attacker who walks off with a machine is the access control list, and the ACL is checked by the kernel of the operating system that mounted the disk. Boot a different operating system off floppy or CD, mount the NTFS volume as a foreign filesystem, and the ACL is just metadata to be ignored. The cryptographic protection of the data is exactly nothing.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s NTFS team responded by adding the first cryptographic primitive to the filesystem itself. Windows 2000 reached general availability on February 17, 2000 (after a December 15, 1999 release-to-manufacturing milestone) and shipped the Encrypting File System -- EFS [@wikipedia-windows2000]. The mechanism is documented in the 1999 Microsoft technical paper &lt;em&gt;Encrypting File System for Windows 2000&lt;/em&gt; [@efs-1999-paper].The original Microsoft Research URL for this paper now returns HTTP 404. A binary PDF mirror is preserved at cypherspace.org, but the PDF is image-streamed and the body text is not retrievable for direct quotation. The Microsoft author list could not be verified against the primary text, so this article cites the paper anonymously. The Microsoft Learn EFS Win32 reference, still on the docs site today, states the design plainly: &lt;em&gt;&quot;The Encrypted File System (EFS) provides an additional level of security for files and directories. It provides cryptographic protection of individual files on NTFS file system volumes using a public-key system&quot;&lt;/em&gt; [@ms-efs-win32].&lt;/p&gt;
&lt;p&gt;That sentence carries three design choices the rest of EFS hangs from. &lt;em&gt;File-level&lt;/em&gt;, not volume-level. &lt;em&gt;NTFS attribute&lt;/em&gt;, not separate database. &lt;em&gt;Public-key system&lt;/em&gt;, not symmetric password. Each of those choices was deliberate. Each fixes a problem the architects of NTFS in 1999 actively worried about.&lt;/p&gt;
&lt;p&gt;The file-level choice answered the &quot;what if BitLocker is on&quot; question seventeen years before BitLocker existed. NTFS already protected files at the access-control layer; what the team wanted was a way to make a particular file unreadable to a different user account on the same machine, not just to a foreign operating system. Volume encryption could not do that. The volume is one thing; users are many. So encryption belonged on the file.&lt;/p&gt;
&lt;p&gt;The NTFS-attribute choice answered the integration question. EFS encryption lives in a named stream attached to the file, &lt;code&gt;$EFS&lt;/code&gt;. The Windows API surface stays the same: &lt;code&gt;CreateFile&lt;/code&gt;, &lt;code&gt;ReadFile&lt;/code&gt;, &lt;code&gt;WriteFile&lt;/code&gt;, &lt;code&gt;CopyFile&lt;/code&gt; all work transparently against an encrypted file when called by an authorised user. Microsoft Learn is explicit about how the integration works: &lt;em&gt;&quot;When the source file is encrypted, CopyFile and CopyFileEx rely on the EFS service (hosted in lsass.exe) to create the target file and apply keys used in encryption of the source file&quot;&lt;/em&gt; [@ms-efs-win32]. Encryption was made invisible to existing applications. That was the only way a 1999 enterprise was going to deploy it.&lt;/p&gt;
&lt;p&gt;The public-key choice answered the recovery question. Public-key crypto lets the file have multiple wrappers around the same symmetric content key -- one for the user, one or more for designated recovery agents. An organisation that lost the user&apos;s private key (employee leaves, password forgotten, hard drive moved to a different machine) could still recover the file using a recovery agent the IT team controlled. The first Microsoft response to &lt;em&gt;&quot;what happens when a user forgets their password?&quot;&lt;/em&gt; was Group-Policy-enforced Data Recovery Agents (DRAs) [@wikipedia-efs]. In Windows 2000, the default DRA was the local Administrator account. From day one, EFS encryption was meant to be reversible by &lt;em&gt;someone&lt;/em&gt; other than the file owner.&lt;/p&gt;
&lt;p&gt;EFS is on the disk now. So what does the encrypted file actually look like? What does NTFS store, and where does the key live?&lt;/p&gt;
&lt;h2&gt;3. How EFS Works -- And Why It Was Always Per-User&lt;/h2&gt;
&lt;p&gt;The EFS key chain is the most important diagram in this article. Read it once carefully; every limitation of EFS that practitioners hit in production drops mechanically out of these arrows.&lt;/p&gt;

flowchart TD
    Plain[Plaintext file] --&amp;gt;|AES with FEK| Cipher[Ciphertext on NTFS]
    FEK[Per-file FEK, symmetric] --&amp;gt;|RSA-wrap| W1[Wrapper for user public key]
    FEK --&amp;gt;|RSA-wrap| W2[Wrapper for DRA public key]
    W1 --&amp;gt; EFSAttr[EFS named stream on the file]
    W2 --&amp;gt; EFSAttr
    UserPriv[User EFS RSA private key] --&amp;gt;|stored in| Profile[APPDATA Microsoft Crypto RSA SID directory]
    Profile --&amp;gt;|sealed by| ClassicDPAPI[classic DPAPI master key]
    ClassicDPAPI --&amp;gt;|derived from| Logon[User logon secret, NTLM hash plus salt]
&lt;p&gt;The chain has four layers. The bottom layer is the file contents themselves, encrypted with a freshly generated symmetric key called the File Encryption Key.&lt;/p&gt;

A per-file symmetric key, generated at the moment a file is first encrypted, used to encrypt the file body. Wikipedia summarises the design: *&quot;EFS works by encrypting a file with a bulk symmetric key, also known as the File Encryption Key, or FEK&quot;* [@wikipedia-efs]. The FEK never leaves the file system in plaintext; it is RSA-wrapped to every authorised principal before being stored in the file&apos;s `$EFS` attribute.
&lt;p&gt;The FEK is symmetric for performance: AES on the file body, not RSA. The Wikipedia EFS article notes that &lt;em&gt;&quot;the FEK (the symmetric key that is used to encrypt the file) is then encrypted with a public key that is associated with the user who encrypted the file, and this encrypted FEK is stored in the &lt;code&gt;$EFS&lt;/code&gt; alternative data stream of the encrypted file&quot;&lt;/em&gt; [@wikipedia-efs]. The same paragraph adds the second wrapper, the one without which enterprise EFS deployments would not work.&lt;/p&gt;

A second principal whose public key is RSA-wrapped around the FEK at encryption time, so that the recovery agent can decrypt the file even if the owning user is unavailable. Wikipedia notes that *&quot;In Windows 2000, the local administrator is the default Data Recovery Agent, capable of decrypting all files encrypted with EFS by any local user&quot;* [@wikipedia-efs]. Group Policy still ships DRA configuration in modern Windows.
&lt;p&gt;The cipher inside the FEK has not been static. EFS shipped with one default cipher in Windows 2000 and has moved several times since; the precise Windows 2000 default is disputed across secondary sources. Rather than commit to a version we cannot verify, this article notes that the FEK cipher has changed across releases. AES has been the default since Windows XP SP1 [@wikipedia-efs]; a later Windows 10 release moved the default key size from AES-128 to AES-256.Microsoft Group Policy / FIPS-compliance guidance documents the AES-128 to AES-256 default-key-size change at Windows 10 1709, but the cited Wikipedia EFS article&apos;s algorithm table lists only &quot;AES&quot; without a specific key size, so this article hedges on the exact version while keeping the AES-since-XP-SP1 anchor verbatim from Wikipedia.&lt;/p&gt;
&lt;p&gt;Now look at the top of the chain. The user&apos;s EFS RSA &lt;em&gt;private&lt;/em&gt; key sits in the user&apos;s roaming profile, in the path &lt;code&gt;%APPDATA%\Microsoft\Crypto\RSA\&amp;lt;SID&amp;gt;\&lt;/code&gt;.This same directory is where &lt;code&gt;cipher.exe /R&lt;/code&gt; writes self-signed DRA certificates and where &lt;code&gt;cipher.exe /K&lt;/code&gt; writes the user&apos;s own EFS keypair if one does not yet exist. Operational confusion lives here, because the same directory holds both per-user EFS keypairs and any recovery-agent certificates the user has imported. The private key is not stored in the clear. It is sealed by &lt;a href=&quot;https://paragmali.com/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/&quot; rel=&quot;noopener&quot;&gt;classic Data Protection API (DPAPI)&lt;/a&gt;, Microsoft&apos;s per-user key-derivation system that wraps user-scoped secrets with a master key derived from the user&apos;s logon credential.&lt;/p&gt;

*Classic DPAPI* is the original Windows Data Protection API. Microsoft Learn describes the original pair: *&quot;Microsoft introduced the data protection application programming interface (DPAPI) in Windows. The API consists of two functions, CryptProtectData and CryptUnprotectData.&quot;* [@ms-dpapi-ng] It is per-user and per-machine: the master key is derived from the user&apos;s logon secret, so decrypting works only when the user is logged on locally. *DPAPI-NG* (Data Protection API &quot;Next Generation&quot;) was added in Windows 8 to extend the same idea to cloud scenarios where content encrypted on one machine must be decrypted on another, or where the unwrap should require a specific authentication factor. Microsoft Learn states the motivation: *&quot;Cloud computing, however, often requires that content encrypted on one computer be decrypted on another. Therefore, beginning with Windows 8, Microsoft extended the idea of using a relatively ... API to encompass cloud scenarios.&quot;* [@ms-dpapi-ng] EFS uses classic DPAPI. PDE, as we will see, uses DPAPI-NG.
&lt;p&gt;Wikipedia&apos;s EFS article states the consequence in one terse sentence: &lt;em&gt;&quot;In Windows 2000, XP or later, the user&apos;s RSA private key is encrypted using a hash of the user&apos;s NTLM password hash plus the user name ... any compromise of the user&apos;s password automatically leads to access to that data&quot;&lt;/em&gt; [@wikipedia-efs]. The cryptographic identity of the file&apos;s owner &lt;em&gt;is&lt;/em&gt; the user&apos;s logon credential, by construction.&lt;/p&gt;
&lt;p&gt;That is the design. Now mechanically derive the consequences.&lt;/p&gt;
&lt;h3&gt;Per-user, not per-process&lt;/h3&gt;
&lt;p&gt;The unwrapping principal of the EFS chain is the user SID. There is no place in the chain where an application identity could insert itself as a separate consumer. If you log on as Alice, every process running as Alice can ask the EFS service in &lt;code&gt;lsass.exe&lt;/code&gt; to unwrap any file Alice owns. The EFS service is a single user-mode endpoint; it does not gate on the calling process.&lt;/p&gt;
&lt;p&gt;Contrast this with &lt;a href=&quot;https://paragmali.com/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/&quot; rel=&quot;noopener&quot;&gt;Credential Guard&lt;/a&gt; and the LSAIso enclave, which deliberately move secret material into a Virtualization-Based Security enclave that even a kernel-mode caller in the host VTL cannot read. EFS is per-user; LSAIso is per-process-with-attestation. Different threat models, different mechanics.Credential Guard&apos;s LSAIso isolation is the kernel-mode equivalent of &quot;the application sees plaintext only if the application is the right application.&quot; EFS predates this design vocabulary by a decade and a half; its arrows simply do not include an application-identity step.&lt;/p&gt;
&lt;h3&gt;Password reset destroys access&lt;/h3&gt;
&lt;p&gt;If the only thing protecting the user&apos;s EFS RSA private key is classic DPAPI keyed off the user&apos;s password, then anything that breaks the user-password-to-master-key derivation also breaks the user&apos;s access to every EFS-encrypted file they own. Resetting a user&apos;s password from a domain administrator account does exactly this. Wikipedia warns in plain terms: &lt;em&gt;&quot;any compromise of the user&apos;s password automatically leads to access to that data&quot;&lt;/em&gt; [@wikipedia-efs] -- which is the same statement read the other way. Lose the password, lose the data. The DRA exists precisely so that the &lt;em&gt;organisation&lt;/em&gt; still has access; the user, however, is locked out.&lt;/p&gt;
&lt;h3&gt;Decryption on cross-volume or cross-protocol copy&lt;/h3&gt;
&lt;p&gt;EFS is bound to NTFS. When a file is copied to a different filesystem -- FAT32, exFAT, or pre-24H2 ReFS -- the destination cannot store the &lt;code&gt;$EFS&lt;/code&gt; stream, and the file is decrypted in transit. Wikipedia again: &lt;em&gt;&quot;Files and folders are decrypted before being copied to a volume formatted with another file system, like FAT32. Finally, when encrypted files are copied over the network using the SMB/CIFS protocol, the files are decrypted before they are sent over the network&quot;&lt;/em&gt; [@wikipedia-efs].&lt;/p&gt;
&lt;p&gt;This is not an EFS bug; it is what falls out when the encryption is implemented as a filesystem attribute and the destination filesystem has no equivalent. The cryptography ends where the attribute ends.&lt;/p&gt;
&lt;h3&gt;Opt-in, per file&lt;/h3&gt;
&lt;p&gt;EFS is enabled by setting the encrypt-attribute on a file or folder via right-click &lt;code&gt;Properties &amp;gt; Advanced &amp;gt; Encrypt contents to secure data&lt;/code&gt;, or via &lt;code&gt;cipher.exe /e&lt;/code&gt;. The user has to remember to do it. The volume default is unprotected. That is the entire mechanism: there is no &quot;encrypt every file Alice creates in her profile&quot; policy in classic EFS. PDE, twenty-two years later, finally addresses this.&lt;/p&gt;
&lt;h3&gt;Mutually exclusive with PDE&lt;/h3&gt;
&lt;p&gt;Microsoft Learn states the mutual exclusion plainly: &lt;em&gt;&quot;No, Personal Data Encryption and EFS are mutually exclusive&quot;&lt;/em&gt; [@ms-pde-faq]. A file cannot have both an EFS wrapper and a PDE wrapper at the same time. We will see why in §5; for now, register that the two layers compete at this layer of the stack, not compose.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every limitation of EFS drops mechanically out of one design decision: the protection root is the user&apos;s logon secret. EFS is per-user because the cryptographic identity is the user. To close the gaps EFS leaves, you cannot keep using the user&apos;s logon secret as the root. You need a different root.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{`
// Illustrative only. Real EFS uses CNG primitives inside the EFS service in lsass.exe.
// Do not run this against real keys or files.&lt;/p&gt;
&lt;p&gt;function encryptFileWithEFS(plaintext, userPublicKey, draPublicKeys) {
  // 1. Generate a per-file symmetric File Encryption Key (FEK).
  const fek = randomBytes(32); // AES-256 since Windows 10 1709&lt;/p&gt;
&lt;p&gt;  // 2. Encrypt the file body with the FEK.
  const ciphertext = aesEncrypt(plaintext, fek);&lt;/p&gt;
&lt;p&gt;  // 3. RSA-wrap the FEK to every authorised principal.
  const wrappers = [];
  wrappers.push({ sid: &apos;user-sid&apos;, wrappedFek: rsaWrap(fek, userPublicKey) });
  for (const dra of draPublicKeys) {
    wrappers.push({ sid: dra.sid, wrappedFek: rsaWrap(fek, dra.publicKey) });
  }&lt;/p&gt;
&lt;p&gt;  // 4. Store wrappers in the file&apos;s $EFS attribute. Body is on disk.
  return { body: ciphertext, efsAttribute: wrappers };
}&lt;/p&gt;
&lt;p&gt;// Decryption is the reverse: locate the wrapper for the calling user&apos;s SID,
// unwrap the FEK with the user&apos;s EFS private key (loaded from
// %APPDATA%\Microsoft\Crypto\RSA\\ and unsealed by classic DPAPI from
// the user&apos;s logon secret), then AES-decrypt the body.
console.log(&apos;EFS encryption shape: one FEK, multiple RSA wrappers&apos;);
`}&lt;/p&gt;
&lt;p&gt;EFS is per-user because the cryptographic identity is the user. To close the gaps EFS leaves, you have to change the root. That is what the next twenty-six years of Windows file-data protection do, one root at a time.&lt;/p&gt;
&lt;h2&gt;4. Six Generations of Closing Each Other&apos;s Gaps&lt;/h2&gt;
&lt;p&gt;Each generation of Windows file-data protection is engineered to close a gap left by the previous one, and each new layer introduces a different protection-key root because each gap has a different threat model. Here is the twenty-six-year sequence.&lt;/p&gt;

timeline
    title Windows file-data protection generations
    2000 : EFS ships with Windows 2000
         : Per-user per-file, RSA wrap, classic DPAPI root
    2003 : RMS ships with Windows Server 2003
         : Per-content envelope, identity service authorization
    2006 : BitLocker ships with Windows Vista
         : Volume-level, TPM-sealed VMK
    2013-2014 : Azure RMS reaches general availability
         : Tenant key in Azure, cross-organisation default
    2018-2019 : Microsoft Information Protection unifies labels
         : Same RMS engine, single labelling plane
    2022 : Microsoft Purview brand consolidation
         : MIP becomes Microsoft Purview Information Protection
    2022 : Personal Data Encryption ships in 22H2
         : Hello-bound DEK via DPAPI-NG
    2022 : Windows Information Protection sunsets
         : &quot;Honest employees&quot; tool retired
    2024 : PDE for known folders ships in 24H2
         : Desktop, Documents, Pictures auto-encrypted
&lt;p&gt;Each year row in this diagram is anchored to a primary source cited inline in the corresponding generation section below: the Windows 2000 EFS milestone [@wikipedia-windows2000], the Windows Server 2003 RMS debut and lineage [@wikipedia-adrms], the November 30, 2006 BitLocker release [@wikipedia-bitlocker], the Azure Rights Management general-availability lineage [@ms-azure-rms], the Microsoft Information Protection brand and its April 2022 consolidation into Microsoft Purview [@ms-purview-launch], the Windows 11 22H2 / 24H2 Personal Data Encryption rollout [@ms-pde-overview], and the Windows Information Protection sunset [@ms-wip-deprecation]. Mermaid syntax does not accept pandoc inline citations inside the diagram body, so the citations live in the prose immediately after.&lt;/p&gt;
&lt;h3&gt;Generation 1 -- EFS (2000)&lt;/h3&gt;
&lt;p&gt;Covered in §2 and §3. One paragraph recap: per-user, per-file, opt-in, RSA-wrapped FEK, user EFS RSA private key sealed by classic DPAPI from the user&apos;s logon secret. Root: the user&apos;s password. Threat model: a different user on the same machine, or a foreign operating system that mounts NTFS without honouring ACLs.&lt;/p&gt;
&lt;h3&gt;Generation 2 -- BitLocker (2006)&lt;/h3&gt;
&lt;p&gt;Six years after EFS, Microsoft moved encryption &lt;em&gt;off&lt;/em&gt; the file and &lt;em&gt;down&lt;/em&gt; to the volume. BitLocker shipped with Windows Vista on November 30, 2006 [@wikipedia-bitlocker]; the consumer launch of Vista that included it followed on January 30, 2007 [@wikipedia-bitlocker]. The cipher in the first BitLocker release was AES-CBC with Niels Ferguson&apos;s Elephant Diffuser, a manipulation-resistance construction documented in the 2006 Microsoft technical paper &lt;em&gt;AES-CBC + Elephant Diffuser: A Disk Encryption Algorithm for Windows Vista&lt;/em&gt; [@ferguson-2006].Niels Ferguson is the named cryptographer behind BitLocker&apos;s original cipher mode. He is the only individual this article names with primary-source confidence. Most other work in this space ships team-attributed.&lt;/p&gt;
&lt;p&gt;Later releases moved to XTS-AES with 128-bit or 256-bit keys; XTS-AES has been the default since a Windows 10 release in the mid-2010s [@wikipedia-bitlocker].&lt;/p&gt;
&lt;p&gt;The cipher mode is not the point. The point is what changed in the &lt;em&gt;root&lt;/em&gt;. BitLocker&apos;s Volume Master Key (VMK) is sealed in the TPM against a set of Platform Configuration Registers, and released automatically when the registers match the expected boot state.&lt;/p&gt;

A key-encrypting key that wraps the Full Volume Encryption Key. If a user changes their password or a new recovery key is escrowed, only the VMK wrappings change -- the entire volume does not need re-encryption. The VMK itself is sealed in the TPM against the platform&apos;s boot-state PCRs and released at boot when the PCRs match [@wikipedia-bitlocker].
&lt;p&gt;The human is removed from the encrypt-this-file decision. There is no per-file opt-in; the volume protects everything, including system files, swap, and hibernation. There is no per-user wrapping; the VMK is one thing, the volume is one thing.&lt;/p&gt;
&lt;p&gt;This is why BitLocker does not subsume EFS. The two layers protect different things. BitLocker protects the volume at rest, before the OS boots; EFS protects per-file per-user &lt;em&gt;after&lt;/em&gt; the OS has mounted the volume and a particular user has logged on. The &quot;BitLocker is on&quot; vignette in §1 is exactly the gap BitLocker structurally cannot close: BitLocker is unlocked the moment the TPM unseals, and the unseal happens before any human authenticates.&lt;/p&gt;

A dedicated BitLocker article on this site covers volume-internal mechanics in depth -- VMK, FVEK, recovery key escrow, TPM+PIN configuration, cipher migration. This article assumes that BitLocker knowledge and concentrates on the *above-volume* layers. The reader who wants the volume internals should read that article alongside this one.
&lt;h3&gt;Generation 3 -- RMS and Azure RMS (2003, 2013-2014)&lt;/h3&gt;
&lt;p&gt;Three years after EFS, Microsoft shipped a completely different shape of file encryption with Windows Server 2003: Rights Management Services. Wikipedia traces the lineage: &lt;em&gt;&quot;Active Directory Rights Management Services (AD RMS, known as Rights Management Services or RMS before Windows Server 2008) is a server software for information rights management shipped with Windows Server&quot;&lt;/em&gt; and &lt;em&gt;&quot;RMS debuted in Windows Server 2003, with client API libraries made available for Windows 2000 and later&quot;&lt;/em&gt; [@wikipedia-adrms].&lt;/p&gt;
&lt;p&gt;RMS solved a different problem from EFS or BitLocker. The question was: &lt;em&gt;can a document remain encrypted when emailed outside the organisation, or copied to a USB stick, or stored in a shared folder a different user has read access to?&lt;/em&gt; EFS could not -- decrypted on cross-protocol copy. BitLocker could not -- the volume is unlocked. RMS introduced a different shape: each protected document carries an envelope that includes a wrapped Content Encryption Key and a policy reference, and decryption requires the consumer to obtain a use license from the RMS service against an authenticated identity.&lt;/p&gt;

A per-content symmetric key generated when a document is protected with a Purview sensitivity label that applies encryption. The CEK is wrapped by the tenant root key (or by the customer-held DKE key, where Double Key Encryption is configured) and travels embedded in the document file alongside policy metadata. Microsoft Learn describes the topology: *&quot;The Azure Rights Management tenant key is your organization&apos;s root key for the main encryption service for Microsoft Purview Information Protection. Other keys can be derived from this root key, including user keys, computer keys, or document encryption keys&quot;* [@ms-byok].

A short-lived authorization artifact issued by the Azure Rights Management service to a specific authenticated user, granting them the rights expressed by the document&apos;s policy (view, edit, print, copy, forward). Microsoft Learn states the cross-organisation default: *&quot;By default, collaboration with other organizations that already have a Microsoft 365 or a Microsoft Entra directory is automatically supported&quot;* [@ms-azure-rms]. A user without a valid use license cannot decrypt the CEK, even if they possess the file.
&lt;p&gt;A few years after AD RMS shipped, Microsoft moved the RMS engine to the cloud as Azure RMS. The protection topology stayed the same: per-content CEK, tenant root key, use-license issuance against an identity service. What changed is that the identity service is now Microsoft Entra ID and the root key sits in Azure (or, with Bring Your Own Key, in an Azure Key Vault customer hold) instead of on a Windows Server. Microsoft Learn defines Azure RMS as &lt;em&gt;&quot;the main cloud-based encryption service from Microsoft Purview Information Protection&quot;&lt;/em&gt; and notes that &lt;em&gt;&quot;Encryption settings remain with your data, even when it leaves your organization&apos;s boundaries&quot;&lt;/em&gt; [@ms-azure-rms].&lt;/p&gt;
&lt;p&gt;This is the &quot;travels with the file&quot; generation. Email a CEK-wrapped DOCX to an external recipient; the recipient still needs a use license from Azure RMS; the document does not become plaintext just because it changed hands.&lt;/p&gt;
&lt;h3&gt;Generation 4 -- MIP, then Microsoft Purview Information Protection (late 2010s, 2022)&lt;/h3&gt;
&lt;p&gt;The late-2010s reorganisation is fundamentally a &lt;em&gt;policy-plane&lt;/em&gt; unification, not a new engine. Azure Information Protection&apos;s classification and labelling, the Office unified labelling client, and a growing set of policy controls were brought together under the Microsoft Information Protection (MIP) name in the late 2010s. The encryption engine underneath stayed Azure RMS.&lt;/p&gt;
&lt;p&gt;In April 2022, the entire compliance, classification, and information-protection portfolio got a single brand: Microsoft Purview. The April 19, 2022 launch blog post explained the consolidation: &lt;em&gt;&quot;To meet the challenges of today&apos;s decentralized, data-rich workplace, we&apos;re introducing Microsoft Purview ... that help you govern, protect, and manage your entire data estate&quot;&lt;/em&gt; [@ms-purview-launch]. The same post&apos;s product-naming table mapped &lt;em&gt;&quot;Microsoft Information Protection&quot;&lt;/em&gt; to &lt;em&gt;&quot;Microsoft Purview Information Protection&quot;&lt;/em&gt; directly. Same engine. Same envelope shape. New name.&lt;/p&gt;
&lt;p&gt;For the practitioner, this matters less than it looks. The on-disk artifact of a Purview-labelled document is the same CEK-wrapped envelope it was under MIP, AIP, and AD RMS. The label is metadata; whether the label &lt;em&gt;applies&lt;/em&gt; encryption depends on the label&apos;s settings. Microsoft Learn states the engine plainly: &lt;em&gt;&quot;Unless you&apos;re using S/MIME for Outlook, encryption that&apos;s applied by sensitivity labels to documents, emails, and meeting invites all use the Azure Rights Management service from Microsoft Purview Information Protection&quot;&lt;/em&gt; [@ms-purview-labels].&lt;/p&gt;
&lt;h3&gt;Generation 5 -- PDE (December 2022)&lt;/h3&gt;
&lt;p&gt;December 8, 2022. Microsoft announced Personal Data Encryption in a Tech Community post with a title that telegraphs the threat model: &lt;em&gt;Introducing Personal Data Encryption, securing user data before login and under lock&lt;/em&gt; [@ms-pde-announcement]. The verbatim contrast with BitLocker, from the same post, is the cleanest statement of the gap PDE closes:&lt;/p&gt;

Bitlocker provides full volume encryption and Bitlocker protected data is available when the device boots up, whereas PDE protected data is available only after the user authenticates to Windows Hello for Business at login or to unlock the screen.
&lt;p&gt;That sentence carries the entire design. BitLocker unlocks at boot. PDE unlocks at Hello sign-in. The post-boot pre-logon window the §1 vignette dwelled in is exactly the window PDE was built to close. PDE shipped with Windows 11 22H2 [@ms-pde-overview]. The cipher is AES-CBC with a 256-bit key [@ms-pde-overview]. The protector binds to a &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;Windows Hello for Business&lt;/a&gt; credential, not to a password.&lt;/p&gt;
&lt;p&gt;The PDE FAQ adds the second key constraint: &lt;em&gt;&quot;the keys used by Personal Data Encryption to encrypt content are protected by Windows Hello credentials and can only be unlocked when signing on with Windows Hello (PIN or biometrics)&quot;&lt;/em&gt; [@ms-pde-faq]. Password sign-in does not unlock PDE content. RDP does not unlock it. Other users on the same machine do not unlock it. We will walk the full mechanism in §5 and §6; for now, register that the root is Windows Hello for Business, not the user&apos;s password.&lt;/p&gt;
&lt;h3&gt;Generation 6 -- PDE for Known Folders (Windows 11 24H2)&lt;/h3&gt;
&lt;p&gt;The 22H2 release of PDE was API-only [@ms-pde-announcement]. Applications could call &lt;code&gt;Windows.Security.DataProtection.UserDataProtectionManager.ProtectStorageItemAsync&lt;/code&gt; to wrap an individual file, but Windows itself did not encrypt anything by default. That changed with Windows 11 24H2.&lt;/p&gt;
&lt;p&gt;Microsoft Learn describes the 24H2 addition: &lt;em&gt;&quot;Starting in Windows 11, version 24H2, Personal Data Encryption is further enhanced with Personal Data Encryption for known folders. Once enabled, the Windows folders Desktop, Documents, and Pictures, along with their contents, are automatically encrypted&quot;&lt;/em&gt; [@ms-pde-overview]. The CSP node tree (configured via Intune or any MDM that speaks &lt;code&gt;./User/Vendor/MSFT/PDE&lt;/code&gt;) gained &lt;code&gt;ProtectFolders/ProtectDesktop&lt;/code&gt;, &lt;code&gt;ProtectFolders/ProtectDocuments&lt;/code&gt;, and &lt;code&gt;ProtectFolders/ProtectPictures&lt;/code&gt; for this purpose [@ms-pde-csp]. The PDE CSP itself was added in 22H2 (build 10.0.22621), while the known-folder nodes are gated to 24H2 (build 10.0.26100) and later [@ms-pde-csp].&lt;/p&gt;
&lt;p&gt;For the first time since EFS, Windows shipped a per-user file-encryption mechanism that did not require the user to opt every individual file in. The default for the three best-known per-user folders -- if the administrator enables it -- is encrypted.&lt;/p&gt;
&lt;h3&gt;The dead-end branch -- Windows Information Protection (2016 to mid-2022)&lt;/h3&gt;
&lt;p&gt;One more entry belongs on the timeline. Windows Information Protection, originally Enterprise Data Protection, was Microsoft&apos;s mid-2010s attempt at &quot;container-style&quot; data separation: corporate files in a container, personal files outside the container, copy-paste between them gated by policy. Microsoft Learn&apos;s &lt;code&gt;/previous-versions/&lt;/code&gt; landing page for WIP states the design intent: &lt;em&gt;&quot;Windows Information Protection (WIP), previously known as enterprise data protection (EDP), helps to protect against this potential data leakage without otherwise interfering with the employee experience&quot;&lt;/em&gt; [@ms-wip-deprecation].&lt;/p&gt;
&lt;p&gt;The same page is candid about the limit: &lt;em&gt;&quot;While Windows Information Protection can stop accidental data leaks from honest employees, it is not intended to stop malicious insiders from removing enterprise data&quot;&lt;/em&gt; [@ms-wip-deprecation]. WIP was sunset in mid-2022 and the recommended replacement was the Microsoft Purview Information Protection plus Microsoft Purview Data Loss Prevention combination [@ms-wip-deprecation].&lt;/p&gt;
&lt;p&gt;Each generation chose a different protection-key root. That is the most important observation in the article -- and it has been hiding in plain sight since 2003.&lt;/p&gt;
&lt;h2&gt;5. Three Layers, Three Roots, Three Threat Models&lt;/h2&gt;
&lt;p&gt;BitLocker, EFS, PDE, and Purview sensitivity labels use four different protection-key roots because each one closes a different gap, and each gap has a different threat model. That is by design.&lt;/p&gt;
&lt;p&gt;The four roots:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Protection-key root&lt;/th&gt;
&lt;th&gt;Sealed by&lt;/th&gt;
&lt;th&gt;Unlocked at&lt;/th&gt;
&lt;th&gt;Granularity&lt;/th&gt;
&lt;th&gt;Travels with file&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;BitLocker&lt;/td&gt;
&lt;td&gt;TPM-sealed VMK&lt;/td&gt;
&lt;td&gt;TPM, against PCRs&lt;/td&gt;
&lt;td&gt;Boot, when PCRs match&lt;/td&gt;
&lt;td&gt;Volume&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EFS&lt;/td&gt;
&lt;td&gt;User EFS RSA private key&lt;/td&gt;
&lt;td&gt;classic DPAPI from logon secret&lt;/td&gt;
&lt;td&gt;First file access in logon session&lt;/td&gt;
&lt;td&gt;File, per-user&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDE&lt;/td&gt;
&lt;td&gt;DEK bound to Hello credential&lt;/td&gt;
&lt;td&gt;DPAPI-NG protection descriptor&lt;/td&gt;
&lt;td&gt;Hello sign-in (PIN or biometric)&lt;/td&gt;
&lt;td&gt;File, per-Hello-user&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Purview labels&lt;/td&gt;
&lt;td&gt;Per-content CEK wrapped by tenant key&lt;/td&gt;
&lt;td&gt;Azure Key Vault (Microsoft, BYOK, or DKE)&lt;/td&gt;
&lt;td&gt;Use-license issuance by Azure RMS against Entra ID&lt;/td&gt;
&lt;td&gt;Per-content envelope&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Let us walk each root one at a time. The story changes at every row.&lt;/p&gt;

flowchart LR
    subgraph BitLocker
        BL_VMK[VMK] --&amp;gt; BL_TPM[TPM, sealed against PCRs]
    end
    subgraph EFS
        EFS_FEK[Per-file FEK] --&amp;gt; EFS_Priv[User EFS RSA private key]
        EFS_Priv --&amp;gt; EFS_DPAPI[classic DPAPI master key]
        EFS_DPAPI --&amp;gt; EFS_Logon[User logon secret]
    end
    subgraph PDE
        PDE_DEK[Per-file DEK] --&amp;gt; PDE_DPAPING[DPAPI-NG protector]
        PDE_DPAPING --&amp;gt; PDE_Hello[Windows Hello for Business credential]
    end
    subgraph Purview
        P_CEK[Per-content CEK] --&amp;gt; P_Tenant[Tenant root key]
        P_Tenant --&amp;gt; P_KV[Azure Key Vault, BYOK or DKE]
        P_License[Use license] --&amp;gt; P_Entra[Microsoft Entra ID authorization]
    end
&lt;h3&gt;Root 1 -- BitLocker, the TPM-sealed VMK&lt;/h3&gt;
&lt;p&gt;BitLocker terminates at the TPM. The VMK wraps the Full Volume Encryption Key; the TPM seals the VMK against the platform&apos;s PCR measurements; if the boot chain has not been tampered with, the TPM releases the VMK without any human input. That is the entire mechanism, and it is exactly why &quot;BitLocker is on&quot; leaves the gap the §1 vignette walks through. The threat BitLocker addresses is &lt;em&gt;the powered-off device on a thief&apos;s workbench&lt;/em&gt;. It is mute against everything that happens after the OS has booted.&lt;/p&gt;
&lt;h3&gt;Root 2 -- EFS, the user EFS RSA private key sealed by classic DPAPI&lt;/h3&gt;
&lt;p&gt;EFS terminates at the user&apos;s logon credential. Microsoft Learn defines the EFS service surface as a public-key system for individual files [@ms-efs-win32]. Wikipedia walks the chain end to end: per-file FEK, RSA-wrapped to the user&apos;s EFS public key, private key sealed by classic DPAPI from the user&apos;s logon secret [@wikipedia-efs].&lt;/p&gt;
&lt;p&gt;The threat EFS addresses is &lt;em&gt;a different user on the same machine, after both have signed on at one point or another&lt;/em&gt;. It is mute against three other things: the user&apos;s own ransomware (which runs as the user and can decrypt every EFS file the user owns), password reset (which destroys the DPAPI derivation and locks the user out unless a DRA is configured), and cross-protocol copy (decrypted before SMB transit).&lt;/p&gt;
&lt;h3&gt;Root 3 -- PDE, a DPAPI-NG protector bound to a Windows Hello credential&lt;/h3&gt;
&lt;p&gt;PDE terminates at Windows Hello for Business. Microsoft Learn states the binding directly: &lt;em&gt;&quot;Personal Data Encryption is a security feature that provides file-based data encryption capabilities to Windows. It utilizes Windows Hello for Business to link data encryption keys with user credentials&quot;&lt;/em&gt; [@ms-pde-overview]. The PDE FAQ confirms the unlock condition: &lt;em&gt;&quot;the keys used by Personal Data Encryption to encrypt content are protected by Windows Hello credentials and can only be unlocked when signing on with Windows Hello (PIN or biometrics)&quot;&lt;/em&gt; [@ms-pde-faq].&lt;/p&gt;
&lt;p&gt;The likely engineering mechanism is a DPAPI-NG protection descriptor. DPAPI-NG (Microsoft&apos;s &quot;Next Generation&quot; Data Protection API, in Windows 8 and later) is the only Windows API surface that publicly documents Hello-bound key release. Its protection-descriptor grammar accepts a small set of principal types, documented at Microsoft Learn: &lt;code&gt;SID=&lt;/code&gt;, &lt;code&gt;SDDL=&lt;/code&gt;, &lt;code&gt;LOCAL=user&lt;/code&gt;, &lt;code&gt;LOCAL=machine&lt;/code&gt;, &lt;code&gt;WEBCREDENTIALS=&lt;/code&gt;, &lt;code&gt;CERTIFICATE=HashID:sha1_hash_of_certificate&lt;/code&gt;, and &lt;code&gt;CERTIFICATE=CertBlob:base64String&lt;/code&gt; [@ms-protection-descriptors]. Microsoft&apos;s own protection-descriptor reference adds: &lt;em&gt;&quot;The protection descriptor you specify automatically determines which key protection provider is used&quot;&lt;/em&gt; [@ms-protection-descriptors].&lt;/p&gt;

The rule string passed to `NCryptCreateProtectionDescriptor` that names the principal or principals whose authentication will be required to unwrap a protected blob. The protection descriptor is the place in DPAPI-NG where &quot;encrypted only for this Hello-bound principal&quot; is expressed. Microsoft Learn documents the rule grammar (SID, SDDL, LOCAL, WEBCREDENTIALS, CERTIFICATE) and the use of `AND` and `OR` connectors to combine principals [@ms-protection-descriptors].
&lt;p&gt;Microsoft has not published a mechanism document that says, in those words, &lt;em&gt;&quot;PDE uses &lt;code&gt;NCryptProtectSecret&lt;/code&gt; with a protection descriptor naming the Windows Hello for Business credential.&quot;&lt;/em&gt; What Microsoft has published is the binding (&quot;it utilizes Windows Hello for Business to link data encryption keys with user credentials&quot;) and the API surface (&quot;DPAPI-NG, with Hello-aware protectors&quot;). The two compose in exactly one way that fits the verified primaries. Treat the protection-descriptor binding as the likely engineering mechanism rather than the directly-stated one.The DPAPI-NG protection-descriptor grammar is broader than just Hello. The same API surface backs WinRT user-profile secrets, web-credentials-vault items, and certificate-protected blobs. PDE is one consumer; the API itself is general.&lt;/p&gt;

flowchart TD
    Plain[Plaintext file] --&amp;gt;|AES-CBC 256-bit| Cipher[Ciphertext on NTFS]
    DEK[Per-file Data Encryption Key] --&amp;gt;|wrap| DPAPING[DPAPI-NG NCryptProtectSecret]
    DPAPING --&amp;gt;|protection descriptor| Desc[&quot;Hello-bound principal, likely SID or LOCAL=user&quot;]
    Desc --&amp;gt; HelloKey[Hello-bound asymmetric key in TPM]
    HelloKey --&amp;gt;|released by| Auth[Windows Hello PIN or biometric sign-in]
&lt;p&gt;The arrows above are the cleanest single-page summary of PDE. From Microsoft Learn: the file body uses &lt;em&gt;&quot;AES-CBC with a 256-bit key&quot;&lt;/em&gt; [@ms-pde-overview]. From the PDE FAQ: &lt;em&gt;&quot;the keys used by Personal Data Encryption to encrypt content are protected by Windows Hello credentials and can only be unlocked when signing on with Windows Hello (PIN or biometrics)&quot;&lt;/em&gt; [@ms-pde-faq]. From the DPAPI-NG reference: the API surface includes &lt;code&gt;NCryptCreateProtectionDescriptor&lt;/code&gt;, &lt;code&gt;NCryptProtectSecret&lt;/code&gt;, and &lt;code&gt;NCryptUnprotectSecret&lt;/code&gt; for exactly this purpose [@ms-dpapi-ng]. From the protection-descriptor reference: the rule grammar accepts principal types that include SID and LOCAL principals, which is where the Hello-bound binding lives [@ms-protection-descriptors].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PDE uses AES-CBC, not an authenticated mode like AES-GCM. CBC is malleable: an attacker who can modify ciphertext on disk can flip predictable bits in plaintext. The argument that closes this gap is composition: PDE expects to run on top of BitLocker, whose modern default is XTS-AES [@wikipedia-bitlocker]. PDE&apos;s CBC mode by itself has no manipulation resistance; PDE composed with BitLocker inherits BitLocker&apos;s XTS-AES floor. This composition is intentional. Microsoft&apos;s own recommendation is to run PDE under BitLocker: &lt;em&gt;&quot;it&apos;s recommended to encrypt all volumes with BitLocker Drive Encryption for increased security&quot;&lt;/em&gt; [@ms-pde-faq].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The threat PDE addresses is &lt;em&gt;the laptop at the lock screen with a plaintext volume, in the user&apos;s own absence&lt;/em&gt;. PDE files are unreadable until the user re-authenticates to Hello, even though BitLocker has long since released the volume.&lt;/p&gt;
&lt;p&gt;This is, importantly, the &lt;em&gt;only&lt;/em&gt; place in the four-layer story where &quot;DPAPI-NG is involved&quot; is true. EFS uses classic DPAPI, not DPAPI-NG. Purview labels use Azure RMS, not DPAPI-NG. BitLocker uses neither. The folk-knowledge framing &quot;DPAPI-NG under everything&quot; collapses three different roots into one and obscures the actual architecture.&lt;/p&gt;
&lt;h3&gt;Root 4 -- Purview labels, the Azure RMS tenant key plus Entra ID authorization&lt;/h3&gt;
&lt;p&gt;Purview sensitivity labels (where the label applies encryption) terminate at the Azure Rights Management tenant key and at Microsoft Entra ID. Microsoft Learn states the engine: &lt;em&gt;&quot;Unless you&apos;re using S/MIME for Outlook, encryption that&apos;s applied by sensitivity labels to documents, emails, and meeting invites all use the Azure Rights Management service from Microsoft Purview Information Protection&quot;&lt;/em&gt; [@ms-purview-labels].&lt;/p&gt;
&lt;p&gt;The on-disk envelope contains the wrapped CEK and policy metadata, &lt;em&gt;and the wrapped CEK can be re-issued to any authorised principal&lt;/em&gt;. When Bob in Contoso emails an &quot;Internal&quot; labelled DOCX to Alice in Fabrikam, Azure RMS issues Alice a use license against her Entra ID identity, provided that the document&apos;s policy admits her. The cross-organisation default is on by default [@ms-azure-rms].&lt;/p&gt;
&lt;p&gt;The tenant root can vary. Microsoft Learn describes the topology: &lt;em&gt;&quot;The root key for your Azure Rights Management service can either be: Generated by Microsoft ... Generated by customers with Bring Your Own Key (BYOK)&quot;&lt;/em&gt; [@ms-byok]. Above BYOK sits Double Key Encryption, which puts a customer-controlled key in series with the Azure-held key.&lt;/p&gt;

A two-key model on top of Purview&apos;s tenant root, in which decryption requires both an Azure-held key and an on-premises customer-held key. Microsoft Learn states the design: *&quot;DKE lets you maintain control of your encryption keys. It uses two keys to protect data; one key in your control and a second key you store securely in Microsoft Azure. You maintain control of one of your keys using the Double Key Encryption service. Viewing data protected with Double Key Encryption requires access to both keys&quot;* [@ms-dke]. The same page adds the operational consequence: *&quot;DKE encrypted data isn&apos;t accessible at rest to Microsoft 365 services including Copilot&quot;* [@ms-dke].
&lt;p&gt;The threat Purview labels address is &lt;em&gt;the file that leaves the organisation&lt;/em&gt;. A Purview-encrypted file emailed to a personal Gmail account, copied to a USB stick, uploaded to a third-party SaaS -- still encrypted, still requires a use license from Azure RMS against an authenticated identity, still subject to the policy the original author attached. BitLocker, EFS, and PDE all stop at the local volume or local user; Purview labels are the only one of the four that follows the file across machines, tenants, and protocols.&lt;/p&gt;
&lt;h3&gt;The asymmetry is the design&lt;/h3&gt;
&lt;p&gt;A single unifying root would have collapsed real distinctions. If everything terminated at the TPM, no protection could survive the file leaving the device. If everything terminated at the user&apos;s password, no per-content cross-tenant story would be possible. If everything terminated at Entra ID, the offline laptop at a lock screen would have no answer when the network is unreachable. The four-root architecture is what it is because the four threats are what they are.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Three layers, three protection-key roots, three threat models. The asymmetry is the point: each root exists precisely because the threats are different. A single unified root would not be an improvement -- it would collapse real distinctions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that you know the roots, you can ask the right questions about the state of the art: what does each layer ship today, and how do you compose them?&lt;/p&gt;
&lt;h2&gt;6. State of the Art: Each Layer in 2026&lt;/h2&gt;
&lt;p&gt;Each layer ships today, supported, documented, and deployed. Here is what each one actually looks like as of mid-2026.&lt;/p&gt;
&lt;h3&gt;EFS in 2026&lt;/h3&gt;
&lt;p&gt;EFS still ships in Windows 11 and Windows Server 2025. It is documented at the Win32 file-encryption reference [@ms-efs-win32]. It is deprecated for new development -- the recommended replacement for new per-file scenarios on Entra-joined Hello-using devices is PDE [@ms-pde-faq] -- but the implementation is intact, Group Policy still ships DRA configuration, and existing EFS-encrypted files continue to work.&lt;/p&gt;
&lt;p&gt;What EFS does not work on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;ReFS before 24H2&lt;/em&gt;. Historically the &lt;code&gt;$EFS&lt;/code&gt; attribute had no home on ReFS, so EFS-protected files were decrypted in transit when copied to a ReFS volume. Windows 11 24H2 and Windows Server 2025 added file-system-encryption support to ReFS [@wikipedia-efs], so the absolute &quot;no home&quot; framing is now out of date; on older ReFS, the cryptography still ends at the volume boundary.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;FAT32 / exFAT on legacy Windows&lt;/em&gt;. Wikipedia notes that &lt;em&gt;&quot;Files and folders are decrypted before being copied to a volume formatted with another file system, like FAT32&quot;&lt;/em&gt; [@wikipedia-efs]. Windows 10 1607 and Windows Server 2016 added EFS support on FAT and exFAT [@wikipedia-efs], which softens the absolute version of that statement; the cryptography still ends at SMB transit and at any destination the source EFS service does not recognise as compatible.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;System files and root directories&lt;/em&gt;. Not encryptable; the chicken-and-egg problem of needing to read the user&apos;s profile before the user has authenticated.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Compressed files&lt;/em&gt;. EFS and NTFS file compression are mutually exclusive on the same file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default cipher inside the FEK has been AES since Windows XP SP1 [@wikipedia-efs]; the default key size moved from AES-128 to AES-256 in a later Windows 10 release. Operationally, the most common source of confusion is &lt;code&gt;cipher.exe /K&lt;/code&gt;, which generates a fresh self-signed EFS certificate for the current user if one does not already exist; the certificate goes into the user&apos;s personal store, the private key into &lt;code&gt;%APPDATA%\Microsoft\Crypto\RSA\&amp;lt;SID&amp;gt;\&lt;/code&gt;, and the EFS service in &lt;code&gt;lsass.exe&lt;/code&gt; from then on prefers the new certificate for new wraps. Existing EFS files do not rewrap themselves.&lt;/p&gt;
&lt;p&gt;The DRA story works cleanly only in classic AD-domain deployments where Group Policy can push a recovery-agent certificate to every machine and the EFS service knows to add the DRA wrapper at encryption time. In an Entra-joined-only environment, the AD-domain DRA story does not transplant cleanly; this is one of the seven live operational problems we will catalogue in §9.&lt;/p&gt;
&lt;h3&gt;PDE in 2026&lt;/h3&gt;
&lt;p&gt;Personal Data Encryption ships on Windows 11 22H2 and later, in Enterprise and Education SKUs [@ms-pde-overview]. As of Windows 11 24H2, the known-folder auto-encryption mode brings Desktop, Documents, and Pictures under PDE without requiring per-file API calls [@ms-pde-overview].&lt;/p&gt;
&lt;p&gt;The prerequisites are strict, and they are spelled out on the PDE overview page: &lt;em&gt;&quot;The devices must be Microsoft Entra joined or Microsoft Entra hybrid joined. Domain-joined devices aren&apos;t supported&quot;&lt;/em&gt; and &lt;em&gt;&quot;Automatic Restart Sign On (ARSO) must be disabled&quot;&lt;/em&gt; [@ms-pde-overview]. The configure page emphasises the ARSO point: &lt;em&gt;&quot;Winlogon automatic restart sign-on (ARSO) isn&apos;t supported for use with Personal Data Encryption. To use Personal Data Encryption, ARSO must be disabled&quot;&lt;/em&gt; [@ms-pde-configure].&lt;/p&gt;
&lt;p&gt;PDE has two protection levels, defined by how long after sign-in the content remains decrypted in memory. The original announcement explains both:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;Level 1(L1) security protects contents during the early boot stage -- from the time that the machines boots, until the user logs in using Windows Hello for Business credentials. Level 2(L2) security protects data from the time the user&apos;s device locks till the device is unlocked using Windows Hello for Business credentials.&quot;&lt;/em&gt; [@ms-pde-announcement]&lt;/p&gt;
&lt;p&gt;L1 is &quot;protected from boot until first sign-in.&quot; L2 is &quot;protected from lock until next unlock.&quot; L1 is the default; L2 is opt-in and stricter, because re-decrypting on every unlock is more disruptive to apps that hold open file handles.&lt;/p&gt;
&lt;p&gt;The Configuration Service Provider node tree:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;./User/Vendor/MSFT/PDE/EnablePersonalDataEncryption&lt;/code&gt; -- introduced in 22H2, build 10.0.22621 [@ms-pde-csp].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./User/Vendor/MSFT/PDE/ProtectFolders/ProtectDesktop&lt;/code&gt; -- introduced in 24H2, build 10.0.26100 [@ms-pde-csp].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./User/Vendor/MSFT/PDE/ProtectFolders/ProtectDocuments&lt;/code&gt; -- 24H2 [@ms-pde-csp].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;./User/Vendor/MSFT/PDE/ProtectFolders/ProtectPictures&lt;/code&gt; -- 24H2 [@ms-pde-csp].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An earlier draft of this article&apos;s research wrote these paths without the &lt;code&gt;ProtectFolders&lt;/code&gt; parent node, and so do several blog posts on the public web. The Microsoft Learn CSP reference is authoritative: the folder-protection nodes nest under &lt;code&gt;ProtectFolders&lt;/code&gt;. Practitioners running CSP queries against the un-nested path will see them return no value.&lt;/p&gt;
&lt;p&gt;For per-file application use, the WinRT API is &lt;code&gt;Windows.Security.DataProtection.UserDataProtectionManager.ProtectStorageItemAsync&lt;/code&gt; [@ms-userdataprotectionmgr]. The class provides static methods to obtain an instance for the current or a provided user, and instance methods that include &lt;code&gt;GetStorageItemProtectionInfoAsync&lt;/code&gt;, &lt;code&gt;ProtectBufferAsync&lt;/code&gt;, &lt;code&gt;ProtectStorageItemAsync&lt;/code&gt;, &lt;code&gt;TryGetDefault&lt;/code&gt;, &lt;code&gt;TryGetForUser&lt;/code&gt;, and &lt;code&gt;UnprotectBufferAsync&lt;/code&gt;, along with the &lt;code&gt;DataAvailabilityStateChanged&lt;/code&gt; event [@ms-userdataprotectionmgr].The &lt;code&gt;UserDataProtectionManager&lt;/code&gt; API was introduced in Windows 10 1903 (build 10.0.18362), under &lt;code&gt;Windows.Foundation.UniversalApiContract&lt;/code&gt; v8.0 -- predating the 22H2 ship of PDE itself by three years.&lt;/p&gt;
&lt;p&gt;The gotchas list is long enough that the PDE FAQ enumerates each one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Password sign-in fails&lt;/em&gt;. Hello-only release; a user who signs in with a password (e.g., via Ctrl-Alt-Del fallback after a Hello failure) cannot read PDE content.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;RDP fails&lt;/em&gt;. Microsoft Learn states it explicitly: &lt;em&gt;&quot;No, it&apos;s not supported to access protected content over RDP&quot;&lt;/em&gt; [@ms-pde-faq].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Other-user fails&lt;/em&gt;. Each user&apos;s PDE content is bound to their own Hello credential.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mutually exclusive with EFS&lt;/em&gt;. PDE and EFS are mutually exclusive on the same file (see §3).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;OneDrive sync sees plaintext&lt;/em&gt;. &lt;em&gt;&quot;Personal Data Encryption&apos;s encryption only applies to local data saved to the disk. Applications accessing the files, including OneDrive when it syncs data, get cleartext data&quot;&lt;/em&gt; [@ms-pde-faq]. This is the price of &quot;transparent decryption&quot; for the calling user&apos;s processes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Memory dumps can expose keys&lt;/em&gt;. &lt;em&gt;&quot;Kernel-mode crash dumps and live dumps can potentially cause the keys used by Personal Data Encryption to protect content to be exposed&quot;&lt;/em&gt; / &lt;em&gt;&quot;Hibernation files can potentially cause the keys used by Personal Data Encryption to protect content to be exposed&quot;&lt;/em&gt; [@ms-pde-configure].&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; EFS has a Data Recovery Agent model. BitLocker has recovery-key escrow (to Microsoft account, to Active Directory, to Microsoft Entra ID, to a printout). Purview has tenant-key escrow plus a super-user role. PDE has &lt;em&gt;none&lt;/em&gt; of these. The PDE FAQ is explicit: OneDrive is recommended as a &quot;second copy&quot;, not as a key-recovery mechanism, and &lt;em&gt;&quot;Personal Data Encryption doesn&apos;t have a requirement for a backup provider, including OneDrive in Microsoft 365. However, backups are recommended in case the keys used by Personal Data Encryption to protect files are lost&quot;&lt;/em&gt; [@ms-pde-faq]. Plan for this before deploying PDE at scale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Microsoft Purview Information Protection in 2026&lt;/h3&gt;
&lt;p&gt;Purview&apos;s labelling and encryption story is the most operationally distinct of the four, because the encryption is enforced by a cloud service. Microsoft Learn enumerates the four guarantees the engine makes for a label-encrypted file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&quot;Can be decrypted only by users authorized by the label&apos;s encryption settings&quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&quot;Remains encrypted no matter where it resides, inside or outside your organization, even if the file&apos;s renamed&quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&quot;Is encrypted both at rest (for example, in a OneDrive account) and in transit (for example, email as it traverses the internet)&quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Encryption is applied automatically by the chosen label settings [@ms-purview-labels].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Where the tenant root key sits is configurable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Microsoft-managed by default&lt;/em&gt;. The root key is generated and held by Microsoft in Azure. This is the default for most tenants and the lowest-friction option.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;BYOK&lt;/em&gt;. The customer generates the root key (typically in a Thales HSM or equivalent), uploads it to an Azure Key Vault under their control, and Azure RMS uses the customer&apos;s Azure-held key as the tenant root [@ms-byok].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;DKE&lt;/em&gt;. Two keys, one held by Microsoft and one held on-premises by the customer, both required for decryption [@ms-dke]. The DKE path narrows what Microsoft can do for the customer in exchange for the strongest possible client-side root.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Microsoft Learn frames DKE as a high-end option: &lt;em&gt;&quot;Highly sensitive (about 5% of data)&quot;&lt;/em&gt; is the documentation&apos;s own scoping language [@ms-dke]. The page makes the trade-off candid: &lt;em&gt;&quot;DKE encrypted data isn&apos;t accessible at rest to Microsoft 365 services including Copilot&quot;&lt;/em&gt; [@ms-dke]. DKE is the &quot;crown jewels&quot; tier; using it for everything would blind every Microsoft 365 server-side service from search to Copilot to compliance.&lt;/p&gt;
&lt;p&gt;Labels are applied to documents in three ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Manually&lt;/em&gt;, by users in Office desktop, Office on the web, or Outlook, via the Sensitivity menu.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Automatically&lt;/em&gt;, when a Purview auto-labelling policy matches a trainable classifier or content-inspection rule.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;On the wire&lt;/em&gt;, via Exchange transport rules that label messages as they leave the organisation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once applied, the label&apos;s encryption settings (if any) determine which authorised principals can request a use license. Microsoft Learn states the cross-organisation default: &lt;em&gt;&quot;By default, collaboration with other organizations that already have a Microsoft 365 or a Microsoft Entra directory is automatically supported&quot;&lt;/em&gt; [@ms-azure-rms]. The travels-with-file guarantee is enforced precisely because the file&apos;s wire format embeds the wrapped CEK and the policy reference: a recipient who has the file but cannot obtain a use license from Azure RMS holds ciphertext.&lt;/p&gt;
&lt;p&gt;Those are the layers you compose. But the practitioner reasonably asks: what about everything else? What about WIP, macOS, Linux, third-party DRM?&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches Within and Beyond Windows&lt;/h2&gt;
&lt;p&gt;Four within-Windows alternatives and three cross-platform alternatives the reader will ask about. Two of them are dead ends.&lt;/p&gt;
&lt;h3&gt;Group Policy plus NTFS ACLs&lt;/h3&gt;
&lt;p&gt;NTFS ACLs are not encryption. They are OS-enforced access control: the kernel checks the ACL before satisfying a &lt;code&gt;ReadFile&lt;/code&gt;. Boot a different operating system that does not honour NTFS ACLs and the protection is gone. EFS exists because ACLs alone are not enough; nothing in this article displaces ACLs, but ACLs alone do not appear on any of the four roots above.&lt;/p&gt;
&lt;h3&gt;BitLocker To Go&lt;/h3&gt;
&lt;p&gt;BitLocker To Go is BitLocker for removable media -- USB sticks, external drives. It uses the same XTS-AES cipher and the same VMK/FVEK topology, with the recovery key delivered to Active Directory, Entra ID, a Microsoft account, or a printout depending on the policy [@wikipedia-bitlocker]. Treat it as the same Generation 2 root as BitLocker proper, restricted to removable storage.&lt;/p&gt;
&lt;h3&gt;Windows Information Protection -- the dead branch&lt;/h3&gt;
&lt;p&gt;Already named in §4. Microsoft Learn&apos;s &lt;code&gt;/previous-versions/&lt;/code&gt; page is the canonical citation for the deprecation [@ms-wip-deprecation]. The same page is candid about why WIP did not survive: &lt;em&gt;&quot;While Windows Information Protection can stop accidental data leaks from honest employees, it is not intended to stop malicious insiders from removing enterprise data&quot;&lt;/em&gt; [@ms-wip-deprecation]. The honest-employees framing is the most precise statement of WIP&apos;s threat model -- and of its limit. The recommended replacement is the Microsoft Purview Information Protection plus Microsoft Purview Data Loss Prevention combination. Do not deploy WIP in 2026.&lt;/p&gt;
&lt;h3&gt;macOS FileVault 2&lt;/h3&gt;
&lt;p&gt;Apple Platform Security documents the cipher and the key location succinctly: &lt;em&gt;&quot;FileVault uses the AES-XTS data encryption algorithm to protect full volumes on internal and removable storage devices&quot;&lt;/em&gt; and &lt;em&gt;&quot;All FileVault key handling occurs in the Secure Enclave; encryption keys are never directly exposed to the CPU&quot;&lt;/em&gt; [@apple-filevault]. Architecturally, FileVault 2 is BitLocker&apos;s analogue: volume-level, hardware-rooted, automatic at boot. There is no per-file user-bound layer in macOS that maps cleanly to PDE or EFS. The cross-platform reader looking for a PDE analogue on macOS will not find one in the OS itself; the equivalent has to come from per-application sandboxing (the Data Vault APIs, the App Sandbox container) or from Purview labels applied via Office for Mac.&lt;/p&gt;
&lt;h3&gt;Linux LUKS and fscrypt&lt;/h3&gt;
&lt;p&gt;LUKS is volume-level full-disk encryption, analogous to BitLocker. fscrypt is per-directory file encryption on ext4, F2FS, UBIFS, and CephFS; the kernel documentation states the supported filesystems explicitly: &lt;em&gt;&quot;currently ext4, F2FS, UBIFS, and CephFS&quot;&lt;/em&gt; [@fscrypt-kernel]. Architecturally, fscrypt is closer to PDE than to EFS: per-directory keying, key wrapping by a user-bound credential, designed so that different files can have different keys. The kernel docs also state the bound that matters most for our purposes: &lt;em&gt;&quot;Unlike dm-crypt, fscrypt operates at the filesystem level rather than at the block device level. This allows it to encrypt different files with different keys&quot;&lt;/em&gt; [@fscrypt-kernel]. The Linux stack has had a PDE-shaped tool for years; what it does not have is Hello-equivalent identity infrastructure baked in.&lt;/p&gt;
&lt;h3&gt;Third-party DRM&lt;/h3&gt;
&lt;p&gt;Commercial information-rights-management products from various vendors occupy roughly the same architectural slot as Purview labels: per-content envelope encryption, policy enforced at the rendering application against an identity service. The trade-offs differ on tenant ownership, identity binding, and Office integration; the architectural shape is the same.&lt;/p&gt;
&lt;p&gt;Those are the alternatives. None of them changes the fact that on Windows, the three above-BitLocker layers we have catalogued are the layers you actually pick from. So how far can those layers actually go? What is the theoretical ceiling?&lt;/p&gt;
&lt;h2&gt;8. Where Cryptography Ends and Trust Begins&lt;/h2&gt;
&lt;p&gt;Three bounds. Each is structural. Each tells you something about where cryptography unavoidably terminates.&lt;/p&gt;
&lt;h3&gt;Bound 1 -- At-rest encryption cannot protect plaintext in use&lt;/h3&gt;
&lt;p&gt;Every layer this article catalogues encrypts data &lt;em&gt;at rest&lt;/em&gt;. None of them encrypts data while it is in use by the application that opened it. The plaintext must materialise in process address space for the application to read it; once it is there, the same operating system that handed the application the plaintext also exposes that address space to debuggers, to dump-on-crash, to memory-scrapers, to anything with &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Linux fscrypt kernel documentation states this property explicitly:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;After an encryption key has been added, fscrypt does not hide the plaintext file contents or filenames from other users on the same system. Instead, existing access control mechanisms such as file mode bits, POSIX ACLs, LSMs, or namespaces should be used for this purpose.&quot;&lt;/em&gt; [@fscrypt-kernel]&lt;/p&gt;
&lt;p&gt;The same property holds for BitLocker, EFS, PDE, and Purview labels. Once unlocked, the bytes are bytes. The protection against &quot;another process running as the same user&quot; is the operating system&apos;s access-control layer, not the encryption.&lt;/p&gt;
&lt;h3&gt;Bound 2 -- Authorised-reader exfiltration is unbounded&lt;/h3&gt;
&lt;p&gt;A user who is &lt;em&gt;authorised&lt;/em&gt; to view a file can do anything with the displayed pixels. They can screen-capture, photograph the screen with a phone, dictate the contents aloud, retype them into an unprotected document, paste them into Notepad. This is the &quot;rendezvous problem&quot;, or in older folk vocabulary the &quot;analog hole&quot;.Both &quot;rendezvous problem&quot; and &quot;analog hole&quot; are folk-knowledge terms used descriptively in industry; they are not citations to a named published conjecture, and we do not assert that any particular paper coined either. No cipher can prevent it, because the cipher&apos;s correctness requires that the authorised viewer &lt;em&gt;can&lt;/em&gt; read the plaintext.&lt;/p&gt;
&lt;p&gt;Microsoft itself is candid about where this leaves the RMS family of technologies. The Wikipedia AD RMS article quotes Microsoft&apos;s policy-enforcement framing:&lt;/p&gt;

the differentiation between different usage rights for authorized users is considered part of its policy enforcement capabilities, which Microsoft claims to be implemented as &apos;best effort&apos;, so it is not considered by Microsoft to be a security issue but a policy enforcement limitation. [@wikipedia-adrms]
&lt;p&gt;The &quot;do not print&quot; rights bit on an RMS document is not cryptographically enforced. It is enforced by Microsoft Word, by Outlook, by the rendering applications that the use license names. A user who controls the rendering application can ignore the bit. The cipher protects against &lt;em&gt;unauthorised&lt;/em&gt; readers; it cannot constrain &lt;em&gt;authorised&lt;/em&gt; readers.&lt;/p&gt;
&lt;h3&gt;Bound 3 -- The key-binding root limits the protection ceiling&lt;/h3&gt;
&lt;p&gt;The third bound is the cleanest restatement of the article&apos;s thesis. No layer can be stronger than its root.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;EFS&lt;/em&gt;. The root is the user&apos;s logon secret, via classic DPAPI. The Wikipedia EFS article states the ceiling: &lt;em&gt;&quot;In Windows 2000, XP or later, the user&apos;s RSA private key is encrypted using a hash of the user&apos;s NTLM password hash plus the user name ... any compromise of the user&apos;s password automatically leads to access to that data&quot;&lt;/em&gt; [@wikipedia-efs]. EFS cannot be stronger than the user&apos;s password hygiene.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;PDE&lt;/em&gt;. The root is Windows Hello for Business. PDE cannot be stronger than Hello&apos;s own ceiling: TPM-bound asymmetric keys plus user PIN or biometric, with all the assumptions about anti-hammering, TPM attestation, and ARSO-off that the PDE configure page enumerates [@ms-pde-configure].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Purview labels&lt;/em&gt;. The root is the Azure Rights Management tenant key, plus Microsoft Entra ID for authorization. The ceiling is Azure Key Vault custodial security plus Entra authorization correctness. DKE raises the ceiling by adding a customer-held key in series with the Azure-held key [@ms-dke], at the cost of blinding Microsoft 365 service-side processing of that content [@ms-dke].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of the three roots is unconditionally stronger than the others. Each makes a trade-off that is sensible for the threat model it addresses. EFS optimises for &quot;this exact user account, this exact machine, after both have signed on.&quot; PDE optimises for &quot;this Hello-authenticated user, this exact device, even across boot-and-lock.&quot; Purview labels optimise for &quot;this Entra-authenticated user, across organisations, across protocols, across time.&quot; There is no fourth option that is simply &quot;stronger.&quot; There is only the choice of &lt;em&gt;which&lt;/em&gt; root the data is bound to, made deliberately.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Cryptography pushes the trust boundary up but cannot eliminate it. Every layer terminates at &quot;the application has the plaintext and the application can do anything.&quot; What changes between layers is &lt;em&gt;where&lt;/em&gt; that boundary sits, not whether it exists.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Theoretically impossible&lt;/th&gt;
&lt;th&gt;Current best on Windows&lt;/th&gt;
&lt;th&gt;Remaining gap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Per-process gating&lt;/td&gt;
&lt;td&gt;No (with attestation, e.g., LSAIso)&lt;/td&gt;
&lt;td&gt;Credential Guard / LSAIso for credentials; not extended to user files&lt;/td&gt;
&lt;td&gt;No file-encryption layer gates at app identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorised-reader exfiltration&lt;/td&gt;
&lt;td&gt;Yes (analog hole)&lt;/td&gt;
&lt;td&gt;RMS &quot;best effort&quot; policy enforcement [@wikipedia-adrms]&lt;/td&gt;
&lt;td&gt;Cannot be closed by cipher; closed only by hardware DRM / endpoint controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pre-logon file protection&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;PDE L1 [@ms-pde-announcement]&lt;/td&gt;
&lt;td&gt;Limited to known folders, Hello, Entra-join, 24H2+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-tenant per-content protection&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Purview labels via Azure RMS [@ms-purview-labels]&lt;/td&gt;
&lt;td&gt;Cross-tenant policy and revocation are per-tenant&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Those are the structural limits. The operational limits -- the things Microsoft has not yet shipped a fix for -- are different. Let&apos;s look at those next.&lt;/p&gt;
&lt;h2&gt;9. Open Problems Microsoft Has Not Yet Shipped&lt;/h2&gt;
&lt;p&gt;Seven live operational problems. None of them is academic. Each is a question your CISO is asking, and none of them has a Microsoft-shipped answer as of May 2026.&lt;/p&gt;
&lt;h3&gt;1. PDE has no DRA-equivalent&lt;/h3&gt;
&lt;p&gt;EFS has a Data Recovery Agent. BitLocker has recovery-key escrow to Active Directory, Entra ID, a Microsoft account, or a printout. Purview has tenant-key escrow and a super-user role. PDE has none of these. The PDE FAQ does not equivocate: &lt;em&gt;&quot;Personal Data Encryption doesn&apos;t have a requirement for a backup provider, including OneDrive in Microsoft 365. However, backups are recommended in case the keys used by Personal Data Encryption to protect files are lost&quot;&lt;/em&gt; [@ms-pde-faq]. &quot;Backups&quot; here means a second copy of the plaintext, made before the keys were lost; it is not key recovery. A user whose Hello credential is irrecoverably reset, and who had no second copy at the time, has unreadable files.&lt;/p&gt;
&lt;h3&gt;2. EFS in an Entra-only world&lt;/h3&gt;
&lt;p&gt;The DRA story works because Group Policy in a classic Active Directory deployment can push a recovery-agent certificate to every machine. In an Entra-joined-only environment, there is no equivalent shipped configuration. The EFS Win32 reference still documents EFS [@ms-efs-win32]; what it does not document is &quot;how to maintain an organisational EFS DRA on a fleet of Entra-joined-only devices in 2026.&quot; The migration path -- whether the answer is &quot;stop using EFS for new files and move to PDE&quot; (which the PDE FAQ implies [@ms-pde-faq]) or &quot;configure DRA via Intune&quot; (which is not a documented Intune-shipped flow) -- is not in Microsoft Learn.&lt;/p&gt;
&lt;h3&gt;3. Cross-tenant sensitivity-label collaboration&lt;/h3&gt;
&lt;p&gt;Cross-organisation sharing of Purview-encrypted content works for documents emailed or shared with a recipient whose tenant is configured to accept the policy [@ms-azure-rms]. Cross-organisation revocation is harder. A use license issued to an external recipient is bound to the issuing tenant&apos;s RMS service; revoking the recipient&apos;s access requires the issuing tenant to act, not the recipient&apos;s. Cross-tenant collaboration policies need explicit configuration, and revocation is per-tenant, not per-policy [@ms-purview-labels]. CISOs running federation-heavy programmes ask about this every week; the answer is &quot;configure explicitly, audit explicitly, accept that the recipient tenant has its own controls.&quot;&lt;/p&gt;
&lt;h3&gt;4. PDE composition with Windows Recall&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://paragmali.com/blog/microsoft-recall-2024-2026-re-architecture/&quot; rel=&quot;noopener&quot;&gt;Windows Recall&lt;/a&gt; (the AI-driven on-device timeline of screenshots and OCR text, shipping under Copilot+ PC programmes) introduces a new question for PDE: when Recall captures a screenshot of a PDE-protected document open on screen, does the resulting Recall snapshot inherit PDE protection, or is it merely VBS-enclave-protected? Microsoft&apos;s Recall documentation describes the VBS-enclave protection model and a separate set of opt-outs for &quot;sensitive content&quot;; what is &lt;em&gt;not&lt;/em&gt; documented is whether a Recall snapshot of a PDE-protected file is itself a PDE-protected file. This is a live design question.&lt;/p&gt;
&lt;h3&gt;5. DPAPI-NG protector revocation at Hello rotation&lt;/h3&gt;
&lt;p&gt;If a user enrols a new device into Entra ID, the Hello credential on that new device is a different credential -- a fresh asymmetric key in the new device&apos;s TPM, attested at a fresh enrolment event. PDE files encrypted under the &lt;em&gt;old&lt;/em&gt; device&apos;s Hello protector cannot be unwrapped on the new device, unless a recovery mechanism re-issues the wrap. There is no shipped recovery mechanism (see problem 1 above), so the question is operational: what does the user do with PDE files synced via OneDrive -- which sees plaintext, per the PDE FAQ [@ms-pde-faq] -- when they move to a new device? The answer is &quot;OneDrive re-encrypts them under the new device&apos;s Hello on first access, because OneDrive saw plaintext.&quot; That works, and it tells you something about how thin PDE&apos;s &quot;encryption that travels&quot; story is.&lt;/p&gt;
&lt;h3&gt;6. Per-process cryptographic gating&lt;/h3&gt;
&lt;p&gt;None of the four layers gates at the &lt;em&gt;application&lt;/em&gt; identity. EFS, PDE, Purview labels all release plaintext to any process running as the authorised user (or any process holding a valid use license, in Purview&apos;s case). The CISO question that has no answer in the file-encryption stack today is &lt;em&gt;&quot;can I keep ransomware running as Alice from encrypting Alice&apos;s labelled files?&quot;&lt;/em&gt; Credential Guard and LSAIso show that per-process gating with attestation is technically feasible for credentials; nothing in the file-encryption layers extends that mechanism to user files. This is the single most asked open question in the working-architect audience.&lt;/p&gt;
&lt;h3&gt;7. Cipher-mode modernisation&lt;/h3&gt;
&lt;p&gt;PDE&apos;s choice of AES-CBC is deliberate, but it is also old. AEAD modes -- GCM, OCB3, ChaCha20-Poly1305 -- bundle integrity and confidentiality together; CBC does not. PDE composed with BitLocker XTS-AES is acceptable in practice [@wikipedia-bitlocker], but the PDE layer in isolation has no integrity guarantee. Whether Microsoft will modernise the PDE cipher in a future Windows release (and what the file-format compatibility story would look like if they did) is unanswered as of May 2026.&lt;/p&gt;
&lt;p&gt;Those are the open problems. The article&apos;s last sections turn from research into action: how does a working architect actually use these layers?&lt;/p&gt;
&lt;h2&gt;10. Composing the Layers: A Practical Guide&lt;/h2&gt;
&lt;p&gt;A decision tree. Then the common implementation pitfalls. Then an audit checklist for the layered architecture you should be aiming for.&lt;/p&gt;
&lt;h3&gt;The decision tree&lt;/h3&gt;

flowchart TD
    H[NTFS on hardware]
    BL[BitLocker XTS-AES, TPM+PIN protector]
    PDE_KF[PDE known folders: Desktop, Documents, Pictures]
    EFS_Legacy[EFS legacy files only, no new EFS]
    Purview[Purview sensitivity labels with encryption]
    Apps[Office, Outlook, OneDrive sync clients]
    H --&amp;gt; BL
    BL --&amp;gt; PDE_KF
    BL --&amp;gt; EFS_Legacy
    PDE_KF --&amp;gt; Apps
    EFS_Legacy --&amp;gt; Apps
    Purview --&amp;gt; Apps
&lt;p&gt;The decision tree, walked once:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Need to protect the volume at rest, against a powered-off-device thief?&lt;/em&gt; BitLocker. Configure TPM+PIN protector to close the post-boot pre-logon gap at the boot layer where you can.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Need to protect per-user on a shared device, including the post-boot pre-logon window?&lt;/em&gt; PDE, on Windows 11 22H2 or later, with Entra-join, Hello, ARSO disabled. For Windows 11 24H2, prefer the known-folder mode (Desktop, Documents, Pictures auto-encrypted).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Have legacy &lt;code&gt;$EFS&lt;/code&gt; files inherited from a previous Windows generation?&lt;/em&gt; Leave EFS for those legacy files; do not encrypt new files with EFS on devices that can run PDE. Choose PDE or EFS per file, not both (mutual exclusion; §3).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Need protection that travels with the file across machines, tenants, and protocols?&lt;/em&gt; Purview sensitivity labels with encryption settings. Use Microsoft-managed tenant keys by default; BYOK for tenants that need customer-controlled keys; DKE for the ~5% of crown-jewel content where Microsoft 365 service-side processing must be blinded [@ms-dke].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;All of the above, on the same file, on a modern Entra-joined Windows 11 24H2 Enterprise device?&lt;/em&gt; Yes. BitLocker + PDE-known-folders + Purview label is the modern default. EFS is the legacy slot.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For most Entra-joined Windows 11 24H2 deployments: BitLocker (TPM+PIN) under PDE (known-folder mode) under Purview sensitivity labels. EFS legacy only. The three above-BitLocker layers compose; the four roots stay distinct; the threat coverage adds up. Nothing in this composition needs DKE -- save DKE for the ~5% of content where Copilot blinding is desired.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Common implementation pitfalls&lt;/h3&gt;
&lt;p&gt;Seven pitfalls, in order from &quot;easy to miss&quot; to &quot;easy to misdiagnose.&quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Forgetting to disable ARSO before enabling PDE&lt;/em&gt;. Microsoft Learn states the constraint twice: &lt;em&gt;&quot;Automatic Restart Sign On (ARSO) must be disabled&quot;&lt;/em&gt; [@ms-pde-overview] and &lt;em&gt;&quot;To use Personal Data Encryption, ARSO must be disabled&quot;&lt;/em&gt; [@ms-pde-configure]. Enabling &lt;code&gt;EnablePersonalDataEncryption=1&lt;/code&gt; while ARSO is still on does not produce a clean error.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Expecting &lt;code&gt;EnablePersonalDataEncryption=1&lt;/code&gt; to migrate existing files&lt;/em&gt;. It does not. The CSP value enables the API surface (and, on 24H2, the known-folder protection). Files that existed before PDE was enabled are not automatically wrapped. Plan a separate migration pass.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Letting kernel-mode crash dumps or hibernation expose PDE keys&lt;/em&gt;. Microsoft&apos;s PDE configure page is explicit: &lt;em&gt;&quot;Kernel-mode crash dumps and live dumps can potentially cause the keys used by Personal Data Encryption to protect content to be exposed&quot;&lt;/em&gt; and &lt;em&gt;&quot;Hibernation files can potentially cause the keys used by Personal Data Encryption to protect content to be exposed&quot;&lt;/em&gt; [@ms-pde-configure]. Configure dump policy alongside PDE; do not deploy PDE on devices that produce kernel-mode dumps to untrusted destinations.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Assuming OneDrive sync preserves PDE protection in the cloud&lt;/em&gt;. It does not. The PDE FAQ states it plainly: &lt;em&gt;&quot;Personal Data Encryption&apos;s encryption only applies to local data saved to the disk. Applications accessing the files, including OneDrive when it syncs data, get cleartext data&quot;&lt;/em&gt; [@ms-pde-faq]. Cloud-side protection is the labelling layer&apos;s job, not PDE&apos;s.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Deploying DKE everywhere&lt;/em&gt;. DKE breaks Microsoft 365 server-side service integration -- search, eDiscovery, transport rules, Copilot -- because Microsoft cannot decrypt content at rest. Microsoft Learn says it: &lt;em&gt;&quot;DKE encrypted data isn&apos;t accessible at rest to Microsoft 365 services including Copilot&quot;&lt;/em&gt; [@ms-dke]. DKE is for the ~5% of content explicitly scoped that way; deploying it more broadly produces a tenant where every server-side feature degrades.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Trying to use PDE over RDP&lt;/em&gt;. &lt;em&gt;&quot;No, it&apos;s not supported to access protected content over RDP&quot;&lt;/em&gt; [@ms-pde-faq]. PDE binds to local Hello sign-in; a remote desktop session is not that.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Treating EFS as a current-generation solution on new devices&lt;/em&gt;. The Microsoft replacement for new per-file scenarios is PDE [@ms-pde-faq]. Leaving EFS in place for legacy files is fine; encrypting new files with EFS on a device that could run PDE is not the recommended path.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Audit checklist&lt;/h3&gt;
&lt;p&gt;Five commands and CSP queries that establish where each layer actually stands on a given device.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;BitLocker&lt;/em&gt;. Run &lt;code&gt;manage-bde -status&lt;/code&gt; (PowerShell, elevated). Look at the protection status, encryption method (XTS-AES 128 or 256), and key protectors. A TPM+PIN protector closes the pre-logon gap at the volume layer.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;EFS&lt;/em&gt;. Run &lt;code&gt;cipher.exe /C &amp;lt;file&amp;gt;&lt;/code&gt; to inspect the EFS attribute on a given file -- it prints the user SIDs and DRA SIDs that hold wrappers. Run &lt;code&gt;cipher.exe /U /N&lt;/code&gt; to enumerate every encrypted file on the volume without changing anything. The output tells you whether legacy EFS state actually exists.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;PDE -- top-level enablement&lt;/em&gt;. Query the CSP node &lt;code&gt;./User/Vendor/MSFT/PDE/EnablePersonalDataEncryption&lt;/code&gt;. A value of 1 means the PDE API surface is on; 0 (or absent) means it is off [@ms-pde-csp].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;PDE -- known folders&lt;/em&gt;. Query &lt;code&gt;./User/Vendor/MSFT/PDE/ProtectFolders/ProtectDesktop&lt;/code&gt;, &lt;code&gt;./User/Vendor/MSFT/PDE/ProtectFolders/ProtectDocuments&lt;/code&gt;, &lt;code&gt;./User/Vendor/MSFT/PDE/ProtectFolders/ProtectPictures&lt;/code&gt;. Note the &lt;code&gt;ProtectFolders&lt;/code&gt; parent node; the un-nested form will return nothing [@ms-pde-csp].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Purview labels&lt;/em&gt;. From Exchange Online PowerShell (after &lt;code&gt;Connect-IPPSSession&lt;/code&gt;), &lt;code&gt;Get-Label&lt;/code&gt; enumerates the sensitivity labels published in the tenant, including their encryption settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;what BitLocker on its own buys you&quot; table closes the audit out:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;BitLocker alone&lt;/th&gt;
&lt;th&gt;EFS adds&lt;/th&gt;
&lt;th&gt;PDE adds&lt;/th&gt;
&lt;th&gt;Purview label adds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Powered-off device at rest&lt;/td&gt;
&lt;td&gt;Protected&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Device on lock screen, post-boot pre-logon&lt;/td&gt;
&lt;td&gt;Plaintext to OS&lt;/td&gt;
&lt;td&gt;Plaintext (no logon)&lt;/td&gt;
&lt;td&gt;Encrypted, Hello-bound&lt;/td&gt;
&lt;td&gt;Encrypted, requires use license&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-user on the same device&lt;/td&gt;
&lt;td&gt;Plaintext to OS&lt;/td&gt;
&lt;td&gt;Per-user wrapping&lt;/td&gt;
&lt;td&gt;Per-Hello-user wrapping&lt;/td&gt;
&lt;td&gt;Per-policy wrapping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File emailed outside the tenant&lt;/td&gt;
&lt;td&gt;Plaintext&lt;/td&gt;
&lt;td&gt;Decrypted on SMB / cross-FS copy&lt;/td&gt;
&lt;td&gt;Plaintext on cross-protocol egress&lt;/td&gt;
&lt;td&gt;Encrypted, travels with file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The four layers map (loosely; this is not a regulatory opinion) to different regulatory expectations. BitLocker is the typical anchor for &quot;data at rest&quot; baselines in HIPAA, PCI DSS, and GDPR Article 32 (security of processing). Purview labels are where cross-organisation handling and Article 30 records-of-processing find a tractable enforcement story, because the policy travels with the data. PDE is the modern interpretation of &quot;user-bound access&quot; for shared devices and pre-logon scenarios. None of these regulatory frameworks names any specific layer; the practitioner&apos;s job is to map controls to expectations, not to ship a checklist of vendor features.
&lt;p&gt;{`
// Illustrative composition check. Given the per-layer status flags this device
// reports, identify which protection gaps remain. Run mentally over your device.&lt;/p&gt;
&lt;p&gt;function evaluateLayerCoverage(state) {
  const gaps = [];&lt;/p&gt;
&lt;p&gt;  if (!state.bitlockerEnabled) {
    gaps.push(&apos;BitLocker is OFF: volume is plaintext at rest&apos;);
  } else if (!state.bitlockerHasPIN) {
    gaps.push(&apos;BitLocker is on, but TPM-only: post-boot pre-logon window is open&apos;);
  }&lt;/p&gt;
&lt;p&gt;  if (!state.pdeEnabled) {
    gaps.push(&apos;PDE is OFF: per-user pre-logon and post-lock window not closed&apos;);
  } else if (!state.pdeKnownFoldersOn) {
    gaps.push(&apos;PDE enabled but no known-folder protection: user files not auto-encrypted&apos;);
  }&lt;/p&gt;
&lt;p&gt;  if (state.pdeEnabled &amp;amp;&amp;amp; state.efsLegacyFilesPresent) {
    gaps.push(&apos;Legacy EFS files coexist with PDE: mutually exclusive per file, migrate carefully&apos;);
  }&lt;/p&gt;
&lt;p&gt;  if (!state.purviewLabelsPublished) {
    gaps.push(&apos;No Purview labels published: no travels-with-file protection&apos;);
  }&lt;/p&gt;
&lt;p&gt;  if (state.dkeEverywhere) {
    gaps.push(&apos;DKE applied broadly: Microsoft 365 service-side processing will degrade&apos;);
  }&lt;/p&gt;
&lt;p&gt;  return gaps.length === 0
    ? &apos;Composition complete: all four layers configured with no obvious conflicts.&apos;
    : gaps;
}&lt;/p&gt;
&lt;p&gt;// Example: a modern Entra-joined Windows 11 24H2 Enterprise device with proper config.
const exampleDevice = {
  bitlockerEnabled: true,
  bitlockerHasPIN: true,
  pdeEnabled: true,
  pdeKnownFoldersOn: true,
  efsLegacyFilesPresent: false,
  purviewLabelsPublished: true,
  dkeEverywhere: false
};
console.log(evaluateLayerCoverage(exampleDevice));
`}&lt;/p&gt;

PowerShell (elevated) on the target device:&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;manage-bde -status C:
cipher.exe /C &quot;C:\Users\alice\Documents\sample.txt&quot;
# CSP queries via the Settings &amp;gt; Accounts &amp;gt; Access work or school export, or via
# the Intune CSP report for the device, against the nodes listed above.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From an Exchange Online PowerShell session:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Connect-IPPSSession
Get-Label | Format-Table -AutoSize
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Composed correctly, those layers give you the threat coverage no single layer can. But the practitioner still has questions.&lt;/p&gt;
&lt;h2&gt;11. Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;Five questions. Each addresses a misconception or operational concern the audit checklist exposes.&lt;/p&gt;

No. The two recovery models do not compose. BitLocker&apos;s recovery key unwraps the Volume Master Key against the TPM&apos;s seal; once the volume is unlocked, every plain NTFS file is readable again. PDE files sit *above* the volume layer, sealed by a DPAPI-NG protector bound to Windows Hello, not to the VMK. The PDE FAQ is explicit that PDE has no key-recovery model analogous to BitLocker&apos;s: *&quot;Personal Data Encryption doesn&apos;t have a requirement for a backup provider, including OneDrive in Microsoft 365. However, backups are recommended in case the keys used by Personal Data Encryption to protect files are lost&quot;* [@ms-pde-faq]. If the user&apos;s Hello credential is irrecoverably reset and there is no second-copy backup of the plaintext, BitLocker recovery does not help.

No -- not directly. EFS files are encrypted with a per-file symmetric File Encryption Key (FEK), which is RSA-wrapped to the user&apos;s EFS public key (and to one or more Data Recovery Agent public keys). The user&apos;s EFS RSA *private* key is stored in `%APPDATA%\Microsoft\Crypto\RSA\\` and is sealed by classic DPAPI from the user&apos;s logon secret [@wikipedia-efs]. So the password protects the *private key that unwraps the FEK*, not the file body. The Wikipedia EFS article puts the resulting ceiling sharply: any compromise of the user&apos;s password automatically leads to access to that data [@wikipedia-efs].

Partially. On Entra-joined Windows 11 22H2 or later devices with Windows Hello for Business, PDE is the recommended replacement for new per-file encryption scenarios, and Microsoft Learn states the mutual exclusion: PDE and EFS are mutually exclusive on the same file [@ms-pde-faq]. EFS continues to ship -- legacy `$EFS` files still decrypt, the Win32 API surface still works, Group Policy DRA configuration still functions [@ms-efs-win32]. PDE is the forward direction; EFS is the legacy slot. Plan for both during transition.

Labels are metadata. A *label that applies encryption* is metadata that triggers the Azure Rights Management service to encrypt the file with a per-content key and embed the wrapped key and policy reference in the file&apos;s wire format [@ms-purview-labels]. A label that applies only marking, watermarking, or DLP triggers is policy without encryption. The label itself is a classification; the encryption (if any) is a property attached to the label&apos;s settings.

Yes, with one caveat. The default modern composition for an Entra-joined Windows 11 24H2 Enterprise device is BitLocker (TPM+PIN) plus PDE (known-folder mode) plus a Purview sensitivity label that applies encryption [@ms-pde-faq] [@ms-purview-labels]. The caveat is the PDE / EFS mutual exclusion -- a given file is either PDE-wrapped or EFS-wrapped, not both [@ms-pde-faq]. So the rule is: BitLocker + (PDE OR EFS, mutually exclusive) + Purview label. That is the maximum legal composition.
&lt;p&gt;The answer the article opened with was the journey, not the destination. The destination is one sentence: three above-BitLocker layers, three protection-key roots, three threat models, by design. EFS exists because some files have to be unreadable to a different person sitting at the keyboard. PDE exists because some files have to be unreadable to the running OS itself, between boot and Hello sign-in. Purview labels exist because some files have to stay encrypted no matter which machine or protocol carries them next.&lt;/p&gt;
&lt;p&gt;When you next see a security document that asserts &quot;the data is protected because BitLocker is on,&quot; you now know exactly which threats that covers, and which it does not. The four roots compose. They do not compete. The asymmetry -- the very thing that makes the architecture look untidy from a distance -- is what lets each layer do what no other layer can.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;beyond-bitlocker-efs-pde-purview&quot; keyTerms={[
  { term: &quot;FEK&quot;, definition: &quot;File Encryption Key. The per-file symmetric key EFS uses to encrypt the file body; itself RSA-wrapped to each authorised principal.&quot; },
  { term: &quot;DRA&quot;, definition: &quot;Data Recovery Agent. A second principal whose public key is wrapped around the EFS FEK so the organisation can decrypt the file even if the user is unavailable.&quot; },
  { term: &quot;VMK&quot;, definition: &quot;Volume Master Key. The BitLocker key-encrypting key wrapping the Full Volume Encryption Key; sealed in the TPM against PCRs.&quot; },
  { term: &quot;CEK&quot;, definition: &quot;Content Encryption Key. The per-content symmetric key used by Azure Rights Management to encrypt a Purview-labelled document; embedded in the document, wrapped by the tenant root key.&quot; },
  { term: &quot;Use license&quot;, definition: &quot;A short-lived authorization artifact issued by Azure RMS to a specific authenticated user, granting decryption and policy-defined rights for a particular protected document.&quot; },
  { term: &quot;Protection descriptor&quot;, definition: &quot;The DPAPI-NG rule string that names the principal whose authentication will be required to unwrap a protected blob; supports SID, SDDL, LOCAL, WEBCREDENTIALS, and CERTIFICATE principal types.&quot; },
  { term: &quot;DKE&quot;, definition: &quot;Double Key Encryption. A two-key model in which Purview-protected content requires both an Azure-held key and a customer-on-premises-held key to decrypt; blinds Microsoft 365 service-side processing.&quot; },
  { term: &quot;classic DPAPI&quot;, definition: &quot;The original Windows Data Protection API; per-user wrapping derived from the user&apos;s logon secret. EFS depends on classic DPAPI to seal the user&apos;s EFS RSA private key.&quot; },
  { term: &quot;DPAPI-NG&quot;, definition: &quot;The Windows 8+ Data Protection API extension that supports cross-machine and identity-aware protectors via protection descriptors; PDE is built on this surface.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>bitlocker</category><category>encryption</category><category>personal-data-encryption</category><category>microsoft-purview</category><category>encrypting-file-system</category><category>dpapi</category><category>sensitivity-labels</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>DPAPI and DPAPI-NG: The Credential Vault Under Everything</title><link>https://paragmali.com/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/</link><guid isPermaLink="true">https://paragmali.com/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/</guid><description>A 25-year tour of Windows Data Protection API: the four-stage classic chain, the 2012 DPAPI-NG redesign, the KDS root key, and the five structural ceilings the design cannot close.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Classic DPAPI (Windows 2000, February 17, 2000 [@wikipedia-windows2000]) wraps every per-user Windows secret -- browser cookies, WiFi keys, EFS file keys, Outlook passwords, Credential Manager entries -- in a four-stage chain rooted at the user&apos;s password.** DPAPI-NG (Windows 8 / Server 2012) [@wikipedia-winserver2012] replaces the (user, machine) decryption boundary with a protection descriptor [@ms-protection-descriptors] and rides the Microsoft Key Distribution Service [@ms-gmsa-overview] to give every domain controller in the forest the same per-(group, period) key without inter-DC sync. Group Managed Service Accounts, delegated Managed Service Accounts [@ms-dmsa-overview], Windows Hello for Business on TPM-less devices, and Credential Guard&apos;s isolated-secret persistence all sit on top. The 2022-2025 Golden gMSA [@semperis-golden-gmsa], Golden dMSA [@semperis-golden-dmsa], and Chromium app-bound encryption [@thn-app-bound] disclosures all admit the same thing: DPAPI&apos;s structural ceilings (user-context binding, single-password derivation, KDS-root-key irrotability, hibernation, domain-backup-key concentration) are the design, not bugs.
&lt;h2&gt;1. A Thumb Drive, a Profile Directory, and Three Mimikatz Commands&lt;/h2&gt;
&lt;p&gt;A DFIR analyst slides a stolen laptop&apos;s drive into a write-blocker. The volume mounts because BitLocker&apos;s recovery key was already in the corporate KMS. Six files in &lt;code&gt;C:\Users\alice\AppData\Roaming\Microsoft\Protect\S-1-5-21-...&lt;/code&gt; -- five GUIDs and a &lt;code&gt;Preferred&lt;/code&gt; pointer -- are the only thing standing between the analyst and a decade of Alice&apos;s saved Windows secrets.&lt;/p&gt;
&lt;p&gt;Three Mimikatz [@mimikatz-dpapi-wiki] commands later (&lt;code&gt;dpapi::masterkey /in:&amp;amp;lt;GUID&amp;amp;gt; /sid:S-1-5-21-... /password:&amp;lt;known&amp;gt;&lt;/code&gt;, then &lt;code&gt;dpapi::cred /in:&amp;lt;credfile&amp;gt; /masterkey:&amp;lt;unwrapped&amp;gt;&lt;/code&gt;, then &lt;code&gt;dpapi::chrome /in:&quot;Login Data&quot;&lt;/code&gt;) the analyst has Alice&apos;s saved RDP password to the production jump host, her Microsoft 365 session cookie, the home WiFi PSK, the KeePass &quot;Windows User Account&quot; master password, and the EFS keys for her protected documents (each item is itemised with primary citations in §5&apos;s eleven-row credential-vault inventory). No kernel exploit. No live login. Just one (account-password, SID) pair recovered offline from last week&apos;s NTDS.dit backup.&lt;/p&gt;
&lt;p&gt;The trick that makes that scene possible is older than most working engineers. It shipped in Windows 2000 GA on February 17, 2000 [@wikipedia-windows2000], it has been the same shape for 25 years, and its single-secret design assumption has been public and tractable since February 3, 2010 [@bursztein-talk-page]. The trick has a name: the &lt;strong&gt;Data Protection API&lt;/strong&gt;, or DPAPI.&lt;/p&gt;
&lt;p&gt;This article walks the API end-to-end at the level of detail an academic survey would, but with the working-engineer&apos;s framing the topic deserves. We open the four-stage classic-DPAPI chain at the SHA-1-of-NT-hash-into-PBKDF2-with-the-SID-as-UTF-16LE-salt level. We open the 2012 DPAPI-NG redesign [@ms-cng-dpapi] and the Microsoft Key Distribution Service&apos;s L0/L1/L2 derivation chain [@ms-gkdi-landing] at the same level of precision.&lt;/p&gt;
&lt;p&gt;We name the four production consumers that ride the new chain in 2026: gMSAs, dMSAs, Windows Hello for Business [@ms-whfb-howitworks] software-KSP credentials, and Credential Guard [@paragmali-com-the-en]&apos;s isolated-secret persistence. We name the five structural ceilings the 2022 Golden gMSA [@semperis-golden-gmsa], 2024 Chromium app-bound encryption [@google-security-blog-app-bound], and 2025 Golden dMSA [@semperis-golden-dmsa] disclosures all admit out loud. And we close with what a 2026 practitioner -- developer, defender, red-teamer, platform engineer -- actually does with all of it.&lt;/p&gt;
&lt;p&gt;A note on adjacent topics: the companion &lt;em&gt;Credential Guard&lt;/em&gt; article in this series covers the LSAISO trustlet&apos;s isolation boundary; the companion &lt;em&gt;VBS Trustlets&lt;/em&gt; [@paragmali-com-secure-kernel] article covers the trustlet model itself; the &lt;em&gt;TPM in Windows&lt;/em&gt; [@paragmali-com-the-c] article covers TPM-bound key storage providers; the &lt;em&gt;BitLocker on Windows&lt;/em&gt; [@paragmali-com-limits-of] article covers full-volume encryption; the &lt;em&gt;NTLMless&lt;/em&gt; [@paragmali-com-in-windows] article covers Kerberoasting and Golden Ticket disambiguation. Where we touch those topics, we touch them briefly and refer out -- the goal here is to make DPAPI&apos;s chain legible from &lt;code&gt;CryptProtectData&lt;/code&gt; all the way to the four-phase &lt;code&gt;GoldenDMSA&lt;/code&gt; pipeline.&lt;/p&gt;
&lt;p&gt;If you can read those six files in Alice&apos;s &lt;code&gt;Protect&lt;/code&gt; directory and you have her password&apos;s SHA-1 hash, you have everything Windows ever encrypted for her. The next eleven sections explain why -- and why the 2012 redesign that was supposed to fix it produced a new ceiling that, by 2022, turned out to be even harder to live with.&lt;/p&gt;
&lt;h2&gt;2. Why Windows 2000 Needed a Credential Vault: Generation 0 and Generation 1&lt;/h2&gt;
&lt;p&gt;Three years before DPAPI shipped, an attacker with a logged-in user&apos;s session could read every Internet Explorer auto-complete password, every Outlook Express account password, every saved-FTP credential, and every dial-up RAS phonebook entry on the machine -- without breaking any cryptography. The late-1990s reversing tradition (the original &lt;code&gt;pwdump&lt;/code&gt;, &lt;em&gt;L0phtCrack&lt;/em&gt;, Cain &amp;amp; Abel&apos;s &quot;Protected Storage PassView,&quot; the ad-hoc Outlook Express and IE 4 form-fill stealers documented across Bugtraq and ntbugtraq mailing lists at the time) defeated all of it uniformly. The &quot;encryption&quot; applications used was honoured by the OS, faithfully, for the attacker&apos;s process as for the legitimate one -- because there was no system primitive that distinguished one from the other. Each application baked its own key into the binary; every reverser who pulled the binary apart pulled the key out with it.&lt;/p&gt;

The system-provided per-user and per-machine secret-storage primitive that ships in every Windows release from Windows 2000 onward [@wikipedia-dpapi]. The classic API surface is two flat-C functions -- `CryptProtectData` [@ms-cryptprotectdata] and `CryptUnprotectData` -- that take a plaintext, an optional caller entropy parameter, and return a self-contained opaque BLOB. The cryptographic chain inside those two functions is rooted at the user&apos;s login password and is what every &quot;encrypted&quot; Windows secret of the next 25 years sits on top of.
&lt;p&gt;If the attacker is the user&apos;s session, what does &quot;encrypt this for the user&quot; even mean? That is the question every Generation 0 design dodged and every modern credential-vault design has to answer head-on. The 1990s answer (XOR-with-a-baked-in-key) and Microsoft&apos;s first attempt at a real system primitive (Protected Storage / PStore) both missed the same point in different ways.&lt;/p&gt;
&lt;h3&gt;Generation 1: Protected Storage&lt;/h3&gt;
&lt;p&gt;Protected Storage shipped with Internet Explorer 4 and stayed in the OS until Microsoft formally deprecated it. The &lt;code&gt;pstore.dll&lt;/code&gt; [@ms-pstore] item taxonomy is a four-tuple &lt;code&gt;(Key, Type, Subtype, Name)&lt;/code&gt; -- a folder hierarchy of named secret entries. The API was the first system-level secret store on Windows that any application could use without writing its own key derivation; the conceptual contribution survived even after the implementation was abandoned.&lt;/p&gt;
&lt;p&gt;PStore had two ideas the post-Vista world kept and one it dropped. The two it kept: secrets live in a &lt;em&gt;system primitive&lt;/em&gt;, not in each application; secrets are addressed by &lt;em&gt;name&lt;/em&gt;, not by raw key handle. The one it dropped: an &lt;em&gt;Authenticode access-rule&lt;/em&gt; clause that would have bound a stored item to the signing identity of the application that created it. No application ever used the access-rule clause in production. Microsoft&apos;s developer notes are blunt about how the story ended: &lt;em&gt;&quot;Pstore uses an older implementation of data protection. Developers are strongly encouraged to take advantage of the stronger data protection provided by the &lt;code&gt;CryptProtectData&lt;/code&gt; [@ms-cryptprotectdata] and &lt;code&gt;CryptUnprotectData&lt;/code&gt; functions&quot;&lt;/em&gt;; PStore is &lt;em&gt;&quot;only available for read-only operations in Windows Server 2008 and Windows Vista, but may be unavailable in subsequent versions.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The PStore code-identity-pinning idea (Authenticode access rules) was abandoned in 2000 and re-invented twenty-six years later by Chromium 2024 app-bound encryption, which we will reach in §10.3.&lt;/p&gt;
&lt;h3&gt;What survived into DPAPI&lt;/h3&gt;
&lt;p&gt;The Generation 2 design that shipped with Windows 2000 in February 2000 made four moves at once. It kept the two PStore ideas worth keeping (&quot;system-level, not per-application&quot; and &quot;secret addressed by structured name&quot;). It dropped the unused Authenticode access-rule clause. It pushed the cryptographic chain down to a key derived directly from the user&apos;s login password. And it added a domain-recovery sidecar (the BackupKey Remote Protocol [@ms-bkrp-landing], which we open in §5) so managed enterprises would adopt it.&lt;/p&gt;
&lt;p&gt;The canonical first public design document [@learn-microsoft-com-versions-ms995355vmsdn10]) -- NAI Labs / Network Associates&apos; &lt;em&gt;&quot;Windows Data Protection&quot;&lt;/em&gt; whitepaper, MSDN ms995355, October 2001 -- is unambiguous about the layering: &lt;em&gt;&quot;DPAPI initially generates a strong key called a MasterKey, which is protected by the user&apos;s password. DPAPI uses a standard cryptographic process called Password-Based Key Derivation, described in PKCS #5, to generate a key from the password.&quot;&lt;/em&gt; And: &lt;em&gt;&quot;DPAPI is a password-based data protection service. It requires a password to provide protection.&quot;&lt;/em&gt;Some secondary sources attribute a &quot;Microsoft Windows Data Protection API&quot; whitepaper to Niels Ferguson at &lt;code&gt;niels.ferguson.com/research/dpapi.html&lt;/code&gt;. That URL has been TCP-unreachable for years, has zero Wayback captures across four candidate variants, and the Wikipedia &lt;em&gt;Niels Ferguson&lt;/em&gt; article [@wikipedia-niels-ferguson] lists no DPAPI publication for him -- his named Microsoft paper is the 2006 BitLocker / Elephant-diffuser paper, not anything DPAPI-related. The verifiable Microsoft-blessed first design document is the NAI Labs ms995355 whitepaper [@learn-microsoft-com-versions-ms995355vmsdn10]).&lt;/p&gt;
&lt;p&gt;The two-function flat-C API Microsoft shipped with Windows 2000 in February 2000 is what every Windows secret of the next 25 years has been encrypted with. The four-stage chain it hides behind those two function names is what we open up next.&lt;/p&gt;
&lt;h2&gt;3. The Four-Stage Chain: How &lt;code&gt;CryptProtectData&lt;/code&gt; Actually Encrypts&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;CryptProtectData&lt;/code&gt; [@ms-cryptprotectdata] call goes in with a plaintext buffer and an optional entropy parameter; out comes a self-contained opaque BLOB whose header adds roughly 100-150 bytes to the plaintext (the exact size depends on the algorithm choice and the master-key GUID encoding; the field-by-field BLOB layout is documented in the Bursztein-Picod 2010 paper [@bursztein-paper-pdf] and parsed by the Mimikatz &lt;code&gt;dpapi::blob&lt;/code&gt; [@mimikatz-dpapi-wiki] module). There is no &lt;code&gt;pszProvider&lt;/code&gt; argument, no &lt;code&gt;hKey&lt;/code&gt;, no algorithm choice exposed to the caller. Behind those two parameters is a four-stage cryptographic chain that has been the same shape for a quarter-century. Each stage takes the previous stage&apos;s output and one new input; the &lt;em&gt;only&lt;/em&gt; secret in the entire chain that an offline attacker has to guess is the user&apos;s password.&lt;/p&gt;

flowchart TD
    Password[&quot;User password&quot;] --&amp;gt; NTHash[&quot;NT hash&lt;br /&gt;(MD4 of UTF-16LE password)&quot;]
    NTHash --&amp;gt; Sha1NT[&quot;SHA-1(NT hash)&quot;]
    SID[&quot;User SID&lt;br /&gt;(UTF-16LE)&quot;] --&amp;gt; PBKDF2
    Sha1NT --&amp;gt; PBKDF2[&quot;Stage 1: PBKDF2&lt;br /&gt;(HMAC-SHA1 / HMAC-SHA512)&quot;]
    PBKDF2 --&amp;gt; PreKey[&quot;Pre-key&quot;]
    MK[&quot;Stage 2: Master key&lt;br /&gt;(64 random bytes)&quot;] --&amp;gt;|encrypted under| AESCBC[&quot;version-cipher wrap (AES-CBC on Win7+)&quot;]
    PreKey --&amp;gt; AESCBC
    AESCBC --&amp;gt; MKFile[&quot;%APPDATA%/Microsoft/Protect/&amp;lt;SID&amp;gt;/&amp;lt;GUID&amp;gt;&quot;]
    MK --&amp;gt; SessionKey[&quot;Stage 3: Session key&lt;br /&gt;HMAC(MK, salt || entropy)&quot;]
    SessionKey --&amp;gt; Wrap[&quot;Stage 4: BLOB wrap&lt;br /&gt;(3DES or AES-256, salt, HMAC)&quot;]
    Plaintext[&quot;Plaintext&quot;] --&amp;gt; Wrap
    Wrap --&amp;gt; Blob[&quot;DPAPI BLOB&quot;]
&lt;h3&gt;Stage 1: Pre-key derivation&lt;/h3&gt;
&lt;p&gt;The pre-key is a function of three values. The user-account password (or its NT-hash equivalent, supplied by &lt;code&gt;LSASS&lt;/code&gt; to the local DPAPI provider) is hashed with SHA-1; the SHA-1 result is fed into PBKDF2 as the input keying material; the user&apos;s security identifier (SID) [@learn-microsoft-com-versions-ms995355vmsdn10]) UTF-16LE-encoded is the salt; and a Windows-version-dependent iteration count completes the call. The output is a fixed-width pre-key that Stage 2 will use to wrap the master key.&lt;/p&gt;
&lt;p&gt;The chain has changed &lt;em&gt;parameters&lt;/em&gt; across Windows versions but has kept the four-stage &lt;em&gt;shape&lt;/em&gt; since 2000. The Passcape master-key analysis table [@passcape-master-key-analysis] records the migration verbatim:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Windows version&lt;/th&gt;
&lt;th&gt;Symmetric cipher&lt;/th&gt;
&lt;th&gt;HMAC&lt;/th&gt;
&lt;th&gt;PBKDF2 iterations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Windows 2000&lt;/td&gt;
&lt;td&gt;RC4&lt;/td&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows XP&lt;/td&gt;
&lt;td&gt;3DES&lt;/td&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;4 000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows Vista&lt;/td&gt;
&lt;td&gt;3DES&lt;/td&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;24 000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 7&lt;/td&gt;
&lt;td&gt;AES-256&lt;/td&gt;
&lt;td&gt;SHA-512&lt;/td&gt;
&lt;td&gt;5 600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 10 / 11&lt;/td&gt;
&lt;td&gt;AES-256&lt;/td&gt;
&lt;td&gt;SHA-512&lt;/td&gt;
&lt;td&gt;8 000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The shift from PBKDF2-HMAC-SHA1 / 3DES (Windows 2000 -- Vista) to PBKDF2-HMAC-SHA512 / AES-256 (Windows 7 onward) happened at Windows 7, not Windows 10; Bursztein and Picod&apos;s 2010 USENIX WOOT paper [@usenix-woot10] documented the SHA-1/3DES era through Windows 7 (the Black Hat DC 2010 talk and WOOT paper covered XP&apos;s 4,000-iteration regime and Vista&apos;s 24,000-iteration regime; Windows 7&apos;s PBKDF2-SHA512/AES-256 shift had only recently shipped when the research was finalised).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 8 000 iterations of HMAC-SHA-512 is not strong against a modern wordlist attack on a leaked NT hash. Cumulative updates can raise the iteration count further; the actual count is recorded in the master-key file&apos;s header and is not implicit. When you read someone&apos;s master key, read the iteration count from the file -- do not assume.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Stage 2: The master key&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;master key&lt;/em&gt; is a 64-byte cryptographically random secret; one is generated per user, on first use of DPAPI, and a fresh one is generated every 90 days by default. Master keys live as files inside &lt;code&gt;%APPDATA%\Microsoft\Protect\&amp;amp;lt;SID&amp;amp;gt;\&amp;amp;lt;GUID&amp;amp;gt;&lt;/code&gt;, where the GUID is the master-key identifier embedded in every BLOB that uses it. The file begins with a service header (containing the iteration count and algorithm IDs) followed by four distinct slots: (1) the user-master-key blob (encrypted under the Stage 1 pre-key with the version-dependent cipher -- RC4 on Windows 2000, 3DES on XP through Vista, AES-256-CBC on Windows 7 and later); (2) the local-encryption-key slot; (3) the local-backup-key (Windows 2000) or CREDHIST GUID (Windows XP and later); and (4) the domain-backup-key blob [@ms-bkrp-landing] (encrypted to the DC&apos;s backup public key, see §5).&lt;/p&gt;

A 64-byte random secret per user, persisted as a file under `%APPDATA%\Microsoft\Protect\&amp;lt;SID&amp;gt;\&amp;lt;GUID&amp;gt;`, encrypted under a pre-key derived from the user&apos;s password and SID. Every DPAPI BLOB the user ever creates is wrapped under a session key derived from one of these master keys. Master keys rotate every 90 days by default per the NAI Labs design document [@learn-microsoft-com-versions-ms995355vmsdn10]) and the Passcape master-key analysis [@passcape-master-key-analysis], but old master keys remain on disk so old BLOBs can still be decrypted.
&lt;h3&gt;Stage 3: The per-call session key&lt;/h3&gt;
&lt;p&gt;For every call to &lt;code&gt;CryptProtectData&lt;/code&gt;, DPAPI generates a fresh per-blob salt, computes an HMAC of the master key with the salt and the optional caller entropy, and uses that HMAC as the session key for the actual symmetric encryption. The session key is never stored; it is derivable from (master key, salt, entropy) at unwrap time per the Bursztein-Picod 2010 paper [@bursztein-paper-pdf] §3.3 and the Mimikatz &lt;code&gt;dpapi::blob&lt;/code&gt; parser [@mimikatz-dpapi-wiki]. The salt is in the BLOB header; the entropy, if any, must be supplied by the caller at unwrap time.&lt;/p&gt;
&lt;h3&gt;Stage 4: The BLOB wrap&lt;/h3&gt;
&lt;p&gt;The output BLOB is a self-describing structure with a fixed header. The provider GUID &lt;code&gt;{df9d8cd0-1501-11d1-8c7a-00c04fc297eb}&lt;/code&gt; identifies it as a classic-DPAPI blob; the master-key GUID names the master key under which it was wrapped; an &lt;code&gt;algCrypt&lt;/code&gt; algorithm identifier records which symmetric cipher was used (&lt;code&gt;0x6603&lt;/code&gt; for &lt;code&gt;CALG_3DES&lt;/code&gt; on legacy builds, &lt;code&gt;0x6610&lt;/code&gt; for &lt;code&gt;CALG_AES_256&lt;/code&gt; on later builds); the salt, ciphertext, and HMAC fill the rest. The Mimikatz &lt;code&gt;dpapi&lt;/code&gt; module wiki [@mimikatz-dpapi-wiki] documents the verbatim field layout that every offline DPAPI tool parses to this day.&lt;/p&gt;

The `algCrypt` field in the DPAPI BLOB header is a CryptoAPI algorithm identifier from `wincrypt.h`: `0x6603` is `CALG_3DES` (the historical default, encoded as `ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES`); `0x6610` is `CALG_AES_256` (used on Windows 7 and later, encoded as `ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256`). The provider GUID `{df9d8cd0-1501-11d1-8c7a-00c04fc297eb}` is the magic constant that marks every classic-DPAPI BLOB and is the same value the Mimikatz `dpapi::blob` module [@mimikatz-dpapi-wiki] and the Bursztein-Picod 2010 paper [@bursztein-paper-pdf] §3.3.1 print when they parse one.
&lt;p&gt;{`&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parse --&amp;gt; Cert&amp;amp;#123;&quot;CERTIFICATE=&quot;&amp;amp;#125;
Parse --&amp;gt; Local&amp;amp;#123;&quot;LOCAL=&quot;&amp;amp;#125;
Parse --&amp;gt; Web&amp;amp;#123;&quot;WEBCREDENTIALS=&quot;&amp;amp;#125;
Sid --&amp;gt; KSP[&quot;Microsoft Key Protection Provider&amp;lt;br/&amp;gt;+ kdssvc.dll [MS-GKDI]&quot;]
Cert --&amp;gt; CertKSP[&quot;Cert&apos;s KSP&amp;lt;br/&amp;gt;(TPM-backed possible)&quot;]
Local --&amp;gt; LocalProv[&quot;Microsoft Key Protection Provider&amp;lt;br/&amp;gt;(LOCAL=user / LOCAL=machine)&quot;]
Web --&amp;gt; Broker[&quot;Microsoft Client Key Protection Provider&amp;lt;br/&amp;gt;(credential broker)&quot;]
KSP --&amp;gt; Wrap
CertKSP --&amp;gt; Wrap
LocalProv --&amp;gt; Wrap
Broker --&amp;gt; Wrap
Wrap[&quot;Derive wrapping key,&amp;lt;br/&amp;gt;encrypt content&quot;] --&amp;gt; Blob[&quot;Self-describing blob&amp;lt;br/&amp;gt;(descriptor + provider info&amp;lt;br/&amp;gt;+ key id + ciphertext + HMAC)&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output blob is self-describing per the protected-data-format reference [@ms-protected-data-format]: descriptor, provider info, key identifier, ciphertext, HMAC. Any device with a CNG implementation that can satisfy the descriptor decrypts. There is no out-of-band key shipping. There is no &quot;encrypt the blob and ship the key separately.&quot; The descriptor &lt;em&gt;is&lt;/em&gt; the key-distribution policy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; DPAPI-NG separates &lt;em&gt;who can decrypt&lt;/em&gt; (the descriptor) from &lt;em&gt;where the key material lives&lt;/em&gt; (the provider). The descriptor is the contract; the provider is the implementation. This is the structural innovation that lets a blob protected on one machine be decrypted on another without any application-layer key-management code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The CNG DPAPI overview page lists only &lt;em&gt;two&lt;/em&gt; principal classes -- AD group and web credentials -- whereas the protection-descriptors page enumerates three (adding the certificate-store class). Both are correct: the certificate descriptor maps to a different provider, hence the two-principal framing on the higher-level overview page and the three-keyword framing on the descriptors-grammar page.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;LOCAL=user&lt;/code&gt; and &lt;code&gt;CERTIFICATE=&lt;/code&gt; cases are interesting but mostly variations on themes that classic DPAPI or the Windows certificate store could already do. The case that required Microsoft to ship a new DC-side daemon -- the case that turned DPAPI-NG into the substrate for gMSAs [@ms-gmsa-overview], dMSAs [@ms-dmsa-overview], Hello for Business, and Credential Guard&apos;s persistence layer -- is the &lt;code&gt;SID=&lt;/code&gt; AD-group descriptor. The next section opens its substrate: the Microsoft Key Distribution Service and the &lt;code&gt;[MS-GKDI]&lt;/code&gt; protocol.&lt;/p&gt;
&lt;h2&gt;7. The Microsoft Key Distribution Service: How &lt;code&gt;[MS-GKDI]&lt;/code&gt; Computes the Same Group Key on Every DC Without Talking to Any of Them&lt;/h2&gt;
&lt;p&gt;Imagine a forest with seven writable domain controllers. A laptop in Singapore protects a DPAPI-NG blob with &lt;code&gt;SID=S-1-5-21-...XYZ&lt;/code&gt; (some AD group). Three months later, a phone in Seoul -- a member of the same group, on a different DC -- needs to decrypt it. Neither DC has ever heard of the blob. Both DCs derive &lt;em&gt;exactly the same group key&lt;/em&gt; and hand it to the requesting member. No inter-DC synchronisation. No key-distribution code in either application. The mechanism is one forest-wide root key plus a deterministic key-derivation function.&lt;/p&gt;

The DC-side daemon that ships in every writable domain controller from Windows Server 2012 onward [@wikipedia-winserver2012]. Implements the [`[MS-GKDI]` Group Key Distribution Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a) (current revision class 10.0, April 2024) and is the substrate for every DPAPI-NG `SID=` blob, every gMSA password, every dMSA password, and the TPM-less software-KSP path of Windows Hello for Business. The service has one job: given a (group, time-period) request from a member computer, derive and return the per-(group, period) key from a single forest-wide root key.
&lt;h3&gt;Provisioning the root key&lt;/h3&gt;
&lt;p&gt;Every forest needs exactly one KDS root key before any DPAPI-NG &lt;code&gt;SID=&lt;/code&gt; consumer can use it. The PowerShell cmdlet &lt;code&gt;Add-KdsRootKey&lt;/code&gt; [@ms-add-kdsrootkey] is the provisioning entry point. The Microsoft Learn page is verbatim about the constraints: &lt;em&gt;&quot;The Add-KdsRootKey cmdlet generates a new root key for the Microsoft Group Key Distribution Service (KdsSvc) within Active Directory... It is required to run this only once per forest.&quot;&lt;/em&gt; The default &lt;code&gt;EffectiveTime&lt;/code&gt; is &lt;em&gt;&quot;10 days after the current date&quot;&lt;/em&gt; to allow Active Directory replication to converge across all writable DCs before any consumer tries to derive against the new key.The &lt;code&gt;Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10))&lt;/code&gt; override is for &lt;em&gt;single-DC test forests only&lt;/em&gt;. Production forests should let the 10-day default replicate; using the back-dated override means the first consumer to call into the KDS may target a DC that has not yet received the new root key from replication.&lt;/p&gt;
&lt;p&gt;The root key lives at &lt;code&gt;CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,&amp;lt;forest-DN&amp;gt;&lt;/code&gt; and carries four attributes that downstream offensive-research tools enumerate: &lt;code&gt;msKds-RootKeyData&lt;/code&gt; (the actual key bytes), &lt;code&gt;msKds-KDFAlgorithmID&lt;/code&gt; (the KDF identifier, currently SP800-108 HMAC-SHA512), &lt;code&gt;msKds-KDFParam&lt;/code&gt; (the KDF parameter block), and &lt;code&gt;msKds-PrivateKeyLength&lt;/code&gt;. These four attributes, together, are everything a deterministic-KDF derivation needs to recompute every group key the forest will ever produce.&lt;/p&gt;

The single forest-wide secret that anchors every per-(group, period) key the Microsoft Key Distribution Service will ever derive, for every DPAPI-NG `SID=` blob, every gMSA, every dMSA, every Hello-for-Business software-KSP container, and every Credential-Guard isolated-secret persistence wrap. Provisioned with `Add-KdsRootKey` [@ms-add-kdsrootkey], exactly once per forest. Stored as four attributes (`msKds-RootKeyData`, `msKds-KDFAlgorithmID`, `msKds-KDFParam`, `msKds-PrivateKeyLength`) under `CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,`. Currently, Microsoft documents no rotation procedure [@ms-cng-dpapi-backup-keys]; see §9.3.
&lt;h3&gt;The L0 / L1 / L2 derivation chain&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-GKDI]&lt;/code&gt; specification&lt;/a&gt; (current revision class 10.0, April 23 2024) describes the protocol. Internally, the KDS computes a three-level derivation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;L0 seed key&lt;/strong&gt;: derived from the root key and a label that includes the period-in-hours-thousands tier and the group-related input, via a NIST SP 800-108 KDF in counter mode using HMAC-SHA-512 (see NIST SP 800-108r1 [@nist-sp-800-108r1], August 2022).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L1 seed key&lt;/strong&gt;: derived from L0 with a second-tier label.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L2 seed key&lt;/strong&gt;: derived from L1 with the third-tier label. This is the actual symmetric key the DPAPI-NG blob&apos;s content key wraps under (or the seed for a per-period group ECDH key pair, in the public-key DPAPI-NG mode).&lt;/li&gt;
&lt;/ul&gt;

The first level of the [`[MS-GKDI]`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a) three-tier derivation chain. Computed deterministically from the KDS root key and a label that combines the time-period tier (in units of `period-in-hours / 1000`) and a group-related input. The whole point of the chain is that any DC that holds the same root key, given the same label, derives the same L0 seed key without coordination with any other DC -- which is also the whole reason a single root-key compromise compromises every key the forest will ever derive.

flowchart TD
    Root[&quot;KDS root key&lt;br /&gt;(forest-wide secret)&quot;] --&amp;gt; L0[&quot;L0 seed key&lt;br /&gt;(period_hours / 1000 + group input)&quot;]
    L0 --&amp;gt; L1[&quot;L1 seed key&lt;br /&gt;(second-tier label)&quot;]
    L1 --&amp;gt; L2[&quot;L2 seed key&lt;br /&gt;(third-tier label)&quot;]
    L2 --&amp;gt; Symmetric[&quot;Per-(group, period)&lt;br /&gt;symmetric key OR&lt;br /&gt;ECDH key-pair seed&quot;]
    KDF[&quot;SP800-108 counter-mode&lt;br /&gt;KDF, HMAC-SHA-512&quot;] -.derives.-&amp;gt; L0
    KDF -.derives.-&amp;gt; L1
    KDF -.derives.-&amp;gt; L2
&lt;h3&gt;The &lt;code&gt;GetKey&lt;/code&gt; round trip&lt;/h3&gt;
&lt;p&gt;A member computer&apos;s local KDS-NG provider calls the &lt;code&gt;GetKey&lt;/code&gt; RPC (the primary opnum of &lt;code&gt;[MS-GKDI]&lt;/code&gt;) against any reachable writable DC. The DC computes the L0/L1/L2 chain on demand and returns the per-(group, period) key material. No inter-DC synchronisation is needed because the KDF is deterministic.&lt;/p&gt;

sequenceDiagram
    participant Member as &quot;Member computer (Microsoft Key Protection Provider)&quot;
    participant DC as &quot;Nearest writable DC (kdssvc.dll)&quot;
    participant Root as Root key (AD-replicated)
    Member-&amp;gt;&amp;gt;DC: GetKey(group_sid, period_id)
    DC-&amp;gt;&amp;gt;Root: Read msKds-RootKeyData + KDF params
    Root--&amp;gt;&amp;gt;DC: Root-key material
    DC-&amp;gt;&amp;gt;DC: Compute L0(period, group) -&amp;gt; L1 -&amp;gt; L2
    DC--&amp;gt;&amp;gt;Member: Per-(group, period) key material
    Member-&amp;gt;&amp;gt;Member: Wrap (or unwrap) DPAPI-NG blob

Because the KDF is deterministic by design -- this is exactly the security property NIST SP 800-108r1 [@nist-sp-800-108r1] §5 establishes -- an attacker who reads the four root-key attributes once can derive every per-(group, period) key the KDS will ever produce, *for that root key*, without further DC interaction. The same property that lets a Singapore laptop and a Seoul phone derive the same key without talking to each other lets an attacker who reads the root key derive every gMSA password the forest will ever issue. This is the same property that makes Golden gMSA [@semperis-golden-gmsa] work in §10.
&lt;p&gt;Every DC in the forest runs the same &lt;code&gt;kdssvc.dll&lt;/code&gt; over the same root key with the same KDF; every authorised member of the named group can ask any DC for the per-(group, period) key and receive the same answer. The architecture is elegant. It is also, by structural necessity, the architecture that makes a one-shot read of the root key into a one-shot compromise of every key the forest will ever derive. Hold that thought; it is what §10 is built on. First we look at what actually rides on this substrate today.&lt;/p&gt;
&lt;h2&gt;8. The Four Things That Ride DPAPI-NG in 2026&lt;/h2&gt;
&lt;p&gt;One protocol, four production consumers. The same KDS root key that protects a &lt;code&gt;SID=&lt;/code&gt; DPAPI-NG blob is also the root from which every gMSA password, every dMSA password, every TPM-less Windows Hello private key, and every Credential Guard isolated NT-hash is derived.&lt;/p&gt;

A Windows-Server-2012-introduced Active Directory account class whose password is computed automatically by the Microsoft Key Distribution Service [@ms-gmsa-overview] on the DC, rotated every 30 days, 256 bytes long, and shared across multiple service hosts via the `msDS-GroupMSAMembership` SDDL gate. From the Microsoft Learn overview verbatim: *&quot;For a gMSA, the domain controller computes the password on the key that the Key Distribution Services provides, along with other attributes of the gMSA.&quot;* `Install-ADServiceAccount` on each member computer caches the derivation locally so the service can boot under the account.

flowchart TD
    Root[&quot;KDS root key&quot;] --&amp;gt; Chain[&quot;[MS-GKDI] L0/L1/L2 chain&quot;]
    Chain --&amp;gt; GMSA[&quot;gMSA password&lt;br /&gt;(30-day rotation,&lt;br /&gt;256 bytes)&quot;]
    Chain --&amp;gt; DMSA[&quot;dMSA password&lt;br /&gt;(machine-bound,&lt;br /&gt;Server 2025)&quot;]
    Chain --&amp;gt; WHfB[&quot;WHfB software-KSP&lt;br /&gt;(TPM-less devices,&lt;br /&gt;SID + device descriptor)&quot;]
    Chain --&amp;gt; CG[&quot;Credential Guard&lt;br /&gt;LsaIso-isolated secret&lt;br /&gt;(trustlet identity descriptor)&quot;]
&lt;h3&gt;8.1 Group Managed Service Accounts&lt;/h3&gt;
&lt;p&gt;gMSAs shipped in Windows Server 2012 (GA September 2012). The model: one AD account, multiple service hosts, no admin-managed password rotation, no per-service password file. The Microsoft Learn overview [@ms-gmsa-overview] is verbatim about the chain: &lt;em&gt;&quot;The Microsoft Key Distribution Service (kdssvc.dll) lets you securely obtain the latest key or a specific key with a key identifier for an Active Directory account... For a gMSA, the domain controller computes the password on the key that the Key Distribution Services provides, along with other attributes of the gMSA.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The constructed attribute that surfaces the password to authorised member computers is &lt;code&gt;msDS-ManagedPassword&lt;/code&gt; [@ms-ms-adts-managedpassword]; it is computed on demand by the DC from the KDS chain when an authorised member queries it. The authorisation gate is the &lt;code&gt;msDS-GroupMSAMembership&lt;/code&gt; security descriptor on the gMSA object: only principals whose SIDs satisfy that SDDL get the password back. Rotation is every 30 days. The password length is 256 bytes -- &lt;em&gt;&quot;a randomly generated password of 256 bytes, making it infeasible to crack&quot;&lt;/em&gt; per the Semperis Golden gMSA write-up [@semperis-golden-gmsa], which is true &lt;em&gt;if and only if&lt;/em&gt; the KDS root key is intact. We come back to that &lt;em&gt;if and only if&lt;/em&gt; in §10.&lt;/p&gt;
&lt;h3&gt;8.2 Delegated Managed Service Accounts&lt;/h3&gt;
&lt;p&gt;dMSAs shipped in Windows Server 2025 (GA November 1, 2024 [@wikipedia-winserver2025]). The same KDS chain; a different authorisation gate. Rather than binding to AD group membership, dMSA authentication binds to &lt;em&gt;machine identity&lt;/em&gt;: the Microsoft Learn overview [@ms-dmsa-overview] describes dMSAs as &lt;em&gt;&quot;a machine account with managed and fully randomized keys, while disabling original service account passwords. Authentication for dMSA is linked to the device identity, which means that only specified machine identities mapped in Active Directory (AD) can access the account.&quot;&lt;/em&gt; The &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; attribute carries a machine-binding component. Microsoft&apos;s marketing framing positions dMSA as the &quot;Kerberoast-immune&quot; replacement for static service accounts.&lt;/p&gt;
&lt;p&gt;The Server 2025 dMSA design has its own §10 footnote: the July 2025 Semperis Golden dMSA disclosure [@semperis-golden-dmsa] found that the &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; time-component has predictable structure with only ~1 024 plausible values, making offline brute-forcing tractable once the KDS root key is in hand.&lt;/p&gt;
&lt;h3&gt;8.3 Windows Hello for Business software-KSP credentials&lt;/h3&gt;
&lt;p&gt;The Hello for Business &lt;em&gt;how it works&lt;/em&gt; page [@ms-whfb-howitworks] describes the credential as a per-user per-device asymmetric key pair. On TPM-equipped devices the private key lives in the TPM and DPAPI-NG is not in the wrap path. On TPM-less devices (the structural worst case) the WHfB private key sits in a CNG software Key Storage Provider container persisted as a DPAPI-NG-protected file [@ms-whfb-howitworks] whose protection descriptor binds it to the user SID + device. The &lt;em&gt;TPM in Windows&lt;/em&gt; article in this series covers the TPM-bound case; here we record only that the software-KSP fallback rides on DPAPI-NG and inherits the KDS root-key dependency for the SID-bound branch.&lt;/p&gt;

A non-hardware-bound CNG key-storage provider that persists key material in DPAPI-NG-protected files in the user profile. Used by Windows Hello for Business on TPM-less devices [@ms-whfb-howitworks] and as the fallback when no hardware-bound KSP (TPM, smart card, Secure Enclave equivalent) is available. The structural worst case for the WHfB credential, because the private key lives in a file the OS can read in any user-context process, wrapped under a DPAPI-NG blob whose protection descriptor reduces back to the KDS root key for SID-anchored bindings.
&lt;h3&gt;8.4 Credential Guard isolated-secret persistence&lt;/h3&gt;
&lt;p&gt;The companion &lt;em&gt;Credential Guard&lt;/em&gt; article in this series covers &lt;code&gt;LsaIso.exe&lt;/code&gt; and the LSAISO trustlet&apos;s isolation boundary in depth; what matters here is that the trustlet&apos;s persistence layer is DPAPI-NG. &lt;code&gt;LsaIso.exe&lt;/code&gt;, running in VTL1 IUM, stores the isolated NT one-way function outputs and Kerberos session keys in DPAPI-NG blobs whose protection descriptor binds them to the trustlet&apos;s own identity. The VSM master key (TPM-bound on TPM-2.0 systems per Microsoft Learn&apos;s Credential Guard [@ms-credential-guard] overview, which describes how Credential Guard &quot;uses Virtualization-based security (VBS) [@ms-vbs] to isolate secrets&quot;) is what the trustlet seals its DPAPI-NG protection state under across reboots. The end result is that even though the Credential Guard model puts the credential outside &lt;code&gt;lsass.exe&lt;/code&gt;, the &lt;em&gt;persistence&lt;/em&gt; of that isolated secret rides on the same KDS-rooted DPAPI-NG chain every other consumer in this section uses.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Consumer&lt;/th&gt;
&lt;th&gt;Rotation&lt;/th&gt;
&lt;th&gt;Authorisation gate&lt;/th&gt;
&lt;th&gt;On-disk artefact&lt;/th&gt;
&lt;th&gt;Recovery story&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;gMSA&lt;/td&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msDS-GroupMSAMembership&lt;/code&gt; SDDL&lt;/td&gt;
&lt;td&gt;Cached on member via &lt;code&gt;Install-ADServiceAccount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recompute via KDS at any time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dMSA&lt;/td&gt;
&lt;td&gt;Managed by KDS&lt;/td&gt;
&lt;td&gt;Machine identity in AD&lt;/td&gt;
&lt;td&gt;Cached on member; &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; carries machine binding&lt;/td&gt;
&lt;td&gt;Recompute via KDS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WHfB software-KSP&lt;/td&gt;
&lt;td&gt;Per-credential lifetime&lt;/td&gt;
&lt;td&gt;User SID + device&lt;/td&gt;
&lt;td&gt;DPAPI-NG-wrapped key container in user profile&lt;/td&gt;
&lt;td&gt;New enrollment if lost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LsaIso DPAPI-NG persistence&lt;/td&gt;
&lt;td&gt;Boot-cycle bound&lt;/td&gt;
&lt;td&gt;Trustlet identity&lt;/td&gt;
&lt;td&gt;Trustlet-managed VTL1 store, sealed under VSM master key&lt;/td&gt;
&lt;td&gt;Re-derive on next logon&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Every shipping Windows credential primitive that &lt;em&gt;just works&lt;/em&gt; across multiple devices, multiple service hosts, or multiple cold-boot cycles -- without per-application key-management code -- is sitting on the same KDS root key. The architectural bet is that the root key never leaks. The next two sections are about what happens when it does.&lt;/p&gt;
&lt;h2&gt;9. The Five Structural Ceilings DPAPI Cannot Close&lt;/h2&gt;
&lt;p&gt;A reader who has followed the chain through §§3-8 has earned the right to a sharp question: where does this whole architecture &lt;em&gt;fail&lt;/em&gt;? Not where does it have bugs (it has very few cryptographic ones); where does the &lt;em&gt;design&lt;/em&gt; draw a line that no implementation patch can move? There are exactly five such lines.&lt;/p&gt;
&lt;h3&gt;9.1 The user-context ceiling&lt;/h3&gt;
&lt;p&gt;Any process running as the user can call &lt;code&gt;CryptUnprotectData&lt;/code&gt; [@ms-cryptprotectdata] or &lt;code&gt;NCryptUnprotectSecret&lt;/code&gt; [@ms-ncryptprotectsecret] against any blob the user could decrypt. The chain binds the secret to the &lt;em&gt;user identity&lt;/em&gt;, not the &lt;em&gt;consuming process identity&lt;/em&gt;. This is the structural reason every modern browser-cookie-stealer family (Lokibot, Vidar, RedLine, Lumma, StealC) works against DPAPI-protected Chrome state keys; it is also the reason Google introduced Chrome app-bound encryption [@thn-app-bound] in July 2024 &lt;em&gt;outside&lt;/em&gt; DPAPI. Will Harris of the Chrome security team is verbatim about why the patch had to live outside DPAPI rather than inside it: &lt;em&gt;&quot;On Windows, Chrome uses the Data Protection API (...). However, the DPAPI does not protect against malicious applications able to execute code as the logged in user -- which info-stealers take advantage of.&quot;&lt;/em&gt;&lt;/p&gt;

On Windows, Chrome uses the Data Protection API (DPAPI). However, the DPAPI does not protect against malicious applications able to execute code as the logged in user -- which info-stealers take advantage of.
-- Will Harris, Chrome security team, July 2024
&lt;h3&gt;9.2 The single-password-derivation ceiling&lt;/h3&gt;
&lt;p&gt;The classic-DPAPI master-key wrap is &lt;code&gt;PBKDF2-HMAC-SHA512(SHA1(NT-hash), SID-as-UTF16LE, ~8000 iterations)&lt;/code&gt; in the modern (Windows 10/11) era per the Passcape table [@passcape-master-key-analysis]. 8 000 iterations of HMAC-SHA-512 is not strong against a modern wordlist attack on a leaked NT hash. The structural limit is &lt;em&gt;the user&apos;s password&lt;/em&gt;, not the cryptographic primitive. The KDF parameter is tunable; the &lt;em&gt;single secret in the chain&lt;/em&gt; is not -- a strong password makes the chain strong, a weak password makes the chain weak, and there is no architectural way to recover from a weak password short of re-deriving every user&apos;s master key under a stronger one.&lt;/p&gt;
&lt;h3&gt;9.3 The KDS-root-key irrotability ceiling&lt;/h3&gt;
&lt;p&gt;Once a KDS root key is in production use, rotating it would invalidate every gMSA &lt;code&gt;msDS-ManagedPassword&lt;/code&gt;, every dMSA password, every &lt;code&gt;SID=&lt;/code&gt; blob, every Hello-for-Business software-KSP container, and every Credential-Guard isolated-secret blob ever produced under it. Microsoft&apos;s documented mitigation is &lt;em&gt;preventative&lt;/em&gt; (a system access control list on &lt;code&gt;msKds-RootKeyData&lt;/code&gt;), not recoverable. This is the same structural ceiling that the Microsoft Learn DPAPI-backup-keys page [@ms-cng-dpapi-backup-keys] admits for the older &lt;code&gt;[MS-BKRP]&lt;/code&gt; keys, in identical language: &lt;em&gt;&quot;There currently is no officially supported way of changing or rotating these DPAPI backup keys on the domain controllers.&quot;&lt;/em&gt; Burn-the-forest-and-rebuild for &lt;code&gt;[MS-BKRP]&lt;/code&gt;; SACL-the-attribute-and-hope for KDS root keys.&lt;/p&gt;
&lt;h3&gt;9.4 The hibernation / S4 ceiling&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CryptProtectMemory&lt;/code&gt; / &lt;code&gt;CryptUnprotectMemory&lt;/code&gt; [@ms-cryptprotectmemory] provide an in-memory scrub primitive that scopes a secret across same-process / cross-process / cross-session lifetimes. They cannot scrub RAM written to &lt;code&gt;hiberfil.sys&lt;/code&gt; on suspend-to-disk. On resume the master key is in plaintext in the page cache. The structural defence is BitLocker on the system volume (the &lt;em&gt;BitLocker on Windows&lt;/em&gt; article in this series covers full-volume encryption end-to-end); within DPAPI itself the ceiling cannot move because the OS has to be able to resume.&lt;/p&gt;
&lt;h3&gt;9.5 The domain-backup-key concentration ceiling&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-BKRP]&lt;/code&gt;&lt;/a&gt; backup key is the recoverability story for the password-reset case -- and it is &lt;em&gt;also&lt;/em&gt; the structural reason any DA who can dump LSASS on a writable DC has every user&apos;s master key in the forest. &lt;code&gt;mimikatz &quot;lsadump::backupkeys /system:dc.contoso.local /export&quot;&lt;/code&gt; is the canonical primitive, documented in the Mimikatz DPAPI wiki [@mimikatz-dpapi-wiki]. The architectural answer (HSM-backing the DC&apos;s RSA private key) is not in Microsoft&apos;s mainline guidance; the recommendation when these keys are compromised [@ms-cng-dpapi-backup-keys] is the burn-the-forest-and-rebuild line we just quoted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; These five ceilings are not bugs. They are the design&apos;s price for the design&apos;s other guarantees. The user-context ceiling buys ubiquitous adoption. The single-password ceiling buys a usable recovery path. The KDS-root-key ceiling buys cross-DC determinism. The hibernation ceiling buys process performance and resumability. The domain-backup-key ceiling buys enterprise recovery. Every one of the next five years&apos; DPAPI incidents will hit one of these five ceilings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The 2022-2025 disclosures are not five surprises. They are five different attackers naming five different ceilings out loud. The next section walks the named incidents one ceiling at a time.&lt;/p&gt;
&lt;h2&gt;10. The 2022-2025 Residual Class: Golden gMSA, Golden dMSA, and Chromium App-Bound Encryption&lt;/h2&gt;
&lt;p&gt;In March 2022, Yuval Gordon (Microsoft Security Researcher, via Semperis blog) published &lt;em&gt;Introducing the Golden GMSA Attack&lt;/em&gt; [@semperis-golden-gmsa] and the &lt;code&gt;GoldenGMSA&lt;/code&gt; [@goldengmsa-repo] C# tool. In July 2024, Google announced Chrome&apos;s app-bound encryption [@google-security-blog-app-bound]. In July 2025, Adi Malyanker (also Semperis) published &lt;em&gt;Golden dMSA: What Is dMSA Authentication Bypass?&lt;/em&gt; [@semperis-golden-dmsa] and the &lt;code&gt;GoldenDMSA&lt;/code&gt; [@goldendmsa-repo] tool, mirrored on PR Newswire with a July 16, 2025 dateline [@prnewswire-semperis-dmsa]. Three disclosures in three years, three different ceilings -- but the same underlying pattern: each one is an admission that the structural ceiling cannot be patched inside DPAPI.&lt;/p&gt;

flowchart LR
    C1[&quot;§9.1 user-context&quot;] --&amp;gt; Chromium[&quot;Chromium app-bound encryption&lt;br /&gt;(July 2024, Will Harris)&quot;]
    C2[&quot;§9.3 KDS-root-key irrotability&quot;] --&amp;gt; GGMSA[&quot;Golden gMSA&lt;br /&gt;(March 2022, Y. Gordon)&quot;]
    C2 --&amp;gt; GDMSA[&quot;Golden dMSA&lt;br /&gt;(July 2025, A. Malyanker)&quot;]
    C3[&quot;§9.5 domain-backup-key&quot;] --&amp;gt; MimikatzBKK[&quot;mimikatz lsadump::backupkeys&quot;]
    C4[&quot;§9.4 hibernation / S4&quot;] --&amp;gt; BL[&quot;BitLocker article cross-link&quot;]
&lt;h3&gt;10.1 Golden gMSA (Yuval Gordon, Microsoft / Semperis blog, March 2022)&lt;/h3&gt;
&lt;p&gt;Targets the §9.3 KDS-root-key irrotability ceiling. Gordon is verbatim about the two-step nature of the attack: &lt;em&gt;&quot;An attacker with high privileges can obtain all the ingredients for generating the password of any gMSA in the domain at any time with two steps: Retrieve several attributes from the KDS root key in the domain... Use the GoldenGMSA tool to generate the password of any gMSA associated with the key, without a privileged account.&quot;&lt;/em&gt; Step 1 is a one-shot read of the KDS root key attributes. Step 2 is offline derivation. There is no further DC interaction, ever, because the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-GKDI]&lt;/code&gt; chain is deterministic&lt;/a&gt; by NIST SP 800-108r1 design.&lt;/p&gt;
&lt;p&gt;The defensive answer is in the GoldenGMSA repository [@goldengmsa-repo]: &lt;em&gt;&quot;configure a SACL on the KDS root key objects for everyone reading the msKds-RootKeyData attribute. Once the system access control list (SACL) is configured, any attempt to dump the key data of a KDS root key will generate security event 4662 on the DC where the object type is msKds-ProvRootKey and the account name is not a DC.&quot;&lt;/em&gt; Plus the cross-trust SACL on &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; with property GUID &lt;code&gt;{0e78295a-c6d3-0a40-b491-d62251ffa0a6}&lt;/code&gt;. This is a &lt;em&gt;detective&lt;/em&gt; control, not a &lt;em&gt;recovery&lt;/em&gt; control. Once the root key has been read, every gMSA password the forest has ever issued or will ever issue under that root key is offline-derivable.&lt;/p&gt;

An attacker with high privileges can obtain all the ingredients for generating the password of any gMSA in the domain at any time with two steps.
-- Yuval Gordon, Microsoft / Semperis blog, March 2022
&lt;p&gt;The Golden gMSA SACL detects same-trust reads only. Cross-trust reads of &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; from a forest the auditing forest does not control are the documented detection blind-spot. If your gMSA-using forest has a one-way trust from a forest you do not own, you cannot see its reads.&lt;/p&gt;
&lt;h3&gt;10.2 Golden dMSA (Adi Malyanker, Semperis, July 2025)&lt;/h3&gt;
&lt;p&gt;Targets the §9.3 ceiling, plus a fresh dMSA-specific surface. Malyanker is verbatim about the structural flaw: &lt;em&gt;&quot;a critical design flaw: a structure that&apos;s used for the password-generation computation contains predictable time-based components with only 1,024 possible combinations, making brute-force password generation computationally trivial.&quot;&lt;/em&gt; The four-phase pipeline is enumerated in the GoldenDMSA repository [@goldendmsa-repo]: &lt;em&gt;&quot;Phase 1: Key Material Extraction (pre requirement of the attack) -- Dump the KDS Root Key from the DC. Phase 2: Enumerate dMSA accounts ... Phase 3: ManagedPasswordID guessing ... Phase 4: Password Generation.&quot;&lt;/em&gt; The tool exposes commands &lt;code&gt;wordlist&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;kds&lt;/code&gt;, &lt;code&gt;bruteforce&lt;/code&gt;, &lt;code&gt;compute&lt;/code&gt;, and &lt;code&gt;convert&lt;/code&gt; -- the operational vocabulary the four-phase pipeline needs.&lt;/p&gt;
&lt;p&gt;Semperis&apos; own rating is MODERATE with the explicit caveat &lt;em&gt;&quot;to exploit it, attackers must possess a KDS root key available only to only the most privileged accounts: root Domain Admins, Enterprise Admins, and SYSTEM.&quot;&lt;/em&gt; That is exactly the §9.3 ceiling re-stated. The novelty in dMSA is the 1 024-combination time-component flaw -- a design weakness on top of the structural ceiling, not a substitute for it.&lt;/p&gt;
&lt;h3&gt;10.3 Chromium app-bound encryption (Will Harris, Google Chrome, July 30, 2024)&lt;/h3&gt;
&lt;p&gt;Targets the §9.1 user-context ceiling. The Google Security Blog announcement [@google-security-blog-app-bound] describes a COM-elevation service that wraps the Chrome state key with both DPAPI &lt;em&gt;and&lt;/em&gt; a per-binary identity check the COM service enforces. The verbatim quote, mirrored via The Hacker News [@thn-app-bound]: &lt;em&gt;&quot;Because the app-bound service is running with system privileges, attackers need to do more than just coax a user into running a malicious app. Now, the malware has to gain system privileges, or inject code into Chrome, something that legitimate software shouldn&apos;t be doing.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The architecturally important word is &lt;em&gt;&quot;app-bound.&quot;&lt;/em&gt; Chromium&apos;s response &lt;em&gt;to the user-context ceiling&lt;/em&gt; lives outside DPAPI. DPAPI itself is unchanged. The 2024 patch is application-layer code-identity pinning -- exactly what Generation-1 Protected Storage&apos;s abandoned Authenticode-access-rule clause was supposed to be in 2000, exactly what Apple Keychain [@apple-platform-security-keychain] has shipped on macOS for over two decades, exactly what the §11 wishlist asks for.&lt;/p&gt;
&lt;h3&gt;10.4 The recurring pattern&lt;/h3&gt;
&lt;p&gt;Each disclosure does &lt;em&gt;not&lt;/em&gt; break a cryptographic primitive. Each is a re-statement of &quot;the design&apos;s ceiling is the design&apos;s ceiling.&quot; The defensive answers are &lt;em&gt;detection&lt;/em&gt; (SACL audit; cross-trust read alerting; binary-identity check) and &lt;em&gt;workaround at a higher layer&lt;/em&gt; (the COM-elevation service Chrome wraps DPAPI in), never &lt;em&gt;cryptographic strengthening of DPAPI itself&lt;/em&gt;. The 2026 reader&apos;s job is to recognise which ceiling each new incident hits.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Disclosure&lt;/th&gt;
&lt;th&gt;Ceiling hit&lt;/th&gt;
&lt;th&gt;Tool reference&lt;/th&gt;
&lt;th&gt;Defensive answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;Golden gMSA (Y. Gordon, Microsoft / Semperis blog)&lt;/td&gt;
&lt;td&gt;§9.3 KDS irrotability&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GoldenGMSA&lt;/code&gt; [@goldengmsa-repo]&lt;/td&gt;
&lt;td&gt;SACL on &lt;code&gt;msKds-RootKeyData&lt;/code&gt;; Event 4662&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;Chromium app-bound encryption (W. Harris, Google)&lt;/td&gt;
&lt;td&gt;§9.1 user-context&lt;/td&gt;
&lt;td&gt;Chrome 127 release notes [@chromereleases-127-stable]&lt;/td&gt;
&lt;td&gt;COM-elevation per-binary identity check, outside DPAPI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025&lt;/td&gt;
&lt;td&gt;Golden dMSA (A. Malyanker, Semperis)&lt;/td&gt;
&lt;td&gt;§9.3 + dMSA &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; predictability&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GoldenDMSA&lt;/code&gt; [@goldendmsa-repo]&lt;/td&gt;
&lt;td&gt;SACL plus monitoring &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; brute-force&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;By 2026 the pattern is clear: DPAPI&apos;s structural ceilings produce a steady drip of disclosures, each defensively answerable but none cryptographically fixable inside DPAPI itself. The open question is what the &lt;em&gt;successor&lt;/em&gt; would even look like -- and that is the next section.&lt;/p&gt;
&lt;h2&gt;11. Open Problems&lt;/h2&gt;
&lt;p&gt;A few sharp open problems remain at the design layer -- problems that a future Generation 4 of the credential-vault tradition would have to solve. None of them is in Microsoft&apos;s published roadmap as of 2026.&lt;/p&gt;
&lt;h3&gt;KDS root-key rotation&lt;/h3&gt;
&lt;p&gt;A hybrid wrap-then-re-wrap-on-first-decrypt-under-new-root scheme could in principle restore rotation without invalidating existing blobs: every consumer would carry a tag indicating which root-key generation last unwrapped it; on first unwrap under a generation-N+1 root the system would re-wrap the consumer-side cache. No standard or product implements this today; no public proposal revises &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-GKDI]&lt;/code&gt;&lt;/a&gt; to add it.&lt;/p&gt;
&lt;h3&gt;Code-identity pinning&lt;/h3&gt;
&lt;p&gt;Apple Keychain [@apple-platform-security-keychain] enforces &lt;em&gt;&quot;keychain items can be shared only between apps from the same developer ... enforced through code signing, provisioning profiles, and the Apple Developer Program.&quot;&lt;/em&gt; DPAPI / DPAPI-NG have no equivalent. A &lt;code&gt;CALLER_ATTRIBUTION=Publisher:&amp;lt;wdac-rule-hash&amp;gt;&lt;/code&gt; descriptor would, in principle, give Windows the same property -- the SHA-256 hash of the WDAC rule [@paragmali-com-app-ide] that authorises the calling binary, baked into the descriptor, checked at unwrap time. No one is shipping it. The 2024 Chromium app-bound encryption response [@thn-app-bound] is the application-layer workaround that proves the design gap is real.&lt;/p&gt;
&lt;h3&gt;Post-quantum migration&lt;/h3&gt;
&lt;p&gt;DPAPI-NG today uses RSA or ECDH key transport via CMS enveloped-content format (&lt;code&gt;CERTIFICATE=&lt;/code&gt; with RSA private keys, &lt;code&gt;SID=&lt;/code&gt; for group descriptors) per the protected-data-format [@ms-protected-data-format] reference. Both wrap algorithms are vulnerable to Shor&apos;s algorithm on a sufficiently large quantum computer, and the persistent on-disk blob format is the harvest-now-decrypt-later target -- a framing surfaced across NIST&apos;s broader post-quantum migration corpus, including the NIST PQC project page [@nist-pqc-project] and the linked NIST IR 8547 migration-timeline document. The migration story for the symmetric chain is comparatively easy (the SP800-108 KDF is parameterised; HMAC-SHA-512 has no quantum-cliff weakness for the relevant key sizes). The migration story for the public-key wrap is the hard part. NIST published FIPS 203 (ML-KEM) [@nist-fips-203] and FIPS 204 (ML-DSA) [@nist-fips-204] in August 2024; OpenSSH 9.9 [@openssh-9-9-release] (September 2024) and TLS deployments shipped hybrid post-quantum key exchange. Windows added experimental post-quantum TLS support in 2024 but has not yet announced ML-KEM CNG-DPAPI providers; see the companion &lt;em&gt;Post-Quantum Cryptography on Windows&lt;/em&gt; [@paragmali-com-year-migrati] article in this series for the broader Windows migration story. The shape that fits DPAPI&apos;s ceiling-laden design is hybrid wrap-then-re-wrap-on-first-decrypt: a hybrid wrap (&lt;code&gt;RSA-OAEP || ML-KEM&lt;/code&gt; or &lt;code&gt;ECDH || ML-KEM&lt;/code&gt;) -- protect under (RSA+ML-KEM) or (ECDH+ML-KEM) today; let consumers re-wrap to the new combiner on first unwrap; phase out the classical half on a long horizon -- is the only forward-compatible answer; Microsoft&apos;s published DPAPI-NG protection-providers [@ms-protection-providers] have not yet announced one.&lt;/p&gt;
&lt;h3&gt;Credential roaming for Entra-joined-only / unmanaged-device estates&lt;/h3&gt;
&lt;p&gt;Classic DPAPI&apos;s cross-device story has always been &quot;use roaming profiles&quot; (deprecated) or &quot;use the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-BKRP]&lt;/code&gt;&lt;/a&gt; backup key&quot; (admin-recovery, not user-driven). DPAPI-NG&apos;s &lt;code&gt;SID=&lt;/code&gt; solves it cleanly for AD-joined estates but the modern Entra-only estate has no native equivalent -- the &lt;code&gt;LOCAL=user&lt;/code&gt; descriptor is per-machine. An &lt;code&gt;ENTRAGROUP=&amp;lt;object-id&amp;gt;&lt;/code&gt; descriptor that resolved through Entra ID Token Service the way &lt;code&gt;SID=&lt;/code&gt; resolves through KDS would close the gap. No public roadmap announces this.&lt;/p&gt;
&lt;h3&gt;Hibernation / S4&lt;/h3&gt;
&lt;p&gt;BitLocker [@wikipedia-bitlocker] on the system volume defends the disk; suspending fully to ROM (or refusing S4 entirely) defends the in-RAM master key. Hardware-bound key derivation (TPM-released-only-while-PCRs-stable) would close more of the gap; the &lt;em&gt;TPM in Windows&lt;/em&gt; article in this series covers TPM-bound primitives that approximate this property.&lt;/p&gt;
&lt;p&gt;Every one of these is a &lt;em&gt;design&lt;/em&gt; gap -- a property the architecture would need a new primitive to satisfy. None is on Microsoft&apos;s announced roadmap. The architecture we have is the architecture we will have for at least the next five years; the practitioner&apos;s job is to know which ceilings their estate is exposed to and how to detect each of them.&lt;/p&gt;
&lt;h2&gt;12. Practical Guide and Closing&lt;/h2&gt;
&lt;p&gt;The four-audience guide for the 2026 practitioner.&lt;/p&gt;
&lt;h3&gt;12.1 For a developer&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;CryptProtectData&lt;/code&gt; / &lt;code&gt;CryptUnprotectData&lt;/code&gt; [@ms-cryptprotectdata] for per-user-on-this-device secrets. Pass &lt;code&gt;pOptionalEntropy&lt;/code&gt; to &lt;em&gt;bind&lt;/em&gt; the blob to a per-application secret -- but understand it is security-by-obscurity, not a code-identity check; any reader of the SharpDPAPI source [@sharpdpapi-readme] who knows your constant entropy can reproduce the unprotect call as the user.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;NCryptProtectSecret&lt;/code&gt; [@ms-ncryptprotectsecret] with the appropriate descriptor for cross-device or multi-principal cases. &lt;code&gt;LOCAL=user&lt;/code&gt; mirrors classic DPAPI on a single machine. &lt;code&gt;SID=&amp;lt;group-sid&amp;gt;&lt;/code&gt; reaches AD groups via KDS. &lt;code&gt;CERTIFICATE=HashID:&amp;lt;sha1&amp;gt;&lt;/code&gt; reaches a named certificate (TPM-backed for the high-security case). Use the WebAuthn / FIDO2 path for &lt;em&gt;authentication&lt;/em&gt; secrets; do not store passwords in DPAPI when WHfB / passkey paths are available.&lt;/p&gt;
&lt;p&gt;{`
// Returns the appropriate DPAPI-NG protection-descriptor string for a use case.
// Reference: learn.microsoft.com windows win32 seccng protection-descriptors
function descriptorFor(useCase, ctx) {
  switch (useCase) {
    case &quot;single-device-single-user&quot;:
      return &quot;LOCAL=user&quot;;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;case &quot;ad-group&quot;:
  // Multiple machines, AD-authorized group members can decrypt.
  return &quot;SID=&quot; + ctx.groupSid;

case &quot;tpm-backed-cert&quot;:
  // Decrypter must hold the named certificate&apos;s private key (TPM-bound KSP).
  return &quot;CERTIFICATE=HashID:&quot; + ctx.certThumbprintSha1;

case &quot;web-credential&quot;:
  // Resolves through the Windows credential broker.
  return &quot;WEBCREDENTIALS=&quot; + ctx.credName;

default:
  throw new Error(&quot;Unknown use case: &quot; + useCase);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  }
}&lt;/p&gt;
&lt;p&gt;console.log(descriptorFor(&quot;single-device-single-user&quot;));
console.log(descriptorFor(&quot;ad-group&quot;, { groupSid: &quot;S-1-5-21-...-5101&quot; }));
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;pOptionalEntropy&lt;/code&gt; parameter to &lt;code&gt;CryptProtectData&lt;/code&gt; lets you tag a blob with an extra secret the unwrap call must supply. It does not bind the blob to a process or a publisher. If your &quot;entropy&quot; is a constant compiled into your binary, every reverse-engineer who reads the binary can reproduce your unprotect call as the user. For real per-application separation today, use the Chromium 2024 pattern [@thn-app-bound]: wrap your DPAPI / DPAPI-NG blob in a SYSTEM-elevated COM service that enforces a per-binary identity check.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;12.2 For a defender or DFIR analyst&lt;/h3&gt;
&lt;p&gt;Triage the credential-vault inventory in §5 first. The high-value paths are &lt;code&gt;%APPDATA%\Microsoft\Protect\&amp;amp;lt;SID&amp;amp;gt;\&lt;/code&gt;, &lt;code&gt;%APPDATA%\Microsoft\Protect\CREDHIST&lt;/code&gt;, &lt;code&gt;%APPDATA%\Microsoft\Credentials\&lt;/code&gt;, &lt;code&gt;%LOCALAPPDATA%\Microsoft\Vault\&lt;/code&gt;, the Chromium / Edge profile databases, and the AD &lt;code&gt;CN=Master Root Keys,...&lt;/code&gt; container.&lt;/p&gt;
&lt;p&gt;The SACL guidance from the GoldenGMSA repository [@goldengmsa-repo] is the only detective control today: &lt;em&gt;&quot;configure a SACL on the KDS root key objects for everyone reading the msKds-RootKeyData attribute. Once the system access control list (SACL) is configured, any attempt to dump the key data of a KDS root key will generate security event 4662 on the DC where the object type is msKds-ProvRootKey and the account name is not a DC.&quot;&lt;/em&gt; Plus the cross-trust SACL on &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; with property GUID &lt;code&gt;{0e78295a-c6d3-0a40-b491-d62251ffa0a6}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tooling: Mimikatz [@mimikatz-dpapi-wiki] &lt;code&gt;dpapi::*&lt;/code&gt; modules, SharpDPAPI [@sharpdpapi-readme], DPAPIck [@bursztein-talk-page] (Bursztein-Picod 2010), GoldenGMSA [@goldengmsa-repo], GoldenDMSA [@goldendmsa-repo], and the Volatility [@volatility3-repo] &lt;code&gt;lsadump&lt;/code&gt; / &lt;code&gt;cachedump&lt;/code&gt; / &lt;code&gt;hashdump&lt;/code&gt; plugins for live-memory extraction of &lt;code&gt;DPAPI_SYSTEM&lt;/code&gt; and the other LSA secrets that seed SYSTEM-context master-key derivation.&lt;/p&gt;
&lt;p&gt;{`&lt;/p&gt;
Walk a synthetic profile-directory layout and emit a DPAPI-relevant triage report.
&lt;p&gt;import os
from collections import defaultdict&lt;/p&gt;
Synthetic profile layout for demonstration only.
&lt;p&gt;synthetic = {
    &quot;Users/alice/AppData/Roaming/Microsoft/Protect/S-1-5-21-1234-1001/Preferred&quot;: &quot;8KB&quot;,
    &quot;Users/alice/AppData/Roaming/Microsoft/Protect/S-1-5-21-1234-1001/0d4a...&quot;: &quot;740B&quot;,
    &quot;Users/alice/AppData/Roaming/Microsoft/Protect/CREDHIST&quot;: &quot;176B&quot;,
    &quot;Users/alice/AppData/Roaming/Microsoft/Credentials/abcdef...&quot;: &quot;300B&quot;,
    &quot;Users/alice/AppData/Local/Microsoft/Vault/4BF4C442-9B8A-41A0-B380-DD4A704DDB28/Policy.vpol&quot;: &quot;180B&quot;,
    &quot;Users/alice/AppData/Local/Google/Chrome/User Data/Default/Cookies&quot;: &quot;4MB&quot;,
    &quot;Users/alice/AppData/Local/Google/Chrome/User Data/Local State&quot;: &quot;12KB&quot;,
}&lt;/p&gt;
&lt;p&gt;categories = {
    &quot;Master keys&quot;:          &quot;/Microsoft/Protect/S-1-&quot;,
    &quot;CREDHIST chain&quot;:       &quot;/Protect/CREDHIST&quot;,
    &quot;Credential Manager&quot;:   &quot;/Microsoft/Credentials/&quot;,
    &quot;Windows Vault&quot;:        &quot;/Microsoft/Vault/&quot;,
    &quot;Chrome state key&quot;:     &quot;/Google/Chrome/User Data/Local State&quot;,
    &quot;Chrome cookies&quot;:       &quot;/Google/Chrome/User Data/Default/Cookies&quot;,
}&lt;/p&gt;
&lt;p&gt;report = defaultdict(list)
for path, size in synthetic.items():
    for label, marker in categories.items():
        if marker in path:
            report[label].append((path, size))&lt;/p&gt;
&lt;p&gt;for label, items in report.items():
    print(&quot;==&quot;, label)
    for path, size in items:
        print(&quot;  &quot;, path, &quot;(&quot; + size + &quot;)&quot;)
`}&lt;/p&gt;
&lt;h3&gt;12.3 For a red-team operator&lt;/h3&gt;
&lt;p&gt;The chain of primitives most-commonly used (verbatim from the harmj0y operational guide [@harmj0y-operational-guide] and the Mimikatz wiki [@mimikatz-dpapi-wiki]):&lt;/p&gt;

The operational vocabulary, in order of dependency:&lt;ol&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;sekurlsa::dpapi&quot;&lt;/code&gt; -- enumerate cached master keys from a live &lt;code&gt;lsass.exe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;dpapi::masterkey /in:&amp;lt;MK&amp;gt; /sid:&amp;amp;lt;SID&amp;amp;gt; /password:&amp;lt;known&amp;gt;&quot;&lt;/code&gt; -- unwrap a master-key file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;dpapi::cred /in:&amp;lt;credfile&amp;gt;&quot;&lt;/code&gt; -- decrypt a Credential Manager entry.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;lsadump::backupkeys /system:dc.contoso.local /export&quot;&lt;/code&gt; -- export the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-BKRP]&lt;/code&gt;&lt;/a&gt; RSA private key from a writable DC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SharpDPAPI triage /pvk:key.pvk&lt;/code&gt; -- offline triage with the domain backup key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SharpChrome cookies /pvk:key.pvk&lt;/code&gt; -- decrypt Chrome / Edge cookies offline.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GoldenGMSA gmsainfo&lt;/code&gt; then &lt;code&gt;GoldenGMSA compute -k &amp;lt;root-key-guid&amp;gt; -s &amp;lt;gmsa-sid&amp;gt; -m &amp;lt;managed-password-id&amp;gt;&lt;/code&gt; -- offline gMSA password derivation per the March 2022 disclosure [@semperis-golden-gmsa].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GoldenDMSA wordlist&lt;/code&gt; / &lt;code&gt;bruteforce&lt;/code&gt; / &lt;code&gt;compute&lt;/code&gt; -- the four-phase Server 2025 dMSA pipeline per the July 2025 disclosure [@semperis-golden-dmsa].&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;The post-Credential-Guard scope reality: LSASS-isolated NT-hashes are gone (the &lt;em&gt;Credential Guard&lt;/em&gt; article in this series covers what &lt;code&gt;LsaIso.exe&lt;/code&gt; actually computes); on-disk DPAPI master keys, Chrome cookies, and Vault credentials are still there. The credential-vault inventory in §5 is the operator&apos;s map; the §10 disclosure list is the operator&apos;s playbook.&lt;/p&gt;
&lt;h3&gt;12.4 For a platform or identity engineer&lt;/h3&gt;
&lt;p&gt;Provision the KDS root key carefully. Use the &lt;code&gt;Add-KdsRootKey&lt;/code&gt; [@ms-add-kdsrootkey] default 10-day &lt;code&gt;EffectiveTime&lt;/code&gt; for production forests so AD replication converges before any consumer derives against the new key; the &lt;code&gt;-EffectiveTime ((Get-Date).AddHours(-10))&lt;/code&gt; override is for single-DC test forests only, never production.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Golden gMSA defensive answer is detective, not preventive. Configure the &lt;code&gt;msKds-RootKeyData&lt;/code&gt; SACL &lt;em&gt;before&lt;/em&gt; any production gMSA exists, so every read of the root-key attributes generates Security Event 4662 and you have a baseline of &quot;DC accounts only, no humans, ever.&quot; Add the &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; cross-trust audit on day 1 too. After-the-fact SACL provisioning leaves a window during which the key may have been read silently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Server 2025 dMSA, monitor the &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; [@ms-ms-adts-managedpassword] brute-force surface until Microsoft addresses the time-component predictability the Golden dMSA disclosure [@semperis-golden-dmsa] named.&lt;/p&gt;
&lt;p&gt;For Hello for Business, prefer the TPM-bound KSP (&lt;code&gt;MS_PLATFORM_CRYPTO_PROVIDER&lt;/code&gt;); the software-KSP DPAPI-NG fallback [@ms-whfb-howitworks] is the structural worst case (per §8.3) and inherits the KDS root-key dependency on every TPM-less device.&lt;/p&gt;
&lt;p&gt;Cross-platform context: Apple Keychain [@apple-platform-security-keychain] reaches a stronger upper bound (Secure-Enclave-bound + code-identity-pinned via the Apple Developer Program); GNOME libsecret [@libsecret-reference] covers the analogous Linux primitive over the Secret Service D-Bus interface. Neither is a drop-in replacement; both have shapes worth borrowing if Microsoft ever publishes the Generation-4 design.&lt;/p&gt;
&lt;h3&gt;12.5 The closing reflection&lt;/h3&gt;
&lt;p&gt;The credential vault under everything has a single-sentence summary in 2026: classic DPAPI is as strong as the user&apos;s password; DPAPI-NG is as strong as the KDS root key&apos;s life-cycle SOP is; both architectures admit ceilings the cryptography cannot move. The literacy a practitioner needs is the ability to recognise which ceiling any new incident hits. Twelve sections later, you have it.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;

No. Credential Guard [@ms-credential-guard] protects LSA-isolated secrets only. Chrome cookies live in the user&apos;s profile under DPAPI / DPAPI-NG and are decryptable by any process running as the user, exactly as before. The Chromium 2024 app-bound encryption [@thn-app-bound] is a per-process workaround for the §9.1 user-context ceiling, not a fix inside DPAPI itself.

A web reset of a *consumer* Microsoft Account password does not append to CREDHIST and does not benefit from [`[MS-BKRP]`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/) backup -- there is no domain in the consumer scenario. Master keys encrypted under the previous password become irrecoverable for consumer Microsoft Accounts, full stop. Domain-joined enterprise users escape this because the domain backup key still works.

True if the KDS root key [@ms-add-kdsrootkey] is intact -- the Semperis write-up [@semperis-golden-gmsa] records the *&quot;randomly generated password of 256 bytes, making it infeasible to crack&quot;* claim. False under the Golden gMSA / Golden dMSA [@semperis-golden-dmsa] assumption that any DA / SYSTEM on a DC can read `msKds-RootKeyData`. A 256-byte random password is irrelevant if the attacker can derive it offline.

No. DPAPI-NG [@ms-cng-dpapi] is a redesign whose protection model is *descriptor-based* (multi-principal, multi-device) rather than *user-and-machine-bound*. The two APIs coexist; classic DPAPI is still the default for `CryptProtectData` [@ms-cryptprotectdata] callers, and DPAPI-NG is the path for `NCryptProtectSecret` [@ms-ncryptprotectsecret] callers.

No. On TPM-less devices the WHfB private key sits in a CNG software-KSP container persisted as a DPAPI-NG blob whose protection descriptor binds it to user SID + device, per the Hello for Business architecture [@ms-whfb-howitworks]. The TPM-bound case is the preferred deployment; the software-KSP fallback is the structural worst case and inherits the §9.3 KDS root-key dependency.

No. `CryptProtectMemory` [@ms-cryptprotectmemory] scrubs in-memory secrets between same-process / cross-process / cross-session lifetimes but cannot prevent the OS from writing the page-protected RAM into `hiberfil.sys` on suspend-to-disk. BitLocker on the system volume is the structural defence (the *BitLocker on Windows* article in this series covers full-volume encryption end-to-end).

No. It broke the *secrecy of DPAPI&apos;s design*. The 2010 disclosure [@usenix-woot10] made the master-key chain public and tractable for offline forensics; it did not weaken the cryptography. The &quot;break&quot; was always structural -- DPAPI is as strong as the user&apos;s password is. The two-author byline is Bursztein and Picod (Black Hat DC 2010, USENIX WOOT 10), not &quot;Bursztein, Picod and Aussel.&quot;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;dpapi-and-dpapi-ng-the-credential-vault-under-everything&quot; keyTerms={[
  { term: &quot;DPAPI&quot;, definition: &quot;The Data Protection API; the per-user / per-machine secret-storage primitive in every Windows release from Windows 2000 onward.&quot; },
  { term: &quot;Master key&quot;, definition: &quot;A 64-byte random secret per user, stored under %APPDATA%/Microsoft/Protect/&amp;lt;SID&amp;gt;/&amp;lt;GUID&amp;gt;, encrypted under a pre-key derived from the user&apos;s password and SID.&quot; },
  { term: &quot;[MS-BKRP] BackupKey Remote Protocol&quot;, definition: &quot;The LSASS-hosted RPC interface that lets a member computer dual-wrap its master key under both the user password pre-key and a DC RSA backup public key; the canonical universal-decryption primitive available to Domain Admins.&quot; },
  { term: &quot;CREDHIST&quot;, definition: &quot;The previous-password hash chain stored in %APPDATA%/Microsoft/Protect/CREDHIST; one entry per self-initiated password change; broken by administrative reset and consumer-Microsoft-Account web reset.&quot; },
  { term: &quot;Protection descriptor (DPAPI-NG)&quot;, definition: &quot;The DPAPI-NG self-describing string (SID, SDDL, LOCAL, WEBCREDENTIALS, CERTIFICATE) that names the set of principals permitted to remove protection from a blob.&quot; },
  { term: &quot;Microsoft Key Distribution Service (kdssvc.dll)&quot;, definition: &quot;The DC-side daemon that implements the [MS-GKDI] protocol and computes per-(group, period) keys deterministically from a single forest-wide root key.&quot; },
  { term: &quot;KDS root key&quot;, definition: &quot;The single forest-wide secret that anchors every per-(group, period) key the KDS will ever derive; provisioned exactly once per forest with Add-KdsRootKey; documented as having no rotation procedure.&quot; },
  { term: &quot;Group Managed Service Account (gMSA)&quot;, definition: &quot;A Server-2012-introduced AD account whose 256-byte password is derived from the KDS chain and rotated every 30 days, gated by the msDS-GroupMSAMembership SDDL.&quot; },
  { term: &quot;Software KSP&quot;, definition: &quot;The non-hardware-bound CNG Key Storage Provider that persists key material as DPAPI-NG-protected files; used as the WHfB fallback on TPM-less devices.&quot; },
  { term: &quot;Golden gMSA / Golden dMSA&quot;, definition: &quot;The 2022 / 2025 Semperis offline-derivation attacks that compute any gMSA / dMSA password the forest will ever issue, given a one-shot read of the four KDS root-key attributes.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>dpapi</category><category>dpapi-ng</category><category>kds</category><category>gmsa</category><category>credential-guard</category><category>mimikatz</category><category>golden-gmsa</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Edge&apos;s Two Password Cryptographies: A Beautiful PSI on the Wire, and Plaintext RAM by Design</title><link>https://paragmali.com/blog/edge-two-password-cryptographies/</link><guid isPermaLink="true">https://paragmali.com/blog/edge-two-password-cryptographies/</guid><description>Microsoft Edge ships a homomorphic-encryption PSI for breach checking and decrypts every saved password into process RAM at launch. Both designs are deliberate. They defend different threat models.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
Microsoft Edge ships two cryptographic designs for &quot;passwords&quot; inside the same `msedge.exe` binary, owned by the same product team, with radically different threat models. The first -- Password Monitor -- is a deployed Private Set Intersection protocol built on Microsoft SEAL, the first production consumer homomorphic-encryption deployment in a browser, and is state-of-the-art cryptography for defending against a compromised breach-corpus server. The second -- Edge&apos;s local credential storage -- decrypts every saved password into process memory at browser launch and keeps it there for the lifetime of the session, a design Tom Joran Sonstebyseter Ronning&apos;s `EdgeSavedPasswordsDumper` (May 4, 2026) made legible and that Microsoft classified as &quot;by design.&quot; These are not incompatible designs. They are precise statements about which threat models the Edge product team is and is not defending against, and treating them as one unified &quot;password security&quot; story masks where the actual compromise happens in 2026.
&lt;h2&gt;1. Two cryptographies, one product, one week&lt;/h2&gt;
&lt;p&gt;On &lt;strong&gt;January 21, 2021&lt;/strong&gt;, Microsoft Research&apos;s Cryptography and Privacy group announced Edge&apos;s Password Monitor ships a homomorphic-encryption-based Private Set Intersection protocol built on Microsoft SEAL. The post is explicit that this is &quot;possible due to pioneering cryptography research and technology incubation done here at Microsoft Research,&quot; that it is the result of a collaboration &quot;between [the] Cryptography and Privacy Research Group, and Edge product team,&quot; and that the protocol descends from two specific papers: &quot;Fast Private Set Intersection from Homomorphic Encryption&quot; and &quot;Labeled PSI from Fully Homomorphic Encryption with Malicious Security&quot; [@msr-password-monitor-2021]. It is, by a comfortable margin, the first production consumer deployment of homomorphic encryption in a browser.&lt;/p&gt;
&lt;p&gt;On &lt;strong&gt;May 4, 2026, at 14:29:51 UTC&lt;/strong&gt;, a researcher in Oslo named Tom Joran Sonstebyseter Ronning posted to X: &quot;Microsoft Edge loads all your saved passwords into memory in cleartext -- even when you&apos;re not using them&quot; [@ronning-x]. He linked a GitHub repository called &lt;code&gt;EdgeSavedPasswordsDumper&lt;/code&gt;: roughly 230 lines of C# that opens a handle to the parent &lt;code&gt;msedge.exe&lt;/code&gt; process and reads every saved credential as plaintext, with no kernel exploit, no admin (against same-user processes), and no &lt;a href=&quot;https://paragmali.com/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/&quot; rel=&quot;noopener&quot;&gt;DPAPI&lt;/a&gt; bypass [@ronning-github]. The README confirms the behaviour is present in &quot;any Edge versions that&apos;s Chromium based (from version 79 and newer, including 147.0.3912.98 and any future version)&quot; [@ronning-github]. Two days later, on &lt;strong&gt;May 6, 2026&lt;/strong&gt;, Microsoft told Forbes that the in-memory behaviour is &quot;an expected feature of the application&quot; and &quot;by design&quot; [@forbes-winder].&lt;/p&gt;
&lt;p&gt;Both designs ship in the same binary. Both are owned by the same product team. Both can be defended on technical grounds. And both stories get told about the same word: &quot;passwords.&quot;&lt;/p&gt;
&lt;p&gt;This article argues they are about two different threat models, and the apparent contradiction in the headline disappears once you separate them.&lt;/p&gt;

A two-party cryptographic protocol in which Alice holds a set $S_A$, Bob holds a set $S_B$, and they jointly compute $S_A \cap S_B$ such that each party learns the intersection (or, in some variants, only one party does) and nothing else about the other party&apos;s set beyond what the intersection implies.
&lt;p&gt;The PSI story is genuinely beautiful. It begins in 1986 with a paper hardly anyone reads, climbs through a 35-year cryptographic engineering effort to make oblivious transfer cheap enough to be free, lands in 2017 on a homomorphic-encryption breakthrough whose cost curve fits the breach-checking problem exactly, and ships on consumers&apos; desktops by 2021 [@msr-password-monitor-2021]. The endpoint-storage story is genuinely awkward. Edge unwraps every DPAPI-encrypted saved credential into process memory when the password feature first activates, keeps the plaintext resident for the lifetime of the session, and accepts that any same-user process can read it back out [@ronning-github]. Microsoft&apos;s official position is that local code execution on the user&apos;s machine is &quot;outside the threat model&quot; of the browser password store -- a position that is internally consistent with a decade of MSRC policy and also true [@forbes-winder].&lt;/p&gt;
&lt;p&gt;The thesis: &lt;strong&gt;&quot;password security&quot; is at least two threat models&lt;/strong&gt;, and Microsoft has chosen to deploy genuinely state-of-the-art cryptography against one of them while explicitly conceding the other. Treating both as one unified story is how product narratives obscure where the actual compromise happens in 2026.&lt;/p&gt;

timeline
    title PSI and browser credential storage, 1986 to 2026
    1986 : Meadows PSI
         : NRL matchmaking
    1999 : Huberman-Franklin-Hogg
         : DH meet-in-the-middle
    2003 : IKNP03 OT extension
    2004 : FNP04 polynomial PSI
    2015 : KOS15 active security
    2016 : KKRT16 OPRF-PSI
    2017 : CLR17 HE-PSI
         : Signal SGX contact discovery
    2018 : CHLR18 Labeled PSI
         : HIBP v2 k-anonymity
    2019 : Google Password Checkup
         : Silent OT
    2021 : Edge Password Monitor ships
         : Cong et al. CCS 2021
    2024 : Chrome App-Bound Encryption
    2026 : Ronning EdgeSavedPasswordsDumper
         : Microsoft &quot;by design&quot;
&lt;p&gt;To see why the two designs are not a contradiction, we need to understand how PSI got to be deployable at all -- a story that begins thirty-five years before Edge Password Monitor existed.&lt;/p&gt;
&lt;h2&gt;2. Why Private Set Intersection exists at all&lt;/h2&gt;
&lt;p&gt;Imagine two parties, neither of whom trusts the other. Alice has a set of identifiers; Bob has a set of identifiers. They want to learn which identifiers they share -- and only that. Each party wants to learn nothing about elements not in the intersection.&lt;/p&gt;
&lt;p&gt;This is not an obvious problem to need a protocol for. If Alice and Bob trusted a third party, they would hand over their sets. If they trusted each other, they would compare directly. The problem only becomes interesting when neither assumption holds. The 2026 canonical version looks like this: &lt;em&gt;Microsoft holds a curated set of roughly five billion breached credentials, and the user holds a few hundred passwords saved in their browser. The user wants to know which of their passwords appear in Microsoft&apos;s breach corpus -- and they want Microsoft to learn nothing about the passwords that do not.&lt;/em&gt; (Throughout this article the &quot;five billion&quot; figure is the author&apos;s 2026 forward projection of Microsoft&apos;s compromised-credential corpus; the contemporaneous Microsoft Research figure used in the 2021 Password Monitor announcement is four billion [@msr-password-monitor-2021], and the §3 sidenote spells out the inference.)&lt;/p&gt;
&lt;p&gt;That framing did not exist in 1986. The original motivation was much weirder.&lt;/p&gt;
&lt;h3&gt;The 1986 paper&lt;/h3&gt;
&lt;p&gt;Catherine Meadows, then at the U.S. Naval Research Laboratory, published &quot;A More Efficient Cryptographic Matchmaking Protocol for Use in the Absence of a Continuously Available Third Party&quot; at the 1986 IEEE Symposium on Security and Privacy [@meadows-1986][@ieee-6234864]. The titular &quot;matchmaking&quot; problem was prosaic. Two parties want to learn whether they share an interest in some sensitive list -- classified-mailing-list membership, intelligence-source overlap, the everyday work of compartmented information systems -- without revealing anything else.&lt;/p&gt;
&lt;p&gt;Meadows&apos;s protocol uses commutative encryption. Alice and Bob both raise the elements of their sets to private exponents over a Diffie-Hellman group. After two rounds, both parties hold the doubly-blinded versions of both sets. Equal underlying elements produce equal doubly-blinded values, because exponentiation in an Abelian group commutes. Unequal elements look like uniform-random group elements to both sides. The intersection comes out; the rest does not.&lt;/p&gt;
&lt;p&gt;Meadows wrote this ten years before Diffie-Hellman key exchange shipped in SSL 3.0 (November 1996), the protocol family TLS would standardise in 1999 [@wikipedia-tls], and thirty-five years before her protocol&apos;s intellectual descendants would ship in a consumer browser.&lt;/p&gt;
&lt;h3&gt;The 1999 revival&lt;/h3&gt;
&lt;p&gt;The same protocol shape was rediscovered and given its modern formulation by Bernardo Huberman, Matthew Franklin, and Tad Hogg at Xerox PARC in 1999. Their paper &quot;Enhancing Privacy and Trust in Electronic Communities&quot; was published at the First ACM Conference on Electronic Commerce [@hfh-1999]. The motivations were online-community problems that look quaint today: which of your friends are on this matchmaking site, do we share interests on a sensitive bulletin board, can two early-internet communities establish trust without leaking their member lists. The protocol they wrote down -- usually called &quot;DH meet-in-the-middle&quot; or just &quot;the Huberman-Franklin-Hogg protocol&quot; -- is the canonical PSI shape every security engineer still reaches for first.The dblp BibTeX record gives the canonical DOI as 10.1145/336992.337012, which the ACM Digital Library 403s to most non-browser User-Agents. The dblp HTML mirror returns 200 and confirms the citation [@dblp-hfh].&lt;/p&gt;
&lt;h3&gt;What had to exist before&lt;/h3&gt;
&lt;p&gt;PSI predates breach checking by twenty years. The cryptographers who built PSI did not know they were building Edge Password Monitor. They were building a protocol primitive that happened, much later, to map cleanly onto a problem the world did not yet have.&lt;/p&gt;
&lt;p&gt;The first such mapping landed in 2018 with HIBP&apos;s k-anonymity API and the cluster of academic and industry PSI deployments that followed [@hunt-pwned-v2-2018]. The primitive predated the killer application by two and a half decades. This is the normal shape of cryptographic engineering: the primitive sits on the shelf until the world needs it.&lt;/p&gt;
&lt;p&gt;The DH meet-in-the-middle protocol is elegant. It is also catastrophically wrong for the breach-checking use case. To see why, we have to count exponentiations.&lt;/p&gt;
&lt;h2&gt;3. Early approaches: DH meet-in-the-middle and FNP04&lt;/h2&gt;
&lt;p&gt;Let us walk the DH meet-in-the-middle protocol step by step. Alice holds a set $S_A$. Bob holds a set $S_B$. Both parties agree on a Diffie-Hellman group $G$ of prime order $q$ with generator $g$, and on a cryptographic hash function $H: {0,1}^* \to G$ that maps set elements into the group. Alice picks a private exponent $a \in \mathbb{Z}_q$; Bob picks $b$.&lt;/p&gt;
&lt;p&gt;The protocol proceeds in two rounds:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Alice computes ${H(x)^a : x \in S_A}$, shuffles, and sends to Bob.&lt;/li&gt;
&lt;li&gt;Bob computes ${H(y)^b : y \in S_B}$, shuffles, and sends to Alice.&lt;/li&gt;
&lt;li&gt;Alice exponentiates every value Bob sent her by $a$, producing ${H(y)^{ab} : y \in S_B}$. She sends this set back to Bob &lt;em&gt;in the order Bob originally sent his&lt;/em&gt; ${H(y)^b}$, so Bob can index by his own set.&lt;/li&gt;
&lt;li&gt;Bob exponentiates Alice&apos;s first-round values by $b$, producing ${H(x)^{ab} : x \in S_A}$. (In the symmetric variant Bob also sends his doubly-blinded set back to Alice; either side can then perform the match.)&lt;/li&gt;
&lt;li&gt;Both parties now hold the same doubly-blinded set for both sides. Equal underlying elements collide; unequal ones do not. They intersect locally.&lt;/li&gt;
&lt;/ol&gt;

sequenceDiagram
    participant A as Alice (set S_A)
    participant B as Bob (set S_B)
    Note over A,B: shared group G, hash H, private exponents a (Alice), b (Bob)
    A-&amp;gt;&amp;gt;B: shuffled set of H(x)^a for x in S_A
    B-&amp;gt;&amp;gt;A: shuffled set of H(y)^b for y in S_B
    A-&amp;gt;&amp;gt;A: compute H(y)^(ba) for each item from Bob
    B-&amp;gt;&amp;gt;B: compute H(x)^(ab) for each item from Alice
    Note over A,B: equal underlying elements yield equal doubly-blinded values
    A-&amp;gt;&amp;gt;B: ordered set of H(y)^(ab) for matching
    Note over A,B: intersection computed locally
&lt;p&gt;Why this is right. Under the Decisional Diffie-Hellman (DDH) assumption in $G$, the doubly-blinded values $H(x)^{ab}$ for $x \notin S_A \cap S_B$ look uniformly random to the other side. Equal underlying elements collide; unequal underlying elements do not. The reader can verify this for themselves in the demonstration below, which is the canonical pedagogical version of the protocol.&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;// Toy PSI -- pedagogical only, NOT secure (small modulus, weak hash). const p = 2n ** 61n - 1n;      // Mersenne prime, small for demo const g = 37n;                  // generator over Z_p* (toy) const H = s =&amp;gt; {   // toy hash: deterministic map string -&amp;gt; [1, p-1]   let h = 1469598103934665603n;   for (const c of s) h = ((h ^ BigInt(c.charCodeAt(0))) * 1099511628211n) % p;   return h === 0n ? 1n : h; }; const expMod = (base, exp, mod) =&amp;gt; {   let r = 1n, b = base % mod, e = exp;   while (e &amp;gt; 0n) {     if (e &amp;amp; 1n) r = (r * b) % mod;     b = (b * b) % mod;     e &amp;gt;&amp;gt;= 1n;   }   return r; }; const S_A = [&quot;alice-at-example.com&quot;, &quot;bob-at-example.com&quot;, &quot;carol-at-example.com&quot;]; const S_B = [&quot;dave-at-example.com&quot;, &quot;bob-at-example.com&quot;, &quot;carol-at-example.com&quot;]; const a = 0xC0FFEEn, b = 0xBADCAFEn; const A1 = S_A.map(x =&amp;gt; expMod(H(x), a, p));   // Alice -&amp;gt; Bob const B1 = S_B.map(y =&amp;gt; expMod(H(y), b, p));   // Bob -&amp;gt; Alice const A2 = A1.map(v =&amp;gt; expMod(v, b, p));       // Bob blinds Alice&apos;s set const B2 = B1.map(v =&amp;gt; expMod(v, a, p));       // Alice blinds Bob&apos;s set // Reveal intersection by matching doubly-blinded values const setA2 = new Set(A2.map(String)); const intersection = S_B.filter((_, i) =&amp;gt; setA2.has(String(B2[i]))); console.log(&quot;Intersection:&quot;, intersection);&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;The protocol does work. It gives semi-honest security under DDH and costs $O(|S_A| + |S_B|)$ group exponentiations per side, plus the same again to blind the received set. In a balanced setting -- two sets of similar size, perhaps a few thousand elements each -- it is genuinely deployable.&lt;/p&gt;
&lt;h3&gt;The three things that go wrong at scale&lt;/h3&gt;
&lt;p&gt;For breach checking, the protocol breaks in three documented ways.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Set-cardinality leakage.&lt;/strong&gt; The shuffled lists Alice and Bob send each other have lengths $|S_A|$ and $|S_B|$. Bob learns precisely how many passwords Alice has saved; Alice learns precisely how big Bob&apos;s breach corpus is. The first leak is small but real; the second is fine when the server publishes its corpus size anyway (HIBP does), but the protocol does not hide it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Online-cost asymmetry.&lt;/strong&gt; The server pays $O(|S_B|)$ exponentiations per client query. At the five-billion-element scale of Microsoft&apos;s compromised-credential corpus, no realistic group exponentiation cost makes this feasible per query: even at 100 microseconds per exponentiation (optimistic for $|q| = 256$), five billion exponentiations is more than five days of single-core CPU. Sharding helps. Caching helps. Pre-computation helps. None makes the asymptotic curve workable as the corpus grows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No labeled variant.&lt;/strong&gt; The protocol returns set membership, not associated metadata. Edge Password Monitor wants to tell you &quot;this credential appeared in breach X&quot; -- so the protocol has to support associating a server-side label with each set element and returning the label for matched elements. DH meet-in-the-middle does not, without unpleasant extensions.&lt;/p&gt;
&lt;h3&gt;FNP04: the right idea, wrong substrate&lt;/h3&gt;
&lt;p&gt;The algebraic alternative arrived in 2004 with Freedman, Nissim, and Pinkas&apos;s &quot;Efficient Private Matching and Set Intersection&quot; at EUROCRYPT [@fnp-2004]. The idea is gorgeous. Alice encodes her set $S_A = {x_1, \dots, x_n}$ as the polynomial whose roots are her set:&lt;/p&gt;
&lt;p&gt;$$p(z) = \prod_{i=1}^{n} (z - x_i)$$&lt;/p&gt;
&lt;p&gt;Alice encrypts each coefficient of $p$ under an additively-homomorphic encryption scheme (Paillier, in the paper). She sends the encrypted coefficients to Bob. Bob homomorphically evaluates $p(y)$ for every element $y$ of his set $S_B$ and returns the encrypted results. If $y \in S_A$, then $p(y) = 0$, and after decryption Alice sees a zero in the corresponding position. If $y \notin S_A$, then $p(y)$ is a non-trivial polynomial evaluation that, randomized correctly, decrypts to a uniform value Alice cannot interpret.&lt;/p&gt;
&lt;p&gt;This is the first asymmetric PSI -- the first protocol where one party can do most of the work while the other sends only a small encrypted query. It is also, in deployment terms, structurally infeasible at scale. Paillier ciphertexts live in $\mathbb{Z}^*_{n^2}$ and are $2 \cdot |n|$ bits each [@paillier-1999] (2048 bits for FNP04&apos;s $|n| = 1024$ default; 4096 bits for the $|n| \geq 2048$ that modern security demands). Paillier homomorphic evaluation needs full-size modular exponentiation per coefficient, and the server compute scales as $O(|S_A| \cdot |S_B|)$. At Edge Password Monitor&apos;s target scale -- a client set of a few hundred passwords against a five-billion-element server corpus -- a single query would take minutes to hours of server compute and tens of megabytes of round-trip data per query.The 5-billion-element estimate is INFERRED, not measured (see §2 for the article-wide projection disclosure). No published source benchmarks FNP04 at that scale; the inference combines the $O(|S_A| \cdot |S_B|)$ asymptotic with measured Paillier throughput on commodity hardware. The order-of-magnitude conclusion is sound; treat the precise number as a back-of-envelope.The polynomial-roots idea is not dead. Thirteen years later, Chen, Laine, and Rindal will revive exactly this construction inside CLR17 [@clr-2017], with Paillier replaced by BFV-style somewhat-homomorphic encryption and a partition-and-evaluate trick that fixes the $O(|S_A| \cdot |S_B|)$ blow-up. The structure survives; the substrate gets swapped.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Era&lt;/th&gt;
&lt;th&gt;Server cost&lt;/th&gt;
&lt;th&gt;Communication&lt;/th&gt;
&lt;th&gt;Verdict at 5B-element scale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;DH meet-in-the-middle [@hfh-1999]&lt;/td&gt;
&lt;td&gt;1999&lt;/td&gt;
&lt;td&gt;$O(&lt;/td&gt;
&lt;td&gt;S_B&lt;/td&gt;
&lt;td&gt;)$ DH exponentiations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FNP04 [@fnp-2004]&lt;/td&gt;
&lt;td&gt;2004&lt;/td&gt;
&lt;td&gt;$O(&lt;/td&gt;
&lt;td&gt;S_A&lt;/td&gt;
&lt;td&gt;\cdot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(preview) HE-PSI on BFV [@clr-2017]&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;$O(&lt;/td&gt;
&lt;td&gt;S_B&lt;/td&gt;
&lt;td&gt;\log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The naive approach -- &quot;just hash and compare&quot; -- leaks set cardinality at a minimum, and plain hashing is brute-forceable against any password the server can guess. Doing PSI properly under encryption requires either $O(|S_A| \cdot |S_B|)$ server work and 2048-bit Paillier ciphertexts (FNP04, dead at billions), or a new primitive: oblivious transfer at scale. It takes a decade of engineering to make that primitive free.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;FNP04&apos;s polynomial idea will turn out to be the right idea -- but only after we replace Paillier with somewhat-homomorphic encryption thirteen years later. Before we can get there, we need a different breakthrough: making the underlying oblivious-transfer primitive cheap enough that &lt;em&gt;every&lt;/em&gt; PSI in the literature can ride on it.&lt;/p&gt;
&lt;h2&gt;4. The evolution: oblivious transfer extension&lt;/h2&gt;
&lt;p&gt;Here is the central fact that drove a decade of cryptographic engineering: &lt;strong&gt;every PSI protocol that scales eventually reduces to &quot;many oblivious transfers.&quot;&lt;/strong&gt; OT is the universal building block. Once you can do millions of OTs per second, you can do nearly any two-party secure computation, including PSI. The question is how cheap &quot;many OTs&quot; can become.&lt;/p&gt;

A two-party primitive. In 1-out-of-2 OT, the sender holds two messages $(m_0, m_1)$, the receiver chooses a bit $b$, and after the protocol runs the receiver learns $m_b$ while the sender learns nothing about $b$. OT is universal -- it suffices for secure two-party computation of any function -- and it is also expensive: implemented directly from public-key primitives, each OT costs at least one Diffie-Hellman exponentiation, on the order of a millisecond per OT on commodity hardware.

A two-phase protocol that performs $m$ OTs at the cost of $\kappa$ &quot;base&quot; OTs (typically $\kappa = 128$, implemented with public-key crypto) plus $O(m)$ symmetric primitive calls. Because $\kappa$ is small and constant, the per-OT cost drops from public-key cost (~1 ms) to symmetric-crypto cost (~100 ns) -- roughly three orders of magnitude, and the asymptotic gap widens with $m$.
&lt;h3&gt;Generation 1: IKNP03&lt;/h3&gt;
&lt;p&gt;In 2003, Yuval Ishai, Joe Kilian, Kobbi Nissim, and Erez Petrank published &quot;Extending Oblivious Transfers Efficiently&quot; at CRYPTO 2003 [@iknp-2003].&lt;/p&gt;
&lt;p&gt;Ishai and Petrank are at Technion; Kilian and Nissim were at NEC Labs America at the time. The construction is short enough to summarize in one paragraph and important enough to be called &lt;em&gt;the&lt;/em&gt; OT extension: start with $\kappa$ &quot;base&quot; OTs done the expensive way (one public-key operation each), then use them to seed pseudorandom generators and a clever transposition trick that, with $O(m)$ hash-function calls, produces $m$ effective OTs. The base cost stays fixed at $\kappa$ public-key operations; the per-OT marginal cost collapses to a few hash invocations.&lt;/p&gt;
&lt;p&gt;The numerical impact: before IKNP, secure-computation researchers cited oblivious-transfer cost in milliseconds; after IKNP, in hundreds of nanoseconds. Three orders of magnitude is the difference between &quot;research artifact&quot; and &quot;this protocol can ship.&quot;No IACR ePrint preprint existed at publication time; a post-conference upload appeared in 2008 as ePrint 2008/508. ePrint 2003/052 is a different paper (Klima, Pokorny, Rosa). The Springer LNCS chapter [@iknp-2003] is the canonical reference.&lt;/p&gt;
&lt;h3&gt;Generation 2: KOS15&lt;/h3&gt;
&lt;p&gt;IKNP03 is secure against a &lt;em&gt;semi-honest&lt;/em&gt; adversary -- one who follows the protocol but tries to learn extra information from the transcript. Real-world deployments often need &lt;em&gt;active&lt;/em&gt; security: protection against an adversary who deviates to extract information or bias the output.&lt;/p&gt;
&lt;p&gt;In 2015, Marcel Keller, Emmanuela Orsini, and Peter Scholl published &quot;Actively Secure OT Extension with Optimal Overhead&quot; [@kos-2015]. The construction adds a correlation-check phase on top of IKNP03 that catches active deviations with overwhelming probability. The paper&apos;s own abstract: &quot;no more than 5% more time than the passively secure IKNP extension, in both LAN and WAN environments, and thus is essentially optimal with respect to the passive protocol.&quot; Modern implementations (libOTe, EMP-toolkit, MP-SPDZ) report on the order of 10-20% wall-clock overhead and 5-10% communication overhead over semi-honest IKNP03 in production -- the &quot;optimal overhead&quot; in the title is the claim that this margin vanishes as the OT count grows.&lt;/p&gt;
&lt;p&gt;After KOS15, &quot;active security is free&quot; became the industry default. Every modern OT-extension library -- libOTe, EMP-toolkit, MP-SPDZ -- ships KOS15 (or a close variant) as the production-grade default. The earlier semi-honest-only choice is a research artifact.&lt;/p&gt;
&lt;h3&gt;Generation 3: Silent OT&lt;/h3&gt;
&lt;p&gt;In 2019, a six-author collaboration -- Elette Boyle, Geoffroy Couteau, Niv Gilboa, Yuval Ishai, Lisa Kohl, and Peter Scholl -- published &quot;Efficient Pseudorandom Correlation Generators: Silent OT Extension and More&quot; at CRYPTO 2019 [@silent-ot-2019]. The construction replaces the communication-heavy IKNP/KOS phase with a &lt;em&gt;Pseudorandom Correlation Generator&lt;/em&gt; (PCG): the two parties exchange a few-kilobyte seed and locally expand it into millions of correlated OTs.&lt;/p&gt;

A protocol primitive that, given a short shared seed, lets two parties locally expand the seed into long correlated random strings -- in the OT case, the random correlations needed to &quot;consume&quot; each OT call. Once the seed is exchanged, no further communication is needed to produce more OTs; the parties simply expand more locally. PCGs reduce the per-OT wire cost to zero in the post-seed phase.
&lt;p&gt;The numerical impact this time is &lt;em&gt;bandwidth&lt;/em&gt;. Pre-Silent-OT, OT-extension protocols sent on the order of $\kappa$ bits per OT. Silent OT sends a polylogarithmic amount of data total for the entire extension. The precursor construction &quot;Compressing Vector OLE&quot; by Boyle, Couteau, Gilboa, Ishai, Kohl, and Rindal [@boyle-vector-ole-2019] laid the algebraic foundation.&lt;/p&gt;
&lt;p&gt;For Edge Password Monitor&apos;s deployment shape (small client set, large server set), Silent OT does not land in the production protocol -- HE-PSI provides the asymmetric communication scaling -- but its existence in 2019 is part of why the industry treats OT extension as essentially solved engineering and feels free to ride a higher-layer protocol on top.&lt;/p&gt;
&lt;h3&gt;The OPRF-PSI plateau: KKRT16&lt;/h3&gt;
&lt;p&gt;Pure OT-extension is one substrate; the other is the Oblivious Pseudorandom Function.&lt;/p&gt;

A two-party protocol in which the sender holds a key $k$, the receiver holds an input $x$, and after the protocol the receiver learns $F_k(x)$ while the sender learns nothing about $x$. The receiver gets the PRF output without giving up the input; the sender keeps the key without giving up the output. OPRFs are the building block under most modern PSI: each party evaluates the OPRF on their set, then plaintext-compares the outputs.
&lt;p&gt;In 2016, Vladimir Kolesnikov, Ranjit Kumaresan, Mike Rosulek, and Ni Trieu published &quot;Efficient Batched Oblivious PRF with Applications to Private Set Intersection&quot; at CCS 2016 [@kkrt-2016]. The paper builds a batched OPRF directly on top of KOS-style OT extension. The reported benchmark: intersecting two $2^{20}$-element sets on a LAN took about 3.8 seconds total. For several years, KKRT16 was the deployment-grade symmetric-PSI protocol.&lt;/p&gt;
&lt;p&gt;KKRT16 is great if your two sets are roughly the same size. The Edge Password Monitor problem is fundamentally asymmetric -- the client holds a few hundred saved passwords, the server holds billions of breached credentials. For &lt;em&gt;asymmetric&lt;/em&gt; PSI, the OT-extension lineage hits a wall the next generation has to climb.&lt;/p&gt;

flowchart LR
    A[&quot;Kappa base OTs&lt;br /&gt;(public-key)&quot;] --&amp;gt; B[&quot;IKNP03 extension&lt;br /&gt;(symmetric)&quot;]
    B --&amp;gt; C[&quot;KOS15 active security&quot;]
    C --&amp;gt; D[&quot;Silent OT&lt;br /&gt;(PCG-based)&quot;]
    B --&amp;gt; E[&quot;KKRT16 OPRF-PSI&quot;]
    C --&amp;gt; F[&quot;CHLR18 HE-PSI&lt;br /&gt;+ OPRF wrapping&quot;]
    D --&amp;gt; G[&quot;Modern OT-extension libraries:&lt;br /&gt;libOTe, EMP-toolkit&quot;]
    E --&amp;gt; H[&quot;Symmetric balanced PSI&quot;]
    F --&amp;gt; I[&quot;Edge Password Monitor&quot;]
&lt;h2&gt;5. The breakthrough: HE-based PSI&lt;/h2&gt;
&lt;p&gt;Asymmetric PSI requires that the server&apos;s heavy compute stays on the server, and that the client send only a tiny encrypted query whose size is independent of $|S_B|$. That is exactly what fully homomorphic encryption -- or, more precisely, &lt;em&gt;somewhat-homomorphic&lt;/em&gt; encryption -- can offer.&lt;/p&gt;

An encryption scheme is *homomorphic* if operations on ciphertexts decrypt to the corresponding operations on plaintexts. *Somewhat-homomorphic encryption* (SWHE) supports a bounded depth of operations (typically additions and multiplications) before noise growth requires re-encryption. *Fully homomorphic encryption* (FHE) supports arbitrary-depth circuits via bootstrapping. The BFV scheme (Brakerski-Fan-Vercauteren), implemented in Microsoft SEAL [@ms-seal], is the SWHE variant Edge Password Monitor uses; FHE is the popular term but the actual deployed circuit depth fits comfortably within SWHE.
&lt;h3&gt;CLR17: the cost curve flips&lt;/h3&gt;
&lt;p&gt;In 2017, Hao Chen, Kim Laine, and Peter Rindal published &quot;Fast Private Set Intersection from Homomorphic Encryption&quot; at CCS 2017 [@clr-2017]. The construction is a clean revival of FNP04&apos;s polynomial-roots idea, with three engineering moves that fix every reason FNP04 was infeasible.&lt;strong&gt;Move 1: SWHE instead of Paillier.&lt;/strong&gt; BFV ciphertexts pack many plaintext slots and support SIMD-style homomorphic operations. A single ciphertext can encrypt and evaluate over thousands of plaintext values in parallel; the slot count is set at scheme-parameter time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Move 2: Cuckoo hash partitioning.&lt;/strong&gt; The receiver Cuckoo-hashes its set $S_R$ into bins. The sender hashes each element of $S_S$ to the same set of bins. Instead of one giant polynomial whose roots are all of $S_S$, the sender builds one small polynomial per bin -- typically a few thousand bins, each holding a few hundred elements.&lt;/p&gt;

A hashing scheme that uses $k$ hash functions and inserts each element into one of $k$ candidate bins, displacing existing occupants if necessary (the displaced element finds another of its candidate bins). Cuckoo hashing achieves $O(1)$ worst-case lookup; the achievable load factor depends on the number of hash functions and the bucket size -- roughly 49% with $k=2$ (the original Pagh-Rodler 2001 construction [@pagh-rodler-2001]), roughly 91% with $k=3$, and higher with a stash of evicted elements or $k \geq 4$. CLR17 and CHLR18 use parameter choices in the high-load regime. In CLR17, Cuckoo hashing pairs the receiver&apos;s set with the sender&apos;s set so that two equal elements end up in the same bin with overwhelming probability.
&lt;p&gt;&lt;strong&gt;Move 3: Partition-and-evaluate.&lt;/strong&gt; The receiver encrypts its bins under BFV and sends them. The sender homomorphically evaluates its per-bin polynomial at the encrypted receiver&apos;s bin. Because of SIMD slot packing, each bin&apos;s polynomial is evaluated in parallel across all slots, and the sender&apos;s total work is $O(|S_S| \log |S_R|)$ FHE operations instead of FNP04&apos;s $O(|S_R| \cdot |S_S|)$.&lt;/p&gt;
&lt;p&gt;The headline benchmark from the paper, on the MSR publication page: &quot;36 seconds of online-computation and 12.5 MB of round trip communication to intersect five thousand 32-bit strings with 16 million 32-bit strings&quot; [@msr-clr17-pub]. Communication scales linearly in the small set and logarithmically in the large set. The cost curve is finally right.&lt;/p&gt;

sequenceDiagram
    participant C as Client (Edge)
    participant S as Server (Microsoft)
    Note over C,S: stage 1 -- OPRF preprocessing (binds queries to server&apos;s secret key)
    C-&amp;gt;&amp;gt;S: blinded credential beta * H(cred)
    S-&amp;gt;&amp;gt;C: alpha * (blinded H(cred)) using server key alpha
    C-&amp;gt;&amp;gt;C: unblind, obtain F_alpha(cred)
    Note over C,S: stage 2 -- HE-PSI on sharded corpus
    C-&amp;gt;&amp;gt;S: BFV ciphertext encrypting F_alpha(cred), sharded by 2-byte prefix
    S-&amp;gt;&amp;gt;S: Cuckoo-hash shard, evaluate per-bin polynomial homomorphically
    S-&amp;gt;&amp;gt;C: encrypted match result + label ciphertext
    C-&amp;gt;&amp;gt;C: decrypt result, then if match surface breach metadata
&lt;h3&gt;CHLR18: labeled, malicious, deployable&lt;/h3&gt;
&lt;p&gt;The next year, the same authors plus Zhicong Huang published &quot;Labeled PSI from Fully Homomorphic Encryption with Malicious Security&quot; at CCS 2018 [@chlr-2018]. The paper adds three production-grade properties.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Labels.&lt;/strong&gt; Each element in the server&apos;s set can carry an associated label (which breach, when, severity). When the receiver finds a match, they also recover the label.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malicious security.&lt;/strong&gt; The protocol is secure against an actively malicious sender, layered on top of the underlying semi-honest construction via an OPRF preprocessing step. The OPRF is the same primitive we met in §4; here it does double duty: it prevents the client from brute-forcing the server&apos;s corpus offline (the client cannot evaluate $F_k(\cdot)$ without server interaction) and provides the malicious-security guarantee.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arbitrary-length items.&lt;/strong&gt; The protocol handles long inputs (full URLs plus usernames, in the breach-checking case), not just short fixed-width keys.&lt;/p&gt;
&lt;p&gt;The headline benchmark: &quot;for an intersection of $2^{20}$ and 512 size sets of arbitrary length items our protocol has a total online running time of just 1 second (single thread), and a total communication cost of 4 MB&quot; [@msr-chlr18-pub]. A larger benchmark of $2^{28}$ and 1024 takes 12 seconds multithreaded with less than 18 MB of communication.&lt;/p&gt;
&lt;h3&gt;Cong et al. 2021: the production-grade successor&lt;/h3&gt;
&lt;p&gt;The protocol that ships in Edge Password Monitor today is the descendant published by Kelong Cong, Radames Cruz Moreno, Mariana Botelho da Gama, Wei Dai, Ilia Iliashenko, Kim Laine, and Michael Rosenberg at CCS 2021: &quot;Labeled PSI from Homomorphic Encryption with Reduced Computation and Communication&quot; [@cong-2021]. The paper is the basis for Microsoft&apos;s open-source APSI library [@ms-apsi], whose README states verbatim that it &quot;provides a PSI functionality for asymmetric set sizes based on the protocol described in eprint.iacr.org/2021/1116&quot; and that it &quot;uses the BFV encryption scheme implemented in the Microsoft SEAL library.&quot;The Cong et al. 2021 byline is seven authors: Kelong Cong, Radames Cruz Moreno, Mariana Botelho da Gama, Wei Dai, Ilia Iliashenko, Kim Laine, Michael Rosenberg. Some upstream reporting conflates a different author list onto the same URL; the citation_author meta-tags returned by ePrint 2021/1116 confirm this seven-author septuple [@cong-2021].&lt;/p&gt;
&lt;h3&gt;The OPRF wrapping and corpus sharding&lt;/h3&gt;
&lt;p&gt;Two practical layers on top of the bare HE-PSI protocol turn the academic construction into a production deployment, and the Microsoft Research Password Monitor blog is explicit about both [@msr-password-monitor-2021].&lt;/p&gt;
&lt;p&gt;First, the OPRF preprocessing. Without it, a malicious client could send candidate passwords one at a time and observe match results, brute-forcing the server&apos;s corpus. With it, every client query passes through $F_k(\cdot)$ where $k$ is a server secret. The MSR blog states: &quot;the client communicates with the server to obtain a hash $H$ of the credential, where $H$ denotes a hash function that only the server knows... using an OPRF... the client is prevented from performing an efficient dictionary attack on the server&quot; [@msr-password-monitor-2021].&lt;/p&gt;
&lt;p&gt;Second, corpus sharding. The MSR blog notes that the corpus is sharded by the first two bytes of a username-hash. The blog&apos;s verbatim example: &quot;Suppose the database $D$ consists of 4 billion credentials, then after sharding each subset, it will contain about 60,000 credentials on average.&quot; At the article&apos;s 2026 5-billion projection the math is the same -- corpus divided by $2^{16}$ -- and per-shard work is closer to 76,000 credentials. Either way, the per-query homomorphic evaluation runs against tens of thousands of credentials instead of the full corpus. This is the same engineering trade as Apple&apos;s 15-bit bucketing -- a small information leak (the client reveals which shard their query lives in) in exchange for tractable per-query compute.&lt;/p&gt;

A Windows facility, introduced in Windows 2000, that encrypts arbitrary blobs under a user-derived key chain (ultimately rooted in the user&apos;s password, with hardware-bound variants under DPAPI-NG) and exposes a simple `CryptProtectData` / `CryptUnprotectData` API [@ms-learn-dpapi-ng]. Browsers including Chromium store the symmetric key that wraps their saved-password database under DPAPI at rest. This protects the on-disk database when the user is not logged in, but it does not protect process memory after the same user has unwrapped the data into a running browser.

This unique security feature is possible due to pioneering cryptography research and technology incubation done here at Microsoft Research. -- Microsoft Research, January 21, 2021 [@msr-password-monitor-2021]
&lt;p&gt;The administrator-visible group policy that controls this feature is &lt;code&gt;PasswordMonitorAllowed&lt;/code&gt;, documented on Microsoft Learn [@ms-learn-edge-pm].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Asymmetric PSI on somewhat-homomorphic encryption flips the cost curve so that communication scales with the small client set, not the enormous server set. That is why a homomorphic-encryption protocol can ship on a consumer browser in 2021 without melting the user&apos;s CPU. The cryptographic case for Edge Password Monitor is auditable down to the published papers and unequivocally well-engineered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft has shipped the first production consumer homomorphic-encryption deployment in a browser, against the threat &quot;server-side breach corpus leakage,&quot; on the same browser that, in §7, will turn out to hold every saved credential in plaintext RAM the entire time you have it open. To make sense of that contrast, we need to see what the rest of the industry did with the same problem.&lt;/p&gt;
&lt;h2&gt;6. State of the art: four deployed compromised-credential services&lt;/h2&gt;
&lt;p&gt;PSI on paper is one thing. PSI in production is another. The &quot;pure PSI&quot; ideal -- both parties learn the intersection and &lt;em&gt;nothing else&lt;/em&gt;, no information leaks on either side -- is impractical at planetary scale. Every deployed compromised-credential service in 2026 makes a concession somewhere.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The concessions reveal which threats each provider takes most seriously. Read the next table by column 3 (&quot;what is revealed on the wire&quot;) and column 6 (&quot;dictionary-attack hardening&quot;) side by side: that pair tells you the threat model each provider chose.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The four services compared here are HIBP Pwned Passwords v3, Google Password Checkup, Apple Password Monitoring (iCloud Keychain), and Microsoft Edge Password Monitor. A fifth, Signal contact discovery, is technically a contact-discovery service rather than a breach checker, but it sits on the same protocol map and is the canonical &quot;we used a TEE instead of pure crypto&quot; data point.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Protocol family&lt;/th&gt;
&lt;th&gt;What&apos;s revealed on the wire&lt;/th&gt;
&lt;th&gt;Server trust&lt;/th&gt;
&lt;th&gt;Bandwidth at scale&lt;/th&gt;
&lt;th&gt;Dictionary-attack hardening&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;HIBP Pwned Passwords v3 [@hibp-api-v3]&lt;/td&gt;
&lt;td&gt;Pure SHA-1 5-hex-char k-anonymity&lt;/td&gt;
&lt;td&gt;A 20-bit hash prefix per query&lt;/td&gt;
&lt;td&gt;None (zero-trust API)&lt;/td&gt;
&lt;td&gt;Trivial (a few KB per query)&lt;/td&gt;
&lt;td&gt;None on the wire; SHA-1 hash makes corpus searchable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Password Checkup [@thomas-usenix-2019]&lt;/td&gt;
&lt;td&gt;k-anonymity + blinded-hash OPRF&lt;/td&gt;
&lt;td&gt;A small hash prefix per query&lt;/td&gt;
&lt;td&gt;Honest-but-curious&lt;/td&gt;
&lt;td&gt;Tens of KB per query&lt;/td&gt;
&lt;td&gt;OPRF prevents corpus enumeration by the client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apple Password Monitoring [@apple-password-monitoring]&lt;/td&gt;
&lt;td&gt;EC-based PSM on NIST P-256 + 15-bit bucket&lt;/td&gt;
&lt;td&gt;A 15-bit prefix + double-blinded EC point&lt;/td&gt;
&lt;td&gt;Honest-but-curious&lt;/td&gt;
&lt;td&gt;A few hundred KB per query (padded)&lt;/td&gt;
&lt;td&gt;OPRF + double-blinding + padding-to-fixed-count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signal contact discovery (2017) [@signal-private-contact-2017]&lt;/td&gt;
&lt;td&gt;SGX enclave + ORAM (no pure crypto)&lt;/td&gt;
&lt;td&gt;Nothing visible to Signal staff&lt;/td&gt;
&lt;td&gt;TEE attestation&lt;/td&gt;
&lt;td&gt;Negligible (single SGX RPC)&lt;/td&gt;
&lt;td&gt;Enclave isolation rather than crypto hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Edge Password Monitor [@msr-password-monitor-2021]&lt;/td&gt;
&lt;td&gt;HE-PSI on Microsoft SEAL + OPRF + 2-byte shard&lt;/td&gt;
&lt;td&gt;2-byte username-hash prefix + BFV ciphertext&lt;/td&gt;
&lt;td&gt;Honest-but-curious&lt;/td&gt;
&lt;td&gt;Single MB-range round trip&lt;/td&gt;
&lt;td&gt;OPRF binds queries to server key; HE prevents transcript leaks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;HIBP Pwned Passwords v3: the k-anonymity baseline&lt;/h3&gt;
&lt;p&gt;Troy Hunt launched Pwned Passwords v2 in 2018 with the help of Junade Ali at Cloudflare, adding a k-anonymity API; the design is published in two posts, Hunt&apos;s &quot;I&apos;ve Just Launched Pwned Passwords Version 2&quot; and Ali&apos;s &quot;Validating Leaked Passwords with k-Anonymity&quot; [@hunt-pwned-v2-2018][@ali-cloudflare-2018]. The protocol is delightfully simple: the client hashes the candidate password under SHA-1, sends the first 5 hex characters (20 bits) of the hash to the API, and the API returns every suffix in that bucket. The client compares locally.&lt;/p&gt;

A privacy property: each query produces output that is consistent with at least $k$ other potential queries the client could have made. In the HIBP context, $k$ is the number of distinct password hashes that share the same 20-bit SHA-1 prefix -- typically a few hundred. The server learns the bucket but not which specific password the client cares about, and (because hashes are sparse over the prefix space) cannot easily distinguish &quot;the user has password X&quot; from &quot;the user has password Y&quot; if X and Y share the prefix.
&lt;p&gt;The HIBP corpus serves &quot;18B+ Monthly Requests&quot; against roughly a billion hashes [@hibp-passwords]. Operationally, this is a one-shot HTTP GET. There is no PSI on the wire beyond TLS. The whole protocol fits on the back of an envelope. The cost: each query leaks the 20-bit prefix, which is enough to identify the user&apos;s password if the attacker has independent information narrowing the candidate space.&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;async function sha1Hex(s) {   const buf = new TextEncoder().encode(s);   const hash = await crypto.subtle.digest(&quot;SHA-1&quot;, buf);   return [...new Uint8Array(hash)].map(b =&amp;gt; b.toString(16).padStart(2, &quot;0&quot;)).join(&quot;&quot;).toUpperCase(); } async function showBucket(password) {   const h = await sha1Hex(password);   const prefix = h.slice(0, 5);    // 5 hex chars -- 20 bits sent to server   const suffix = h.slice(5);   console.log(&quot;Password:&quot;, password);   console.log(&quot;SHA-1:   &quot;, h);   console.log(&quot;Prefix (leaves your device):&quot;, prefix);   console.log(&quot;Suffix (compared locally):  &quot;, suffix);   console.log(&quot;Approx bucket size: ~&quot;, Math.round(847_223_402 / (1&amp;lt;&amp;lt;20)), &quot;entries&quot;); } showBucket(&quot;hunter2&quot;);&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;The mental model the runnable above gives is the precise shape of the trade. Every HIBP query says &quot;I am asking about a password whose SHA-1 starts with these 20 bits.&quot; There are roughly $2^{20} \approx 1{,}048{,}576$ possible prefixes, so each query narrows the server&apos;s posterior over your password by exactly that much.&lt;/p&gt;
&lt;h3&gt;Google Password Checkup: k-anonymity with an OPRF on top&lt;/h3&gt;
&lt;p&gt;In August 2019, Kurt Thomas and colleagues at Google published &quot;Protecting Accounts from Credential Stuffing with Password Breach Alerting&quot; at USENIX Security [@thomas-usenix-2019]. The accompanying blog post on the Google Security Blog announces the deployment [@google-blog-password-checkup-2019]. The numbers are familiar at this point: &quot;a cloud service that mediates access to over 4 billion credentials found in breaches and a Chrome extension serving as an initial client. Based on anonymous telemetry from nearly 670,000 users and 21 million logins, we find that 1.5% of logins on the web involve breached credentials&quot; [@thomas-usenix-2019].&lt;/p&gt;
&lt;p&gt;The protocol upgrades HIBP&apos;s k-anonymity baseline with an OPRF preprocessing round: instead of hashing under SHA-1 locally and sending the prefix, the client first obtains $F_k(\text{password})$ via an OPRF interaction, where $k$ is a Google-held key. The OPRF output is then bucketed and matched against Google&apos;s corpus. The OPRF prevents the client from enumerating Google&apos;s corpus offline; the bucketing limits per-query server work.&lt;/p&gt;
&lt;h3&gt;Apple Password Monitoring: PSM with double-blinding&lt;/h3&gt;
&lt;p&gt;Apple&apos;s protocol is the most cryptographically elaborate of the four. The Apple Platform Security guide is unusually explicit [@apple-password-monitoring][@apple-security-guide-pdf]. From the guide, verbatim: &quot;a form of cryptographic private set intersection is deployed that compares the users&apos; passwords against a large set of leaked passwords&quot;; the corpus is &quot;approximately 1.5 billion passwords... into $2^{15}$ different buckets&quot;; and the protocol uses elliptic-curve PSM on NIST P-256 with a double-blinded structure.&lt;/p&gt;
&lt;p&gt;The math, slightly compressed. Let $H_{\text{SWU}}$ be the Shallue-van de Woestijne-Ulas hash-to-curve.&lt;/p&gt;
&lt;p&gt;Google publishes an open-source PSM construction at &lt;code&gt;google/private-membership&lt;/code&gt; [@google-private-membership-github]; Apple&apos;s protocol shares the EC double-blinding skeleton. Apple computes a per-corpus-element representation:&lt;/p&gt;
&lt;p&gt;$$P_{pw} = \alpha \cdot H_{\text{SWU}}(pw)$$&lt;/p&gt;
&lt;p&gt;where $\alpha$ is a secret random key known only to Apple. The client computes its query:&lt;/p&gt;
&lt;p&gt;$$P_c = \beta \cdot H_{\text{SWU}}(pw)$$&lt;/p&gt;
&lt;p&gt;with $\beta$ chosen randomly per-query. The interaction lets the client recover $\alpha \cdot H_{\text{SWU}}(pw)$ and check it against a 15-bit bucket of $P_{pw}$ values. (Apple&apos;s public documentation hashes only the password; whether the production implementation includes additional salting is not disclosed.) The double-blinding is the point: $\alpha$ stays Apple&apos;s secret (so the client cannot enumerate); $\beta$ stays per-query random (so Apple cannot link two queries from the same client).Apple&apos;s PSM defends &lt;em&gt;also&lt;/em&gt; against the server learning how many unique passwords a user has, by padding-to-fixed-count with random queries: &quot;if a user has fewer than this number, random passwords are generated and added to the queries to make up the difference&quot; [@apple-password-monitoring]. None of the other four services deploys this defence. The padding cost is the price.&lt;/p&gt;
&lt;h3&gt;Signal contact discovery: the TEE outlier&lt;/h3&gt;
&lt;p&gt;In September 2017, Moxie Marlinspike published &quot;Technology Preview: Private Contact Discovery&quot; on Signal&apos;s blog [@signal-private-contact-2017]. The post is candid about the cost calculation that drove Signal toward Intel SGX rather than pure cryptographic PSI:&lt;/p&gt;

Signal clients will be able to efficiently and scalably determine whether the contacts in their address book are Signal users *without revealing the contacts in their address book to the Signal service*. -- Moxie Marlinspike, September 2017 [@signal-private-contact-2017]
&lt;p&gt;Marlinspike is explicit about the cost calculation: &quot;Doing better is difficult. There are a range of options that don&apos;t work... like using bloom filters, encrypted bloom filters, sharded bloom filters.&quot; Signal examines pure cryptographic PSI and decides, given its scale and latency requirements, that an SGX enclave running a constant-time ORAM-protected lookup is the better engineering trade [@signal-cds-github].&lt;/p&gt;

The SGX choice came with side-channel debt that subsequent literature made expensive. Foreshadow (2018) [@foreshadow-2018], SgxPectre (2018) [@sgxpectre-2018], SGAxe (2020) [@sgaxe-2020], and AEPIC Leak (2022) [@aepic-leak-2022] all targeted SGX directly. Each disclosure prompted Signal to publish a re-evaluation. Signal eventually migrated to the second-generation Contact Discovery Service (CDSI), which continues to rely on TEEs but with a hardened threat model. The point for our story is not that SGX is bad. It is that &quot;pure crypto vs. TEE&quot; is not a settled question; every provider revisits it under their own latency, corpus, and threat-model constraints, and each makes a different decision.
&lt;h3&gt;Microsoft Edge Password Monitor&lt;/h3&gt;
&lt;p&gt;The Microsoft deployment is the only one shipping a full HE-PSI protocol on the wire against the full corpus. As established in §5, the protocol stack is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Two-byte username-hash shard selection (corpus partitioned, sender does work only against tens of thousands of elements per query -- the MSR blog&apos;s 2021 example uses 4 billion / $2^{16} \approx$ 60,000; the article&apos;s 2026 5-billion projection yields $\approx$ 76,000).&lt;/li&gt;
&lt;li&gt;OPRF preprocessing (binds queries to a server secret; prevents client-side enumeration).&lt;/li&gt;
&lt;li&gt;BFV-encrypted query, evaluated against the Cuckoo-hashed per-bin polynomials, returned as a single ciphertext per shard.&lt;/li&gt;
&lt;li&gt;Client decrypts; if matched, decrypts the associated label (the breach metadata).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All four moving parts are described in the MSR blog, the Cong et al. 2021 paper, and the open-source APSI library [@msr-password-monitor-2021][@cong-2021][@ms-apsi]. Communication scales with the small client set; sender compute scales with the (sharded) server set. The Microsoft Edge enterprise documentation says the feature &quot;helps Microsoft Edge users protect their online accounts by informing them if any of their passwords are found in an online leak&quot; [@ms-learn-edge-pm].&lt;/p&gt;
&lt;h3&gt;Four products, four concessions&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Primary concession&lt;/th&gt;
&lt;th&gt;What it defends against&lt;/th&gt;
&lt;th&gt;What it does not&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;HIBP&lt;/td&gt;
&lt;td&gt;20-bit prefix leak per query&lt;/td&gt;
&lt;td&gt;Server learning the password&lt;/td&gt;
&lt;td&gt;A linkage attack on repeated queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google PCU&lt;/td&gt;
&lt;td&gt;OPRF transcript + prefix&lt;/td&gt;
&lt;td&gt;Client-side corpus enumeration&lt;/td&gt;
&lt;td&gt;Server-side query inference if the prefix is rare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apple PSM&lt;/td&gt;
&lt;td&gt;15-bit bucket + double-blinding overhead&lt;/td&gt;
&lt;td&gt;Both client and server enumeration; query linkage&lt;/td&gt;
&lt;td&gt;Side-channels on the EC implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signal CDS&lt;/td&gt;
&lt;td&gt;TEE attestation trust&lt;/td&gt;
&lt;td&gt;Server-side mass-data exfiltration&lt;/td&gt;
&lt;td&gt;SGX side-channel attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge PM&lt;/td&gt;
&lt;td&gt;2-byte shard leak + OPRF transcript&lt;/td&gt;
&lt;td&gt;Anything short of breach corpus leakage from inside Microsoft&lt;/td&gt;
&lt;td&gt;Endpoint compromise -- see §7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Four products. Four different concessions. Each is internally coherent. None of them solves a problem that Tom Joran Sonstebyseter Ronning&apos;s PoC will turn out to make trivial.&lt;/p&gt;
&lt;h2&gt;7. The other half: plaintext RAM &quot;by design&quot;&lt;/h2&gt;
&lt;p&gt;Now we turn the article inside out.&lt;/p&gt;
&lt;p&gt;Everything we have built so far -- IKNP, KOS, KKRT, CLR17, CHLR18, Cong et al., Apple&apos;s PSM, Google&apos;s k-anonymity wrapping, the entire CCS-grade cryptographic stack inside Edge -- assumes the &lt;em&gt;endpoint&lt;/em&gt; is trustworthy. The question Ronning asked on May 4, 2026 is what happens when it is not.&lt;/p&gt;
&lt;h3&gt;The disclosure&lt;/h3&gt;
&lt;p&gt;The X post arrived at 14:29:51 UTC on May 4, 2026 [@ronning-x]: &quot;Microsoft Edge loads all your saved passwords into memory in cleartext -- even when you&apos;re not using them.&quot; Five hours later the GitHub repository went public, with a complete C# proof-of-concept and a long README [@ronning-github]. PCWorld picked up the story two days later under the byline of Laura Pippig, summarising Microsoft&apos;s response in English [@pcworld-pippig-2026]. The Norwegian origin, ITavisen, carried the verbatim &quot;by design&quot; rendering and named Ronning&apos;s affiliation with the transmission-system operator Statnett [@itavisen-2026]. Davey Winder at Forbes reached Microsoft and obtained the official spokesperson statement on May 6, 2026 [@forbes-winder].Ronning works at Statnett and presented this finding at BigBiteOfTech (Palo Alto Networks Norway) on April 29, 2026 -- five days before the public X-post disclosure [@itavisen-2026]. The X bio describes &quot;#PenetrationTesting using only tools that are already on the system.&quot;&lt;/p&gt;
&lt;h3&gt;What the PoC does&lt;/h3&gt;
&lt;p&gt;The C# program is short. &lt;code&gt;OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, ...)&lt;/code&gt; against the parent &lt;code&gt;msedge.exe&lt;/code&gt;. A walk over committed memory regions via &lt;code&gt;VirtualQueryEx&lt;/code&gt;. &lt;code&gt;ReadProcessMemory&lt;/code&gt; reads of every region. Pattern matching for stored credential structures. Output: every saved Edge password as plaintext.&lt;/p&gt;
&lt;p&gt;The README is explicit on the constraints. &quot;Can be run without Adminstrator rights, but will only be able to access Edge processes ran by the same user. If run with Administrator privileges, the program can access and read memory from other users&apos; Edge processes on the same machine&quot; [@ronning-github]. No kernel exploit. No DPAPI bypass. The DPAPI unwrap happened earlier, when Edge launched (or when the password feature first activated); the cleartext has been sitting in &lt;code&gt;msedge.exe&lt;/code&gt;&apos;s heap ever since.&lt;/p&gt;
&lt;p&gt;The tested target is Edge 147.0.3912.98, but the README explicitly generalises: &quot;Any Edge versions that&apos;s Chromium based (from version 79 and newer, including 147.0.3912.98 and any future version, as Microsoft won&apos;t change this feature)&quot; [@ronning-github].&lt;/p&gt;
&lt;h3&gt;What the architectural choice is&lt;/h3&gt;
&lt;p&gt;The behaviour Ronning identifies is not a memory-safety bug. It is a design choice: Edge unwraps every DPAPI-protected saved credential into process memory when the password manager activates, and keeps the plaintext resident for the lifetime of the session.&lt;/p&gt;

flowchart TD
    A[&quot;Saved password file&lt;br /&gt;(SQLite blob)&quot;] --&amp;gt;|&quot;DPAPI-wrapped at rest&quot;| B[&quot;Disk: encrypted with&lt;br /&gt;per-user DPAPI key&quot;]
    B --&amp;gt;|&quot;msedge.exe launches&quot;| C[&quot;DPAPI CryptUnprotectData()&lt;br /&gt;unwraps key&quot;]
    C --&amp;gt;|&quot;password manager activates&quot;| D[&quot;Plaintext credentials&lt;br /&gt;resident in msedge.exe heap&quot;]
    D --&amp;gt;|&quot;OpenProcess + ReadProcessMemory&lt;br /&gt;(same-user, no admin)&quot;| E[&quot;EdgeSavedPasswordsDumper&lt;br /&gt;reads cleartext&quot;]
    D --&amp;gt;|&quot;autofill flow&quot;| F[&quot;Plaintext copied into&lt;br /&gt;renderer / web form&quot;]
    classDef warn fill:#7a3030,stroke:#a04848,color:#fce8e8
    class D warn,stroke:#c33
    classDef accent fill:#5d3a5d,stroke:#8a5a8a,color:#fde0fd
    class E accent,stroke:#939
&lt;p&gt;Chrome and Brave do not do this. Both browsers decrypt credentials only at the autofill RPC -- the password manager fetches the DPAPI-wrapped blob, decrypts in a narrow window, hands the plaintext to the relevant renderer, and zeroes the buffer [@chromium-os-crypt]. PCWorld corroborates: &quot;Other password managers, including those that are built into browsers, don&apos;t operate in this way -- Ronning says Edge is the only Chromium-based browser he&apos;s tested with this behavior&quot; [@pcworld-pippig-2026].&lt;/p&gt;
&lt;p&gt;In July 2024, Google announced Chrome App-Bound Encryption -- a further hardening of exactly this same-user-LCE threat model. ABE binds the on-disk key unwrap to a verified Chrome process identity, so a malicious program impersonating Chrome cannot ask DPAPI to unwrap Chrome&apos;s data even if it runs as the same user [@google-chrome-abe-2024]. Microsoft has the same DPAPI substrate; Edge has not adopted the equivalent control.&lt;/p&gt;
&lt;h3&gt;The .NET runtime tie-in to AMSI&lt;/h3&gt;
&lt;p&gt;The PoC&apos;s original implementation language is a noteworthy detail. Ronning&apos;s README states: &quot;.NET Framework 4.8.1 (changed from 3.5 originally)&quot; [@ronning-github]. The original .NET 3.5 choice was deliberate. The Antimalware Scan Interface (AMSI) [@ms-amsi-portal] scans .NET 4.8+ assemblies before execution; .NET 3.5 predates AMSI&apos;s &lt;code&gt;Amsi*&lt;/code&gt; API surface entirely [@ms-amsi-dotnet48].The current GitHub README has changed the framework version to .NET 4.8.1 (likely to ensure the PoC runs out-of-the-box on modern Windows), but the original framing -- and the original threat-model point -- was the AMSI evasion that .NET 3.5 enables. The sibling AMSI post in this series explains why the 3.5 framing matters.&lt;/p&gt;
&lt;h3&gt;Microsoft&apos;s response, verbatim&lt;/h3&gt;

Safety and security are foundational to Microsoft Edge. Access to browser data as described in the reported scenario would require the device to already be compromised. Design choices in this area involve balancing performance, usability, and security, and we continue to review it against evolving threats. Browsers access password data in memory to help users sign in quickly and securely -- this is an expected feature of the application. We recommend users install the latest security updates and antivirus software to help protect against security threats. -- Microsoft spokesperson, via Forbes, May 6, 2026 [@forbes-winder]

The statement is technically defensible. The threat model is exactly what the spokesperson says: an attacker who can already execute code as the user on the user&apos;s machine. In MSRC&apos;s published servicing criteria [@msrc-servicing-criteria], &quot;exploitation requires local code execution&quot; is a recurring boundary line -- the same line MSRC applied to Mimikatz against LSASS in the pre-Credential-Guard era, and that Microsoft eventually crossed by shipping [Credential Guard](/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/). The &quot;by design&quot; framing is consistent with a decade of precedent.
Microsoft&apos;s response is internally consistent with a decade of MSRC policy. The &quot;exploitation requires local code execution&quot; framing was applied to Mimikatz against LSASS for years before Credential Guard arrived. It is applied to &quot;give me a debugger and I can read anything&quot; type attacks generally. The position is not improvised, and it is not a special accommodation for Edge. The question this article asks is not &quot;is the position internally consistent&quot; -- it is -- but &quot;what threat model does the position concede.&quot; The answer is the same-user local-code-execution threat model. Whether the concession is acceptable depends on whether the user&apos;s environment makes same-user LCE rare (a single-user Surface) or routine (a Citrix farm, an AVD pool, a shared family computer).
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you operate a multi-user Windows host -- RDS, AVD, Citrix, a shared lab, a family PC with multiple sign-in accounts -- every Edge session&apos;s saved credentials are recoverable by any same-user process during that session, and by an administrator across sessions. The &quot;the device is already compromised&quot; framing is asymmetric: a same-user LCE event on a multi-user host is structurally more common than on a single-user laptop, because there are more identities sharing the same physical machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Edge does not have a credential-storage vulnerability. Edge has a credential-storage architectural choice. The choice is to spend the entire browser session&apos;s worth of plaintext-in-RAM budget on autofill UX latency. The choice is defensible. It is also a precise statement of which threats the Edge product team is and is not defending against.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft&apos;s response is technically defensible. It is also a precise statement of which threat model the Edge product team is and is not defending against. To see why both halves of this article describe the same product, we need to look at the architectural alternatives.&lt;/p&gt;
&lt;h2&gt;8. Competing approaches: where should the secret store live?&lt;/h2&gt;
&lt;p&gt;Three architectural positions present themselves, as siblings rather than as a generational ladder:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Browser-as-secret-store, decrypt-on-launch&lt;/strong&gt; (Edge today). Plaintext-in-RAM window: the entire session. Autofill latency: a memcpy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser-as-secret-store, decrypt-on-autofill&lt;/strong&gt; (Chrome, Brave). Plaintext-in-RAM window: the autofill RPC. Autofill latency: one DPAPI unwrap per fill (microseconds).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OS-as-secret-broker&lt;/strong&gt; (the design the Windows Credential Manager and DPAPI-NG already implement for native apps). Plaintext never crosses into the browser&apos;s process; a higher-privileged broker holds the plaintext at autofill time and the browser receives a handle, not the secret.&lt;/li&gt;
&lt;/ol&gt;

flowchart LR
    subgraph &quot;Decrypt-on-launch (Edge)&quot;
        A1[Disk: DPAPI blob] --&amp;gt; A2[Browser process&lt;br /&gt;plaintext, full session]
        A2 --&amp;gt; A3[Renderer: autofill memcpy]
    end
    subgraph &quot;Decrypt-on-autofill (Chrome / Brave)&quot;
        B1[Disk: DPAPI blob] --&amp;gt; B2[Browser process&lt;br /&gt;plaintext, narrow RPC]
        B2 --&amp;gt; B3[Renderer: autofill]
    end
    subgraph &quot;OS-as-secret-broker&quot;
        C1[Disk: DPAPI-NG blob] --&amp;gt; C2[OS broker process&lt;br /&gt;plaintext only here]
        C2 -.handle.-&amp;gt; C3[Browser receives handle]
        C3 -.autofill via broker.-&amp;gt; C4[Renderer]
    end
&lt;h3&gt;Six-axis comparison&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Axis&lt;/th&gt;
&lt;th&gt;Decrypt-on-launch (Edge)&lt;/th&gt;
&lt;th&gt;Decrypt-on-autofill (Chrome, Brave)&lt;/th&gt;
&lt;th&gt;OS-as-broker&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Plaintext-in-RAM window&lt;/td&gt;
&lt;td&gt;Full session&lt;/td&gt;
&lt;td&gt;Autofill RPC (~ms)&lt;/td&gt;
&lt;td&gt;Never, in the browser process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autofill latency&lt;/td&gt;
&lt;td&gt;Memcpy (nanoseconds)&lt;/td&gt;
&lt;td&gt;DPAPI unwrap (~10s of microseconds)&lt;/td&gt;
&lt;td&gt;IPC + broker policy check (~ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same-user-LCE attack surface&lt;/td&gt;
&lt;td&gt;High (ReadProcessMemory exposes all)&lt;/td&gt;
&lt;td&gt;Low (must catch the RPC window)&lt;/td&gt;
&lt;td&gt;Negligible (no plaintext in the browser)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory-scraping forensics&lt;/td&gt;
&lt;td&gt;Trivial (any same-user dump works)&lt;/td&gt;
&lt;td&gt;Hard (must dump during fill)&lt;/td&gt;
&lt;td&gt;Impossible (no plaintext to dump)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync UX with cloud account&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Standard (broker handles sync)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engineering cost to ship&lt;/td&gt;
&lt;td&gt;Already shipped&lt;/td&gt;
&lt;td&gt;Already shipped (Chromium baseline)&lt;/td&gt;
&lt;td&gt;High (broker IPC, signed code path, extension renegotiation)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The OS-broker position is not hypothetical. The Windows Credential Manager already provides this property for Windows-app credentials. &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;WebAuthn and passkeys&lt;/a&gt; provide it for sites that have adopted the standard. The DPAPI-NG protection descriptors include a &lt;code&gt;WEBCREDENTIALS=&lt;/code&gt; variant [@ms-learn-dpapi-ng][@ms-learn-dpapi-ng-descriptors]. &lt;a href=&quot;https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/&quot; rel=&quot;noopener&quot;&gt;Pluton&lt;/a&gt;-anchored vTPM key unwrap provides a hardware-rooted broker substrate [@ms-learn-pluton]. Credential Guard&apos;s LSAISO trustlet is architecturally an isolated secret-broker for LSASS-derived secrets [@ms-learn-credential-guard].&lt;/p&gt;
&lt;p&gt;None of these primitives are wired into Edge&apos;s saved-passwords path. The engineering cost is non-trivial: the broker needs an IPC contract, the browser needs a signed-and-attested code path that talks to the broker, and the renderer extension API surface needs renegotiation. But the cost is finite, and the alternative is what Google has been shipping in Chrome since 2024 -- Chrome&apos;s App-Bound Encryption (see §7) is exactly a step toward the broker model, and Microsoft has the same DPAPI substrate but no equivalent control for Edge [@google-chrome-abe-2024].&lt;/p&gt;
&lt;h3&gt;What &quot;by design&quot; means structurally&lt;/h3&gt;
&lt;p&gt;Microsoft can take the &quot;by design&quot; position because they are not wrong about cryptography. They are right about the bound. No protocol can autofill plaintext into a child renderer without &lt;em&gt;some&lt;/em&gt; process in the chain holding plaintext at the moment of fill. The architectural question is &lt;em&gt;which&lt;/em&gt; process and &lt;em&gt;for how long&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Edge&apos;s answer: &quot;the parent browser process, for the entire session.&quot; Chrome and Brave&apos;s answer: &quot;the parent browser process, for the autofill RPC.&quot; The broker design&apos;s answer: &quot;a separate, higher-privileged process, for the autofill RPC, and never the browser at all.&quot;&lt;/p&gt;
&lt;p&gt;All three are valid points in the design space. The question is not &quot;which is right&quot; -- the answer depends on the user&apos;s environment -- but &quot;what should the default be for a 2026 consumer browser.&quot; The PSI half of the article shows Microsoft can choose the most demanding default when they want to. The endpoint half shows what default they chose here.&lt;/p&gt;
&lt;p&gt;To see why this is a structural property of the problem, not a Microsoft-specific gap, we need to look at the theoretical limits on both sides.&lt;/p&gt;
&lt;h2&gt;9. Theoretical limits&lt;/h2&gt;
&lt;p&gt;Two lower bounds, in parallel: one cryptographic (the PSI side), one architectural (the endpoint side).&lt;/p&gt;
&lt;h3&gt;PSI side: communication and computation lower bounds&lt;/h3&gt;
&lt;p&gt;The communication lower bound for PSI is folklore, used as the comparison baseline in Pinkas-Schneider-Zohner at USENIX Security 2014 [@psz-2014]. Informally: any PSI protocol must transmit at least $\Omega(\min(n_A, n_B) \cdot \kappa)$ bits, where $\kappa$ is the security parameter. The argument is information-theoretic: the receiver has to learn the intersection, which can have size up to $\min(n_A, n_B)$, and each element identifier needs $\Omega(\kappa)$ bits of representation to avoid collisions.&lt;/p&gt;
&lt;p&gt;Silent OT [@silent-ot-2019] meets this lower bound up to polylogarithmic factors in the symmetric balanced setting. HE-PSI in the asymmetric setting gets to $O(n_R \cdot \log n_S)$ ciphertexts via CLR17&apos;s partition-and-evaluate construction [@clr-2017], which is sublinear in $n_S$ -- the breakthrough that makes Edge Password Monitor practical.&lt;/p&gt;
&lt;p&gt;The computation lower bound on the sender side is $\Omega(n_S)$. The sender must, in the limit, touch each element of its set at least once per query. There is no way around this without trading correctness or privacy. Apple &quot;cheats&quot; by reducing the effective $n_S$: their 15-bit bucket cuts the per-query work to roughly $1.5\text{B} / 2^{15} \approx 46{,}000$ elements. Microsoft&apos;s two-byte shard cuts to roughly $5\text{B} / 2^{16} \approx 76{,}000$ elements. The lower bound applies &lt;em&gt;per shard&lt;/em&gt;, not per total corpus.&lt;/p&gt;
&lt;p&gt;The OT-extension lower bound is $\Omega(\kappa)$ base OTs per protocol session, with the bulk of the OT count amortised away by symmetric crypto. KOS15 meets this; Silent OT improves the wire constants further. By 2026, OT extension is essentially solved engineering.&lt;/p&gt;
&lt;h3&gt;Endpoint side: the &quot;no plaintext in process&quot; lower bound&lt;/h3&gt;
&lt;p&gt;The cryptographic side is comfortably tight. The endpoint side is much weirder.For a process $P$ to autofill a credential into a child form, &lt;em&gt;some component&lt;/em&gt; in the trust chain must hold the plaintext at the moment of fill. There are exactly three possible holders:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;$P$ itself.&lt;/strong&gt; The Edge design. Plaintext lives in the parent browser process throughout the session.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A child renderer $Q$.&lt;/strong&gt; The Chrome / Brave design. Plaintext crosses the parent-renderer boundary for the duration of the autofill RPC and gets zeroed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A separate higher-privileged broker $B$.&lt;/strong&gt; The OS-broker design. Plaintext lives in a sibling process that is harder to dump than the browser (in the limit, a PPL or a Credential-Guard-style trustlet).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No general cryptographic primitive lets a process &lt;em&gt;use&lt;/em&gt; a plaintext credential without ever &lt;em&gt;holding&lt;/em&gt; it. The plaintext is a value; the operations on it (paste-into-form, compute-HMAC-with-it, transmit-over-TLS-as-a-bearer-token) all require it in cleartext at some point. This is not a deficiency of any particular cryptosystem. It is the definition of &quot;use.&quot;&lt;/p&gt;
&lt;p&gt;The plaintext-RAM design Edge ships is not a cryptographic failure. It is a deliberate choice to spend the plaintext-in-RAM budget on UX latency. The escape hatch is &lt;em&gt;architectural&lt;/em&gt;: a hardware-isolated broker process. Pluton-anchored vTPM key unwrap [@ms-learn-pluton], Credential Guard&apos;s LSAISO pattern [@ms-learn-credential-guard], DPAPI-NG with the right protection descriptor [@ms-learn-dpapi-ng-descriptors] -- the OS primitives all exist.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; There is no cryptographic primitive that lets a process autofill plaintext without holding it. The only escape hatch is an architectural one: a higher-privileged broker. Microsoft already ships the broker primitives -- DPAPI-NG, Credential Guard, Pluton. They are not wired into Chromium.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The aha moment the rest of the article was built to deliver: the Ronning PoC is not a &quot;bug&quot; in any meaningful sense. The structural question is whether Microsoft should ship the architectural primitive -- which they already have, in DPAPI-NG and Credential Guard -- but have not wired into Chromium&apos;s password store. The &quot;by design&quot; response is technically true and politically convenient simultaneously. Both are correct readings.&lt;/p&gt;
&lt;p&gt;Both lower bounds are tight or near-tight today. The PSI side is essentially solved engineering; the endpoint side is essentially solved policy and unsolved deployment. The open questions are about which side we invest in next.&lt;/p&gt;
&lt;h2&gt;10. Open problems&lt;/h2&gt;
&lt;p&gt;Four open problems, framed as research directions Microsoft, Apple, and Google have not jointly committed to.&lt;/p&gt;
&lt;h3&gt;Open problem 1: post-quantum PSI and OT extension&lt;/h3&gt;
&lt;p&gt;Every deployed breach-checking protocol today rests on assumptions &lt;a href=&quot;https://paragmali.com/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/&quot; rel=&quot;noopener&quot;&gt;Shor&apos;s algorithm&lt;/a&gt; breaks. The OPRFs in Apple PSM and Google Password Checkup rely on discrete log over elliptic curves; the HE-PSI in Edge Password Monitor relies on BFV-on-classical-parameters; Paillier (historic, FNP04) relies on integer factorisation. Harvest-now-decrypt-later exposure on durable transcripts is the near-term migration question: an adversary capturing PSI transcripts today and storing them until a cryptographically relevant quantum computer arrives could, in principle, reconstruct the queries.&lt;/p&gt;
&lt;p&gt;Lattice-based OT extension exists at currently-secure parameters, at roughly $10\times$ the communication of IKNP per OT in early prototypes. Whether the breach-checking deployments at Microsoft, Apple, and Google migrate on the same timeline as the rest of TLS (the IETF post-quantum-handshake transition) is an open coordination problem.&lt;/p&gt;
&lt;h3&gt;Open problem 2: multi-party breach corpora&lt;/h3&gt;
&lt;p&gt;No production deployment of a $&amp;gt;2$-party breach-checking service exists. HIBP, Google, Apple, and Microsoft each hold corpora that overlap but contain unique breaches. Consolidating them privately -- so a query gets the union of all four corpora&apos;s match metadata without any one provider learning more than their own corpus contributed -- would meaningfully improve detection.&lt;/p&gt;
&lt;p&gt;The academic literature on multi-party PSI is substantial and growing, but the engineering and the governance work has not been done. Each provider has a different commercial relationship with the breach dataset, a different legal posture, and a different operational interest in their corpus being canonical. The cryptographic primitive is the easy part.&lt;/p&gt;
&lt;h3&gt;Open problem 3: sub-linear sender-side amortisation&lt;/h3&gt;
&lt;p&gt;The $\Omega(n_S)$ sender-side computation lower bound is &lt;em&gt;per query&lt;/em&gt;. For a service serving billions of queries against a static $S_S$, can per-query cost be amortised across queries via a preprocessing step the sender pays once?&lt;/p&gt;
&lt;p&gt;Cong et al. 2021 [@cong-2021] reduces constants substantially and pushes the practical envelope. Sub-linear &lt;em&gt;asymptotic&lt;/em&gt; sender-side cost is open. The information-theoretic barrier is real -- the sender must touch any element that could be in the receiver&apos;s query -- but the &lt;em&gt;expected&lt;/em&gt; cost over many queries against a static corpus admits a more aggressive analysis under the right access patterns.&lt;/p&gt;
&lt;h3&gt;Open problem 4: hardware-broker browser secret stores&lt;/h3&gt;
&lt;p&gt;The endpoint architectural problem. Migrate Edge, Chrome, and Brave from &quot;process-RAM plaintext&quot; to &quot;OS-broker (plaintext never crosses into the browser)&quot; using DPAPI-NG with a broker-PPL protection descriptor or a Credential Guard-style trustlet.&lt;/p&gt;
&lt;p&gt;WebAuthn and passkeys offer this property already -- the platform authenticator holds the private key, and the browser receives signed assertions without ever seeing the secret. But passkeys require per-site enrollment that traditional username-password sites have not adopted at scale; the long tail of legacy login forms will remain on saved-passwords-as-strings for years.&lt;/p&gt;
&lt;p&gt;The Windows Credential Manager offers the broker property for &lt;em&gt;Windows-app&lt;/em&gt; credentials -- but it is not wired into Chromium for &lt;em&gt;browser&lt;/em&gt; credentials. The engineering work is real; the cryptographic work is essentially trivial. Whether and when Microsoft, Google, or Brave commit to it is the question.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Open problem&lt;/th&gt;
&lt;th&gt;What&apos;s been tried&lt;/th&gt;
&lt;th&gt;Current best&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Post-quantum PSI&lt;/td&gt;
&lt;td&gt;Lattice-based OT, ring-LWE OPRFs&lt;/td&gt;
&lt;td&gt;Prototype-grade; 10x classical at ~secure parameters&lt;/td&gt;
&lt;td&gt;Harvest-now-decrypt-later on PSI transcripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-party breach corpora&lt;/td&gt;
&lt;td&gt;Multi-party PSI literature (e.g., Kolesnikov et al. CCS 2017)&lt;/td&gt;
&lt;td&gt;Academic constructions; no production deploy&lt;/td&gt;
&lt;td&gt;Each provider&apos;s corpus has unique recall&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sub-linear sender cost&lt;/td&gt;
&lt;td&gt;Cong et al. 2021 constants reduction&lt;/td&gt;
&lt;td&gt;Linear $\Omega(n_S)$ per query&lt;/td&gt;
&lt;td&gt;$5 \times 10^9$ corpus, billions of queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware-broker secret stores&lt;/td&gt;
&lt;td&gt;WebAuthn / passkeys; DPAPI-NG, Credential Guard&lt;/td&gt;
&lt;td&gt;Standards exist; wiring into browsers is missing&lt;/td&gt;
&lt;td&gt;The Ronning PoC threat model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

Open Chromium&apos;s process tree on Windows (Task Manager: Details, group by Path) and look for the `Google Chrome.exe` (or `msedge.exe`) process running with the `--type=` argument absent -- that&apos;s the parent. App-Bound Encryption binds the DPAPI unwrap to that exact parent process&apos;s signature, so a same-user attacker masquerading as Chrome cannot ask DPAPI to unwrap Chrome&apos;s data even with the right user identity. The architectural primitive is sitting in Chrome&apos;s source tree as of July 2024 [@google-chrome-abe-2024]; the equivalent control for Edge&apos;s password store has not shipped.
&lt;p&gt;These four open problems share a structure: each would require coordination across multiple vendors and across the cryptography / platform / browser boundary. None is research-blocked. All are governance-blocked.&lt;/p&gt;
&lt;h2&gt;11. Practical guide&lt;/h2&gt;
&lt;p&gt;What should you do this week?&lt;/p&gt;
&lt;h3&gt;Users&lt;/h3&gt;
&lt;p&gt;If your Edge browser is your password manager and you are on a single-user laptop you control end-to-end, the Ronning PoC&apos;s threat model is &quot;an attacker who can run code as you on your own machine.&quot; If that happens, the attacker is already in a strong position regardless of how Edge holds passwords -- they can keylog the next login, screenshot anything you autofill, or install a malicious browser extension. The marginal risk of the plaintext-RAM design on a single-user laptop is real but bounded.&lt;/p&gt;
&lt;p&gt;If you share a Windows host -- a family PC with multiple accounts, a small-business workstation several employees sign into, a domain-joined laptop on which IT has administrative access -- the calculus changes. Any same-user process can read your Edge plaintext during your session. Any administrator can read it across sessions (the PoC&apos;s &quot;Administrator can access other users&apos; Edge processes&quot; mode). The case for moving saved credentials out of Edge into a dedicated password manager (1Password, Bitwarden, KeePass) is structurally stronger here.&lt;/p&gt;
&lt;p&gt;A dedicated password manager usually still keeps plaintext in &lt;em&gt;its&lt;/em&gt; own process RAM during autofill -- this is the §9 lower bound asserting itself. The difference is the size of the plaintext-in-RAM window: dedicated password managers tend to require an explicit unlock and re-lock after a configurable idle period. Edge&apos;s window is the entire browser session.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On a multi-user Windows machine -- RDS, AVD, Citrix, a family computer with separate accounts -- disable Edge&apos;s password manager via the &lt;code&gt;PasswordManagerEnabled&lt;/code&gt; group policy and route users to an out-of-process credential broker (1Password&apos;s CLI integration, Bitwarden&apos;s desktop helper, or the platform Credential Manager).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Windows admins&lt;/h3&gt;
&lt;p&gt;The two relevant Edge enterprise policies are documented on Microsoft Learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;PasswordManagerEnabled&lt;/code&gt;&lt;/strong&gt; [@ms-learn-passwordmanagerenabled] -- turns Edge&apos;s saved-passwords feature on or off entirely. On a multi-user host with sensitive data, the right value is &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;PasswordMonitorAllowed&lt;/code&gt;&lt;/strong&gt; [@ms-learn-edge-pm] -- controls whether Password Monitor&apos;s breach-checking PSI runs at all. The default is &quot;user-controlled&quot;; in a managed enterprise, you may want to mandatorily enable it (independent of whether the password manager itself is enabled, because Password Monitor can check passwords you type into login forms, not just ones you have saved).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For RDS, AVD, and Citrix environments specifically, the threat model is structurally worse than a single-user laptop. Multiple users share a single Windows host. Their Edge profiles are isolated by Windows ACLs but their &lt;em&gt;processes&lt;/em&gt; are not isolated against an administrator. The PoC&apos;s &quot;Administrator privileges can access other users&apos; Edge processes&quot; mode is exactly the privilege available to a session-host administrator who has been compromised, or to a malicious tenant who escalates locally.&lt;/p&gt;

On a shared-tenant Windows host, the question is not whether same-user LCE will occur -- it is structurally more common than on a single-user laptop -- but how containable it is when it does. Saved browser credentials are an outsized lever for an attacker who pivots laterally: a single compromised user account on a session-host can yield every saved corporate credential for that user, and an administrator escalation can yield every saved credential for every user on the host. The hardening recommendation is to disable browser-based password management entirely (`PasswordManagerEnabled=0`) on session-host images, document an approved credential broker for your environment (Windows Credential Manager for native apps; an enterprise password manager with broker integration for browsers), and audit Edge profile directories on session-host images for stale `Login Data` SQLite files left over from earlier deployments.
&lt;h3&gt;Developers&lt;/h3&gt;
&lt;p&gt;If you ship a component that handles credentials, the design lesson from §9 is not &quot;never hold plaintext&quot; -- you cannot avoid it without an OS-level broker -- but &quot;minimise the plaintext-in-RAM window.&quot;&lt;/p&gt;
&lt;p&gt;The Chrome App-Bound Encryption pattern from July 2024 [@google-chrome-abe-2024] is a template: bind your at-rest key unwrap to a verified process identity so an attacker who exfiltrates your wrapped data cannot trivially unwrap it from a different process. If you must hold plaintext in the parent process for the lifetime of the session (the Edge design), make the trade explicit in the threat model documentation and ensure operations consuming the plaintext are auditable.&lt;/p&gt;
&lt;p&gt;If you can architecturally afford a broker, do it. The IPC cost is real (low-microsecond per call) but small compared to the operational reduction in incident severity. WebAuthn / passkeys are the long-term destination for credentials; the broker pattern is the short-term destination for everything else.&lt;/p&gt;
&lt;h2&gt;12. Frequently asked questions&lt;/h2&gt;

Yes, at rest on disk. DPAPI wraps the symmetric key that encrypts Edge&apos;s `Login Data` SQLite file under a key chain rooted in the user&apos;s password. When the user is logged out (or the machine is powered off), the on-disk blob is opaque to anyone who does not have the user&apos;s DPAPI credentials. The protection ends the moment Edge unwraps the DPAPI blob into process memory, which happens during browser launch or the first password-feature activation. Once unwrapped, the credentials sit in `msedge.exe`&apos;s heap until the process exits, and `ReadProcessMemory` from any same-user process reads them as plaintext. DPAPI is an at-rest control, not an in-memory one.

Partially. If Edge ran as a protected process at an appropriate signature level, only an antimalware-PPL-elevated process could open it for `ReadProcessMemory`, which would substantially raise the bar against a same-user attacker. Browser-process PPL has implications for every loaded DLL (each must be signed at or above the host&apos;s PPL level) and every extension API the renderer expects to call. Chrome and Brave have not adopted PPL for the browser process either. Microsoft has the option; they have not used it. PPL would address the same-user-LCE concern but not the administrator-across-sessions concern.

No. Credential Guard isolates LSASS-derived secrets (NTLM hashes, Kerberos tickets, cached credentials) into the LSAISO trustlet running under Virtualization-Based Security, which is unreachable from the normal-world kernel let alone normal-world user-mode processes. It does not cover browser-owned secrets. Saved Edge credentials live in `msedge.exe`&apos;s heap, not in LSASS, and Credential Guard does not extend protection to arbitrary user-mode application secret stores.

No, in the strict cryptographic sense. K-anonymity leaks the bucket index by design -- the server learns a 20-bit (HIBP), 15-bit (Apple), or 16-bit (Edge shard) prefix of the hash being queried, which carries non-trivial information about which password the client is asking about. A proper PSI protocol leaks nothing beyond the intersection itself. The argument for k-anonymity is that the bucket is large enough -- on the order of hundreds to thousands of possible hashes per bucket -- that the residual information is not actionable for the threats most users face. It is a precise statement of &quot;a small leak in exchange for vast practical efficiency&quot;; the cost is documented and bounded, and that is why every deployed service uses some variant of it. But it is not zero-leak.

Threat-model differences and SGX&apos;s well-documented side-channel literature (see the §6 Aside for the four-attack chronology). For a breach-checking service whose threat model is &quot;the corpus must not leak from inside Microsoft,&quot; HE-PSI offers a clean cryptographic argument that does not depend on any TEE&apos;s silicon-level security claims. The MSR Cryptography and Privacy group had been publishing the relevant HE-PSI papers since 2017 and shipping the SEAL library publicly since 2018, so the substrate was in-house. The cost is real (orders of magnitude more compute than an SGX enclave) but tractable at the sharded scale Edge Password Monitor operates at. The trade is reasonable, and it is documented in the MSR blog [@msr-password-monitor-2021].

AMSI evasion. The Antimalware Scan Interface scans .NET 4.8+ assemblies before execution; .NET 3.5 predates AMSI&apos;s API surface entirely. A C# program targeting .NET 3.5 will run on any modern Windows with the legacy framework installed (which is most of them, because .NET 3.5 is shipped as a Windows feature) and will not be subject to the same managed-runtime scanning that 4.8+ assemblies are. The current GitHub README says &quot;.NET Framework 4.8.1 (changed from 3.5 originally)&quot; [@ronning-github] -- likely to ease running on a clean modern Windows -- but the original .NET 3.5 framing was the deliberate AMSI-evasion choice. The sibling AMSI post in this series explains the scanning architecture in detail.

Per the researcher&apos;s claim and the PCWorld relay, no -- see §7 for the decrypt-on-autofill contrast and Chrome&apos;s App-Bound Encryption hardening [@pcworld-pippig-2026][@google-chrome-abe-2024]. The observable difference is direct: a `ReadProcessMemory`-based scrape of an idle Chrome process returns markedly less than the same scrape of an idle Edge process.

Yes (with caveats). See §7&apos;s MSRC-servicing-criteria Aside for the full framing [@msrc-servicing-criteria]: the short answer is that the position is internally consistent with a decade of MSRC policy and with the §9 architectural lower bound, but it concedes the same-user LCE threat model and shifts defence onto endpoint controls (antivirus, application-control policies, PPL on antimalware processes only) that may not exist on the user&apos;s machine. The architectural primitive that would close the gap (an OS broker) exists on Windows but is not wired into Chromium.
&lt;p&gt;The PSI on the wire is real. The plaintext-RAM concession is also real. Both are statements about which threat model the Edge product team is defending against, and the apparent contradiction in the title disappears once you read them as such.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;edges-two-password-cryptographies&quot; keyTerms={[
  { term: &quot;Private Set Intersection (PSI)&quot;, definition: &quot;A two-party cryptographic protocol that computes the intersection of two sets without revealing anything else.&quot; },
  { term: &quot;Oblivious Transfer (OT)&quot;, definition: &quot;A primitive in which a sender holds two messages, a receiver picks one, and neither learns the other&apos;s choice or the unsent message.&quot; },
  { term: &quot;OT extension&quot;, definition: &quot;Two-phase protocol that turns kappa public-key OTs into m symmetric-cost OTs, collapsing per-OT cost by orders of magnitude.&quot; },
  { term: &quot;Oblivious Pseudorandom Function (OPRF)&quot;, definition: &quot;Two-party protocol where the receiver learns F_k(x) without revealing x to the sender or learning k.&quot; },
  { term: &quot;Pseudorandom Correlation Generator (PCG)&quot;, definition: &quot;Primitive that locally expands a short shared seed into long correlated random strings, used to make Silent OT communication-free post-seed.&quot; },
  { term: &quot;Homomorphic encryption (HE / SWHE / FHE)&quot;, definition: &quot;Encryption supporting operations on ciphertexts that decrypt to operations on plaintexts; SWHE is bounded depth, FHE is unbounded via bootstrapping.&quot; },
  { term: &quot;Cuckoo hashing&quot;, definition: &quot;Hashing with k candidate bins per element and displacement, achieving O(1) lookup at high load -- the partitioning trick under CLR17 and CHLR18.&quot; },
  { term: &quot;k-anonymity (password monitoring)&quot;, definition: &quot;A precise small information leak: each query is consistent with at least k possible passwords sharing the bucket prefix.&quot; },
  { term: &quot;Data Protection API (DPAPI)&quot;, definition: &quot;Windows facility that wraps blobs under user-derived keys; an at-rest control, not an in-process-memory control.&quot; },
  { term: &quot;App-Bound Encryption (Chrome, July 2024)&quot;, definition: &quot;Chrome control that binds DPAPI unwrap of saved data to the verified Chrome process identity, blocking same-user impersonation attacks.&quot; }
]} questions={[
  { q: &quot;Why does the DH meet-in-the-middle PSI protocol fail at breach-checking scale?&quot;, a: &quot;It costs O(|S_B|) group exponentiations per query, leaks set cardinality on both sides, and provides no labeled-PSI variant.&quot; },
  { q: &quot;What three engineering moves let CLR17 revive FNP04&apos;s polynomial-roots PSI?&quot;, a: &quot;(1) BFV SWHE replaces Paillier for slot-packed homomorphic evaluation, (2) Cuckoo hash partitioning splits the giant polynomial into per-bin polynomials, (3) partition-and-evaluate bounds server work to O(|S_S| log |S_R|).&quot; },
  { q: &quot;What does the OPRF preprocessing layer add to Edge Password Monitor&apos;s bare HE-PSI?&quot;, a: &quot;It prevents a malicious client from brute-forcing the server&apos;s corpus offline; the client cannot evaluate F_k(x) without server interaction.&quot; },
  { q: &quot;What does the EdgeSavedPasswordsDumper PoC require to read Edge passwords as cleartext?&quot;, a: &quot;Same-user OpenProcess + ReadProcessMemory on the parent msedge.exe. No kernel exploit, no admin (against same-user processes), no DPAPI bypass.&quot; },
  { q: &quot;Why is &apos;no cryptographic primitive closes the plaintext-RAM gap&apos; the structural claim of section 9?&quot;, a: &quot;Using a plaintext value requires holding it; the only escape hatch is moving the holder to a higher-privileged broker process, which is an architectural choice, not a cryptographic one.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>private-set-intersection</category><category>homomorphic-encryption</category><category>microsoft-edge</category><category>password-security</category><category>threat-modeling</category><category>dpapi</category><category>cryptography</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>