C# 利用AEC算法加密解密实现前台后台安全校验,附前端后台代码示例

3 篇文章 0 订阅
1 篇文章 0 订阅

最近再新入职公司查看前端登录用ajax请求,发现使用这个AES加密,提升了一定的安全性,也加强了对

对密钥等概念的理解,和体会,所以研究了下记录于此。

关于AES算法解释见https://blog.csdn.net/qq_28205153/article/details/55798628

第一部分:前台加密

可以在这个GitHub的https://github.com/brix/crypto-js上下载该js,它可以单独引入所需要加密方式的js;

主要是方便模块化

还可以引入一个crypto-js.js 这个文件,它相当于引入了所有的加密方式,我使用的就是后者一次引入所有的加密文件,这个文件也不是很大,还可以接受。下载地址https://cdn.bootcss.com/crypto-js/3.1.9-1/crypto-js.min.js (右键另存为即可)

参考如下https://www.cnblogs.com/lz2017/p/8046816.html


<%--<script src="CryptoJS/components/core.js"></script>
<script src="CryptoJS/components/cipher-core.js"></script>
<script src="CryptoJS/components/mode-ecb.js"></script>
<script src="CryptoJS/components/enc-base64.js"></script>
<script src="CryptoJS/components/aes.js"></script>--%>
<script src="CryptoJS/crypto-js.min.js"></script>
<%--<script src="CryptoJS/CrptoJS.js"></script>--%>
<script>
    var Crypto = {
        Encrypt: function (plaintText) {
            var rsEncrypt = CryptoJS.AES.encrypt(plaintText, this.GenKey(), {
                iv: this.GenIV(),
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.Pkcs7
            });

            return CryptoJS.enc.Base64.stringify(rsEncrypt.ciphertext);
        },
        GenKey: function () {
            return CryptoJS.enc.Utf8.parse('X9Q0uft9inKg5Q50ImqQXg9inKg5Q56W');
        },
        GenIV: function () {
            return CryptoJS.enc.Utf8.parse('1234567890000000');
        }
    };
    save();
    function save() {
        var auth = Crypto.Encrypt("我是要加密的内容,且转为base64码的字符串,解密记得先转为对应!");
        console.log(auth);
        //var formData = new FormData();
        //formData.append("pdsauth", auth);   
    }
</script>

相关用法解释见https://www.jb51.net/article/145746.htm 

采用自定义密钥,和初始化变量,加密明文得到密文转为base64码后,变成如下字符串,

 

 

第二部分:后台加密 

https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.aescryptoserviceprovider?view=netframework-4.8

加密:

new一个服务器提供器,分别赋值四个常用字段,

通过key密钥,vi初始化值构造加密器

定义一个内存流,加上加密器,构造加密流,

将明文写入加密流

https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.aescryptoserviceprovider.createencryptor?view=netframework-4.8

解密

同样new一个服务提供器对象,分别赋值,里面key和vi要一致

通过key密钥,vi初始化值构造解密器

用密文字节数组构造一个内存流,加上解密器,构造解密流

将解密流读出

https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.aescryptoserviceprovider.createdecryptor?view=netframework-4.8#System_Security_Cryptography_AesCryptoServiceProvider_CreateDecryptor

系统提供加密解密方法,都是操作密文的字节数组,

可能我们平时需要变成字符串密文,这里加密后得到密文数组,

加密后的密文数组,转为为字符串方式,常用转为base64或是上面自定义的方式,转为16进制字符串

那么解密也需要对应方式,将字符串按照同样的方式,转化为数组,这个一定要保持一致,

相关代码如下:

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

namespace Util.SecutyUtil
{
    public abstract class AESUtil
    {

        private const string DEFAULT_AES_KEY = "X9Q0uft9inKg5Q50ImqQXg9inKg5Q56W";//32位 
        private const string DEFAULT_AES_IV = "1234567890000000";//16位 

