問題描述
我需要通過 TCP 連接將機密數據發送到服務器.我做了很多研究,我理解了理論部分.根據我的研究,我想做以下事情:
I need to send confidential data to a server over a TCP connection. I have done a lot of researching and I understand the theoretical part. Based on what I have researched I want to do the following:
注意有一個服務器和一個客戶端:(我們假設任何人都可以獲取客戶端或服務器的公鑰)
Note there is a server and a client: (we assume that public keys of either the client or server can be obtain by anyone)
客戶創建他的公鑰和私鑰.他能夠用他的私鑰加密并用他的公鑰解密.
client creates his public and private key. He is able to encrypt with his private key and decrypt with his public key.
服務器創建他的公鑰和私鑰.私鑰用于解密消息,公鑰用于加密消息.(注意與客戶端相反)
server creates his public and private keys. private key is used to decrypt messages and public key is used to encrypt messages. (note is the other way around as with the client)
客戶端獲取服務器的公鑰.然后,客戶端將能夠使用該密鑰加密消息,而唯一能夠解密該消息的將是服務器的私鑰.
the client get's the server's public key. client then will be able to encrypt messages with that key and the only one that will be able to decrypt that message would be the server's private key.
由于服務器需要確定消息來自該特定客戶端,因此客戶端將使用他的私鑰加密他的名字(簽名).
since the server needs to be certain that the message comes from that specific client then the client will encrypt his name (signature) with his private key.
因此客戶端消息將包含:要發送的數據、客戶端的公鑰、使用客戶端私鑰加密的客戶端名稱.
so the client message will contain: data to be send, client's public key, client name encrypted with the client's private key.
客戶端將使用來自服務器的公鑰加密消息.然后客戶端會將該消息發送到服務器.
the client will encrypt the message with the public key from the server. client will then send that message to the server.
服務器將使用他的私鑰解密它剛剛收到的消息.
the server will decrypt the message it just received with his private key.
一旦消息被解密,它將包含數據(信息)、加密簽名、來自客戶端的公鑰.
once the message is decrypted it will contain the data (info), encrypted signature, public key from client.
最后,服務器將使用消息中包含的公鑰解密客戶端簽名,以驗證消息是否來自該客戶端.
finally, the server will decrypt the client signature with the public key that was contained on the message to verify that the message is from that client.
<小時>
好的,這就是非對稱加密的工作原理.我還研究了使您能夠使用 .NET 框架創建此密鑰對的類.我研究的能夠讓你創建這個公鑰和私鑰對的類是:
OK so this is how asymmetric cryptography works. I have also researched about the classes that enable you to create this key pairs with the .NET framework. The classes that I researched that enable you do create this public and private key pairs are:
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# 來完成它?我了解理論部分是如何工作的,但我該如何做我剛才用代碼描述的事情.我研究了一些例子,但我很難理解它們.
so now my problems comes on how do I use one of this classes to do it with C#? I understand how the theoretical part works but how do I do what I just described with code. I have researched for some examples but I am having a hard time understanding them.
這是我發現的一個例子,我相信它符合我所描述的:
here is one example that I found that I believe does what I described:
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.我必須把這個程序分成兩部分.我很難理解它,如果我試一試,我很可能會成功.無論如何,我如何將該程序拆分為服務器端代碼和客戶端代碼.我知道如何在服務器和客戶端之間發送字節.但我不想在不了解發生了什么的情況下讓它工作.也許你們可以給我看一個更簡單的例子.
In this program I believe the client is Alice and the server is Bob. I have to split this program into two parts. I am having a hard time understanding it and if I give it a try most likely I will make it work. Anyways how can I split this program into a server side code and client side code. I know how to send bytes between server and client. But I don't want to make it work without understanding what is going on. maybe you guys can show me an easier example.
我設法將代碼分開:這是服務器代碼(我的計算機的IP地址恰好是192.168.0.120):
I managed to separate the code: here is the server code (the ip address of my computer happened to be 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;
}
}
}
我認為它非常安全.每次它發送一個不同的字節數組雖然發送相同的信息!
I thinks it is pretty secure. Every time it sends a different byte array although sending the same info!
推薦答案
如您所見,您是加密貨幣的初學者.如果這是一個有趣的玩具項目來了解加密,那就太好了.如果這是真正的生產代碼你將不安全地實現它.您應該使用現成的工具(例如 SSL/HTTPS/其他工具)來解決此問題,而不是自己做錯事.
As you note, you are a beginner at crypto. If this is a fun toy project to learn about crypto, great. If this is real production code you are going to implement it insecurely. You should be using off-the-shelf tools like SSL/HTTPS/whatever to solve this problem rather than doing it wrong yourself.
我會借此機會指出你的草圖存在致命弱點的地方.
I'll take this opportunity to point out areas where your sketch is fatally weak.
3) 客戶端獲取服務器的公鑰.
3) the client get's the server's public key.
好的.如何?這是最重要的一步. 整個系統的安全都依賴于這一步,而你完全掩蓋了它是如何工作的.客戶端如何獲取服務器的公鑰? 是什么阻止了一個邪惡的人打電話給客戶端并說嘿客戶端,我是服務器.這是我的公鑰!"現在客戶端正在加密只能由作惡者解密的消息.作惡者擁有真實服務器的公鑰,所以作惡者用真實的公鑰重新加密消息并繼續發送.您的整個系統因此受到損害.只有在存在安全的密鑰交換機制時,公鑰密碼系統才是安全的.(那么一個合理的問題是:如果您有一個安全的密鑰交換機制,為什么不首先簡單地使用它來交換消息?)
OK. How? This is the most important step. The security of the entire system relies upon this step, and you have completely glossed over how it works. How does the client obtain the public key of the server? What stops an evil person from calling up the client and saying "hey client, I'm the server. Here's my public key!" And now the client is encrypting messages that can only be decrypted by the evildoer. The evildoer has the real server's public key, so the evildoer re-encrypts the message with the real public key and sends it on. Your whole system is thereby compromised. The public key cryptosystem is only secure if there is a secure key exchange mechanism. (And a reasonable question then is: if you have a secure key exchange mechanism, why not simply use it to exchange the message in the first place?)
4) 由于服務器需要確定消息來自該特定客戶端,因此客戶端將使用他的私鑰加密他的名字(簽名).
4) since the server needs to be certain that the message comes from that specific client then the client will encrypt his name (signature) with his private key.
客戶端應該加密整個消息的哈希作為簽名,而不僅僅是消息的一部分.這樣,服務器就有證據表明整個消息來自客戶端.
The client should encrypt a hash of the entire message as the signature, not just a part of the message. That way the server has evidence that the whole message was from the client.
6) 客戶端將使用來自服務器的公鑰加密消息.然后客戶端會將該消息發送到服務器.
6) the client will encrypt the message with the public key from the server. client will then send that message to the server.
這效率極低.更好的是讓服務器和客戶端就對稱密碼系統的密鑰達成一致.可以使用公鑰密碼系統在服務器和客戶端之間傳輸密鑰.服務器和客戶端現在有一個共享密鑰,可用于此通信會話.
This is extremely inefficient. Better is for the server and client to agree upon a key to a symmetric cryptosystem. The key can be transmitted between the server and the client using the public key cryptosystem. The server and client now have a shared secret key that they can use for this communication session.
9) 最后,服務器將使用消息中包含的公鑰解密客戶端簽名,以驗證消息是否來自該客戶端.
9) lastly, the server will decrypt the client signature with the public key that was contained on the message to verify that the message is from that client.
這到底有什么幫助?我想給你發消息.你想知道它來自誰.所以我給你發了一份我的駕照復印件,這樣你就可以比較駕照上的簽名和信息上的簽名.你怎么知道我寄給你的是我的駕照而不是別人的復印件?這根本不能解決客戶端身份驗證問題.同樣,您需要解決密鑰分發問題.系統依賴于有一個安全的密鑰分發基礎設施,它你沒有指定.
How on earth does that help anything? I want to send you a message. You want to know who it comes from. So I send you a photocopy of my drivers license, so you can compare the signature on the license with the signature on the message. How do you know I sent you my drivers license and not a photocopy of someone else's? This doesn't solve the client authentication problem at all. Again, you need to solve the key distribution problem. The system depends on there being a secure key distribution infrastructure, which you have not specified.
這篇關于C# 中的非對稱加密示例的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!