C# AES 加密解密,微信敏感数据解密
2022-12-16重新编辑C# AES加密解密
在调用RijndaelManaged 时发现生成加密的时候设置参数的顺序和解密赋值参数的顺序不一致时解密不了。这可能是因为RijndaelManaged封装的get/set时加了处理。
所以要统一加密和解密的RijndaelManaged 对象
1 /// <summary> 2 /// 统一创建加密和解密参数顺序设置 3 /// </summary> 4 /// <param name="key">key 是明文,不需要bas64这些</param> 5 /// <param name="sha1">是否对key进行sha1,是的话key值只需要大于16位即可,取keySize/8的值</param> 6 /// <returns></returns> 7 private static RijndaelManaged CreateAES(string key, bool sha1 = false) 8 { 9 if (sha1 == false) 10 { 11 if (key.Length != 16 && key.Length != 24) 12 { 13 throw new Exception("key的位数必须是16或24"); 14 } 15 } 16 else 17 { 18 if (key.Length < 16) 19 { 20 throw new Exception("key的位数必须是大于16"); 21 } 22 } 23 RijndaelManaged rm = new RijndaelManaged 24 { 25 Mode = CipherMode.ECB, 26 Padding = PaddingMode.PKCS7, 27 KeySize = 128, 28 BlockSize = 128 29 }; 30 if (sha1 == false) 31 { 32 rm.Key = Encoding.UTF8.GetBytes(key); 33 } 34 else 35 { 36 rm.Key = GetSecretKey(key, rm.KeySize / 8); 37 } 38 return rm; 39 }
key应该是16或24位。但是这就比较局限性了,所以在我们不经意间设置了不是这个长度的key时,就会报错啦。为了决解这个问题,我们就要固定这个key的长度。通过哈希来实现。
1 /// <summary> 2 /// .NET与JAVA的AES互通【SecureRandom.getInstance("SHA1PRNG")】 3 /// </summary> 4 /// <param name="password"></param> 5 /// <returns></returns> 6 private static byte[] GetSecretKey(string password, int size = 16) 7 #region 8 { 9 byte[] keyArray; 10 byte[] seed = Encoding.UTF8.GetBytes(password); 11 using (var st = new SHA1CryptoServiceProvider()) 12 { 13 using (var nd = new SHA1CryptoServiceProvider()) 14 { 15 var rd = nd.ComputeHash(st.ComputeHash(seed)); 16 keyArray = rd.Take(size).ToArray(); 17 } 18 } 19 return keyArray; 20 } 21 #endregion
SHA1:返回一个160位的byte[]数组,20字节,我们取前面16位刚好满足。
创建加密实例:
1 public static string Encrypt(string text, string key, bool keyNeedHash = false) 2 { 3 var rm = CreateAES(key, keyNeedHash); 4 ICryptoTransform transform = rm.CreateEncryptor(); 5 byte[] plainText = Encoding.UTF8.GetBytes(text); 6 byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length); 7 return Convert.ToBase64String(cipherBytes); 8 }
解密方法:
public static string Decrypt(string base64_encodeText, string key, bool keyNeedHash = false) { var rm = CreateAES(key, keyNeedHash); ICryptoTransform transform = rm.CreateDecryptor(); byte[] plainText = Convert.FromBase64String(base64_encodeText); byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length); return Encoding.UTF8.GetString(cipherBytes); }
以上是新整理的笔记。
以下是之前的笔记,做个对比。
/// AES加密解密方式
/// ECB模式不许偏移量iv
/// 提供输出base64和Hex 16进制格式
1 public class AES_Cipher 2 { 3 /// <summary> 4 /// AES 算法加密(ECB模式) 将明文加密,加密后进行Hex编码,返回密文 5 /// </summary> 6 /// <param name="str">明文</param> 7 /// <param name="key">密钥</param> 8 /// <returns>加密后Hex编码的密文</returns> 9 public static string AesEncryptor_ECB_Hex(string str, string key) 10 { 11 if (string.IsNullOrEmpty(str)) return null; 12 Byte[] toEncryptArray = Encoding.UTF8.GetBytes(str); 13 14 RijndaelManaged rm = new RijndaelManaged 15 { 16 //Key = StrToHexByte(key), //把key转成16进制 17 Key = Encoding.UTF8.GetBytes(key), 18 Mode = CipherMode.ECB, 19 Padding = PaddingMode.PKCS7 20 }; 21 22 ICryptoTransform cTransform = rm.CreateEncryptor(); 23 Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 24 25 return ToHexString(resultArray); 26 } 27 28 29 /// <summary> 30 ///AES 算法解密(ECB模式) 将密文Hex解码后进行解密,返回明文 31 /// </summary> 32 /// <param name="str">密文</param> 33 /// <param name="key">密钥</param> 34 /// <returns>明文</returns> 35 public static string AesDecryptor_ECB_Hex(string str, string key) 36 { 37 if (string.IsNullOrEmpty(str)) return null; 38 Byte[] toEncryptArray = StrToHexByte(str); 39 40 RijndaelManaged rm = new RijndaelManaged 41 { 42 //Key = StrToHexByte(key), //key16进制解码 43 Key = Encoding.UTF8.GetBytes(key), 44 Mode = CipherMode.ECB, 45 Padding = PaddingMode.PKCS7 46 }; 47 48 ICryptoTransform cTransform = rm.CreateDecryptor(); 49 Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 50 51 return Encoding.UTF8.GetString(resultArray); 52 } 53 54 /// <summary> 55 /// byte数组Hex编码 56 /// </summary> 57 /// <param name="bytes">需要进行编码的byte[]</param> 58 /// <returns></returns> 59 public static string ToHexString(byte[] bytes) 60 { 61 string hexString = string.Empty; 62 if (bytes != null) 63 { 64 StringBuilder strB = new StringBuilder(); 65 for (int i = 0; i < bytes.Length; i++) 66 { 67 strB.Append(bytes[i].ToString("X2")); 68 } 69 hexString = strB.ToString(); 70 } 71 return hexString; 72 } 73 /// <summary> 74 /// 字符串进行Hex解码(Hex.decodeHex()) 75 /// </summary> 76 /// <param name="hexString">需要进行解码的字符串</param> 77 /// <returns></returns> 78 public static byte[] StrToHexByte(string hexString) 79 { 80 hexString = hexString.Replace(" ", ""); 81 if ((hexString.Length % 2) != 0) 82 hexString += " "; 83 byte[] returnBytes = new byte[hexString.Length / 2]; 84 for (int i = 0; i < returnBytes.Length; i++) 85 returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); 86 return returnBytes; 87 } 88 89 90 /// <summary> 91 /// AES 算法加密(ECB模式) 将明文加密,加密后进行Base64编码,返回密文 92 /// </summary> 93 /// <param name="str">明文</param> 94 /// <param name="key">密钥</param> 95 /// <returns>加密后Base64编码的密文</returns> 96 public static string AesEncryptor_ECB_Base64(string str, string key) 97 { 98 if (string.IsNullOrEmpty(str)) return null; 99 Byte[] toEncryptArray = Encoding.UTF8.GetBytes(str); 100 101 RijndaelManaged rm = new RijndaelManaged 102 { 103 //Key = Convert.FromBase64String(key), //如果key是base64编码过的就解码转换,如果按照规范明文和key都应该传入base64 104 Key = Encoding.UTF8.GetBytes(key), 105 Mode = CipherMode.ECB, 106 Padding = PaddingMode.PKCS7 107 }; 108 109 ICryptoTransform cTransform = rm.CreateEncryptor(); 110 Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 111 112 return Convert.ToBase64String(resultArray); 113 } 114 115 /// <summary> 116 ///AES 算法解密(ECB模式) 将密文Base64解码后进行解密,返回明文 117 /// </summary> 118 /// <param name="base64Str">密文(base64编码格式)</param> 119 /// <param name="key">密钥</param> 120 /// <returns>明文</returns> 121 public static string AesDecryptor_ECB_Base64(string base64Str, string key) 122 { 123 if (string.IsNullOrEmpty(base64Str)) return null; 124 Byte[] toEncryptArray = Convert.FromBase64String(base64Str); 125 126 RijndaelManaged rm = new RijndaelManaged 127 { 128 //Key = Convert.FromBase64String(key), //如果key是base64编码过的就解码转换,如果按照规范密文和key都应该传入base64 129 Key = Encoding.UTF8.GetBytes(key), 130 Mode = CipherMode.ECB, 131 Padding = PaddingMode.PKCS7 132 }; 133 134 ICryptoTransform cTransform = rm.CreateDecryptor(); 135 Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 136 137 return Encoding.UTF8.GetString(resultArray); 138 }
微信敏感数据解密
1 /// <summary> 2 /// 微信敏感数据解密 3 /// </summary> 4 /// <param name="encryptedData">密文</param> 5 /// <param name="iv">加密算法的初始向量</param> 6 /// <param name="sessionKey">登录获取的session_key</param> 7 /// <returns></returns> 8 public static string AESDecrypt(string encryptedData, string iv, string sessionKey) 9 { 10 var encryptedDataByte = Convert.FromBase64String(encryptedData); 11 var rijndaelCipher = new RijndaelManaged 12 { 13 Key = Convert.FromBase64String(sessionKey), 14 IV = Convert.FromBase64String(iv), 15 Mode = CipherMode.CBC, 16 Padding = PaddingMode.PKCS7 17 }; 18 19 var transform = rijndaelCipher.CreateDecryptor(); 20 var plainText = transform.TransformFinalBlock(encryptedDataByte, 0, encryptedDataByte.Length); 21 var result = Encoding.UTF8.GetString(plainText); 22 return result; 23 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构