使用RSA演算法實現對資料的加解密
阿新 • • 發佈:2019-02-07
在我們現實當中經常會存在需要對某些資料進行加密保護 然後進行解密的操作,比方,我們需要對某些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 裡面如何實現該演算法.
將資料流連結到加密轉換的流CryptoStream類:
程式集: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());
}
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());
}