{"record":{"id":"ac42ddcefdbc79e1","repo":"dotnet/wpf","slug":"sr-hashalgorithmmustbereusable","errorCode":null,"errorMessage":"SR.HashAlgorithmMustBeReusable","messagePattern":"SR\\.HashAlgorithmMustBeReusable","errorType":"validation","errorClass":"System.ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/XmlSignatureManifest.cs","lineNumber":482,"sourceCode":"        /// <param name=\"hashAlgorithm\">hash algorithm to hash with</param>\n        /// <param name=\"parts\">parts to sign - possibly null</param>\n        /// <param name=\"relationshipSelectors\">relationshipSelectors that represent the\n        /// relationships that have to be signed - possibly null</param>\n        /// <returns></returns>\n        internal static XmlNode GenerateManifest(\n            PackageDigitalSignatureManager manager,\n            XmlDocument xDoc,\n            HashAlgorithm hashAlgorithm,\n            IEnumerable<Uri> parts,\n            IEnumerable<PackageRelationshipSelector> relationshipSelectors)\n        {\n            Debug.Assert(manager != null);\n            Debug.Assert(xDoc != null);\n            Debug.Assert(hashAlgorithm != null);\n\n            // check args\n            if (!hashAlgorithm.CanReuseTransform)\n                throw new ArgumentException(SR.HashAlgorithmMustBeReusable);\n\n            // <Manifest>\n            XmlNode manifest = xDoc.CreateNode(XmlNodeType.Element,\n                XTable.Get(XTable.ID.ManifestTagName),\n                SignedXml.XmlDsigNamespaceUrl);\n\n            // add part references\n            if (parts != null)\n            {\n                // loop and write - may still be empty\n                foreach (Uri partUri in parts)\n                {\n                    // generate a reference tag\n                    manifest.AppendChild(GeneratePartSigningReference(manager, xDoc, hashAlgorithm, partUri));\n                }\n            }\n\n            // any relationship references?","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/XmlSignatureManifest.cs#L464-L500","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use a standard reusable algorithm such as SHA256CryptoServiceProvider/SHA256Managed (CanReuseTransform == true)","If using a custom hash, implement ICryptoTransform so CanReuseTransform returns true and state resets correctly","Check hashAlgorithm.CanReuseTransform before calling Sign and swap algorithms if false","Create a fresh algorithm instance per signing operation rather than reusing a consumed one"],"exampleFix":"// before\nHashAlgorithm alg = MyCustomHash.Create(); // CanReuseTransform == false\nmanager.Sign(parts, alg);\n// after\nHashAlgorithm alg = new SHA256CryptoServiceProvider(); // reusable\nmanager.Sign(parts, alg);","handlingStrategy":"validation","validationCode":"if (!hashAlgorithm.CanReuseTransform)\n    throw new ArgumentException(\"Algorithm must support CanReuseTransform for package signing\");","typeGuard":"bool IsReusableHash(HashAlgorithm a) => a?.CanReuseTransform == true;","tryCatchPattern":"try { manager.Sign(parts, hashAlgorithm); }\ncatch (ArgumentException ex) { /* fall back to SHA256CryptoServiceProvider */ hashAlgorithm = new SHA256CryptoServiceProvider(); }","preventionTips":["Prefer SHA256CryptoServiceProvider/SHA256Managed for package signing","Assert CanReuseTransform in unit tests for any custom HashAlgorithm","Create a new algorithm instance per signing operation"],"tags":["cryptography","hash-algorithm","digital-signature"],"backgroundTag":"invalid-argument-value","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}