C#使用AES加密解密

2018/4/18 17:13:01


网上很多教程都是使用Rijndael类来加密解密,但是笔者使用这个类却不支持,难道是因为需要特殊的引用?

 

但是笔者参考官方文档找到加解密的方法,即是用AES类,效果一样

 

先上代码再说明:

        /// <summary>  
        /// AES加密  
        /// </summary>  
        /// <param name="data">被加密的明文</param>  
        /// <param name="bKey">密钥</param>  
        /// <param name="bVector">向量</param>  
        /// <returns>明文</returns>  
        private static byte[] AESEncrypt(byte[] data, byte[] bKey, byte[] bVector)
        {
            Aes aesAlg = Aes.Create();
            aesAlg.Key = bKey;
            aesAlg.IV = bVector;
            aesAlg.Padding = PaddingMode.Zeros;

            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
            return encryptor.TransformFinalBlock(data, 0, data.Length);
        }

这是加密用的函数

参数:

  data数组,这是要加密的字节数组。如果是操作文件,建议循环调用函数,每次操作不要太大,这样可以显示进度,同时也防止文件过大消耗太多内存

    这里特别注意的是,数组长度如果不是16的整数倍,则加密后自动在其后补充字节至16的整数倍(这里在解密部分说明原因)

  bKey数组,这是加密使用的密码。这里需要特别注意,密码必须为128位或256位。其实112位也可以,但不普遍。建议128或256.

    如果密码为128位,则加密方式自动调整为AES128。对于256位同理。如果不是特定的长度,则会产生异常

  bVector数组,了解过Aes加密机制的就会知道,这作为加密的初始向量。

    很多人不明白为什么要有这个参数,这不是多此一举吗?不,这很有用!

    比如你加密一个字符串,如果密码相同,其结果即是确定的。这样会降低安全性,别人可能会通过比对的方法找出原信息。

    但是如果你更改了初始向量,也就是AES每轮加密使用的密码都和以前的不同。这样加密后的结果也就不同。

    根据我的理解,初始向量也就相当于AES的第二套密码

返回值:

  这个没什么好说的,就是加密后的数据

 

下面再来看看解密操作

        /// <summary>  
        /// AES解密  
        /// </summary>  
        /// <param name="data">被解密的密文</param>  
        /// <param name="bKey">密钥</param>  
        /// <param name="bVector">向量</param>  
        /// <returns>明文</returns>  
        private static byte[] AESDecrypt(byte[] data, byte[] bKey, byte[] bVector)
        {
            Aes aesAlg = Aes.Create();
            aesAlg.Key = bKey;
            aesAlg.IV = bVector;
            aesAlg.Padding = PaddingMode.Zeros;

            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
            return decryptor.TransformFinalBlock(data, 0, data.Length);
        }

参数好理解,和加密用的参数相同。返回值为解密后的数据

但是这里还有一些要注意的地方:

  前面加密提到,如果加密所用数组长度不是16的整数倍,则自动添加长度。

  这是因为解密的data参数长度也必须为16的整数倍。加密结果是自动增加长度后的数据,则该数据可以直接作为解密函数的参数

 

笔者发现这个类,在控制台、WPF、WinForm、UWP都可以使用,比Rijndael更好用。


如果你想加密字符串,则只需调这两个函数用并做点转换即可

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string AESEncrypt(string data)
        {
            return Encoding.Unicode.GetString(AESEncrypt(Encoding.Unicode.GetBytes(data)));
        }
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string AESDecrypt(string data)
        {
            return Encoding.Unicode.GetString(AESDecrypt(Encoding.Unicode.GetBytes(data)));
        }

是不是非常简单?

 

如果你想加密文件,也只需只需调这两个函数用并做点转换即可(前提是小文件,如果是大文件,必须使用循环多次调用,否则内存消耗太高可能导致程序崩溃)

        /// <summary>
        /// 加密文件
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static void AESEncryptFile(string path)
        {
            File.WriteAllBytes(path, AESEncrypt(File.ReadAllBytes(path)));
        }
        /// <summary>
        /// 解密文件
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static void AESDecryptFile(string path)
        {
            File.WriteAllBytes(path, AESDecrypt(File.ReadAllBytes(path)));
        }

 

如果还有疑问,欢迎联系vivek.wang@outlook.com

 

UWP应用Encipher即主要是使用类似的方法。当然Encipher也可加解密大文件,并支持批量操作,这就需要多次循环并调用加解密函数了