先來複習一下~在產出Message前我們會需要什麼東西呢?
按照慣例,一樣先上圖:
重點來了!我們今天會利用AES-CBC
的方式,來加密產生訊息內文,然後官方文件有提到:
加密後的 Byte 以十六進制2位數字串相加
高階加密標準(Advanced Encryption Standard)是一種常見的對稱加密演算法(加密傳輸,能用於保護電子數據)。
也就是說,在加密
和解密
數據時都是使用相同的金鑰。而在 AES 中,可以使用128、192 和256 位密鑰,並且用128 位(16字節)來分組加密和解密數據。
AES加密算法的詳細介紹與實現
通過分組密碼返回的加密數據的位數與輸入數據相同。迭代加密使用一個循環結構,在該循環中重複置換(permutations )和替換(substitutions)輸入數據。
有興趣的同學們,可以去參考 AES加密算法的實現原理
來個小插曲,到目前為止都還沒有正式到C#處理API Request的Model,既然剛好會用到就順便講一下吧~
這邊想推薦一個筆者平常開發C#專案時,很常使用的線上小工具 Convert Json to C# Classes Online
名副其實的,只要把格式正確的JSON文檔丟下去,按下Convert,這個工具就會幫你自動解析成C#的類別(強者其實都會自己寫一個自己的Converter,但我就懶...好孩子別學我)
不過這個Converter只會幫你處理基本的型別,像int
到float
decimal
,或是 string
和 DateTime
還是需要自己手動調整(如果有人哪天做了一個可以靠欄位名稱自動幫你判斷型別的工具,拜託一定要分享給我xd)
取得結果後,貼到自己的程式碼動手稍微改改就好囉:
using System;
namespace Qpay_Core.Models
{
public class OrderingMessageModel
{
public string ShopNo { get; set; }
public string OrderNo { get; set; }
public decimal Amount { get; set; }
public string CurrencyID { get; set; }
public string PayType { get; set; }
public ATMParam ATMParam { get; set; }
public CardParam CardParam { get; set; }
public ConvStoreParam ConvStoreParam { get; set; }
public string PrdtName { get; set; }
public string ReturnURL { get; set; }
//http://10.11.22.113:8803/QPay.ApiClient/Store/Return
public string BackendURL { get; set; }
//http://10.11.22.113:8803/QPay.ApiClient/AutoPush/PushSuccess
}
public class ATMParam
{
public string ExpireDate { get; set; } //應該能改用DateTime
}
public class CardParam
{
//待續
}
public class ConvStoreParam
{
//待續
}
}
礙於篇幅的關係,今天先不負責任地找了網路上的sample code來實踐CBC模式的AEC加密
AES加密CBC模式相容互通四種程式語言平臺【PHP、Javascript、Java、C#】
這位大大用心提供了四種語言,讓我們來看一下C#的部分:
public static string Encrypt(string toEncrypt, string key, string iv)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.IV = ivArray;
rDel.Mode = CipherMode.CBC;
rDel.Padding = PaddingMode.Zeros;
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string Decrypt(string toDecrypt, string key, string iv)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.IV = ivArray;
rDel.Mode = CipherMode.CBC;
rDel.Padding = PaddingMode.Zeros;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
(2021-09-23補充)
其實上面網友提供的RijndaelManaged
算是年代比較久遠的類別了(AES就是利用Rijndael演算法啦xd)
可以去參考 C# 的 Rijndael、AES、AesManaged、AesCryptoServiceProvider類整理分析
從.NET 3.5開始,就有推出了AES
抽象類別,基於一些實作上的細節差異,現在微軟MSDN其實是比較推薦使用基於AES
抽象基底類別實作的AesManaged
或**AesCryptoServiceProvider**
(較優),永豐銀行提供的samplecode也是這麼做的當初為何不先去好好參考他們的程式碼還要自己亂搞阿
這次的鐵人賽的其中一項目標是希望能把這些方法封裝成完整的.Net Core微服務,前幾天的內容因為很簡單就先暫且略過不提,不過像這次的AES-CBC加解密,以及先前提過的SHA256,其實都能將這些方法變成共用的Helper(Common)類別函式庫
至於要怎麼讓代碼看起來更簡潔也更易讀,之後也會從 .Net Core架構 概念開始,再慢慢帶到實作部分
今天講了不少內容,先喘喘口氣好了(汗
明天見,See you!