This page captures the 14 business rules enforced by SAIF.NetCore.LegacyAuth's cookie-issuance and DPAPI encryption logic. Rule IDs use a plain, sequentially-numbered scheme for this library (see the rule headings below).
Legacy cookie credentials are encrypted with the machine DPAPI scope.
Trigger
SetCookie → DPAPI.Encrypt
Enforcement
LegacyAuthCookieService.Encrypt passes KeyType.MachineKey; DPAPI.Encrypt(KeyType, byte[], byte[], string) maps it to the CRYPTPROTECT_LOCAL_MACHINE flag.
Outcome
The ciphertext can be decrypted by any process on the same machine, and only on that machine.
The cookie value is written without URL-encoding so that the legacy .NET Framework SecurityModule can decrypt it.
Trigger
AddCookieToHeader
Enforcement
LegacyAuthCookieService.AddCookieToHeader builds a SetCookieHeaderValue and appends its rendered string directly to the Set-Cookie header, bypassing Response.Cookies.Append's automatic encoding.
Outcome
Raw Base64 (including +, /, = characters) is sent in the Set-Cookie header.
BR-10 Active HTTP request required for cookie operations¶
Field
Value
Statement
SetCookie requires both an active ambient HttpContext (resolved from IHttpContextAccessor) and a known remote IP on that context; ClearCookie requires only an active ambient HttpContext and never reads the remote IP. AddCookieToHeader is unaffected — it takes an explicit HttpContext parameter rather than resolving one from the accessor.
Trigger
SetCookie, ClearCookie
Enforcement
Neither SetCookie nor ClearCookie guards against a nullHttpContext from _httpContextAccessor.HttpContext before use; SetCookie additionally dereferences context.Connection.RemoteIpAddress.ToString() without a null guard. ClearCookie only accesses context.Response.Cookies, so it never touches RemoteIpAddress.
Outcome
A NullReferenceException is thrown when HttpContext is null for either method, and additionally when RemoteIpAddress is null for SetCookie only.
Every encrypt/decrypt call made through the managed DPAPI wrapper methods must never prompt or show UI. This guarantee applies only to the managed wrapper: a consumer calling the public CryptProtectData/CryptUnprotectData externs directly supplies its own dwFlags and is not subject to it.
Trigger
Every managed Encrypt/Decrypt call
Enforcement
DPAPI.cs's managed Encrypt/Decrypt overloads always include the CRYPTPROTECT_UI_FORBIDDEN flag and initialize the prompt struct with no window handle or prompt text before calling the native primitive.
Outcome
Calls made through the managed wrapper are suitable for non-interactive server processes; direct calls to the raw externs can enable a UI prompt if the caller chooses to omit the flag.
BR-12 Generic exception wrapping on encryption failure¶
Field
Value
Statement
Every failure raised inside the managed byte-array Encrypt(KeyType, byte[], byte[], string) overload's try block surfaces as a generic System.Exception("DPAPI was unable to encrypt data.") wrapping the original cause (a Win32Exception for native API failures). A direct call to the public CryptProtectData extern is not wrapped; it returns the raw native bool result and leaves failure handling to the caller.
Trigger
Any exception raised inside the byte-array Encrypt(KeyType, byte[], byte[], string) overload's try block — not InitPrompt (called before the try block starts), the string overload's own Encoding.UTF8.GetBytes/Convert.ToBase64String calls (which run outside the byte overload entirely), or the finally block's cleanup
Enforcement
A single catch/rethrow wraps every failure path inside that overload's try block, including a CryptProtectData return of false.
Outcome
For the exceptions scoped by the Trigger above (those raised inside the byte-array overload's try block), callers cannot catch a specific exception type; the Win32 error code is only available in the inner exception. Preparation, UTF-8/Base64 conversion, and cleanup failures outside that try block — and any failure from a direct call to the raw extern — propagate unwrapped.
DPAPI is loaded only from the fixed path c:\windows\system32\crypt32.dll.
Trigger
First CryptProtectData call
Enforcement
DllImportAttribute on DPAPI.CryptProtectData and CryptUnprotectData hard-codes the absolute DLL path.
Outcome
Windows-only behavior; it fails on other operating systems or non-default Windows installation directories. A call through the managed Encrypt/Decrypt wrapper has the resulting DllNotFoundException wrapped per BR-12; a direct call to the raw externs receives the unwrapped DllNotFoundException since BR-12 does not apply to that path.
Note: Statements marked with * were inferred from code structure, naming
conventions, or contextual evidence where direct confirmation was not available
in source artifacts.