首页 > 解决方案 > 数字签名显示错误的签名日期

问题描述

我正在学习数字签名以及如何在 c# 中签名。这是我的代码:

签名.cs

    public class Signature
    {
    static readonly string RT_OfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
    static readonly string OfficeObjectID = "idOfficeObject";
    static readonly string SignatureID = "idPackageSignature";
    static readonly string ManifestHashAlgorithm = "http://www.w3.org/2000/09/xmldsig#sha1";

    // Entry Point
    public static void DigiSign(string tempfile)
    {
    // Open the Package    
        using (Package package = Package.Open(tempfile))
        {
            // Get the certificate
            X509Certificate2 certificate = GetCertificate();
            SignAllParts(package, certificate);
        }
    }

    private static void SignAllParts(Package package, X509Certificate certificate)
    {
        if (package == null) throw new ArgumentNullException("SignAllParts(package)");
        List<Uri> PartstobeSigned = new List<Uri>();
        List<PackageRelationshipSelector> SignableReleationships = new List<PackageRelationshipSelector>();

        foreach (PackageRelationship relationship in package.GetRelationshipsByType(RT_OfficeDocument))
        {
            // Pass the releationship of the root. This is decided based on the RT_OfficeDocument (http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument)
            CreateListOfSignableItems(relationship, PartstobeSigned, SignableReleationships);
        }
        // Create the DigitalSignature Manager
        PackageDigitalSignatureManager dsm = new PackageDigitalSignatureManager(package);
        dsm.CertificateOption = CertificateEmbeddingOption.InSignaturePart;

        string signatureID = SignatureID;
        string manifestHashAlgorithm = ManifestHashAlgorithm;
        System.Security.Cryptography.Xml.DataObject officeObject = CreateOfficeObject(signatureID, manifestHashAlgorithm);
        Reference officeObjectReference = new Reference("#" + OfficeObjectID);

        try
        {
            dsm.Sign(PartstobeSigned, certificate, SignableReleationships, signatureID, new System.Security.Cryptography.Xml.DataObject[] { officeObject }, new Reference[] { officeObjectReference });
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine(ex.InnerException.ToString());
        }

    }// end:SignAllParts()

    /**************************SignDocument******************************/
    //  This function is a helper function. The main role of this function is to 
    //  create two lists, one with Package Parts that you want to sign, the other 
    //  containing PacakgeRelationshipSelector objects which indicate relationships to sign.
    /*******************************************************************/
    static void CreateListOfSignableItems(PackageRelationship relationship, List<Uri> PartstobeSigned, List<PackageRelationshipSelector> SignableReleationships)
    {
        // This function adds the releation to SignableReleationships. And then it gets the part based on the releationship. Parts URI gets added to the PartstobeSigned list.
        PackageRelationshipSelector selector = new PackageRelationshipSelector(relationship.SourceUri, PackageRelationshipSelectorType.Id, relationship.Id);
        SignableReleationships.Add(selector);
        if (relationship.TargetMode == TargetMode.Internal)
        {
            PackagePart part = relationship.Package.GetPart(PackUriHelper.ResolvePartUri(relationship.SourceUri, relationship.TargetUri));
            if (PartstobeSigned.Contains(part.Uri) == false)
            {
                PartstobeSigned.Add(part.Uri);
                // GetRelationships Function: Returns a Collection Of all the releationships that are owned by the part.
                foreach (PackageRelationship childRelationship in part.GetRelationships())
                {
                    CreateListOfSignableItems(childRelationship, PartstobeSigned, SignableReleationships);
                }
            }
        }
    }
    /**************************SignDocument******************************/
    //  Once you create the list and try to sign it, Office will not validate the Signature.
    //  To allow Office to validate the signature, it requires a custom object which should be added to the 
    //  signature parts. This function loads the OfficeObject.xml resource.
    //  Please note that GUID being passed in document.Loadxml. 
    //  Background Information: Once you add a SignatureLine in Word, Word gives a unique GUID to it. Now while loading the
    //  OfficeObject.xml, we need to make sure that The this GUID should match to the ID of the signature line. 
    //  So if you are generating a SignatureLine programmtically, then mmake sure that you generate the GUID for the 
    //  SignatureLine and for this element. 
    /*******************************************************************/

    static System.Security.Cryptography.Xml.DataObject CreateOfficeObject(
       string signatureID, string manifestHashAlgorithm)
    {
        XmlDocument document = new XmlDocument();
        document.LoadXml(String.Format(Properties.Resources.OfficeObject, signatureID, manifestHashAlgorithm, "{3CF6B91E-C5F6-46A4-B036-72597274FCC0}"));
        System.Security.Cryptography.Xml.DataObject officeObject = new System.Security.Cryptography.Xml.DataObject();
        // do not change the order of the following two lines
        officeObject.LoadXml(document.DocumentElement); // resets ID
        officeObject.Id = OfficeObjectID; // required ID, do not change
        return officeObject;
    }
    /********************************************************/

    static X509Certificate2 GetCertificate()
    {
        X509Store certStore = new X509Store(StoreLocation.CurrentUser);
        certStore.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certs = X509Certificate2UI.SelectFromCollection(certStore.Certificates, "Select a certificate", "Please select a certificate",
                X509SelectionFlag.SingleSelection);
        return certs.Count > 0 ? certs[0] : null;
    }
}

程序.cs

class Program
{
    static void Main(string[] args)
    {
            Signature.DigiSign(@"D:\abc.docx");
    }
}

和签名后的文件 abc.docx : 关联

在签名的附加信息中,系统日期/时间(签名时间)与我的本地时间和日期/时间格式也不同。我尝试更改我的本地时区并重置日期/时间,但它仍然不起作用。我错过了什么?

标签: c#digital-signature

解决方案


使用 SecureBlackBox for .NET 解决我的问题!


推荐阅读