Files
git.stella-ops.org/src/Cryptography/StellaOps.Cryptography/KeyEscrow/KeyEscrowModels.cs

255 lines
6.7 KiB
C#

// Copyright © StellaOps. All rights reserved.
// SPDX-License-Identifier: AGPL-3.0-or-later
// Sprint: SPRINT_20260112_018_CRYPTO_key_escrow_shamir
// Tasks: ESCROW-003, ESCROW-005
namespace StellaOps.Cryptography.KeyEscrow;
/// <summary>
/// A key share for escrow storage.
/// Contains encrypted share data and metadata for recovery.
/// </summary>
public sealed record KeyShare
{
/// <summary>
/// Unique identifier for this share.
/// </summary>
public required Guid ShareId { get; init; }
/// <summary>
/// Share index (1..N from Shamir splitting).
/// </summary>
public required int Index { get; init; }
/// <summary>
/// Encrypted share data (encrypted with escrow agent's public key or shared key).
/// </summary>
public required byte[] EncryptedData { get; init; }
/// <summary>
/// ID of the key that was split (for correlation during recovery).
/// </summary>
public required string KeyId { get; init; }
/// <summary>
/// Minimum number of shares needed to reconstruct (M in M-of-N).
/// </summary>
public required int Threshold { get; init; }
/// <summary>
/// Total number of shares created (N in M-of-N).
/// </summary>
public required int TotalShares { get; init; }
/// <summary>
/// When this share was created.
/// </summary>
public required DateTimeOffset CreatedAt { get; init; }
/// <summary>
/// When this share expires and should be deleted.
/// </summary>
public required DateTimeOffset ExpiresAt { get; init; }
/// <summary>
/// ID of the custodian (escrow agent) holding this share.
/// </summary>
public required string CustodianId { get; init; }
/// <summary>
/// SHA-256 checksum of the unencrypted share data (hex encoded).
/// Used to verify share integrity after decryption.
/// </summary>
public required string ChecksumHex { get; init; }
/// <summary>
/// Schema version for forward compatibility.
/// </summary>
public string SchemaVersion { get; init; } = "1.0.0";
/// <summary>
/// Key derivation info (salt, algorithm) if share is encrypted with derived key.
/// </summary>
public ShareEncryptionInfo? EncryptionInfo { get; init; }
}
/// <summary>
/// Encryption metadata for a key share.
/// </summary>
public sealed record ShareEncryptionInfo
{
/// <summary>
/// Encryption algorithm used (e.g., "AES-256-GCM").
/// </summary>
public required string Algorithm { get; init; }
/// <summary>
/// Key derivation function if applicable (e.g., "PBKDF2-SHA256", "HKDF-SHA256").
/// </summary>
public string? KeyDerivationFunction { get; init; }
/// <summary>
/// Salt for key derivation (base64 encoded).
/// </summary>
public string? SaltBase64 { get; init; }
/// <summary>
/// Iteration count for PBKDF2 (if applicable).
/// </summary>
public int? Iterations { get; init; }
/// <summary>
/// Nonce/IV for the encryption (base64 encoded).
/// </summary>
public required string NonceBase64 { get; init; }
/// <summary>
/// Authentication tag for AEAD (base64 encoded, if applicable).
/// </summary>
public string? AuthTagBase64 { get; init; }
}
/// <summary>
/// Result of a key escrow operation.
/// </summary>
public sealed record KeyEscrowResult
{
/// <summary>
/// Whether the escrow operation succeeded.
/// </summary>
public required bool Success { get; init; }
/// <summary>
/// ID of the escrowed key.
/// </summary>
public required string KeyId { get; init; }
/// <summary>
/// IDs of all created shares.
/// </summary>
public required IReadOnlyList<Guid> ShareIds { get; init; }
/// <summary>
/// Threshold required for recovery.
/// </summary>
public required int Threshold { get; init; }
/// <summary>
/// Total shares created.
/// </summary>
public required int TotalShares { get; init; }
/// <summary>
/// When the shares expire.
/// </summary>
public required DateTimeOffset ExpiresAt { get; init; }
/// <summary>
/// Error message if operation failed.
/// </summary>
public string? Error { get; init; }
}
/// <summary>
/// Request to recover a key from escrow.
/// </summary>
public sealed record KeyRecoveryRequest
{
/// <summary>
/// ID of the key to recover.
/// </summary>
public required string KeyId { get; init; }
/// <summary>
/// Reason for the recovery (audit requirement).
/// </summary>
public required string Reason { get; init; }
/// <summary>
/// ID of the user initiating recovery.
/// </summary>
public required string InitiatorId { get; init; }
/// <summary>
/// IDs of custodians who have authorized recovery.
/// </summary>
public required IReadOnlyList<string> AuthorizingCustodians { get; init; }
/// <summary>
/// Reference to dual-control ceremony if required.
/// </summary>
public string? CeremonyId { get; init; }
}
/// <summary>
/// Result of a key recovery operation.
/// </summary>
public sealed record KeyRecoveryResult
{
/// <summary>
/// Whether recovery succeeded.
/// </summary>
public required bool Success { get; init; }
/// <summary>
/// ID of the recovered key.
/// </summary>
public required string KeyId { get; init; }
/// <summary>
/// Recovered key material (cleared after use).
/// </summary>
public byte[]? KeyMaterial { get; init; }
/// <summary>
/// Number of shares used in recovery.
/// </summary>
public int SharesUsed { get; init; }
/// <summary>
/// Error message if recovery failed.
/// </summary>
public string? Error { get; init; }
/// <summary>
/// Recovery audit event ID for tracking.
/// </summary>
public Guid? AuditEventId { get; init; }
}
/// <summary>
/// An escrow agent (custodian) who holds key shares.
/// </summary>
public sealed record EscrowAgent
{
/// <summary>
/// Unique agent identifier.
/// </summary>
public required string AgentId { get; init; }
/// <summary>
/// Display name of the agent.
/// </summary>
public required string Name { get; init; }
/// <summary>
/// Contact email for recovery notifications.
/// </summary>
public required string Email { get; init; }
/// <summary>
/// Public key for encrypting shares to this agent (PEM encoded).
/// </summary>
public required string PublicKeyPem { get; init; }
/// <summary>
/// Whether this agent is currently active.
/// </summary>
public bool IsActive { get; init; } = true;
/// <summary>
/// When this agent was registered.
/// </summary>
public required DateTimeOffset RegisteredAt { get; init; }
}