dotnet/wpf · error · System.ArgumentException

SR.HashAlgorithmMustBeReusable

Error message

SR.HashAlgorithmMustBeReusable

What it means

GenerateManifest validates that the hash algorithm passed in supports CanReuseTransform before signing. WPF package signing streams multiple parts through the same hash transform, so a non-reusable algorithm would silently produce wrong digests; the library rejects it up front with ArgumentException.

Solutions

  1. Use a standard reusable algorithm such as SHA256CryptoServiceProvider/SHA256Managed (CanReuseTransform == true)
  2. If using a custom hash, implement ICryptoTransform so CanReuseTransform returns true and state resets correctly
  3. Check hashAlgorithm.CanReuseTransform before calling Sign and swap algorithms if false
  4. Create a fresh algorithm instance per signing operation rather than reusing a consumed one

Example fix

// before
HashAlgorithm alg = MyCustomHash.Create(); // CanReuseTransform == false
manager.Sign(parts, alg);
// after
HashAlgorithm alg = new SHA256CryptoServiceProvider(); // reusable
manager.Sign(parts, alg);
Defensive patterns

Strategy: validation

Validate before calling

if (!hashAlgorithm.CanReuseTransform)
    throw new ArgumentException("Algorithm must support CanReuseTransform for package signing");

Type guard

bool IsReusableHash(HashAlgorithm a) => a?.CanReuseTransform == true;

Try / catch

try { manager.Sign(parts, hashAlgorithm); }
catch (ArgumentException ex) { /* fall back to SHA256CryptoServiceProvider */ hashAlgorithm = new SHA256CryptoServiceProvider(); }

Prevention

When it happens

Trigger: Calling signature generation (XmlSignatureManifest.GenerateManifest, reached via PackageDigitalSignatureManager.Sign) with a HashAlgorithm instance whose CanReuseTransform returns false (e.g. certain crypto provider-backed or non-streaming hash implementations).

Common situations: Passing a custom HashAlgorithm subclass that doesn't support transform reuse; using algorithm objects from a CSP that reset state after TransformBlock; migrating code that previously used the algorithm once elsewhere.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/ac42ddcefdbc79e1. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/XmlSignatureManifest.cs:482

        /// <param name="hashAlgorithm">hash algorithm to hash with</param>
        /// <param name="parts">parts to sign - possibly null</param>
        /// <param name="relationshipSelectors">relationshipSelectors that represent the
        /// relationships that have to be signed - possibly null</param>
        /// <returns></returns>
        internal static XmlNode GenerateManifest(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm,
            IEnumerable<Uri> parts,
            IEnumerable<PackageRelationshipSelector> relationshipSelectors)
        {
            Debug.Assert(manager != null);
            Debug.Assert(xDoc != null);
            Debug.Assert(hashAlgorithm != null);

            // check args
            if (!hashAlgorithm.CanReuseTransform)
                throw new ArgumentException(SR.HashAlgorithmMustBeReusable);

            // <Manifest>
            XmlNode manifest = xDoc.CreateNode(XmlNodeType.Element,
                XTable.Get(XTable.ID.ManifestTagName),
                SignedXml.XmlDsigNamespaceUrl);

            // add part references
            if (parts != null)
            {
                // loop and write - may still be empty
                foreach (Uri partUri in parts)
                {
                    // generate a reference tag
                    manifest.AppendChild(GeneratePartSigningReference(manager, xDoc, hashAlgorithm, partUri));
                }
            }

            // any relationship references?

View on GitHub (pinned to 81131a70a4)