200908081346.NET for C# - RSA分段加解密

當我們用c#的RSACryptoServiceProvider執行非對稱加解密時,有時候會碰到需要加解密物件的長度太長, 此時需要分段加解密,我的做法如下:
先建立空白專案,加入新增項目Windows Form。
(ps.通常加密後的密文與私鑰會另外存在別的地方,以供接收端取得,但這裡不另行論述,只說明如何分段加解密)
使用如下命名空間:
using System;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Collections;
namespace test0730
{
    public partial class Form1 : Form
    {
    public string bobPrivateKey;
    public string bobPublicKey

    private void Form1_Load(object sender, EventArgs e)
    {
// 產生 Bob 的金鑰對。
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
bobPrivateKey = rsa.ToXmlString(true);
bobPublicKey = rsa.ToXmlString(false);
    }
//btnEncrypt按紐執行加密
    private void btnEncrypt_Click(object sender, EventArgs e)
    {
// 建立 RSA 加解密物件。
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
// 匯入公開金鑰(因為要使用接收者的公鑰加密)。
rsa.FromXmlString(bobPublicKey);
// 欲加密的原文。
string orgText = @"Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼
學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, 密碼學!Hello, End";

// *********加密開始*********   
byte[] orgData = Encoding.Default.GetBytes(orgText);
//若byte陣列長度大於117,則採分段式加密 ,rsa.KeySize / 8 - 11 = 117 ;
byte[] encryptedData = null;
ArrayList arrEncrypteToTxt = new ArrayList();
if (orgData.Length > 117)
{
encryptedData = encryptedDataMethod(rsa, orgData, arrEncrypteToTxt);
}
else
{
encryptedData = rsa.Encrypt(orgData, false);
    }
// *********加密結束*********
// *********接下來看加密輸出結果為何*********

// 將加密過的文字顯示於 UI。
txtEncrypted.Text = Convert.ToBase64String(encryptedData);

    }
    ///
    /// RSA分段加密
    ///
    /// RSA物件
    /// 要加密的位元組
    /// 存放每組加密後的字串陣列
    /// 組合後加密後的位元組
    private 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
    }
//按下btnDecrypt按鈕執行解密
    private void btnDecrypt_Click(object sender, EventArgs e)
    {
    //// 建立 RSA 加解密物件。
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
//// 將私密金鑰匯入 RSA 物件。
rsa.FromXmlString(bobPrivateKey);

    // ********解密開始********
//將txtEncrypted.Text字串轉為八位元含正副整數的位元組陣列
byte[] encryptedData = Convert.FromBase64String(txtEncrypted.Text);
//宣告解密結果位元組, 預設為null
byte[] decryptedData = null;
//存放解密後的資料位元組長度
int DecryptedSize = 0;
if (encryptedData.Length > 128)
{
ArrayList arrDecrypteToTxt = new ArrayList();
decryptedData = DecryptedDataMethod(rsa, encryptedData, arrDecrypteToTxt, DecryptedSize);
}
else
    {
    decryptedData = rsa.Decrypt(encryptedData, false);
    }
//********解密結束********

//顯示解密後的資料訊息
    txtDecrypted.Text = Encoding.Default.GetString(decryptedData);
}
/// 
   
