天天看点

AES 256 加密和解密 for C#

这几天在写一个对文件进行加密解密的程序,翻了以前在博客园贴过的一段代码,稍微整理了一下,写成一个方便调用的类,并做了注释。

这里需要特别说明的是,AES 需要提供2个字符串,一个是KEY,一个是IV,并且都有长度要求。但对于一般的加密来说,是比较麻烦的。所以我还提供了一个方便调用的 Simple 方法,只需提供一个密码,通过 MD5 自动处理为 32 位长度的 KEY,并截取其中 16 位作为 IV,这样在调用的时候,也方便许多。

经过试用,觉得 AES 256 在加密小文件的时候,效率是可以的,但加密大文件(例如 1.25G 的视频)效率明显下降,并且占用系统资源很大。

以下是代码:

using System.Security.Cryptography;
using System.Text;
 
// 阿博-STYLE
// www.abo-style.com
namespace AboStyle
{
    /// <summary>
    /// AES 256 加密和解密 for C#
    /// 阿博-STYLE(2012)
    /// </summary>
    public class Aes
    {
        #region Create
        /// <summary>
        /// 创建一个统一配置的加密算法。
        /// </summary>
        /// <param name="key">密钥(32位)</param>
        /// <param name="iv">初始化向量(16位)</param>
        /// <returns>RijndaelManaged</returns>
        private static RijndaelManaged Create(string key, string iv)
        {
            RijndaelManaged rm = new RijndaelManaged();
            rm.Key = Encoding.UTF8.GetBytes(key);   // 这里统一使用UTF8进行编码;
            rm.IV = Encoding.UTF8.GetBytes(iv);     // 如果使用其它编码,要注意长度问题;
            rm.Mode = CipherMode.CBC;
            rm.Padding = PaddingMode.PKCS7;
            return rm;
        }
        #endregion
 
        #region Encryptor
        /// <summary>
        /// 对字节数组进行加密
        /// </summary>
        /// <param name="bs">要加密的字节</param>
        /// <param name="key">密钥(32位)</param>
        /// <param name="iv">初始化向量(16位)</param>
        /// <returns>加密后的结果</returns>
        public static byte[] Encryptor(byte[] bs, string key, string iv)
        {
            ICryptoTransform transform = Create(key, iv).CreateEncryptor();
            return transform.TransformFinalBlock(bs, 0, bs.Length);
        }
        #endregion
 
        #region Decryptor
        /// <summary>
        /// 对字节数组进行解密
        /// </summary>
        /// <param name="bs">要解密的字节</param>
        /// <param name="key">密钥(32位)</param>
        /// <param name="iv">初始化向量(16位)</param>
        /// <returns>解密后的结果</returns>
        public static byte[] Decryptor(byte[] bs, string key, string iv)
        {
            ICryptoTransform transform = Create(key, iv).CreateDecryptor();
            return transform.TransformFinalBlock(bs, 0, bs.Length);
        }
        #endregion
 
        #region Simple
        /// <summary>
        /// 方便简单调用的加密或解密统一方法
        /// </summary>
        /// <param name="encrypt">是否为加密?true 为加密,false 为解密</param>
        /// <param name="bs">要加密或解密的字节</param>
        /// <param name="password">密码(任意长度,使用MD5处理为32位)</param>
        /// <returns>处理后的字节</returns>
        public static byte[] Simple(bool encrypt, byte[] bs, string password)
        {
            // 借用 MD5 算法,将密码统一为32位长度字符串
            StringBuilder md5 = new StringBuilder();
            foreach (byte b in System.Security.Cryptography.MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(password)))
            {
                md5.Append(b.ToString("X2"));
            }
 
            // KEY 为 MD5
            string key = md5.ToString();
 
            // IV 为 MD5 中截取中间的16位字符
            string iv = key.Substring(8, 16);
 
            // 根据是否加密 调用不同的方法
            return encrypt ? Encryptor(bs, key, iv) : Decryptor(bs, key, iv);
        }
        #endregion
    }
}