1. 程式人生 > >使用RSA演算法實現對資料的加解密

使用RSA演算法實現對資料的加解密

在我們現實當中經常會存在需要對某些資料進行加密保護 然後進行解密的操作,比方,我們需要對某些XML配置資訊裡面的某些資料進行加密,以防止任何人開啟該XML配置資訊都能正常的看到該配置資訊裡面的內容,從而被人家篡改程式,甚至致使系統崩潰.下面我就談下現在比較常用的RSA演算法以及如何在Visual C#中如何實現.

1.首先介紹下什麼是RSA演算法,讓大家對RSA演算法有個簡要的理解.
   RSA演算法非常簡單,概述如下:
  找兩素數p和q
   取n=p*q  如:n=3*7=21
   取t=(p-1)*(q-1) 如:t = 2*6 = 12
   取任何一個數e,要求滿足e 
  取d*e%t==1  如:d=7,e=7,則7*7/12剛好等於1滿足要求

  這樣最終得到三個數: n d e,即 n=21,d=7,e=7
  設訊息為數M 
  設c=(M**d)%n就得到了加密後的訊息c
  設m=(c**e)%n則 m == M,從而完成對c的解密。
  注:**表示次方,上面兩式中的d和e可以互換。

  在對稱加密中:
  n d兩個數構成公鑰,可以告訴別人;
  n e兩個數構成私鑰,e自己保留,不讓任何人知道。
  給別人傳送的資訊使用e加密,只要別人能用d解開就證明資訊是由你傳送的,構成了簽名機制。
  別人給你傳送資訊時使用d加密,這樣只有擁有e的你能夠對其解密。
  rsa的安全性在於對於一個大數n,沒有有效的方法能夠將其分解從而在已知n d的情況無法獲得e;同樣在已知n e的情況下無法求得d。


2.上面就是對RSA演算法的一個簡要概括,該描述在很多書本上都有介紹,這裡也就不做過多解釋了,下面我們看下在.net 裡面如何實現該演算法.

   在.net 裡面,有一個叫RSACryptoServiceProvider的類,在MSDN中,我們可以瞭解到該類使用加密服務提供程式 (CSP) 提供的rsa演算法的實現,執行不對稱加密和解密,從繼承關係上我們瞭解到該類繼承自RSA類.通過該類,我們可以匯出加密解密所需要的XML資訊,並且能夠根據我們提供的XML資訊進行加密解密計算,下面是對該類的一些具體操作,主要包括如何匯出金鑰,如何用形成的金鑰進行加密和解密,完成我們一般的操作.

對字串進行加解密:

using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Text;
using System.Security.Cryptography;

public class RSACSPSample : MonoBehaviour {

	// Use this for initialization
	void Start () {
		Decrypt ();
	}
	
	// Update is called once per frame
	void Update () {
	
	}

	void Decrypt()
	{
		try
		{
			//Create a UnicodeEncoder to convert between byte array and string.
			ASCIIEncoding ByteConverter = new ASCIIEncoding();

			string dataString = "Data to Encrypt";

			//Create byte arrays to hold original, encrypted, and decrypted data.
			byte[] dataToEncrypt = ByteConverter.GetBytes(dataString);
			byte[] encryptedData;
			byte[] decryptedData;

			//Create a new instance of the RSACryptoServiceProvider class 
			// and automatically create a new key-pair.
			RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();

			//Display the origianl data to the console.
			Debug.LogFormat("Original Data: {0}", dataString);

			//Encrypt the byte array and specify no OAEP padding.  
			//OAEP padding is only available on Microsoft Windows XP or
			//later.  
			encryptedData = RSAalg.Encrypt(dataToEncrypt, false);

			//Display the encrypted data to the console. 
			Debug.LogFormat("Encrypted Data: {0}", ByteConverter.GetString(encryptedData));

			//Pass the data to ENCRYPT and boolean flag specifying 
			//no OAEP padding.
			decryptedData = RSAalg.Decrypt(encryptedData, false);

			//Display the decrypted plaintext to the console. 
			Debug.LogFormat("Decrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
		}

		catch(CryptographicException e)
		{
			//Catch this exception in case the encryption did
			//not succeed.
			Debug.LogFormat(e.Message);
		}
	}
}

將資料流連結到加密轉換的流CryptoStream類:
using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Security.Cryptography;

public class RijndaelExample : MonoBehaviour {

	// Use this for initialization
	void Start () {
		EncryptAndDecrypt ();
	}
	
	// Update is called once per frame
	void Update () {
	
	}

	void EncryptAndDecrypt()         // 加密、解密
	{
		try
		{
			string original = "Here is some data to encrypt !";

			// Create a new instance of the Rijndael
			// class.  This generates a new key and initialization 
			// vector (IV).
			using (Rijndael myRijndael = Rijndael.Create())
			{
				// Encrypt the string to an array of bytes.
				byte[] encrypted = EncryptStringToBytes(original, myRijndael.Key, myRijndael.IV);

				// Decrypt the bytes to a string.
				string roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);

				//Display the original data and the decrypted data.
				Debug.LogFormat("Original:   {0}", original);
				Debug.LogFormat("Round Trip: {0}", roundtrip);
			}
		}
		catch (Exception e)
		{
			Debug.LogFormat("Error: {0}", e.Message);
		}
	}

