客户端的工作流程是:
建立和发送公共密钥给服务器。
从服务器接收被加密的对称密钥。
解密该对称密钥并将它作为私有的不对称密钥。
接收并使用不对称密钥解密信息。
代码如下:
namespace com.billdawson.crypto{public class CryptoClient {private const int RSA_KEY_SIZE_BITS = 1024;private const int RSA_KEY_SIZE_BYTES = 252;private const int TDES_KEY_SIZE_BITS = 192;private const int TDES_KEY_SIZE_BYTES = 128;private const int TDES_IV_SIZE_BYTES = 128;public static void Main(string[] args){int port;string host;TcpClient client;SymmetricAlgorithm symm;RSACryptoServiceProvider rsa;if (args.Length!=2){Console.WriteLine(USAGE);return;}try{host = args[0];port = Int32.Parse(args[1]); }catch{Console.WriteLine(USAGE);return;}try //连接{client = new TcpClient();client.Connect(host,port);}catch(Exception e){Console.WriteLine(e.Message);Console.Write(e.StackTrace);return;}try{Console.WriteLine("Connected. Sending public key.");rsa = new RSACryptoServiceProvider();rsa.KeySize = RSA_KEY_SIZE_BITS;sendPublicKey(rsa.ExportParameters(false),client);symm = new TripleDESCryptoServiceProvider();symm.KeySize = TDES_KEY_SIZE_BITS;MemoryStream ms = getRestOfMessage(client);extractSymmetricKeyInfo(rsa, symm, ms);showSecretMessage(symm, ms);}catch(Exception e){Console.WriteLine(e.Message);Console.Write(e.StackTrace);}finally{try{client.Close();}catch { //错误}}}private static void sendPublicKey(RSAParameters key,TcpClient client){NetworkStream ns = client.GetStream();BinaryFormatter bf = new BinaryFormatter();bf.Serialize(ns,key);}private static MemoryStream getRestOfMessage(TcpClient client){//获取加密的对称密钥、初始化矢量、秘密信息。对称密钥用公共RSA密钥//加密,秘密信息用对称密钥加密MemoryStream ms = new MemoryStream(); NetworkStream ns = client.GetStream();byte[] buffer = new byte[1024];int len=0;// 将NetStream 的数据写入内存流while((len = ns.Read(buffer, 0, buffer.Length))>0){ms.Write(buffer, 0, len);}ms.Position = 0;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];msOrig.Read(buffer,0,buffer.Length);symm.Key = rsa.Decrypt(buffer,false);// 获取TDES初始化矢量buffer = new byte[TDES_IV_SIZE_BYTES];msOrig.Read(buffer, 0, buffer.Length);symm.IV = rsa.Decrypt(buffer,false);}private static void showSecretMessage(SymmetricAlgorithm symm,MemoryStream msOrig){//内存流中的所有数据都被加密了byte[] buffer = new byte[1024];int len = msOrig.Read(buffer,0,buffer.Length);MemoryStream ms = new MemoryStream();ICryptoTransform transform =symm.CreateDecryptor(symm.Key,symm.IV);CryptoStream cstream =new CryptoStream(ms, transform, CryptoStreamMode.Write);cstream.Write(buffer, 0, len);cstream.FlushFinalBlock();// 内存流现在是解密信息,是字节的形式,将它转换为字符串ms.Position = 0;len = ms.Read(buffer,0,(int) ms.Length);ms.Close();string msg = Encoding.ASCII.GetString(buffer,0,len);Console.WriteLine("The host sent me this secret message:");Console.WriteLine(msg); } } }
结论
使用对称算法加密本地数据时比较适合。在保持代码通用时我们可以选择多种算法,当数据通过特定的CryptoStream时算法使用转换对象加密该数据。需要将数据通过网络发送时,首先使用接收的公共不对称密钥加密对称密钥。
本文只涉及到System.Security.Cryptography名字空间的一部分服务。尽管文章保证只有某个私有密钥可以解密相应公共密钥加密的信息,但是它没有保证是谁发送的公共密钥,发送者也可能是假的。需要使用处理数字证书的类来对付该风险。