        /// <summary>  
        /// AES加密算法  
        /// </summary>  
        /// <param name="input">明文字符串</param>  
        /// <param name="key">密钥(32位)</param>  
        /// <returns>字符串</returns>  
        /// //https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.aescryptoserviceprovider.createencryptor?view=netframework-4.8
        public static string AESEncrypt(string input, string key, string iv)
        {
            if (input == null) return input;

            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = Encoding.UTF8.GetBytes(iv);
                aesAlg.Mode = CipherMode.ECB;
                aesAlg.Padding = PaddingMode.PKCS7;

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(input);
                        }
                        byte[] bytes = msEncrypt.ToArray();
                        //return Encoding.UTF8.GetString(bytes);
                        return ByteArrayToHexString(bytes);
                        //return Convert.ToBase64String(msEncrypt.ToArray());
                    }
                }
            }
        }

        /// <summary>
        /// 使用系统默认的key和iv进行加密
        /// </summary>
        /// <param name="input">待加密的string</param>
        /// <returns>加密后的string</returns>
        public static string AESEncrypt(string input)
        {
            return AESEncrypt(input, DEFAULT_AES_KEY.Substring(0, 32), DEFAULT_AES_IV.Substring(0, 16));
        }

        //https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.aescryptoserviceprovider.createencryptor?view=netframework-4.8
        /// <summary>  
        /// AES解密  
        /// </summary>  
        /// <param name="input">密文字节数组</param>  
        /// <param name="key">密钥(32位)</param>  
        /// <returns>返回解密后的字符串</returns>
        public static string AESDecrypt(string input, string key, string iv)
        {
            if (input == null) return input;
            //byte[] inputBytes = Convert.FromBase64String(input);
            byte[] inputBytes = HexStringToByteArray(input);
            //byte[] inputBytes = Encoding.UTF8.GetBytes(input);
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = Encoding.UTF8.GetBytes(iv);
                aesAlg.Mode = CipherMode.ECB;
                aesAlg.Padding = PaddingMode.PKCS7;

                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream(inputBytes))
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srEncrypt = new StreamReader(csEncrypt))
                        {
                            return srEncrypt.ReadToEnd();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 使用系统默认的key和iv进行解密
        /// </summary>
        /// <param name="input">待解密的string</param>
        /// <returns>解密后的string</returns>
        public static string AESDecrypt(string input)
        {
            return AESDecrypt(input, DEFAULT_AES_KEY.Substring(0, 32), DEFAULT_AES_IV.Substring(0, 16));
        }

        /// <summary>
        /// 将指定的16进制字符串转换为byte数组
        /// </summary>
        /// <param name="s">16进制字符串(如:“7F 2C 4A”或“7F2C4A”都可以)</param>
        /// <returns>16进制字符串对应的byte数组</returns>
        public static byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
            return buffer;
        }

        /// <summary>
        /// 将一个byte数组转换成一个格式化的16进制字符串
        /// </summary>
        /// <param name="data">byte数组</param>
        /// <returns>格式化的16进制字符串</returns>
        public static string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
            {
                //16进制数字
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
                //16进制数字之间以空格隔开
                //sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
            }
            return sb.ToString().ToUpper();
        }
    }
}

 

测试代码和示例如下:

string destr = AESUtil.AESEncrypt("我是要加密的内容,且转为base64码的字符串,解密记得先转为对应!");
            //Console.WriteLine(enstr);
            //string destr = "FOyUSJ1YATG1qH2+kycS9ofTsH3mAieDNTGWr2g7y/cs2u/2WAerCwzT9FwCA2MmeGWzleoeT3em1PyForMifyPsHzDwuidJ8CSOZgyta1ODQzS+ogqiGVYCQTEgRhI/";
            //string destr = "14EC94489D580131B5A87DBE932712F687D3B07DE6022783353196AF683BCBF72CDAEFF65807AB0B0CD3F45C020363267865B395EA1E4F77A6D4FC85A2B3227F23EC1F30F0BA2749F0248E660CAD6B53834334BEA20AA219560241312046123F";
            string ret = AESUtil.AESDecrypt(destr);
            Console.WriteLine(ret);

 

 

注意事项和要点总结,

系统提供加密解密方法,都是操作密文的字节数组,

可能我们平时需要变成字符串密文,这里加密后得到密文数组,

加密后的密文数组,转为为字符串方式,常用转为base64或是上面自定义的方式,转为16进制字符串

那么解密也需要对应方式,将字符串按照同样的方式,转化为数组,这个一定要保持一致,

否则报错如下:

总结:采用相同密钥,初始化变量,明文,不管前端还是后台得到相同结果,那么可以用做安全校验,提升安全性

(当然密钥写在脚本中,前端加密其实安全性有限,这里博主不做讨论,https://www.zhihu.com/question/373064057

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值