- Added DefaultCryptoHmac class implementing ICryptoHmac interface. - Introduced purpose-based HMAC computation methods. - Implemented verification methods for HMACs with constant-time comparison. - Created HmacAlgorithms and HmacPurpose classes for well-known identifiers. - Added compliance profile support for HMAC algorithms. - Included asynchronous methods for HMAC computation from streams.
289 lines
12 KiB
C#
289 lines
12 KiB
C#
namespace StellaOps.Cryptography;
|
|
|
|
/// <summary>
|
|
/// Built-in compliance profiles for different jurisdictional crypto requirements.
|
|
/// </summary>
|
|
public static class ComplianceProfiles
|
|
{
|
|
/// <summary>
|
|
/// Default/World profile using BLAKE3 for graph hashing, SHA-256 for everything else.
|
|
/// Suitable for international deployments without specific compliance requirements.
|
|
/// </summary>
|
|
public static readonly ComplianceProfile World = new()
|
|
{
|
|
ProfileId = "world",
|
|
StandardName = "ISO/Default",
|
|
Description = "Default profile using BLAKE3 for graph content-addressing, SHA-256 for symbol/content hashing.",
|
|
PurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = HashAlgorithms.Blake3_256,
|
|
[HashPurpose.Symbol] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Content] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Merkle] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Attestation] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Interop] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Secret] = PasswordHashAlgorithms.Argon2id,
|
|
},
|
|
HashPrefixes = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = "blake3:",
|
|
[HashPurpose.Symbol] = "sha256:",
|
|
[HashPurpose.Content] = "sha256:",
|
|
[HashPurpose.Merkle] = "sha256:",
|
|
[HashPurpose.Attestation] = "sha256:",
|
|
[HashPurpose.Interop] = "sha256:",
|
|
[HashPurpose.Secret] = "argon2id:",
|
|
},
|
|
HmacPurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HmacPurpose.Signing] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.Authentication] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.WebhookInterop] = HmacAlgorithms.HmacSha256,
|
|
},
|
|
AllowInteropOverride = true,
|
|
};
|
|
|
|
/// <summary>
|
|
/// FIPS 140-3 (US Federal) compliance profile.
|
|
/// Uses only FIPS-approved algorithms: SHA-256, SHA-384, SHA-512, PBKDF2.
|
|
/// Note: BLAKE3 is not FIPS-approved, so SHA-256 is used for graph hashing.
|
|
/// </summary>
|
|
public static readonly ComplianceProfile Fips = new()
|
|
{
|
|
ProfileId = "fips",
|
|
StandardName = "FIPS 140-3",
|
|
Description = "US Federal Information Processing Standard 140-3. Uses only FIPS-approved algorithms.",
|
|
PurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = HashAlgorithms.Sha256, // BLAKE3 not FIPS-approved
|
|
[HashPurpose.Symbol] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Content] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Merkle] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Attestation] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Interop] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Secret] = PasswordHashAlgorithms.Pbkdf2Sha256,
|
|
},
|
|
HashPrefixes = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = "sha256:",
|
|
[HashPurpose.Symbol] = "sha256:",
|
|
[HashPurpose.Content] = "sha256:",
|
|
[HashPurpose.Merkle] = "sha256:",
|
|
[HashPurpose.Attestation] = "sha256:",
|
|
[HashPurpose.Interop] = "sha256:",
|
|
[HashPurpose.Secret] = "pbkdf2:",
|
|
},
|
|
HmacPurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HmacPurpose.Signing] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.Authentication] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.WebhookInterop] = HmacAlgorithms.HmacSha256,
|
|
},
|
|
AllowInteropOverride = true,
|
|
};
|
|
|
|
/// <summary>
|
|
/// GOST R 34.11-2012 (Russian) compliance profile.
|
|
/// Uses GOST Stribog hash for all purposes except Interop (which remains SHA-256 for external compatibility).
|
|
/// </summary>
|
|
public static readonly ComplianceProfile Gost = new()
|
|
{
|
|
ProfileId = "gost",
|
|
StandardName = "GOST R 34.11-2012",
|
|
Description = "Russian GOST R 34.11-2012 (Stribog) hash standard. Interop uses SHA-256 for external tool compatibility.",
|
|
PurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = HashAlgorithms.Gost3411_2012_256,
|
|
[HashPurpose.Symbol] = HashAlgorithms.Gost3411_2012_256,
|
|
[HashPurpose.Content] = HashAlgorithms.Gost3411_2012_256,
|
|
[HashPurpose.Merkle] = HashAlgorithms.Gost3411_2012_256,
|
|
[HashPurpose.Attestation] = HashAlgorithms.Gost3411_2012_256,
|
|
[HashPurpose.Interop] = HashAlgorithms.Sha256, // Override for external compatibility
|
|
[HashPurpose.Secret] = PasswordHashAlgorithms.Argon2id,
|
|
},
|
|
HashPrefixes = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = "gost3411:",
|
|
[HashPurpose.Symbol] = "gost3411:",
|
|
[HashPurpose.Content] = "gost3411:",
|
|
[HashPurpose.Merkle] = "gost3411:",
|
|
[HashPurpose.Attestation] = "gost3411:",
|
|
[HashPurpose.Interop] = "sha256:",
|
|
[HashPurpose.Secret] = "argon2id:",
|
|
},
|
|
HmacPurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HmacPurpose.Signing] = HmacAlgorithms.HmacGost3411,
|
|
[HmacPurpose.Authentication] = HmacAlgorithms.HmacGost3411,
|
|
[HmacPurpose.WebhookInterop] = HmacAlgorithms.HmacSha256, // External compatibility
|
|
},
|
|
AllowInteropOverride = true,
|
|
};
|
|
|
|
/// <summary>
|
|
/// GB/T SM3 (Chinese) compliance profile.
|
|
/// Uses SM3 hash for all purposes except Interop (which remains SHA-256 for external compatibility).
|
|
/// </summary>
|
|
public static readonly ComplianceProfile Sm = new()
|
|
{
|
|
ProfileId = "sm",
|
|
StandardName = "GB/T (SM3)",
|
|
Description = "Chinese GB/T 32905-2016 SM3 cryptographic hash standard. Interop uses SHA-256 for external tool compatibility.",
|
|
PurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = HashAlgorithms.Sm3,
|
|
[HashPurpose.Symbol] = HashAlgorithms.Sm3,
|
|
[HashPurpose.Content] = HashAlgorithms.Sm3,
|
|
[HashPurpose.Merkle] = HashAlgorithms.Sm3,
|
|
[HashPurpose.Attestation] = HashAlgorithms.Sm3,
|
|
[HashPurpose.Interop] = HashAlgorithms.Sha256, // Override for external compatibility
|
|
[HashPurpose.Secret] = PasswordHashAlgorithms.Argon2id,
|
|
},
|
|
HashPrefixes = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = "sm3:",
|
|
[HashPurpose.Symbol] = "sm3:",
|
|
[HashPurpose.Content] = "sm3:",
|
|
[HashPurpose.Merkle] = "sm3:",
|
|
[HashPurpose.Attestation] = "sm3:",
|
|
[HashPurpose.Interop] = "sha256:",
|
|
[HashPurpose.Secret] = "argon2id:",
|
|
},
|
|
HmacPurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HmacPurpose.Signing] = HmacAlgorithms.HmacSm3,
|
|
[HmacPurpose.Authentication] = HmacAlgorithms.HmacSm3,
|
|
[HmacPurpose.WebhookInterop] = HmacAlgorithms.HmacSha256, // External compatibility
|
|
},
|
|
AllowInteropOverride = true,
|
|
};
|
|
|
|
/// <summary>
|
|
/// KCMVP (Korea Cryptographic Module Validation Program) compliance profile.
|
|
/// Uses SHA-256 for hashing. Note: ARIA/SEED/LEA are for encryption, KCDSA for signatures.
|
|
/// </summary>
|
|
public static readonly ComplianceProfile Kcmvp = new()
|
|
{
|
|
ProfileId = "kcmvp",
|
|
StandardName = "KCMVP (Korea)",
|
|
Description = "Korea Cryptographic Module Validation Program. Uses SHA-256 for hashing.",
|
|
PurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Symbol] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Content] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Merkle] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Attestation] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Interop] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Secret] = PasswordHashAlgorithms.Argon2id,
|
|
},
|
|
HashPrefixes = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = "sha256:",
|
|
[HashPurpose.Symbol] = "sha256:",
|
|
[HashPurpose.Content] = "sha256:",
|
|
[HashPurpose.Merkle] = "sha256:",
|
|
[HashPurpose.Attestation] = "sha256:",
|
|
[HashPurpose.Interop] = "sha256:",
|
|
[HashPurpose.Secret] = "argon2id:",
|
|
},
|
|
HmacPurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HmacPurpose.Signing] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.Authentication] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.WebhookInterop] = HmacAlgorithms.HmacSha256,
|
|
},
|
|
AllowInteropOverride = true,
|
|
};
|
|
|
|
/// <summary>
|
|
/// eIDAS/ETSI TS 119 312 (European) compliance profile.
|
|
/// Uses SHA-256 for hashing per ETSI cryptographic suites specification.
|
|
/// </summary>
|
|
public static readonly ComplianceProfile Eidas = new()
|
|
{
|
|
ProfileId = "eidas",
|
|
StandardName = "eIDAS/ETSI TS 119 312",
|
|
Description = "European eIDAS regulation with ETSI TS 119 312 cryptographic suites. Uses SHA-256/384 for hashing.",
|
|
PurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Symbol] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Content] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Merkle] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Attestation] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Interop] = HashAlgorithms.Sha256,
|
|
[HashPurpose.Secret] = PasswordHashAlgorithms.Argon2id,
|
|
},
|
|
HashPrefixes = new Dictionary<string, string>
|
|
{
|
|
[HashPurpose.Graph] = "sha256:",
|
|
[HashPurpose.Symbol] = "sha256:",
|
|
[HashPurpose.Content] = "sha256:",
|
|
[HashPurpose.Merkle] = "sha256:",
|
|
[HashPurpose.Attestation] = "sha256:",
|
|
[HashPurpose.Interop] = "sha256:",
|
|
[HashPurpose.Secret] = "argon2id:",
|
|
},
|
|
HmacPurposeAlgorithms = new Dictionary<string, string>
|
|
{
|
|
[HmacPurpose.Signing] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.Authentication] = HmacAlgorithms.HmacSha256,
|
|
[HmacPurpose.WebhookInterop] = HmacAlgorithms.HmacSha256,
|
|
},
|
|
AllowInteropOverride = true,
|
|
};
|
|
|
|
/// <summary>
|
|
/// All built-in profiles indexed by profile ID.
|
|
/// </summary>
|
|
public static readonly IReadOnlyDictionary<string, ComplianceProfile> All =
|
|
new Dictionary<string, ComplianceProfile>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
[World.ProfileId] = World,
|
|
[Fips.ProfileId] = Fips,
|
|
[Gost.ProfileId] = Gost,
|
|
[Sm.ProfileId] = Sm,
|
|
[Kcmvp.ProfileId] = Kcmvp,
|
|
[Eidas.ProfileId] = Eidas,
|
|
};
|
|
|
|
/// <summary>
|
|
/// Gets a profile by ID, returning the World profile if not found.
|
|
/// </summary>
|
|
/// <param name="profileId">The profile ID to look up.</param>
|
|
/// <returns>The matching profile, or World if not found.</returns>
|
|
public static ComplianceProfile GetProfile(string? profileId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(profileId))
|
|
{
|
|
return World;
|
|
}
|
|
|
|
return All.TryGetValue(profileId, out var profile) ? profile : World;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a profile by ID, throwing if not found.
|
|
/// </summary>
|
|
/// <param name="profileId">The profile ID to look up.</param>
|
|
/// <returns>The matching profile.</returns>
|
|
/// <exception cref="ArgumentException">Thrown when the profile ID is not found.</exception>
|
|
public static ComplianceProfile GetProfileOrThrow(string profileId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(profileId))
|
|
{
|
|
throw new ArgumentException("Profile ID cannot be null or empty.", nameof(profileId));
|
|
}
|
|
|
|
if (!All.TryGetValue(profileId, out var profile))
|
|
{
|
|
throw new ArgumentException(
|
|
$"Unknown compliance profile '{profileId}'. Valid profiles: {string.Join(", ", All.Keys)}",
|
|
nameof(profileId));
|
|
}
|
|
|
|
return profile;
|
|
}
|
|
}
|