mirror of
https://github.com/azaion/admin.git
synced 2026-06-21 15:51:10 +00:00
a77b3f8a59
Refreshes _docs/02_document/ to reflect the cycle-2 auth-modernization
+ CMMC hardening landings (AZ-531..AZ-538). Authoritative source for
the ripple set is ripple_log_cycle2.md.
Covered:
- architecture.md (section 1 rewritten, ADRs 6-9 added)
- data_model.md (sessions, audit_events, user columns, migrations)
- system-flows.md (F1 rewritten; F11-F17 added; F2/F7/F9 minor)
- module-layout.md (cycle-2 sub-component table)
- diagrams/flows/flow_login.md (dual-token + MFA)
- components/{01_data_layer,03_auth_and_security,05_admin_api}
- modules/ (12 new, 8 modified — full Argon2id/ES256/MFA/refresh
/mission/session/audit/jwks rollup)
- tests/{blackbox,security,traceability-matrix}
Step 13 (Update Docs) output for cycle 2.
Co-authored-by: Cursor <cursoragent@cursor.com>
80 lines
4.8 KiB
Markdown
80 lines
4.8 KiB
Markdown
# Module: Azaion.Services.Security
|
||
|
||
## Purpose
|
||
Static utility class providing password hashing and verification. As of cycle 2, hashes new passwords with **Argon2id (RFC 9106)** and transparently re-hashes legacy SHA-384 entries on the next successful login.
|
||
|
||
> **Cycle 1 (2026-05-13) note** — `GetHWHash` deleted; `GetApiEncryptionKey` simplified by AZ-197.
|
||
>
|
||
> **Cycle 2 (2026-05-14) note A** — `GetApiEncryptionKey` / `EncryptTo` / `DecryptTo` removed with the encrypted-download endpoint. The `Azaion.Test` project went with them.
|
||
>
|
||
> **Cycle 2 (2026-05-14) note B (AZ-536)** — `ToHash` was removed and replaced with `HashPassword` + `VerifyPassword`. Hash format is now PHC: `$argon2id$v=19$m=65536,t=3,p=1$<salt-b64>$<hash-b64>`. Legacy SHA-384 hashes (64-char Base64, no `$` prefix) are still accepted for verification and the verify path returns `NeedsRehash=true` so `UserService.ValidateUser` can rewrite them on the success path. Epic AZ-530, CMMC IA.L2-3.5.10.
|
||
|
||
## Public Interface
|
||
|
||
| Method | Signature | Description |
|
||
|--------|-----------|-------------|
|
||
| `HashPassword` | `static string HashPassword(string plaintext)` | Generates a 16-byte salt, computes Argon2id with the conservative defaults below, returns a PHC string. |
|
||
| `VerifyPassword` | `static VerifyResult VerifyPassword(string plaintext, string stored)` | Detects format by prefix. Argon2id PHC → re-derives + constant-time compare; legacy SHA-384 → re-hashes + constant-time compare. Returns `Valid`, plus `NeedsRehash=true` when (a) the stored hash is legacy SHA-384, or (b) the stored Argon2 parameters are weaker than current defaults. |
|
||
|
||
### `record VerifyResult(bool Valid, bool NeedsRehash)`
|
||
|
||
Carries the verification outcome. `NeedsRehash` is the trigger for `UserService.RegisterSuccessfulLogin` to write a fresh Argon2id hash back to the row.
|
||
|
||
## Internal Logic
|
||
|
||
**Defaults (RFC 9106 §4 conservative profile)**:
|
||
- Memory: 65536 KiB (64 MiB)
|
||
- Iterations: 3
|
||
- Parallelism: 1
|
||
- Salt: 16 bytes (128 bits) per RFC §3.1 minimum
|
||
- Hash output: 32 bytes (256 bits)
|
||
|
||
**Format detection**:
|
||
- Argon2id PHC string starts with `$argon2id$`.
|
||
- Legacy SHA-384: exactly 64 base64 characters and does NOT start with `$`.
|
||
- Anything else fails verify with `Valid=false, NeedsRehash=false`.
|
||
|
||
**PHC encoding** uses base64 *without* padding (PHC convention):
|
||
```
|
||
$argon2id$v=19$m=<KiB>,t=<iters>,p=<lanes>$<salt-b64-nopad>$<hash-b64-nopad>
|
||
```
|
||
|
||
**Constant-time comparison** uses `CryptographicOperations.FixedTimeEquals` for both formats — addresses AZ-536 AC-5 (no remotely-observable timing leak).
|
||
|
||
## Dependencies
|
||
|
||
- `Konscious.Security.Cryptography.Argon2` (Argon2id implementation, pure C#)
|
||
- `System.Security.Cryptography.SHA384` (legacy verify path)
|
||
- `System.Security.Cryptography.RandomNumberGenerator` (salt entropy)
|
||
- `System.Security.Cryptography.CryptographicOperations` (constant-time compare)
|
||
|
||
## Consumers
|
||
|
||
- `Azaion.Services/UserService.cs`
|
||
- `RegisterUser` — calls `HashPassword(request.Password)`
|
||
- `ValidateUser` → `RegisterSuccessfulLogin` — calls `VerifyPassword`; on `NeedsRehash` writes a fresh Argon2id hash back transactionally (conditional on the original hash to avoid clobbering a parallel rehash)
|
||
- `Azaion.Services/MfaService.cs`
|
||
- `Enroll` and `Disable` — re-auth via `VerifyPassword(password, user.PasswordHash)`
|
||
|
||
## Data Models
|
||
None.
|
||
|
||
## Configuration
|
||
None directly. The defaults are class-level constants. Bumping them later automatically surfaces `NeedsRehash=true` for any older stored hash, so the upgrade is lazy and transparent.
|
||
|
||
## External Integrations
|
||
None.
|
||
|
||
## Security
|
||
|
||
- Argon2id memory cost (64 MiB) makes GPU bruteforce attacks orders of magnitude slower than the previous SHA-384 path. Each verify costs ~50–200 ms on commodity hardware (intentional latency floor).
|
||
- Legacy SHA-384 hashes are migrated on next successful login (lazy migration). Service accounts that never log in interactively (CompanionPC devices) need an admin-side bulk-reset rotation cycle to upgrade.
|
||
- The verify path is constant-time end-to-end via `FixedTimeEquals` — defends AZ-536 AC-5.
|
||
- The "needs rehash" flag also covers future parameter bumps: raising `Argon2MemoryKib`/`Argon2Iterations` here will make all weaker stored hashes upgrade themselves on the next login.
|
||
|
||
## Tests
|
||
|
||
- `e2e/Azaion.E2E/Tests/PasswordHashingTests.cs` — AC-1 (PHC format), AC-2 (legacy SHA-384 still validates), AC-3 (transparent re-hash), AC-4 (wrong password fails for both formats), AC-5 (constant-time verify).
|
||
- **Known follow-up** (carried from cycle 2 batch 4 review) — `PasswordHashingTests.AC5_Verify_uses_constant_time_comparator_no_obvious_timing_leak` is intermittently flaky under suite-level concurrency; widen the assertion bound or warm Argon2 with a non-test login first.
|
||
- `Azaion.Services` is exercised end-to-end through every login / register / MFA flow in `e2e/Azaion.E2E/Tests/`.
|