255 lines
6.7 KiB
C#
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; }
|
|
}
|