zoukankan      html  css  js  c++  java
  • [转].NET下对二进制文件进行加密解密(C#)

    本文转自:http://blog.csdn.net/veryhappy/archive/2006/01/09/574152.aspx

    下面的类实现了文件的加密和解密操作,试验了几种文件类型均没有问题,现在和大家共享一下。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Security.Cryptography;
    using System.IO;

    namespace MyCryptoHelp
    {
     /// <summary>
     /// 异常处理类
     /// </summary>
     public class CryptoHelpException : ApplicationException
     {
      public CryptoHelpException(string msg):base(msg){}
     }

     /// <summary>
     /// CryptHelp
     /// </summary>
     public class CryptoHelp
     {
      private const ulong FC_TAG = 0xFC010203040506CF;

      private const int BUFFER_SIZE = 128*1024;
      
      /// <summary>
      /// 检验两个Byte数组是否相同
      /// </summary>
      /// <param name="b1">Byte数组</param>
      /// <param name="b2">Byte数组</param>
      /// <returns>true-相等</returns>
      private static bool CheckByteArrays(byte[] b1, byte[] b2)
      {
       if(b1.Length == b2.Length)
       {
        for(int i = 0; i < b1.Length; ++i)
        {
         if(b1[i] != b2[i])
          return false;
        }
        return true;
       }
       return false;
      }

      /// <summary>
      /// 创建Rijndael SymmetricAlgorithm
      /// </summary>
      /// <param name="password">密码</param>
      /// <param name="salt"></param>
      /// <returns>加密对象</returns>
      private static SymmetricAlgorithm CreateRijndael(string password, byte[] salt)
      {
       PasswordDeriveBytes pdb = new PasswordDeriveBytes(password,salt,"SHA256",1000);
       
       SymmetricAlgorithm sma = Rijndael.Create();
       sma.KeySize = 256;
       sma.Key = pdb.GetBytes(32);
       sma.Padding = PaddingMode.PKCS7;
       return sma;
      }

      /// <summary>
      /// 加密文件随机数生成
      /// </summary>
      private static RandomNumberGenerator rand = new RNGCryptoServiceProvider();

      /// <summary>
      /// 生成指定长度的随机Byte数组
      /// </summary>
      /// <param name="count">Byte数组长度</param>
      /// <returns>随机Byte数组</returns>
      private static byte[] GenerateRandomBytes(int count)
      {
       byte[] bytes = new byte[count];
       rand.GetBytes(bytes);
       return bytes;
      }

      /// <summary>
      /// 加密文件
      /// </summary>
      /// <param name="inFile">待加密文件</param>
      /// <param name="outFile">加密后输入文件</param>
      /// <param name="password">加密密码</param>
      public static void EncryptFile(string inFile, string outFile, string password)
      {
       using(FileStream fin = File.OpenRead(inFile),
           fout = File.OpenWrite(outFile))
       {
        long lSize = fin.Length; // 输入文件长度
        int size = (int)lSize;
        byte[] bytes = new byte[BUFFER_SIZE]; // 缓存
        int read = -1; // 输入文件读取数量
        int value = 0;
        
        // 获取IV和salt
        byte[] IV = GenerateRandomBytes(16);
        byte[] salt = GenerateRandomBytes(16);
        
        // 创建加密对象
        SymmetricAlgorithm sma = CryptoHelp.CreateRijndael(password, salt);
        sma.IV = IV;   
        
        // 在输出文件开始部分写入IV和salt
        fout.Write(IV,0,IV.Length);
        fout.Write(salt,0,salt.Length);
        
        // 创建散列加密
        HashAlgorithm hasher = SHA256.Create();
        using(CryptoStream cout = new CryptoStream(fout,sma.CreateEncryptor(),CryptoStreamMode.Write),
            chash = new CryptoStream(Stream.Null,hasher,CryptoStreamMode.Write))
        {
         BinaryWriter bw = new BinaryWriter(cout);
         bw.Write(lSize);
         
         bw.Write(FC_TAG);

         // 读写字节块到加密流缓冲区
         while( (read = fin.Read(bytes,0,bytes.Length)) != 0 )
         {
          cout.Write(bytes,0,read);
          chash.Write(bytes,0,read); 
          value += read;
         }
         // 关闭加密流
         chash.Flush();
         chash.Close();

         // 读取散列
         byte[] hash = hasher.Hash;
         
         // 输入文件写入散列
         cout.Write(hash,0,hash.Length);

         // 关闭文件流
         cout.Flush();
         cout.Close();
        }
       }
      }

      /// <summary>
      /// 解密文件
      /// </summary>
      /// <param name="inFile">待解密文件</param>
      /// <param name="outFile">解密后输出文件</param>
      /// <param name="password">解密密码</param>
      public static void DecryptFile(string inFile, string outFile, string password)
      {
       // 创建打开文件流
       using(FileStream fin = File.OpenRead(inFile),
           fout = File.OpenWrite(outFile))
       {
        int size = (int)fin.Length;
        byte[] bytes = new byte[BUFFER_SIZE];
        int read = -1;
        int value = 0;
        int outValue = 0;

        byte[] IV = new byte[16];
        fin.Read(IV,0,16);
        byte[] salt = new byte[16];
        fin.Read(salt,0,16);
        
        SymmetricAlgorithm sma = CryptoHelp.CreateRijndael(password,salt);
        sma.IV = IV;

        value = 32;
        long lSize = -1;
        
        // 创建散列对象, 校验文件
        HashAlgorithm hasher = SHA256.Create();

        using(CryptoStream cin = new CryptoStream(fin,sma.CreateDecryptor(),CryptoStreamMode.Read),
            chash = new CryptoStream(Stream.Null,hasher,CryptoStreamMode.Write))
        {
         // 读取文件长度
         BinaryReader br = new BinaryReader(cin);
         lSize = br.ReadInt64();
         ulong tag = br.ReadUInt64();
         
         if(FC_TAG != tag)
          throw new CryptoHelpException("文件被破坏");
         
         long numReads = lSize / BUFFER_SIZE;

         long slack = (long)lSize % BUFFER_SIZE;
         
         for(int i = 0; i < numReads; ++i)
         {
          read = cin.Read(bytes,0,bytes.Length);
          fout.Write(bytes,0,read);
          chash.Write(bytes,0,read);
          value += read;
          outValue += read;
         }

         if(slack > 0)
         {
          read = cin.Read(bytes,0,(int)slack);
          fout.Write(bytes,0,read);
          chash.Write(bytes,0,read);
          value += read;
          outValue += read;
         }

         chash.Flush();
         chash.Close();

         fout.Flush();
         fout.Close();

         byte[] curHash = hasher.Hash;

         // 获取比较和旧的散列对象
         byte[] oldHash = new byte[hasher.HashSize / 8];
         read = cin.Read(oldHash,0,oldHash.Length);
         if((oldHash.Length != read) || (!CheckByteArrays(oldHash,curHash)))
          throw new CryptoHelpException("文件被破坏");
        }
        
        if(outValue != lSize)
         throw new CryptoHelpException("文件大小不匹配");
       }
      }
     }
    }

    // 调用

    public class TestClass
    {
        string myPassword = "TEST_PASSWORD_~!@#";
        string myPlainFile = "test.txt";
        string myEncryptedFile = "test.encrypted";
        string myDecryptedFile = "test.decrypted";

        [STAThread]
        static void Main()
        {
            CryptoHelp.EncryptFile(myPlainFile, myEncryptedFile, myPassword);
            CryptoHelp.DecryptFile(myEncryptedFile,myDecryptedFile, myPassword);
        }
    }

    // 微软的加密解密文本文件的方法

    http://support.microsoft.com/kb/307010/zh-cn

  • 相关阅读:
    SSH 多台VM之间无密码登录
    JavaScript Calling WebService by SOAP
    Excel大数据排查重复行内容方法,三步搞定!
    linux添加软件的service start/stop快捷服务(简单版)
    Linux服务器其中一个磁盘满了怎么办?在不做磁盘扩容的情况下,一个软连接就搞定。
    oracle数据库中将clob字段内容利用java提取出至文本文档中
    最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
    mysql数据库误删除操作说明
    mysql5.x升级至mysql5.7后导入之前数据库date出错的解决方法!
    新建ftp账号,并使登陆者只访问当前目录
  • 原文地址:https://www.cnblogs.com/freeliver54/p/1301581.html
Copyright © 2011-2022 走看看