Как подписать Excel с моим закрытым ключом pfx? - PullRequest
0 голосов
/ 14 марта 2019

c # Как подписать Excel с моим личным ключом pfx? Можете ли вы вообще объяснить, какая часть файла Excel должна быть подписана?

// this is our private key array read directly pfx file
byte[] pfkArray = {};

// this is our excel file
byte[] xlsArray = {};

Где / какая часть xlsArray должна быть подписана? Весь файл или несколько сегментов / секторов xlsArray? RFC

Здесь некоторое введение / класс, который мы можем использовать для подписания документа в соответствии с требованиями RFC.

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Web;

namespace Infra
{
    public class SignFile
    {

        private const string ConstLocalRootSerial = @"1c151322b969b79047f5c5d90cb";          
        private const string ConstLocalSerial = @"1c041d12ac33528847ac378283";

        private RSACryptoServiceProvider _key;
        private readonly X509Certificate2 _publicCert;

        public X509Certificate2Collection Certificates
        {
            get
            {
                X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);
                return store.Certificates;
            }
        }

        /// <summary>
        /// Sign file/document/stream/bytes
        /// </summary>
        /// <param name="inputData">some data to sign -> byte[] data = new byte[1024];</param>
        /// <param name="signature"></param>
        /// <returns>signed data</returns>
        public byte[] GetSignature(byte[] inputData)
        {
            //Sign the data
            byte[] signature = _key.SignData(inputData, CryptoConfig.MapNameToOID("SHA256"));
            return signature;
        }

        /// <summary>
        /// Validate after sign was completed
        /// </summary>
        /// <param name="inputData"></param>
        /// <param name="signature">signed data</param>
        /// <returns>true if data was signed</returns>
        public bool ValidateSignature(byte[] inputData, byte[] signature)
        {
            _key = (RSACryptoServiceProvider)_publicCert.PublicKey.Key;
            if (!_key.VerifyData(inputData, CryptoConfig.MapNameToOID("SHA256"), signature))
                throw new CryptographicException();

            return true;
        }


        public X509Certificate2 Open()
        {

            var certificates = Certificates;
            foreach (X509Certificate2 certificate in certificates)
            {
                // TODO: Just change it for BETA/FT/PROD
                if (certificate.SerialNumber.ToUpper() == ConstLocalSerial.ToUpper())
                {
                    return certificate;
                }
            }

            throw new CryptographicException("Certificate serial number is missing from authority");
        }


        public SignFile()
        {                      
            _publicCert = Open();                  
            _key = new RSACryptoServiceProvider();
            _key.FromXmlString(_publicCert.PrivateKey.ToXmlString(true));
        }

        /// <summary>
        /// Sign file with my private key
        /// </summary>
        /// <param name="cer">file path to cer file @"C:\mycertificate.cer"        
        /// string certificateFile  = HttpContext.Current.Server.MapPath("~/App_Data/internal.provident.l.cer");
        /// string certificateFile2 = HttpContext.Current.Request.MapPath("~/internal.provident.l.cer");
        /// </param>
        public SignFile(string pfx)
        {                   
            _publicCert = new X509Certificate2(pfx);           
            X509Certificate2 privateCert = null;
            X509Store store = new X509Store(StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            foreach (X509Certificate2 cert in store.Certificates)
            {
                if (cert.GetCertHashString() == _publicCert.GetCertHashString())
                    privateCert = cert;
            }

            //Round-trip the key to XML and back, there might be a better way but this works
            _key = new RSACryptoServiceProvider();
            _key.FromXmlString(privateCert.PrivateKey.ToXmlString(true));
        }

    }

}

Вот что я не хочу делать


         // Let me first get excel data    
         string excelFilePath = @"/myexcel.xls";
         FileStream f = new FileStream(excelFilePath, FileMode.Open);
         byte[] xlsArray = f.StreamToByteArray();

         // Now we can get private key     
         string certFilePath = @"/certi.pfx";
         FileStream f2 = new FileStream(certFilePath, FileMode.Open);
         byte[] pfkArray = f.StreamToByteArray();

         // Prepare for sign data
         var signer = new SignFile();
         // the problems here are:
         //  - we need to not use SHA256 
         //  - should we need to pass entire xlsArray array???
         byte[] signedData = signer.GetSignature(xlsArray);

1 Ответ

1 голос
/ 21 марта 2019

Вы не можете просто загрузить байты и подписать их.Файл является сборкой OLE-потоков, которые необходимо хэшировать, и структуры подписи, которая также сохраняется в OLE-потоке ...

Вот официальная документация: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/2770c801-5f0f-4326-89e8-d6ef15b68ef1

...