微信小程式開放資料解密 AES-128-CBC 解密(C#版本)
阿新 • • 發佈:2018-11-03
最近朋友在弄微信小程式開發,需要跟微信服務端互動,微信敏感資料都有加密返回,需要在服務端接收進行解密後再返回給客戶端小程式,今天就通過C# 進行資料的解密,以下展示是C# 程式碼
如果你使用的Java,請訪問這個地址(Java版本) https://blog.csdn.net/jasonsong2008/article/details/83588666
我們先來看一下微信官方的說明文件,以下直接文件來自微信小程式官方:
加密資料解密演算法
介面如果涉及敏感資料(如wx.getUserInfo
當中的 openId 和 unionId),介面的明文內容將不包含這些敏感資料。開發者如需要獲取敏感資料,需要對介面返回的加密資料(encryptedData)
- 對稱解密使用的演算法為 AES-128-CBC,資料採用PKCS#7填充。
- 對稱解密的目標密文為 Base64_Decode(encryptedData)。
- 對稱解密祕鑰 aeskey = Base64_Decode(session_key), aeskey 是16位元組。
- 對稱解密演算法初始向量 為Base64_Decode(iv),其中iv由資料介面返回。
通過微信文件的說明編寫了如下解密方法供大家使用
/// <summary> /// AES加解密(C#版本) /// Add by 成長的小豬(Jason.Song) on 2018/10/26 /// http://blog.csdn.net/jasonsong2008 /// /// AES,高階加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael加密法, /// 是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。 /// 嚴格地說,AES和Rijndael加密法並不完全一樣(雖然在實際應用中二者可以互換), /// 因為Rijndael加密法可以支援更大範圍的區塊和金鑰長度:AES的區塊長度固定為128 位元, /// 金鑰長度則可以是128,192或256位元;而Rijndael使用的金鑰和區塊長度可以是32位的整數倍, /// 以128位為下限,256位元為上限。包括AES-ECB,AES-CBC,AES-CTR,AES-OFB,AES-CFB /// </summary> public class AesHelper { #region 微信小程式 開放資料解密 /// <summary> /// 微信小程式 開放資料解密 /// AES解密(Base64) /// Add by 成長的小豬(Jason.Song) on 2018/10/26 /// </summary> /// <param name="encryptedData">已加密的資料</param> /// <param name="sessionKey">解密金鑰</param> /// <param name="iv">IV偏移量</param> /// <returns></returns> public static string DecryptForWeChatApplet(string encryptedData, string sessionKey, string iv) { var decryptBytes = Convert.FromBase64String(encryptedData); var keyBytes = Convert.FromBase64String(sessionKey); var ivBytes = Convert.FromBase64String(iv); var outputBytes = DecryptByAesBytes(decryptBytes, keyBytes, ivBytes); return Encoding.UTF8.GetString(outputBytes); } #endregion #region AES加密 /// <summary> /// AES加密 /// Add by 成長的小豬(Jason.Song) on 2018/10/26 /// </summary> /// <param name="encryptedBytes">待加密的位元組陣列</param> /// <param name="keyBytes">加密金鑰位元組陣列</param> /// <param name="ivBytes">IV初始化向量位元組陣列</param> /// <param name="cipher">運算模式</param> /// <param name="padding">填充模式</param> /// <returns></returns> public static byte[] EncryptToAesBytes(byte[] encryptedBytes, byte[] keyBytes, byte[] ivBytes, CipherMode cipher = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7) { if (encryptedBytes == null || encryptedBytes.Length <= 0) throw new ArgumentNullException(nameof(encryptedBytes)); if (keyBytes == null || keyBytes.Length <= 0) throw new ArgumentNullException(nameof(keyBytes)); if (ivBytes == null || ivBytes.Length <= 0) throw new ArgumentNullException(nameof(ivBytes)); var des = new AesCryptoServiceProvider { Key = keyBytes, IV = ivBytes, Mode = cipher, Padding = padding }; var outputBytes = des.CreateEncryptor().TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); return outputBytes; } #endregion #region AES解密 /// <summary> /// AES解密 /// Add by 成長的小豬(Jason.Song) on 2018/10/26 /// </summary> /// <param name="decryptedBytes">待解密的位元組陣列</param> /// <param name="keyBytes">解密金鑰位元組陣列</param> /// <param name="ivBytes">IV初始化向量位元組陣列</param> /// <param name="cipher">運算模式</param> /// <param name="padding">填充模式</param> /// <returns></returns> public static byte[] DecryptByAesBytes(byte[] decryptedBytes, byte[] keyBytes, byte[] ivBytes, CipherMode cipher = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7) { if (decryptedBytes == null || decryptedBytes.Length <= 0) throw new ArgumentNullException(nameof(decryptedBytes)); if (keyBytes == null || keyBytes.Length <= 0) throw new ArgumentNullException(nameof(keyBytes)); if (ivBytes == null || ivBytes.Length <= 0) throw new ArgumentNullException(nameof(ivBytes)); var aes = new AesCryptoServiceProvider { Key = keyBytes, IV = ivBytes, Mode = cipher, Padding = padding }; var outputBytes = aes.CreateDecryptor().TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length); return outputBytes; } #endregion }
下面是通過以上解密方法進行測試,大家根據自己的情況進行相應呼叫即可
/// <summary> /// 文章來源於成長的小豬 /// http://blog.csdn.net/jasonsong2008 /// </summary> [TestFixture()] public class AesHelperTests { /// <summary> /// 微信小程式 開放資料校驗與解密 加密資料解密演算法 /// Add by 成長的小豬(Jason.Song) on 2018/10/26 /// </summary> [Test()] public void DecryptForWeChatAppletTest() { //微信小程式返回的加密資料 const string encryptedData = "tsyLVebikY1aLQ0aNpg10NHxCTV2Ar+FJHUZdwIchBXFbJU7hXyf5gbDibaLU+lT6bzzut/nVymRFp/U8MrF0c8yOCFbnK5aevyearR7vopeel2y929weVA/s16shDPnRMkIn9xiMfVY3LDmuptnBpy1loZfSW2CPfXFuKXQf2z+Kiruynve1cq2mnzAadNaw3/g/tjHRPzxBnTkMsu8sQ=="; //會話金鑰 const string sessionKey = "vBwBswWRVmD0WQvRbdbMZg=="; //解密演算法初始向量 const string iv = "8IzE0WUF0j5hXy4oIKuLHA=="; var result = AesHelper.DecryptForWeChatApplet(encryptedData, sessionKey, iv); Console.Write(result); } }