	static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] IV)         // 將字串加密成位元組
	{
		// Check arguments.
		if (plainText == null || plainText.Length <= 0)
		{
			throw new ArgumentNullException ("plainText");
		}
		if (key==null || key.Length<=0)
		{
			throw new ArgumentNullException ("Key");
		}
		if (IV==null || IV.Length<=0)
		{
			throw new ArgumentNullException ("IV");
		}
		byte[] encrypted;
		// Create an Rijndael object
		// with the specified key and IV.
		using (Rijndael rijAlg = Rijndael.Create ()) 
		{
			rijAlg.Key = key;
			rijAlg.IV = IV;

			// Create an encryptor to perform the stream transform.
			ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

			// create the stream used for encryption
			using (MemoryStream msEncrypt = new MemoryStream ())
			{
				using (CryptoStream csEncrypt = new CryptoStream (msEncrypt, encryptor, CryptoStreamMode.Write))
				{
					using (StreamWriter swEncrypt = new StreamWriter (csEncrypt))
					{
						// Write all data to the stream
						swEncrypt.Write(plainText);
					}
					encrypted = msEncrypt.ToArray ();
				}
			}
			// Return the encrypted bytes from the memory stream.
			return encrypted;
		}
	}

	static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)     // 將位元組解密成字串
	{
		// Check arguments.
		if (cipherText == null || cipherText.Length <= 0)
			throw new ArgumentNullException("cipherText");
		if (Key == null || Key.Length <= 0)
			throw new ArgumentNullException("Key");
		if (IV == null || IV.Length <= 0)
			throw new ArgumentNullException("IV");

		// Declare the string used to hold
		// the decrypted text.
		string plaintext = null;

		// Create an Rijndael object
		// with the specified key and IV.
		using (Rijndael rijAlg = Rijndael.Create())
		{
			rijAlg.Key = Key;
			rijAlg.IV = IV;

			// Create a decryptor to perform the stream transform.
			ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

			// Create the streams used for decryption.
			using (MemoryStream msDecrypt = new MemoryStream(cipherText))
			{
				using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
				{
					using (StreamReader srDecrypt = new StreamReader(csDecrypt))
					{

						// Read the decrypted bytes from the decrypting stream
						// and place them in a string.
						plaintext = srDecrypt.ReadToEnd();
					}
				}
			}

		}
		return plaintext;

	}

}


將資料流連結到加密轉換的流 CryptoStream類

1.名稱空間:System.Security.Cryptography
程式集:mscorlib(在 mscorlib.dll 中)

----------------------------------------------------
繼承層次結構
-System.Object
----- System.MarshalByRefObject
--------- System.IO.Stream
-------------System.Security.Cryptography.CryptoStream 2.-------------------------------
        公共語言執行庫使用面向流的設計進行加密。該設計的核心是 CryptoStream。實現 CryptoStream 的任何加密物件可以和實現 Stream 的任 何物件連結起來,因此一個物件的流式處理輸出可以饋送到另一個物件的輸入。不需要分別儲存中間結果(第一個物件的輸出)。
        通過呼叫 Close 方法完成 CryptoStream 物件的使用後,始終應該顯式關閉該物件。這會重新整理流並使所有剩餘的資料塊都被 CryptoStream 物件處理。但是,如果在呼叫 Close 方法前發生了異常,CryptoStream 物件可能會關閉。為確保 Close 方法始終被呼叫,請在 try/catch 語句的 finally 塊中放置 Close 方法呼叫。 用目標資料流、要使用的轉換和流的模式初始化 CryptoStream 類的新例項。 public CryptoStream (Stream stream,ICryptoTransform transform,
CryptoStreamMode mode) 引數: stream-- 對其執行加密轉換的流。 transform-- 要對流執行的加密轉換。 mode--CryptoStreamMode 值之一。  任何從 Stream 匯出的物件都可以傳入 stream 引數。任何實現 ICryptoTransform(例如 HashAlgorithm)的物件都可以傳入transform 引數。 3.CryptoStream.Write 方法 
--------------------------------------
將一個位元組序列寫入當前 CryptoStream,並將流中的當前位置提升寫入的位元組數。
public override void Write (byte[ ] buffer, int offset, int count)
引數
buffer: 位元組陣列。此方法將 count 個位元組從 buffer 複製到當前流。
offset:buffer 中的位元組偏移量,從此偏移量開始將位元組複製到當前流。
count:要寫入當前流的位元組數。 4.CryptoStream.FlushFinalBlock 方法 
----------------------------------------------------
用緩衝區的當前狀態更新基礎資料來源或儲存庫,隨後清除緩衝區。
public void FlushFinalBlock () 5.--------------------------------
如:
   private string DecryptString(string Value)
  {
        ICryptoTransform transform1=this.mCSP.CreateDecrytor(this.mCSP.Key,this.mCSP.IV);
       byte [ ] buffer1=Convert.FromBase64String(Value);
       MemoryStream stream1=new MemoryStream();
       CryptoStream  stream2=new CryptoStream(stream1,transform1,CrytoStreamMode.Write);
      stream2.Write(buffer1,0,buffer1.Length);
      stream2.FlushFinalBlock();
      stream2.Close();
      return Encoding.UTF8.GetString(stream1.ToArray());
  }