AES对称加密,Java、C#、JS 互转

AES简介(高级加密)

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥。

加密公式:

					C=E(K,P)
				
					C —— 加密后的字符串
					E —— 加密函数
					K —— 密钥(key)
					P —— 需要加密的字符串(明文)

解密公式:

					P=D(K,C)
				
					C —— 输入加密字符串
					D —— 解密函数
					K —— 密钥(key)
					P —— 解密后的字符串(明文)

AES 加密模式(Mode)

对称/分组密码一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)。对于流加密,需要将分组密码转化为流模式工作。对于块加密(或称分组加密),如果要加密超过块大小的数据,就需要涉及填充和链加密模式。

ECB(Electronic Code Book电子密码本)模式

ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

优点:
1.简单; 
2.有利于并行计算; 
3.误差不会被传送; 
缺点: 
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
因此,此模式适于加密小消息。

CBC(Cipher Block Chaining,加密块链)模式

优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
 1.不利于并行计算; 
 2.误差传递; 
 3.需要初始化向量IV

CFB(Cipher FeedBack Mode,加密反馈)模式

优点:
1.隐藏了明文模式; 
2.分组密码转化为流模式; 
3.可以及时加密传送小于分组的数据; 
缺点: 
1.不利于并行计算; 
2.误差传送:一个明文单元损坏影响多个单元;
3.唯一的IV;

OFB(Output FeedBack,输出反馈)模式

优点:
1.隐藏了明文模式; 
2.分组密码转化为流模式; 
3.可以及时加密传送小于分组的数据; 
缺点: 
1.不利于并行计算; 
2.对明文的主动攻击是可能的; 
3.误差传送:一个明文单元损坏影响多个单元

AES 填充方式(Padding)

NoPadding

无填充

PKCS5Padding

填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。

ISO10126Padding

将原文的长度边长组的大小的整数倍。
最后一个填充是填充的字节数,其它位随机数。

PaddingMode.Zeros

尾部补零

PaddingMode.PKCS7

同PKCS5Padding一样

AES 加密说明

本文java、JS、C#三端均采用CBC模式加密,填充方式选择PKCS7

Java端


 /*
    * AES工具类
    */
public class AESUtil {
	public static String IV = "1234567890000000"; // 自定义
    public static String KEY = "ABCDEFG1234567ABCDEFG12345671111"; // 自定义
    private static String MODE = "AES/CBC/PKCS5Padding"; // 选择CBC模型和PKCS5填充方式
    private static String TYPE = "AES";
    
     /*
    * AES解密函数
    */
    public static String AESDecrypt(String Data, String Key) throws UnsupportedEncodingException
    {
        byte[] inputBytes = Base64StringToByteArray(Data);
        byte[] keyBytes = Key.getBytes("utf-8");
        try {
            SecretKeySpec keySpec = new SecretKeySpec(keyBytes, TYPE);
        	Cipher cipher = Cipher.getInstance(MODE);
			cipher.init(Cipher.DECRYPT_MODE, keySpec,new IvParameterSpec(IV.getBytes("utf-8")));
			inputBytes = cipher.doFinal(inputBytes);
		} catch (Exception e) {
			e.printStackTrace();
		};
        return new String(inputBytes, "utf-8");
    }
    
    /*
    * AES加密函数
    */
    public static String AESEncrypt(String data,String key) {
        try {
        	IvParameterSpec iv = new IvParameterSpec(IV.getBytes("utf-8"));
            SecretKeySpec sKeySpec = new SecretKeySpec(key.getBytes("utf-8"),TYPE);
            Cipher cipher = Cipher.getInstance(MODE);
			cipher.init(Cipher.ENCRYPT_MODE, sKeySpec, iv);
	        byte[] encrypted = cipher.doFinal(data.getBytes("utf-8"));
	        return new String(Base64.encodeBase64(encrypted));	// 需要Base64转化函数
		} catch (Exception e) {
			e.printStackTrace();
		}
        return null;
    }
    /*
    * Base64工具类转化
    */
    public static byte[] Base64StringToByteArray(String s)
    {
		byte[] arr = Base64Decoder.decode(s.substring(s.indexOf(",")+1));
		return arr;
    }
}


Java这里可能会出现一个问题,key长度限制,需要更换Java运行环境,受限的policy文件,文件位于/jre/lib/security下

java.security.InvalidKeyException: Illegal key size

将下面链接中的jar包下载下来,替换jdk 与jre下两个jar包:local_policy.jar和US_export_policy.jar即可。

JDK6: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

JDK7: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

JDK8: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

jdk对应jar包的路径(找自己的路径):C:\Java\jdk1.7.0_67\jre\lib\security
jre对应jar包的路径(找自己的路径):C:\Java\jre7\lib\security\

JavaScript

JS我们可以下载crypto-js 加密库,里面包含了许多加密算法,引用的话只需要引用其中的aes.js

	 var keyStr = "ABCDEFG1234567ABCDEFG12345671111"
     var IVStr = "1234567890000000";//16位
     var iv = CryptoJS.enc.Utf8.parse(IVStr);
     	 key = CryptoJS.enc.Utf8.parse(keyStr);
  // 解密
     function dataDecrypt(data){
      	var bytes  = CryptoJS.AES.decrypt(data, key,{
              iv: iv,
              mode: CryptoJS.mode.CBC,
              padding: CryptoJS.pad.Pkcs7
          });
 		data = bytes.toString(CryptoJS.enc.Utf8);
 		return data;
     }
     // 加密
     function dataEncrypt(jsonList){
      	var ciphertext = CryptoJS.AES.encrypt(jsonList, key,{iv:iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7}).toString();
 		return ciphertext;
     }

