现在的位置: 首页 > 综合 > 正文

C#如何使用数字签名?

2017年11月05日 ⁄ 综合 ⁄ 共 7545字 ⁄ 字号 评论关闭
/// <summary>
    /// 
    /// </summary>
    /// <param name="originalFileName"></param>
    /// <param name="encryptedFileName"></param>
    /// <param name="senderCertificate"></param>
    /// <param name="receiverCertificate"></param>
  private static void EncryptFile(string originalFileName, string encryptedFileName, X509Certificate2 senderCertificate, X509Certificate2 receiverCertificate)
    {
      try
      {
        //生成DES Key用以加密文件内容
        byte[] desKeys = KeyHelper.GenerateDESKey();

        //保护DES密钥,制作签名
        //DES密钥(8字节数组)需要先转换成十六进制的字符串(16字节数组)后,再签名
        byte[] encryptedKeys = SignBeforeEncryptAndEncryptSignature(Utility.GetBytes(Utility.BytesToHexString(desKeys).ToUpper()), senderCertificate, receiverCertificate);

        //转换为Base64字节数组
        encryptedKeys = Utility.ConvertToBase64Bytes(encryptedKeys);

        //创建输出文件,如果文件存在则覆盖
        using (BinaryWriter binWriter =
          new BinaryWriter(File.Open(encryptedFileName, FileMode.Create, FileAccess.Write,FileShare.Read), Utility.GetEncoding()))
{
          //写入密钥密文的长度
          binWriter.Write(Utility.GetBytes(string.Format("{0:D10}", encryptedKeys.Length)));

          //写入密钥密文数据
          binWriter.Write(encryptedKeys);          

          //打开输入文件加密,并写入目标文件
          using (BinaryReader binReader =
            new BinaryReader(File.Open(originalFileName, FileMode.Open, FileAccess.Read, FileShare.Read), Utility.GetEncoding()))
          {
            while (true)
            {
              byte[] originalData = binReader.ReadBytes(Utility.MAX_ENCRYPTODECRYPT_BYTESCOUNT);

              if (originalData.Length == 0)
                break;

              //加密originalData
              byte[] encryptedData = EncryptHelper.EncryptByDES(originalData, desKeys, null);

              binWriter.Write(encryptedData);
            }
          }

          binWriter.Flush();
        }
      }
catch
      {
        throw;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="originalFileName"></param>
    /// <param name="decryptedFileName"></param>
    /// <param name="receiverCertificate"></param>
    private static void DecryptFile(string originalFileName, string decryptedFileName, X509Certificate2 receiverCertificate)
    {
      try
      {
        using (BinaryReader binReader =
          new BinaryReader(File.Open(originalFileName, FileMode.Open, FileAccess.Read,FileShare.Read), Utility.GetEncoding()))
        {
          //读取签名部分长度
          int signatureDataLen;

          if (!Int32.TryParse(Utility.GetString(binReader.ReadBytes(10)), out signatureDataLen))
            throw new InvalidDataException("源文件"+originalFileName+"数据无效。");

          //验证签名并获取用于解密文件内容的DES Key
          //解密出的DES Key数据需要先从十六进制的字符串(16字节数组)转换成DES密钥(8字节数组)
          byte[] dataToVerify = binReader.ReadBytes(signatureDataLen);
          dataToVerify = Utility.ConvertFromBase64Bytes(dataToVerify);

          byte[] desKeys = DecryptSignatureAndVerifyAfterDecrypt(dataToVerify,receiverCertificate);
          desKeys = Utility.HexStringToBytes(Utility.GetString(desKeys));                  

          //创建输出文件,写入解密内容
using (BinaryWriter binWriter = 
            new BinaryWriter(File.Open(decryptedFileName, FileMode.Create, FileAccess.Write,FileShare.Read), Utility.GetEncoding()))
          {
            binWriter.Seek(0, SeekOrigin.Begin);

            while (true)
            {
              byte[] originalData = binReader.ReadBytes(Utility.MAX_ENCRYPTODECRYPT_BYTESCOUNT);

              if (originalData.Length == 0)
                break;

              //解密originalData
              byte[] decryptedData = EncryptHelper.DecryptByDES(originalData, desKeys, null);

              binWriter.Write(decryptedData);
            }

            binWriter.Flush();
          }
        }
      }
      catch
      {
        throw;
      }
    }

 /// <summary>
    /// 
    /// </summary>
    /// <param name="originalData"></param>
    /// <param name="senderCertificate"></param>
    /// <param name="receiverCertificate"></param>
    /// <returns></returns>
    private static byte[] SignBeforeEncryptAndEncryptSignature(byte[] originalData, X509Certificate2 senderCertificate, X509Certificate2 receiverCertificate)
    {
      try
      {
        //****************************************************
        //使用发送者证书私钥PrivateKey签名originalData
        if (!senderCertificate.HasPrivateKey)
          throw new NotSupportedException("证书 "+senderCertificate.Subject+" 不含私钥,无法执行签名!");

        byte[] signedData = SignHelper.HashAndSignBytes(originalData, senderCertificate.PrivateKey, new SHA1CryptoServiceProvider());


        //****************************************************
        //创建字节数组用于TripleDES加密      
        byte[] plainData = new byte[8 + originalData.Length + signedData.Length + senderCertificate.RawData.Length];

        Array.Copy(BitConverter.GetBytes(originalData.Length), 0, plainData, 0, 4); //写入明文数据长度,4字节 Int32
        Array.Copy(BitConverter.GetBytes((short)signedData.Length), 0, plainData, 4, 2); //写入签名数据长度,2字节 Int16
        Array.Copy(BitConverter.GetBytes((short)senderCertificate.RawData.Length), 0, plainData, 6, 2); //
写入发送者证书的原始数据的长度,2字节 Int16
        Array.Copy(originalData, 0, plainData, 8, originalData.Length); //写入明文数据
        Array.Copy(signedData, 0, plainData, 8 + originalData.Length, signedData.Length); //写入签名数据
        Array.Copy(senderCertificate.RawData, 0, plainData, 8 + originalData.Length + signedData.Length, senderCertificate.RawData.Length); //
写入发送者证书的原始数据

        //使用TripleDES对称密钥加密
        byte[] tDESKeys = KeyHelper.GenerateTripleDESKey(128); //生成TripleDES Key 128位 16字节
        byte[] IV = KeyHelper.GenerateTripleDESIV(); //生成TripleDES IV 64位 8字节

        byte[] encryptedData = EncryptHelper.EncryptByTripleDES(plainData, tDESKeys, IV);

        //****************************************************
        //使用接收者证书公钥PublicKey加密对称密钥
        plainData = new byte[24];
        Array.Copy(tDESKeys, 0, plainData, 0, 16); //写入对称密钥tDESKeys
        Array.Copy(IV, 0, plainData, 16, 8); //写入向量IV

        byte[] encryptedKeys = EncryptHelper.EncryptByRSA(plainData, receiverCertificate.PublicKey.Key, false);


        //****************************************************
        //生成最终数据
        byte[] signatureData = new byte[6 + encryptedData.Length + encryptedKeys.Length];

        Array.Copy(BitConverter.GetBytes(encryptedData.Length), 0, signatureData, 0, 4); //写入数据密文数据长度,4字节 Int32
        Array.Copy(BitConverter.GetBytes(encryptedKeys.Length), 0, signatureData, 4, 2); //写入密钥密文数据长度,2字节 Int16
        Array.Copy(encryptedData, 0, signatureData, 6, encryptedData.Length); //写入数据密文数据
        Array.Copy(encryptedKeys, 0, signatureData, 6 + encryptedData.Length, encryptedKeys.Length); //写入密钥密文数据

        return signatureData;
      }
      catch
      {
        throw;
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="cipherData"></param>
    /// <param name="receiverCertificate"></param>
    /// <returns></returns>
    private static byte[] DecryptSignatureAndVerifyAfterDecrypt(byte[] cipherData, X509Certificate2 receiverCertificate)
    {      
      try
      {
        if (!receiverCertificate.HasPrivateKey)
          throw new NotSupportedException("证书 " + receiverCertificate.Subject + " 不含私钥,无法解密签名!");

        Int16 keysCipherLen = BitConverter.ToInt16(cipherData, 4); //密钥密文长度
        Int32 signatureCipherLen = BitConverter.ToInt32(cipherData, 0); //签名密文长度

        //****************************************************
        //先解密密钥密文获取解密签名密文的TripleDES Key和IV
        //****************************************************
        byte[] keysCipherData = new byte[keysCipherLen];
        Array.Copy(cipherData, 6+signatureCipherLen, keysCipherData, 0, keysCipherData.Length);

        //使用接收者证书私钥PrivateKey解密对称密钥
        byte[] keysPlainData = EncryptHelper.DecryptByRSA(keysCipherData, receiverCertificate.PrivateKey, false);

        //获取TripleDES Key和IV
        byte[] tDESKeys = new byte[16];
        Array.Copy(keysPlainData, 0, tDESKeys, 0, 16);

        byte[] IV = new byte[8];
        Array.Copy(keysPlainData, 16, IV, 0, 8);

        //****************************************************
        //使用TripleDES Key和IV解密签名密文
        //****************************************************
        byte[] signatureCipherData = new byte[signatureCipherLen];
        Array.Copy(cipherData, 6, signatureCipherData, 0, signatureCipherData.Length);

        byte[] signaturePlainData = EncryptHelper.DecryptByTripleDES(signatureCipherData, tDESKeys, IV);

        //****************************************************
        //使用发送者证书PublicKey验证签名
        //****************************************************
        //原文
        byte[] dataToVerify = new byte[BitConverter.ToInt32(signaturePlainData,0)];
        Array.Copy(signaturePlainData, 8, dataToVerify, 0, dataToVerify.Length);   

        //签名
        byte[] signedData = new byte[BitConverter.ToInt16(signaturePlainData, 4)];
        Array.Copy(signaturePlainData, 8 +dataToVerify.Length , signedData, 0, signedData.Length);  

        //发送方证书
        byte[] certRawData = new byte[BitConverter.ToInt16(signaturePlainData,6)];
        Array.Copy(signaturePlainData, 8 + dataToVerify.Length + signedData.Length, certRawData, 0,certRawData.Length);

        X509Certificate2 senderCertificate = new X509Certificate2(certRawData);

        if(!SignHelper.VerifySignedHash(dataToVerify,signedData,senderCertificate.PublicKey.Key,new SHA1CryptoServiceProvider()))
          throw new InvalidDataException("签名验证失败。");

        return dataToVerify;
      }
      catch
      {
        throw;
      }
    }

抱歉!评论已关闭.