而小弟最近剛好也類似情境的案例,將序列化加解密的技術整理整理分享給大家。其中加密的方法是使用 .NET提供了 RSACryptoServiceProvider 類別,做簡單的加解密動作。
首先我們先準備一個準備被序列化的 Person Class ,Person 內涵 firstName、MiddleName、LastName 三個屬性。其程式碼如下:
[Serializable] public class Person { public string FirstName { get; set; } public string MiddleName{ get; set; } public string LastName { get; set; } public Person(string first, string middle, string last) { this.FirstName = first; this.MiddleName = middle; this.LastName = last; } public override string ToString() { return "Person:" + FirstName + "," + MiddleName + "," + LastName; } }
其中 Class 上方要 [Serializable] 的 tag ,註明此 Class 的 Object 可以被序列化。否則在序列化過程會有 Exception 出現。
接著我們進入序列化加密的主題。流程為先將 Person Object 序列化成 Byte[],接著對 Byte[] 做 RSA 加密動作,己完成動作。
///EncryptObject 這個 Mehtod 傳入欲加密的 Object 以及 RSACryptoServiceProvider 生出的 public Key String,就會回傳加密的 byte[]。/// Object 序列化後 做 RSA 加密 /// /// 欲加密的Object /// RSA public key ///public static byte[] EncryptObject(object OriginalObject, string clientPubkey) { using (MemoryStream memory = new MemoryStream()) { //物件轉為Byte[] IFormatter formatter = new BinaryFormatter(); formatter.Serialize(memory, OriginalObject); memory.Seek(0, SeekOrigin.Begin); var encrypt = RSAEncrypt(memory.ToArray(), clientPubkey);//加密 return encrypt; } }
其中 RSAEncrypt 的Method 程式如下:
public static byte[] RSAEncrypt(byte[] DataToEncrypt, string clientPubkey) { try { byte[] encryptedData; using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider()) { RSA.FromXmlString(clientPubkey); ArrayList arrEncrypteToTxt = new ArrayList(); if (DataToEncrypt.Length > 117) { encryptedData = encryptedDataMethod(RSA, DataToEncrypt, arrEncrypteToTxt); } else { encryptedData = RSA.Encrypt(DataToEncrypt, false); } } return encryptedData; } catch (CryptographicException e) { Console.WriteLine(e.Message); return null; } }
RSAEncrypt method 主要為 RSA 加密的動作,但你應該發現這邊加密拆成兩個區塊,主要因為 RSA 加密的 method 有size的限制,若array size超過一定的值,內建的加密程式會產生 Exception,因此我上網找到分段加密的 mehtod encryptedDataMethod,可以解決 size太大的問題。
/// RSA分段加密 /// /// RSA物件 /// 要加密的位元組 /// 存放每組加密後的字串陣列 ///組合後加密後的位元組 private static byte[] encryptedDataMethod(RSACryptoServiceProvider rsa, byte[] orgData, ArrayList arrEncrypteToTxt) { //先宣告要回傳的位元組,預設值null byte[] encryptedData = null; try { //加密後位元組再轉成64位數編碼的字串 string strEncrypteToTxt = ""; //暫存要加密的位元組容器 byte[] temp = null; //加密後的位元組 byte[] tempEncrypedData = null; //若傳進來的資料位元組長度大於117 if (orgData.Length > 117) { //temp先預設長度為117 temp = new byte[117]; //再把傳進來的位元組從0-117跑迴圈,一個一個賦予temp每個位元值 for (int i = 0; i < 117; i++) { temp[i] = orgData[i]; } } else { //若傳進來的資料位元組長度介於117之內,則直接指派給temp temp = orgData; } //執行加密 tempEncrypedData = rsa.Encrypt(temp, false); //將加密後的位元組再轉成64編碼的字串 strEncrypteToTxt = Convert.ToBase64String(tempEncrypedData); //將64編碼的字串add到陣列 arrEncrypteToTxt.Add(strEncrypteToTxt); //再判斷一次,若傳進來的資料位元組長度 > 117 if (orgData.Length > 117) { int j = 0; //宣告新的資料位元組長度=傳進來的資料位元長度 - 117 byte[] again = new byte[orgData.Length - 117]; //傳進來的資料位元長度,跑迴圈,從117位址開始,一個一個賦予again每個位元值 for (int i = 117; i < orgData.Length; i++) { again[j] = orgData[i]; j++; } //遞迴呼叫,把rsa參數,新的資料位元組參數,存放每組資料的陣列當參數傳遞 return encryptedDataMethod(rsa, again, arrEncrypteToTxt); } else { //若傳進來的資料位元組 < 117,表示資料已經可以不用分段 //此時傳進來的存放每組資料的陣列計算個數,再乘以128 (因一次加密最多只接受128位元組) encryptedData = new byte[arrEncrypteToTxt.Count * 128]; //宣告加密位元組,預設null Byte[] btFromBase64 = null; int k = 0; //跑陣列回圈,每個陣列位元存放每個分段加密後的64編碼字串 foreach (string strArr in arrEncrypteToTxt) { //再把字串從64位元編碼轉換為8位元的位元組 btFromBase64 = Convert.FromBase64String(strArr); //將位元組資料複製到目的地位元組陣列encryptedData,並指定從目的地陣列k*128的位置貼上 btFromBase64.CopyTo(encryptedData, k * 128); k++; } } } catch (Exception ex) { throw new Exception(ex.Message); } //最後回傳分段加密資料的位元組 return encryptedData; //The End }
這樣我們就可以完整的將任何的 Object 順利序列化機加了。
沒有留言:
張貼留言