C#

  class AESUtil
    {
    	const string IV = "1234567890000000";
    	const string key = "ABCDEFG1234567ABCDEFG12345671111";
		/// <summary>
        /// AES加密(无向量)
        /// </summary>
        /// <param name="Data">被加密的明文</param>
        /// <param name="Key">密钥</param>
        /// <returns>密文</returns>
        public static string AESEncrypt(String Data, String Key)
        {
            MemoryStream mStream = new MemoryStream();
            RijndaelManaged aes = new RijndaelManaged();

            byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
            Byte[] bKey = new Byte[32];
            Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
            byte[] _iv = Encoding.UTF8.GetBytes(IV);
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 256;
            //aes.Key = _key;
            aes.Key = bKey;
            aes.IV = _iv;
            CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
            try
            {
                cryptoStream.Write(plainBytes, 0, plainBytes.Length);
                cryptoStream.FlushFinalBlock();
                return Convert.ToBase64String(mStream.ToArray());
            }
            finally
            {
                cryptoStream.Close();
                mStream.Close();
                aes.Clear();
            }

        }
        /// <summary>
        /// AES解密(无向量)
        /// </summary>
        /// <param name="Data">被加密的明文</param>
        /// <param name="Key">密钥</param>
        /// <returns>明文</returns>
        public static string AESDecrypt(String Data, String Key)
        {
            byte[] inputBytes = Base64StringToByteArray(Data);
            byte[] keyBytes = Encoding.UTF8.GetBytes(Key.Substring(0, 32));
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = Encoding.UTF8.GetBytes(IV.Substring(0, 16));

                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))
                        {
                            string str = srEncrypt.ReadToEnd();
                            srEncrypt.Close();
                            csEncrypt.Close();
                            msEncrypt.Close();
                            return str;
                        }
                    }

                }
            }
        }
        /// <summary>
        /// 将指定的Base64字符串转换为byte数组
        /// </summary>
        /// <param name="s"></param>
        /// <returns>16进制字符串对应的byte数组</returns>
        public static byte[] Base64StringToByteArray(string s)
        {
            byte[] arr = Convert.FromBase64String(s.Substring(s.IndexOf(",") + 1));
            return arr;
        }
        }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双向 RSA + AES 加密是一种常见的加密方式,其使用 RSA 算法加密 AES 密钥,然后使用 AES 算法加密数据。在 C# ,可以使用 `RSACryptoServiceProvider` 类和 `AesCryptoServiceProvider` 类来实现此加密方式。以下是一个简单的示例: ```csharp using System; using System.IO; using System.Security.Cryptography; using System.Text; class Program { static void Main(string[] args) { string plainText = "Hello, world!"; byte[] encryptedData = Encrypt(plainText); string decryptedText = Decrypt(encryptedData); Console.WriteLine("Original text: {0}", plainText); Console.WriteLine("Encrypted data: {0}", Convert.ToBase64String(encryptedData)); Console.WriteLine("Decrypted text: {0}", decryptedText); } static byte[] Encrypt(string plainText) { byte[] aesKey = GenerateAesKey(); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] encryptedAesKey = rsa.Encrypt(aesKey, true); // 使用 RSA 加密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.GenerateIV(); using (var memoryStream = new MemoryStream()) { memoryStream.Write(aes.IV, 0, aes.IV.Length); using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] plainData = Encoding.UTF8.GetBytes(plainText); cryptoStream.Write(plainData, 0, plainData.Length); cryptoStream.FlushFinalBlock(); } byte[] encryptedData = memoryStream.ToArray(); byte[] result = new byte[encryptedAesKey.Length + encryptedData.Length]; Buffer.BlockCopy(encryptedAesKey, 0, result, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, 0, result, encryptedAesKey.Length, encryptedData.Length); return result; } } } } static string Decrypt(byte[] encryptedData) { byte[] encryptedAesKey = new byte[128]; // RSA 加密 AES 密钥得到的密文长度为 128 字节 byte[] encryptedDataOnly = new byte[encryptedData.Length - encryptedAesKey.Length]; Buffer.BlockCopy(encryptedData, 0, encryptedAesKey, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, encryptedAesKey.Length, encryptedDataOnly, 0, encryptedDataOnly.Length); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] aesKey = rsa.Decrypt(encryptedAesKey, true); // 使用 RSA 解密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.IV = encryptedDataOnly.Take(aes.IV.Length).ToArray(); using (var memoryStream = new MemoryStream()) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(encryptedDataOnly, aes.IV.Length, encryptedDataOnly.Length - aes.IV.Length); cryptoStream.FlushFinalBlock(); } byte[] decryptedData = memoryStream.ToArray(); return Encoding.UTF8.GetString(decryptedData); } } } } static byte[] GenerateAesKey() { using (var aes = new AesCryptoServiceProvider()) { aes.GenerateKey(); return aes.Key; } } } ``` 上面的代码,首先调用 `GenerateAesKey` 方法生成 AES 密钥,然后使用 RSA 算法加密 AES 密钥。加密时,先将 AES 密钥使用 RSA 加密,然后使用 AES 算法加密数据。具体来说,将 AES 密钥和 IV 都写入 `MemoryStream` 对象,然后使用 `CryptoStream` 对象将数据写入 `MemoryStream` 对象。最后将密文和 RSA 加密的 AES 密钥一起返回。 解密时,先从密文取出 RSA 加密的 AES 密钥,然后使用 RSA 算法解密 AES 密钥。解密时,先从密文取出 AES 的 IV 值,然后使用 `CryptoStream` 对象将数据解密。最后将解密后的文本返回。 注意,上面的示例仅用于演示 RSA + AES 加密的基本原理,实际使用还需要考虑安全性等因素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值