NET將原來獨立的API和SDK合並到一個框架中這對於程序開發人員非常有利它將CryptoAPI改編進NET的SystemSecurityCryptography名字空間使密碼服務擺脫了SDK平台的神秘性變成了簡單的NET名字空間的使用由於隨著整個框架組件一起共享密碼服務更容易實現了現在僅僅需要學習SystemSecurityCryptography名字空間的功能和用於解決特定方案的類
加密和解密的算法
SystemSecurityCryptography名字空間包含了實現安全方案的類例如加密和解密數據管理密鑰驗證數據的完整性並確保數據沒有被篡改等等本文重點討論加密和解密
加密和解密的算法分為對稱(symmetric)算法和不對稱(asymmetric)算法對稱算法在加密和解密數據時使用相同的密鑰和初始化矢量典型的有DES TripleDES和Rijndael算法它適用於不需要傳遞密鑰的情況主要用於本地文檔或數據的加密不對稱算法有兩個不同的密鑰分別是公共密鑰和私有密鑰公共密鑰在網絡中傳遞用於加密數據而私有密鑰用於解密數據不對稱算法主要有RSADSA等主要用於網絡數據的加密
加密和解密本地文檔
下面的例子是加密和解密本地文本使用的是Rijndael對稱算法
對稱算法在數據流通過時對它進行加密因此首先需要建立一個正常的流(例如I/O流)文章使用FileStream類將文本文件讀入字節數組也使用該類作為輸出機制
接下來定義相應的對象變量在定義SymmetricAlgorithm抽象類的對象變量時我們可以指定任何一種對稱加密算法提供程序代碼使用的是Rijndael算法但是很容易改為DES或者TripleDES算法NET使用強大的隨機密鑰設置了提供程序的實例選擇自己的密鑰是比較危險的接受計算機產生的密鑰是一個更好的選擇文中的代碼使用的是計算機產生的密鑰
下一步算法實例提供了一個對象來執行實際數據傳輸每種算法都有CreateEncryptor和CreateDecryptor兩個方法它們返回實現ICryptoTransform接口的對象
最後現在使用BinaryReader的ReadBytes方法讀取源文件它會返回一個字節數組BinaryReader讀取源文件的輸入流在作為CryptoStreamWrite方法的參數時調用ReadBytes方法指定的CryptoStream實例被告知它應該操作的下層流該對象將執行數據傳遞無論流的目的是讀或者寫
下面是加密和解密一個文本文件的源程序片斷
namespace combilldawsoncrypto
{
class TextFileCrypt
{
public static void Main(string[] args)
{
string file = args[];
string tempfile = PathGetTempFileName();
//打開指定的文件
FileStream fsIn = FileOpen(fileFileModeOpen
FileAccessRead);
FileStream fsOut = FileOpen(tempfile FileModeOpen
FileAccessWrite);
//定義對稱算法對象實例和接口
SymmetricAlgorithm symm = new RijndaelManaged();
ICryptoTransform transform = symmCreateEncryptor();
CryptoStream cstream = new CryptoStream(fsOuttransform
ryptoStreamModeWrite);
BinaryReader br = new BinaryReader(fsIn);
// 讀取源文件到cryptostream
cstreamWrite(brReadBytes((int)fsInLength)(int)fsInLength);
cstreamFlushFinalBlock();
cstreamClose();
fsInClose();
fsOutClose();
ConsoleWriteLine(created encrypted file {} tempfile);
ConsoleWriteLine(will now decrypt and show contents);
// 反向操作解密剛才加密的臨時文件
fsIn = FileOpen(tempfileFileModeOpenFileAccessRead);
transform = symmCreateDecryptor();
cstream = new CryptoStream(fsIntransform
CryptoStreamModeRead);
StreamReader sr = new StreamReader(cstream);
ConsoleWriteLine(decrypted file text: + srReadToEnd());
fsInClose();
}
}
}
加密網絡數據
如果我有一個只想自己看到的文檔我不會簡單的通過email發送給你我將使用對稱算法加密它如果有人截取了它他們也不能閱讀該文檔因為他們沒有用於加密的唯一密鑰但是你也沒有密鑰我需要使用某種方式將密鑰給你這樣你才能解密文檔但是不能冒密鑰和文檔被截取的風險
非對稱算法就是一種解決方案這類算法使用的兩個密鑰有如下關系使用公共密鑰加密的信息只能被相應的私有密鑰解密因此我首要求你給我發送你的公共密鑰在發送給我的途中可能有人會截取它但是沒有關系因為他們只能使用該密鑰給你的信息加密我使用你的公共密鑰加密文檔並發送給你你使用私有密鑰解密該文檔這是唯一可以解密的密鑰並且沒有通過網絡傳遞
不對稱算法比對稱算法計算的花費多速度慢因此我們不希望在線對話中使用不對稱算法加密所有信息相反我們使用對稱算法下面的例子中我們使用不對稱加密來加密對稱密鑰接著就使用對稱算法加密了實際上安全接口層(SSL)建立服務器和浏覽器之間的安全對話使用的就是這種工作方式
示例是一個TCP程序分為服務器端和客戶端服務器端的工作流程是
從客戶端接收公共密鑰
使用公共密鑰加密未來使用的對稱密鑰
將加密了的對稱密鑰發送給客戶端
給客戶端發送使用該對稱密鑰加密的信息
代碼如下
namespace combilldawsoncrypto
{
public class CryptoServer
{
private const int RSA_KEY_SIZE_BITS = ;
private const int RSA_KEY_SIZE_BYTES = ;
private const int TDES_KEY_SIZE_BITS = ;
public static void Main(string[] args)
{
int port;
string msg;
TcpListener listener;
TcpClient client;
SymmetricAlgorithm symm;
RSACryptoServiceProvider rsa;
//獲取端口
try
{
port = IntParse(args[]);
msg = args[];
}
catch
{
ConsoleWriteLine(USAGE);
return;
}
//建立監聽
try
{
listener = new TcpListener(port);
listenerStart();
ConsoleWriteLine(Listening on port {}port);
client = listenerAcceptTcpClient();
ConsoleWriteLine(connection);
}
catch (Exception e)
{
ConsoleWriteLine(eMessage);
ConsoleWriteLine(eStackTrace);
return;
}
try
{
rsa = new RSACryptoServiceProvider();
rsaKeySize = RSA_KEY_SIZE_BITS;
// 獲取客戶端公共密鑰
rsaImportParameters(getClientPublicKey(client));
symm = new TripleDESCryptoServiceProvider();
symmKeySize = TDES_KEY_SIZE_BITS;
//使用客戶端的公共密鑰加密對稱密鑰並發送給客
encryptAndSendSymmetricKey(client rsa symm);
//使用對稱密鑰加密信息並發送
encryptAndSendSecretMessage(client symm msg);
}
catch (Exception e)
{
ConsoleWriteLine(eMessage);
ConsoleWriteLine(eStackTrace);
}
finally
{
try
{
clientClose();
listenerStop();
}
catch
{
//錯誤
}
ConsoleWriteLine(Server exiting);
}
}
private static RSAParameters getClientPublicKey(TcpClient client)
{
// 從字節流獲取串行化的公共密鑰通過串並轉換寫入類的實例
byte[] buffer = new byte[RSA_KEY_SIZE_BYTES];
NetworkStream ns = clientGetStream();
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
RSAParameters result;
int len = ;
int totalLen = ;
while(totalLen (len = nsRead(bufferbufferLength))>)
{
totalLen+=len;
msWrite(buffer len);
}
msPosition=;
result = (RSAParameters)bfDeserialize(ms);
msClose();
return result;
}
private static void encryptAndSendSymmetricKey(
TcpClient client
RSACryptoServiceProvider rsa
SymmetricAlgorithm symm)
{
// 使用客戶端的公共密鑰加密對稱密鑰
byte[] symKeyEncrypted;
byte[] symIVEncrypted;
NetworkStream ns = clientGetStream();
symKeyEncrypted = rsaEncrypt(symmKey false);
symIVEncrypted = rsaEncrypt(symmIV false);
nsWrite(symKeyEncrypted symKeyEncryptedLength);
nsWrite(symIVEncrypted symIVEncryptedLength);
}
private static void encryptAndSendSecretMessage(TcpClient client
SymmetricAlgorithm symm
string secretMsg)
{
// 使用對稱密鑰和初始化矢量加密信息並發送給客戶端
byte[] msgAsBytes;
NetworkStream ns = clientGetStream();
ICryptoTransform transform =
symmCreateEncryptor(symmKeysymmIV);
CryptoStream cstream =
new CryptoStream(ns transform CryptoStreamModeWrite);
msgAsBytes = EncodingASCIIGetBytes(secretMsg);
cstreamWrite(msgAsBytes msgAsBytesLength);
cstreamFlushFinalBlock();
}
}
客戶端的工作流程是
建立和發送公共密鑰給服務器
從服務器接收被加密的對稱密鑰
解密該對稱密鑰並將它作為私有的不對稱密鑰
接收並使用不對稱密鑰解密信息
代碼如下
namespace combilldawsoncrypto
{
public class CryptoClient
{
private const int RSA_KEY_SIZE_BITS = ;
private const int RSA_KEY_SIZE_BYTES = ;
private const int TDES_KEY_SIZE_BITS = ;
private const int TDES_KEY_SIZE_BYTES = ;
private const int TDES_IV_SIZE_BYTES = ;
public static void Main(string[] args)
{
int port;
string host;
TcpClient client;
SymmetricAlgorithm symm;
RSACryptoServiceProvider rsa;
if (argsLength!=)
{
ConsoleWriteLine(USAGE);
return;
}
try
{
host = args[];
port = IntParse(args[]);
}
catch
{
ConsoleWriteLine(USAGE);
return;
}
try //連接
{
client = new TcpClient();
clientConnect(hostport);
}
catch(Exception e)
{
ConsoleWriteLine(eMessage);
ConsoleWrite(eStackTrace);
return;
}
try
{
ConsoleWriteLine(Connected Sending public key);
rsa = new RSACryptoServiceProvider();
rsaKeySize = RSA_KEY_SIZE_BITS;
sendPublicKey(rsaExportParameters(false)client);
symm = new TripleDESCryptoServiceProvider();
symmKeySize = TDES_KEY_SIZE_BITS;
MemoryStream ms = getRestOfMessage(client);
extractSymmetricKeyInfo(rsa symm ms);
showSecretMessage(symm ms);
}
catch(Exception e)
{
ConsoleWriteLine(eMessage);
ConsoleWrite(eStackTrace);
}
finally
{
try
{
clientClose();
}
catch { //錯誤
}
}
}
private static void sendPublicKey(
RSAParameters key
TcpClient client)
{
NetworkStream ns = clientGetStream();
BinaryFormatter bf = new BinaryFormatter();
bfSerialize(nskey);
}
private static MemoryStream getRestOfMessage(TcpClient client)
{
//獲取加密的對稱密鑰初始化矢量秘密信息對稱密鑰用公共RSA密鑰
//加密秘密信息用對稱密鑰加密
MemoryStream ms = new MemoryStream();
NetworkStream ns = clientGetStream();
byte[] buffer = new byte[];
int len=;
// 將NetStream 的數據寫入內存流
while((len = nsRead(buffer bufferLength))>)
{
msWrite(buffer len);
}
msPosition = ;
return ms;
}
private static void extractSymmetricKeyInfo(
RSACryptoServiceProvider rsa
SymmetricAlgorithm symm
MemoryStream msOrig)
{
MemoryStream ms = new MemoryStream();
// 獲取TDES密鑰它被公共RSA密鑰加密使用私有密鑰解密
byte[] buffer = new byte[TDES_KEY_SIZE_BYTES];
msOrigRead(bufferbufferLength);
symmKey = rsaDecrypt(bufferfalse);
// 獲取TDES初始化矢量
buffer = new byte[TDES_IV_SIZE_BYTES];
msOrigRead(buffer bufferLength);
symmIV = rsaDecrypt(bufferfalse);
}
private static void showSecretMessage(
SymmetricAlgorithm symm
MemoryStream msOrig)
{
//內存流中的所有數據都被加密了
byte[] buffer = new byte[];
int len = msOrigRead(bufferbufferLength);
MemoryStream ms = new MemoryStream();
ICryptoTransform transform =
symmCreateDecryptor(symmKeysymmIV);
CryptoStream cstream =new CryptoStream(ms transform
CryptoStreamModeWrite);
cstreamWrite(buffer len);
cstreamFlushFinalBlock();
// 內存流現在是解密信息是字節的形式將它轉換為字符串
msPosition = ;
len = msRead(buffer(int) msLength);
msClose();
string msg = EncodingASCIIGetString(bufferlen);
ConsoleWriteLine(The host sent me this secret message:);
ConsoleWriteLine(msg);
}
}
}
結論
使用對稱算法加密本地數據時比較適合在保持代碼通用時我們可以選擇多種算法當數據通過特定的CryptoStream時算法使用轉換對象加密該數據需要將數據通過網絡發送時首先使用接收的公共不對稱密鑰加密對稱密鑰
From:http://tw.wingwit.com/Article/program/net/201311/13834.html