需要创建数字签名的excel文件,然后在C#中上传后验证签名。
仅靠SpreadsheetDocument.AddDigitalSignatureOriginPart()
方法不能保护Excel文件。 WordprocessingDocument
和PresentationDocument
类的相应方法也是如此。这些方法仅添加一个空的DigitalSignatureOriginPart
作为一个或多个XmlSignaturePart
实例的来源,每个实例均包含基于W3C建议ds:Signature
(XMLDSIG)的XML Signature Syntax and Processing Version 1.1元素。
[要保护Excel文件或任何基于开放包装约定(OPC)的文件,最直接的方法是使用PackageDigitalSignatureManager类,该类包含在System.IO.Packaging
提供的WindowsBase.dll
命名空间中部件。因此,如果您以完整的.NET Framework为目标(例如net471),则可以使用它。但是,如果目标是.Net Core,则需要自己实现该功能。
下面的代码示例演示如何使用PackageDigitalSignatureManager
类:
using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.Linq;
namespace CodeSnippets.Windows.IO.Packaging
{
public static class DigitalSignatureManager
{
public static void Sign(Package package)
{
var dsm = new PackageDigitalSignatureManager(package)
{
CertificateOption = CertificateEmbeddingOption.InSignaturePart
};
List<Uri> parts = package.GetParts()
.Select(part => part.Uri)
.Concat(new[]
{
// Include the DigitalSignatureOriginPart and corresponding
// relationship part, since those will only be added when
// signing.
dsm.SignatureOrigin,
PackUriHelper.GetRelationshipPartUri(dsm.SignatureOrigin)
})
.ToList();
dsm.Sign(parts);
}
public static VerifyResult VerifySignature(Package package)
{
var dsm = new PackageDigitalSignatureManager(package);
return dsm.VerifySignatures(true);
}
}
}
如果您需要自己实现该功能,可以帮助您熟悉许多资源:
基于这些资源,我创建了一个与.Net Core一起使用的部分示例实现。以下代码片段显示了void Sign(OpenXmlPackage, X509Certificate2)
方法,该方法采用OpenXmlPackage
和X509Certificate2
并创建有效的签名:
public static void Sign(OpenXmlPackage openXmlPackage, X509Certificate2 certificate)
{
if (openXmlPackage == null) throw new ArgumentNullException(nameof(openXmlPackage));
if (certificate == null) throw new ArgumentNullException(nameof(certificate));
RSA privateKey = certificate.GetRSAPrivateKey();
using SHA256 hashAlgorithm = SHA256.Create();
// Create KeyInfo.
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
// Create a Signature XmlElement.
var signedXml = new SignedXml { SigningKey = privateKey, KeyInfo = keyInfo };
signedXml.Signature.Id = Constants.PackageSignatureId;
signedXml.SignedInfo.SignatureMethod = Constants.SignatureMethod;
signedXml.AddReference(CreatePackageObjectReference());
signedXml.AddObject(CreatePackageObject(openXmlPackage.Package, hashAlgorithm));
signedXml.ComputeSignature();
XmlElement signature = signedXml.GetXml();
// Get or create the DigitalSignatureOriginPart.
DigitalSignatureOriginPart dsOriginPart =
openXmlPackage.GetPartsOfType<DigitalSignatureOriginPart>().FirstOrDefault() ??
openXmlPackage.AddNewPart<DigitalSignatureOriginPart>();
var xmlSignaturePart = dsOriginPart.AddNewPart<XmlSignaturePart>();
// Write the Signature XmlElement to the XmlSignaturePart.
using Stream stream = xmlSignaturePart.GetStream(FileMode.Create, FileAccess.Write);
using XmlWriter writer = XmlWriter.Create(stream);
signature.WriteTo(writer);
}
上述void Sign(OpenXmlPackage, X509Certificate2)
方法的完整源代码可以在我的CodeSnippets GitHub存储库中找到。在CodeSnippets项目中寻找DigitalSignatureManager类。