namespace com.billdawson.crypto { public class CryptoServer { private const int RSA_KEY_SIZE_BITS = 1024; private const int RSA_KEY_SIZE_BYTES = 252; private const int TDES_KEY_SIZE_BITS = 192;
public static void Main(string[] args) { int port; string msg; TcpListener listener; TcpClient client; SymmetricAlgorithm symm; RSACryptoServiceProvider rsa; //获取端口 try { port = Int32.Parse(args[0]); msg = args[1]; } catch
//建立监听 try { listener = new TcpListener(port); listener.Start(); Console.WriteLine("Listening on port ...",port);
client = listener.AcceptTcpClient(); Console.WriteLine("connection...."); } catch (Exception e)
try { rsa = new RSACryptoServiceProvider(); rsa.KeySize = RSA_KEY_SIZE_BITS;
// 获取客户端公共密钥 rsa.ImportParameters(getClientPublicKey(client));
symm = new TripleDESCryptoServiceProvider(); symm.KeySize = TDES_KEY_SIZE_BITS;
//使用客户端的公共密钥加密对称密钥并发送给客。 encryptAndSendSymmetricKey(client, rsa, symm);
//使用对称密钥加密信息并发送 encryptAndSendSecretMessage(client, symm, msg); } catch (Exception e)
finally
catch
Console.WriteLine("Server exiting..."); } }
private static RSAParameters getClientPublicKey(TcpClient client) { // 从字节流获取串行化的公共密钥,通过串并转换写入类的实例 byte[] buffer = new byte[RSA_KEY_SIZE_BYTES]; NetworkStream ns = client.GetStream(); MemoryStream ms = new MemoryStream(); BinaryFormatter bf = new BinaryFormatter(); RSAParameters result;
int len = 0; int totalLen = 0;
while(totalLen
(len = ns.Read(buffer,0,buffer.Length))>0) { totalLen+=len; ms.Write(buffer, 0, len); }
ms.Position=0;
result = (RSAParameters)bf.Deserialize(ms); ms.Close();
return result;
}
private static void encryptAndSendSymmetricKey( TcpClient client, RSACryptoServiceProvider rsa, SymmetricAlgorithm symm) { // 使用客户端的公共密钥加密对称密钥 byte[] symKeyEncrypted; byte[] symIVEncrypted;
NetworkStream ns = client.GetStream();
symKeyEncrypted = rsa.Encrypt(symm.Key, false); symIVEncrypted = rsa.Encrypt(symm.IV, false);
ns.Write(symKeyEncrypted, 0, symKeyEncrypted.Length); ns.Write(symIVEncrypted, 0, symIVEncrypted.Length);
} private static void encryptAndSendSecretMessage(TcpClient client, SymmetricAlgorithm symm, string secretMsg) { // 使用对称密钥和初始化矢量加密信息并发送给客户端 byte[] msgAsBytes; NetworkStream ns = client.GetStream(); ICryptoTransform transform = symm.CreateEncryptor(symm.Key,symm.IV); CryptoStream cstream = new CryptoStream(ns, transform, CryptoStreamMode.Write);
msgAsBytes = Encoding.ASCII.GetBytes(secretMsg);
cstream.Write(msgAsBytes, 0, msgAsBytes.Length); cstream.FlushFinalBlock(); } } 客户端的工作流程是:
建立和发送公共密钥给服务器。
从服务器接收被加密的对称密钥。
解密该对称密钥并将它作为私有的不对称密钥。
接收并使用不对称密钥解密信息。
代码如下:
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)
try { host = args[0]; port = Int32.Parse(args[1]); } catch
try //连接 { client = new TcpClient(); client.Connect(host,port); } catch(Exception e)
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)
finally
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名字空间的一部分服务。尽管文章保证只有某个私有密钥可以解密相应公共密钥加密的信息,但是它没有保证是谁发送的公共密钥,发送者也可能是假的。需要使用处理数字证书的类来对付该风险。 |