How did the scopes for the CryptProtectMemory function end up in a strange order?

Raymond Chen


A few weeks ago, I left an exercise: Propose a theory as to why the names and values of the scopes for the Crypt­Protect­Memory function are the way they are.

I didn’t know the answer when I posed the exercise, but I went back and dug into it.

The Crypt­Protect­Memory function started out as an internal function back in Windows 2000, and when originally introduced, there were only two scopes: Within a process and cross-process. The Flags parameter therefore defined only a single bit, leaving the other bits reserved (must be zero). If the bottom bit was clear, then the memory was protected within a process; if the bottom bit was set, then the memory was protected across processes.

Later, the team realized that they needed to add a third scope, the one that corresponds to CRYPT­PROTECT_SAME_LOGON. They didn’t want to make a breaking change for existing callers, but they saw that they could retarget what used to be a Flags parameter as an Options parameter, and they added the new scope as a third option.

The numeric values remained unchanged, which meant that the new function was backward-compatible with existing callers.

Bonus chatter: Commenter sense is correct that SAME_LOGON can be used by a service while impersonating the client, however it is not the case that the scope can be larger when impersonating a remote user. The memory block returned by the Crypt­Protect­Memory function can be decrypted only on the same machine that encrypted it, and only as long as the machine has not been rebooted.

Raymond Chen
Raymond Chen

Follow Raymond