    /// <summary>
    /// RSA分段解密
    /// </summary>
    /// <param name="rsa">RSA物件</param>
    /// <param name="orgData">要解密的位元組</param>
    /// <param name="arrDecrypteToTxt">存放每組解密後的字串陣列</param>
    /// <param name="DecryptedSize">存放解密後的位元組資料長度</param>
    /// <returns>組合後解密後的位元組</returns>
    private byte[] DecryptedDataMethod(RSACryptoServiceProvider rsa, byte[] orgData, ArrayList arrDecrypteToTxt, int DecryptedSize)
    {
    byte[] DecryptedData = null;
    try
    {
    //解密後位元組再轉成64位數編碼的字串
    string strDecrypteToTxt = "";
    //暫存要解密的位元組容器
    byte[] temp = null;
    //解密後的位元組
    byte[] tempDecryptedData = null;
    //若要解密的資料位元長度>128
    if (orgData.Length > 128)
    {
    temp = new byte[128];
    //再把傳進來的位元組從0-128跑迴圈,一個一個賦予temp每個位元值
    for (int i = 0; i < 128; i++)
    {
    temp[i] = orgData[i];
    }
    }
    else
    {
    temp = orgData;
    }
    //tempDecryptedData存放解密後的位元組資料
    tempDecryptedData = rsa.Decrypt(temp, false);
    //解密後位元組資料長度
    DecryptedSize += tempDecryptedData.Length;
    //再把tempDecryptedData位元組資料轉成64編碼字串
    strDecrypteToTxt = Convert.ToBase64String(tempDecryptedData);
    //把字串add到陣列裡
    arrDecrypteToTxt.Add(strDecrypteToTxt);

    //再判斷一次傳進來要解密的位元組資料長度
    if (orgData.Length > 128)
    {
    //again存放要解密的位元組資料長度-128
    byte[] again = new byte[orgData.Length - 128];
    int j = 0;
    //傳進來要解密的位元組資料從128位址開始跑迴圈
    for (int i = 128; i < orgData.Length; i++)
    {
    //把傳進來要解密的位元組資料指派給again
    again[j] = orgData[i];
    j++;
    }
    //遞回呼叫DecryptedDataMethod函式,傳入rsa,要再解密位元組資料,存放每組解密資料轉成64編碼的字串陣列
    return DecryptedDataMethod(rsa, again, arrDecrypteToTxt, DecryptedSize);
    }
    else
    {
    //若傳進來要解密的位元組長度小於128,代表不用遞回解密了
    //建立一個新的位元組物件,長度是(存放每組解密資料轉成64編碼的字串陣列的位元數)*117, 117是代表解密出來的位元組長度,是固定的
    //DecryptedData = new byte[arrDecrypteToTxt.Count * 117];
    DecryptedData = new byte[DecryptedSize];
    //宣告解密位元組,預設null
    Byte[] btFromBase64 = null;


    int p = 1;//計算目前位置倍數
    int currentAddr = 0;//目前存放資料的位元位置
    int k = 0;
    double dk = 0;
    dk = Math.Floor((double)(DecryptedSize / 117));//解密後位元組資料長度/117,無條件捨去求整數部分
    k = (int)dk;
    int n = 0;//與k比較用
    //跑陣列回圈,每個陣列位元存放每個分段加密後的64編碼字串
    foreach (string strArr in arrDecrypteToTxt)
    {
    if (n < k)
    {
    //再把字串從64位元編碼轉換為8位元的位元組
    btFromBase64 = Convert.FromBase64String(strArr);
    //將位元組資料複製到目的地位元組陣列eDecryptedData,並指定從目的地陣列n*117的位置貼上
    btFromBase64.CopyTo(DecryptedData, n * 117);
    currentAddr = p * 117;//目前資料已存到的位置
    p++;
    n++;
    }
    else
    {
    //再把字串從64位元編碼轉換為8位元的位元組
    btFromBase64 = Convert.FromBase64String(strArr);
    //將位元組資料複製到目的地位元組陣列eDecryptedData,並指定從目的地陣列currentAddr的位置貼上
    btFromBase64.CopyTo(DecryptedData, currentAddr);
    }

    }
    }

    }
    catch (Exception ex)
    {
    throw new Exception(ex.Message);
    }
    //最後回傳分段加密資料的位元組
    return DecryptedData;
    //The End
    }
    }
}

沒有上一則|日誌首頁|沒有下一則
回應
關鍵字
    沒有新回應!





Powered by Xuite
MoMo&#39;s 小水滴

我的小圈圈