【发布时间】:2011-11-24 07:05:26
【问题描述】:
我需要通过 TCP 连接将机密数据发送到服务器。我做了很多研究,我理解了理论部分。根据我的研究,我想做以下事情:
注意有服务器和客户端:(我们假设任何人都可以获取客户端或服务器的公钥)
客户端创建他的公钥和私钥。他能够用他的私钥加密并用他的公钥解密。
服务器创建他的公钥和私钥。私钥用于解密消息,公钥用于加密消息。 (注意与客户端相反)
客户端获取服务器的公钥。然后客户端将能够使用该密钥加密消息,而唯一能够解密该消息的将是服务器的私钥。
由于服务器需要确定消息来自该特定客户端,因此客户端将使用他的私钥加密他的姓名(签名)。
所以客户端消息将包含:要发送的数据、客户端的公钥、使用客户端私钥加密的客户端名称。
客户端将使用来自服务器的公钥加密消息。然后客户端会将该消息发送到服务器。
服务器将使用他的私钥解密它刚刚收到的消息。
一旦消息被解密,它将包含数据(信息)、加密签名、来自客户端的公钥。
最后,服务器将使用消息中包含的公钥解密客户端签名,以验证消息是否来自该客户端。
好的,这就是非对称加密的工作原理。我还研究了使您能够使用 .NET 框架创建此密钥对的类。我研究的能够让你创建这个公钥和私钥对的类是:
System.Security.Cryptography.DES
System.Security.Cryptography.DSACryptoServiceProvider
System.Security.Cryptography.ECDsa
System.Security.Cryptography.ECDsaCng
System.Security.Cryptography.ECDiffieHellman
System.Security.Cryptography.ECDiffieHellmanCng
System.Security.Cryptography.RSA
System.Security.Cryptography.RSACryptoServiceProvider
所以现在我的问题是如何使用其中一个类来使用 C# 来完成它?我了解理论部分是如何工作的,但我该如何做我刚才用代码描述的事情。我研究了一些例子,但我很难理解它们。
这是我发现的一个例子,我相信它符合我所描述的:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Example
{
class Program
{
static CngKey aliceKey;
static CngKey bobKey;
static byte[] alicePubKeyBlob;
static byte[] bobPubKeyBlob;
static void Main()
{
CreateKeys();
byte[] encrytpedData = AliceSendsData("secret message");
BobReceivesData(encrytpedData);
Console.Read();
}
private static void CreateKeys()
{
aliceKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
bobKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
alicePubKeyBlob = aliceKey.Export(CngKeyBlobFormat.EccPublicBlob);
bobPubKeyBlob = bobKey.Export(CngKeyBlobFormat.EccPublicBlob);
}
private static byte[] AliceSendsData(string message)
{
Console.WriteLine("Alice sends message: {0}", message);
byte[] rawData = Encoding.UTF8.GetBytes(message);
byte[] encryptedData = null;
using (var aliceAlgorithm = new ECDiffieHellmanCng(aliceKey))
using (CngKey bobPubKey = CngKey.Import(bobPubKeyBlob,
CngKeyBlobFormat.EccPublicBlob))
{
byte[] symmKey = aliceAlgorithm.DeriveKeyMaterial(bobPubKey);
Console.WriteLine("Alice creates this symmetric key with " +
"Bobs public key information: {0}",
Convert.ToBase64String(symmKey));
using (var aes = new AesCryptoServiceProvider())
{
aes.Key = symmKey;
aes.GenerateIV();
using (ICryptoTransform encryptor = aes.CreateEncryptor())
using (MemoryStream ms = new MemoryStream())
{
// create CryptoStream and encrypt data to send
var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
// write initialization vector not encrypted
ms.Write(aes.IV, 0, aes.IV.Length);
cs.Write(rawData, 0, rawData.Length);
cs.Close();
encryptedData = ms.ToArray();
}
aes.Clear();
}
}
Console.WriteLine("Alice: message is encrypted: {0}",
Convert.ToBase64String(encryptedData)); ;
Console.WriteLine();
return encryptedData;
}
private static void BobReceivesData(byte[] encryptedData)
{
Console.WriteLine("Bob receives encrypted data");
byte[] rawData = null;
var aes = new AesCryptoServiceProvider();
int nBytes = aes.BlockSize >> 3;
byte[] iv = new byte[nBytes];
for (int i = 0; i < iv.Length; i++)
iv[i] = encryptedData[i];
using (var bobAlgorithm = new ECDiffieHellmanCng(bobKey))
using (CngKey alicePubKey = CngKey.Import(alicePubKeyBlob,
CngKeyBlobFormat.EccPublicBlob))
{
byte[] symmKey = bobAlgorithm.DeriveKeyMaterial(alicePubKey);
Console.WriteLine("Bob creates this symmetric key with " +
"Alices public key information: {0}",
Convert.ToBase64String(symmKey));
aes.Key = symmKey;
aes.IV = iv;
using (ICryptoTransform decryptor = aes.CreateDecryptor())
using (MemoryStream ms = new MemoryStream())
{
var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write);
cs.Write(encryptedData, nBytes, encryptedData.Length - nBytes);
cs.Close();
rawData = ms.ToArray();
Console.WriteLine("Bob decrypts message to: {0}",
Encoding.UTF8.GetString(rawData));
}
aes.Clear();
}
}
}
}
在这个程序中,我相信客户端是 Alice,服务器是 Bob。我必须把这个程序分成两部分。我很难理解它,如果我试一试,我很可能会成功。无论如何,我如何将该程序拆分为服务器端代码和客户端代码。我知道如何在服务器和客户端之间发送字节。但我不想在不了解发生了什么的情况下让它工作。也许你们可以给我看一个更简单的例子。
编辑
我设法将代码分开:这是服务器代码(我的计算机的IP地址恰好是192.168.0.120):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.IO;
namespace ServerListener
{
class Program
{
static TcpListener server;
//static CngKey aliceKey;
static CngKey bobKey;
static byte[] alicePubKeyBlob;
static byte[] bobPubKeyBlob;
static void Main(string[] args)
{
CreateKeys();
IPAddress ipAddress = IPAddress.Parse("192.168.0.120");
server = new TcpListener(ipAddress, 54540);
server.Start();
var client = server.AcceptTcpClient();
var stream = client.GetStream();
alicePubKeyBlob = new byte[bobPubKeyBlob.Length];
stream.Read(alicePubKeyBlob, 0, alicePubKeyBlob.Length);
stream.Write(bobPubKeyBlob, 0, bobPubKeyBlob.Length);
byte[] encrytpedData = new byte[32];
stream.Read(encrytpedData, 0, encrytpedData.Length);
BobReceivesData(encrytpedData);
}
private static void CreateKeys()
{
//aliceKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
bobKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
//alicePubKeyBlob = aliceKey.Export(CngKeyBlobFormat.EccPublicBlob);
bobPubKeyBlob = bobKey.Export(CngKeyBlobFormat.EccPublicBlob);
}
private static void BobReceivesData(byte[] encryptedData)
{
Console.WriteLine("Bob receives encrypted data");
byte[] rawData = null;
var aes = new AesCryptoServiceProvider();
int nBytes = aes.BlockSize >> 3;
byte[] iv = new byte[nBytes];
for (int i = 0; i < iv.Length; i++)
iv[i] = encryptedData[i];
using (var bobAlgorithm = new ECDiffieHellmanCng(bobKey))
using (CngKey alicePubKey = CngKey.Import(alicePubKeyBlob,
CngKeyBlobFormat.EccPublicBlob))
{
byte[] symmKey = bobAlgorithm.DeriveKeyMaterial(alicePubKey);
Console.WriteLine("Bob creates this symmetric key with " +
"Alices public key information: {0}",
Convert.ToBase64String(symmKey));
aes.Key = symmKey;
aes.IV = iv;
using (ICryptoTransform decryptor = aes.CreateDecryptor())
using (MemoryStream ms = new MemoryStream())
{
var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write);
cs.Write(encryptedData, nBytes, encryptedData.Length - nBytes);
cs.Close();
rawData = ms.ToArray();
Console.WriteLine("Bob decrypts message to: {0}",
Encoding.UTF8.GetString(rawData));
}
aes.Clear();
}
}
}
}
这是客户端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.IO;
namespace ClientAlice
{
class Program
{
static CngKey aliceKey;
//static CngKey bobKey;
static byte[] alicePubKeyBlob;
static byte[] bobPubKeyBlob;
static void Main(string[] args)
{
CreateKeys();
bobPubKeyBlob = new byte[alicePubKeyBlob.Length];
TcpClient alice = new TcpClient("192.168.0.120", 54540);
var stream = alice.GetStream();
stream.Write(alicePubKeyBlob, 0, alicePubKeyBlob.Length);
stream.Read(bobPubKeyBlob, 0, bobPubKeyBlob.Length);
byte[] encrytpedData = AliceSendsData(":)");
stream.Write(encrytpedData, 0, encrytpedData.Length);
}
private static void CreateKeys()
{
aliceKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
//bobKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);
alicePubKeyBlob = aliceKey.Export(CngKeyBlobFormat.EccPublicBlob);
//bobPubKeyBlob = bobKey.Export(CngKeyBlobFormat.EccPublicBlob);
}
private static byte[] AliceSendsData(string message)
{
Console.WriteLine("Alice sends message: {0}", message);
byte[] rawData = Encoding.UTF8.GetBytes(message);
byte[] encryptedData = null;
using (var aliceAlgorithm = new ECDiffieHellmanCng(aliceKey))
using (CngKey bobPubKey = CngKey.Import(bobPubKeyBlob,
CngKeyBlobFormat.EccPublicBlob))
{
byte[] symmKey = aliceAlgorithm.DeriveKeyMaterial(bobPubKey);
Console.WriteLine("Alice creates this symmetric key with " +
"Bobs public key information: {0}",
Convert.ToBase64String(symmKey));
using (var aes = new AesCryptoServiceProvider())
{
aes.Key = symmKey;
aes.GenerateIV();
using (ICryptoTransform encryptor = aes.CreateEncryptor())
using (MemoryStream ms = new MemoryStream())
{
// create CryptoStream and encrypt data to send
var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
// write initialization vector not encrypted
ms.Write(aes.IV, 0, aes.IV.Length);
cs.Write(rawData, 0, rawData.Length);
cs.Close();
encryptedData = ms.ToArray();
}
aes.Clear();
}
}
Console.WriteLine("Alice: message is encrypted: {0}",
Convert.ToBase64String(encryptedData)); ;
Console.WriteLine();
return encryptedData;
}
}
}
我认为它非常安全。每次它发送一个不同的字节数组虽然发送相同的信息!
【问题讨论】:
-
听起来您正在重新发明 SSL(或者至少,您的任务可以使用 SSL 完成)。您不想使用 SSL 的任何原因?
-
我不知道知道如何在代码中使用私钥和公钥会很好,而不仅仅是理解理论部分......也许你是对的我应该使用 ssl 但我从未使用过那个伊瑟。我是密码学世界的新手……
-
我不希望你们修改那个例子。有一个更时髦的例子会很好。我发布该示例只是为了向您展示我在寻找什么。我只是想了解它是如何工作的,并使其与代码一起工作......
-
投票关闭它,因为它实际上并没有提出问题。也许代码可以发布在代码审查网站上。但就目前而言,唯一可能的答案是完全解释非对称密码学(包括如何正确拼写)和传输安全性。
-
我的意思是:“第 1 步:客户创建他的公钥和私钥。他可以用他的私钥加密并用他的公钥解密。”太好了,这已经完全错误了。 请勿以上述文字为例。
标签: c# encryption cryptography