---
title: Protect and unprotect sensitive values
summary: Use Windows DPAPI to encrypt or decrypt string and byte-array payloads.
status: draft
owner: SAIF Documentation Team
last_reviewed: 2026-07-30
library: SAIF.Framework.SecurityModule
reference_type: package
operation_id: protect-and-unprotect-sensitive-values
trigger: Caller invokes DPAPI.Encrypt or DPAPI.Decrypt.
---

# Protect and unprotect sensitive values

This operation wraps Windows DPAPI for any caller that needs to protect a plaintext value or recover a value that was previously protected. Inside this library it underpins the credential payload packed into the `SAIFAUTH` cookie, but the public `DPAPI` class exposes the same encrypt/decrypt workflow to any code that can reference this assembly.

| Field | Value |
| --- | --- |
| **Operation ID** | `protect-and-unprotect-sensitive-values` |
| **Trigger** | Caller invokes `DPAPI.Encrypt` or `DPAPI.Decrypt`. |
| **Inputs** | Plaintext/ciphertext strings or byte arrays, optional entropy, optional description, optional key scope |
| **Outputs** | Base64 ciphertext, plaintext string/bytes, or a wrapped exception |
| **Primary components** | `DPAPI.Encrypt`, `DPAPI.Decrypt`, `DPAPI.InitBLOB`, `DPAPI.InitPrompt` |
| **Entry point** | `SAIF.Framework.SecurityModule\DAPIEncrypt.vb` |

## Steps

1. Normalize nullable string inputs to empty strings in the string overloads, then convert string payloads to UTF-8 byte arrays before delegating to the byte-oriented overloads that do the actual work.
2. Initialize unmanaged `DATA_BLOB` structures for the payload and any optional entropy by allocating unmanaged memory and copying the input bytes into it.
   - On failure: if allocation fails, raise an exception immediately, before any Win32 encryption or decryption call is attempted.
3. Initialize a zeroed `CRYPTPROTECT_PROMPTSTRUCT`, since the DPAPI Win32 functions require this structure even when interactive prompting is disabled.
4. On the encryption path, set `CRYPTPROTECT_UI_FORBIDDEN`, add `CRYPTPROTECT_LOCAL_MACHINE` when the caller selected `MachineKey` scope, and call Win32 `CryptProtectData`.
   - If the API call fails, capture `Marshal.GetLastWin32Error()` and wrap it in a `Win32Exception`, then a higher-level `Exception`.
   - If the API call succeeds, copy the protected bytes out of the output BLOB and return them either as a raw byte array or as a Base64 string, depending on the overload called.
5. On the decryption path, Base64-decode the input when the string overload was used, initialize ciphertext and entropy BLOBs, and call Win32 `CryptUnprotectData`.
   - If the API call fails, capture `Marshal.GetLastWin32Error()` and wrap it in a `Win32Exception`, then a higher-level `Exception`.
   - If the API call succeeds, copy the plaintext bytes out of the output BLOB and return them either as a raw byte array or as a UTF-8 string.
6. In `Finally`, free every unmanaged buffer that was allocated for plaintext, ciphertext, and entropy BLOBs, whether the call returns normally or rethrows.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Encrypt or decrypt request]) --> S1[Normalize inputs]
	S1 --> S2[Allocate DATA_BLOB structures]
	S2 --> D1{Encrypt path?}
	D1 -->|Yes| S3[Call CryptProtectData]
	D1 -->|No| S4[Call CryptUnprotectData]
	S3 --> S5[Copy output bytes]
	S4 --> S5
	S5 --> EndOk([Free buffers and return result])
```

## Failure and edge-case behavior

- Null plaintext, entropy, and description values are normalized to empty strings rather than rejected, so callers do not need to guard against nulls before calling the string overloads.
- Both the encrypt and decrypt paths wrap Win32 failures in higher-level exceptions that preserve the underlying Win32 error code, so callers can still diagnose the root cause.
- Every unmanaged buffer allocated during the call is freed in `Finally`, including when initialization or the DPAPI call itself fails — the operation does not leak unmanaged memory on the error path.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Configuration](../configuration.md)

## Sources
- `SAIF.Framework.SecurityModule\DAPIEncrypt.vb`
