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


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.

Comments (4)
  1. skSdnW says:

    And when was it added? During a 2000 SP? In XP? When the function moved to crypt32.dll with 2003?

    Was it added because of TS/RDP reasons or something else?

    [It was added while the function was still internal. I don't know why it was added. -Raymond]
  2. Burov Dmitry says:

    @skSdnW Win2003 = WinXP x64 = WinNT 5.2

    For what i recall from Delphi Win32 API project, it was moved and given name in Vista. In XP/2003 it only had a number index, not a public name

  3. Burov Dmitry says:

    "The memory block returned by the CryptProtectMemory function can be decrypted only on the same machine that encrypted it, and only as long as the machine has not been rebooted"

    This line only is about "SAME_LOGON" option. In "same windows instance" aka cross-process mode the function works across reboots.

    SAME_LOGON is just a bad, ambiguous constant name, it can stand for both "SAME_USER_IDENTITY" and "SAME_USER_SESSION", the latter obviously cannot survive reboot.

    An obvious consequence of this fuction being internal one that occasionally leaked out and after found used by 3rd party applications eventually published "as is" without a lot of effort to document it

    ["Typically, you use the CryptProtectMemory function to encrypt sensitive information that you are going to decrypt while your process is running. Do not use this function to save data that you want to decrypt later; you will not be able to decrypt the data if the computer is restarted." This is in the general discussion, not in the SAME_LOGON section. -Raymond]
  4. Myria says:

    Looks like my theory #2 from the old thread was essentially correct =^-^=

    “Theory 2 (IMO more likely): dwFlags was originally intended to be a flags parameter, but now doesn't really mean "flags".  Only one flag was defined at first, CRYPTPROTECTMEMORY_CROSS_PROCESS.  Eventually, the meaning of dwFlags morphed into meaning "scope" rather than "flags".  The absence of the former "flag" had to be given a name, hence CRYPTPROTECTMEMORY_SAME_PROCESS.  The same-machine scope was left as the former flag's name, CRYPTPROTECTMEMORY_CROSS_PROCESS.  The new functionality was added as CRYPTPROTECTMEMORY_SAME_LOGON.”

Comments are closed.

Skip to main content