< Summary

Information
Class: AsiBackbone.Core.Signing.CanonicalPayloadHash
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/CanonicalPayloadHash.cs
Line coverage
100%
Covered lines: 54
Uncovered lines: 0
Coverable lines: 54
Total lines: 162
Line coverage: 100%
Branch coverage
78%
Covered branches: 11
Total branches: 14
Branch coverage: 78.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_ArtifactType()100%11100%
get_ArtifactId()100%11100%
get_PayloadSchemaVersion()100%11100%
get_CanonicalizationVersion()100%11100%
get_HashAlgorithm()100%11100%
get_HashValue()100%11100%
Create(...)100%11100%
ToSigningMetadata(...)80%1010100%
NormalizeHashAlgorithm(...)75%44100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Signing/CanonicalPayloadHash.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2
 3namespace AsiBackbone.Core.Signing;
 4
 5/// <summary>
 6/// Represents provider-neutral hash metadata for a canonical AsiBackbone payload.
 7/// </summary>
 8public sealed class CanonicalPayloadHash
 9{
 39410    private CanonicalPayloadHash(
 39411        string artifactType,
 39412        string artifactId,
 39413        string payloadSchemaVersion,
 39414        string canonicalizationVersion,
 39415        string hashAlgorithm,
 39416        string hashValue)
 17    {
 39418        ArtifactType = artifactType;
 39419        ArtifactId = artifactId;
 39420        PayloadSchemaVersion = payloadSchemaVersion;
 39421        CanonicalizationVersion = canonicalizationVersion;
 39422        HashAlgorithm = hashAlgorithm;
 39423        HashValue = hashValue;
 39424    }
 25
 26    /// <summary>
 27    /// Gets the artifact type bound into the hashed payload.
 28    /// </summary>
 64429    public string ArtifactType { get; }
 30
 31    /// <summary>
 32    /// Gets the artifact identifier bound into the hashed payload.
 33    /// </summary>
 60434    public string ArtifactId { get; }
 35
 36    /// <summary>
 37    /// Gets the payload schema version bound into the hashed payload.
 38    /// </summary>
 44839    public string PayloadSchemaVersion { get; }
 40
 41    /// <summary>
 42    /// Gets the canonicalization version used before hashing.
 43    /// </summary>
 52444    public string CanonicalizationVersion { get; }
 45
 46    /// <summary>
 47    /// Gets the hash algorithm descriptor.
 48    /// </summary>
 59649    public string HashAlgorithm { get; }
 50
 51    /// <summary>
 52    /// Gets the lowercase hexadecimal hash value.
 53    /// </summary>
 113254    public string HashValue { get; }
 55
 56    /// <summary>
 57    /// Creates provider-neutral hash metadata.
 58    /// </summary>
 59    public static CanonicalPayloadHash Create(
 60        string artifactType,
 61        string artifactId,
 62        string payloadSchemaVersion,
 63        string canonicalizationVersion,
 64        string hashAlgorithm,
 65        string hashValue)
 66    {
 39467        ArgumentException.ThrowIfNullOrWhiteSpace(artifactType);
 39468        ArgumentException.ThrowIfNullOrWhiteSpace(artifactId);
 39469        ArgumentException.ThrowIfNullOrWhiteSpace(payloadSchemaVersion);
 39470        ArgumentException.ThrowIfNullOrWhiteSpace(canonicalizationVersion);
 39471        ArgumentException.ThrowIfNullOrWhiteSpace(hashAlgorithm);
 39472        ArgumentException.ThrowIfNullOrWhiteSpace(hashValue);
 73
 39474        return new CanonicalPayloadHash(
 39475            artifactType.Trim(),
 39476            artifactId.Trim(),
 39477            payloadSchemaVersion.Trim(),
 39478            canonicalizationVersion.Trim(),
 39479            NormalizeHashAlgorithm(hashAlgorithm),
 39480            hashValue.Trim().ToLowerInvariant());
 81    }
 82
 83    /// <summary>
 84    /// Creates signing metadata that carries the hash and canonical payload descriptors without implying that the artif
 85    /// </summary>
 86    public SigningMetadata ToSigningMetadata(IReadOnlyDictionary<string, string>? metadata = null)
 87    {
 21688        Dictionary<string, string> hashMetadata = new(StringComparer.Ordinal)
 21689        {
 21690            ["artifact_id"] = ArtifactId,
 21691            ["artifact_type"] = ArtifactType,
 21692            ["canonicalization_version"] = CanonicalizationVersion,
 21693            ["payload_schema_version"] = PayloadSchemaVersion
 21694        };
 95
 21696        if (metadata is not null)
 97        {
 7698            foreach (KeyValuePair<string, string> item in metadata)
 99            {
 20100                if (string.IsNullOrWhiteSpace(item.Key))
 101                {
 102                    continue;
 103                }
 104
 18105                hashMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 106            }
 107        }
 108
 216109        return SigningMetadata.Create(
 216110            signingHash: HashValue,
 216111            hashAlgorithm: HashAlgorithm,
 216112            metadata: hashMetadata);
 113    }
 114
 115    internal static string NormalizeHashAlgorithm(string hashAlgorithm)
 116    {
 938117        string normalized = hashAlgorithm.Trim();
 118
 938119        return normalized.Equals("SHA256", StringComparison.OrdinalIgnoreCase)
 938120            ? CanonicalPayloadOptions.DefaultHashAlgorithm
 938121            : normalized.Equals(CanonicalPayloadOptions.DefaultHashAlgorithm, StringComparison.OrdinalIgnoreCase)
 938122                ? CanonicalPayloadOptions.DefaultHashAlgorithm
 938123                : normalized;
 124    }
 125}
 126
 127/// <summary>
 128/// Computes provider-neutral hashes for canonical AsiBackbone payloads.
 129/// </summary>
 130public static class CanonicalPayloadHasher
 131{
 132    /// <summary>
 133    /// Computes a hash over the canonical payload bytes.
 134    /// </summary>
 135    public static CanonicalPayloadHash ComputeHash(
 136        CanonicalPayload payload,
 137        string? hashAlgorithm = null)
 138    {
 139        ArgumentNullException.ThrowIfNull(payload);
 140
 141        string algorithm = CanonicalPayloadHash.NormalizeHashAlgorithm(
 142            string.IsNullOrWhiteSpace(hashAlgorithm)
 143                ? CanonicalPayloadOptions.DefaultHashAlgorithm
 144                : hashAlgorithm);
 145
 146        if (!algorithm.Equals(CanonicalPayloadOptions.DefaultHashAlgorithm, StringComparison.Ordinal))
 147        {
 148            throw new NotSupportedException($"The built-in canonical payload hasher supports {CanonicalPayloadOptions.De
 149        }
 150
 151        byte[] hashBytes = SHA256.HashData(payload.ToUtf8Bytes());
 152        string hashValue = Convert.ToHexString(hashBytes).ToLowerInvariant();
 153
 154        return CanonicalPayloadHash.Create(
 155            payload.ArtifactType,
 156            payload.ArtifactId,
 157            payload.PayloadSchemaVersion,
 158            payload.CanonicalizationVersion,
 159            algorithm,
 160            hashValue);
 161    }
 162}