在C#中不对称加密例子 [英] Asymetric cryptography example in c#

查看:187
本文介绍了在C#中不对称加密例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要通过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:

请注意有一个服务器和一个客户端:(我们假定eather的公共密钥的客户端或服务器可以是由任何人获得)

Note there is a server and a client: (we assume that public keys of eather the client or server can be obtain by anyone)

1)客户端创建自己的公钥和私钥。他能够用他的私钥来加密并用他的公共密钥进行解密。

1) client creates his public and private key. He is able to encrypt with his private key and decrypt with his public key.

2)服务器创建自己的公钥和私钥。私钥用于解密消息和公共密钥用于加密消息。 (注意是其他方式与客户端)

2) 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)

3)客户端获取的该服务器的公共密钥。然后客户将能够消息与该密钥和唯一的一个,将能够解密消息将是服务器的私钥进行加密。

3) 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.

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.

5),这样客户端消息将包含:数据被发送,客户端的公钥,客户端名称加密与客户的私钥

5) so the client message will contain: data to be send, client's public key, client name encrypted with the client's private key.

6),客户端将与来自服务器的公钥加密该消息。然后客户端将发送消息到服务器。

6) the client will encrypt the message with the public key from the server. client will then send that message to the server.

7)服务器将解密它只是用自己的私钥收到消息。

7) the server will decrypt the message it just received with his private key.

8)一旦消息被解密,将包含数据(信息),加密签名,从客户端的公钥。

8) once the message is decrypted it will contain the data (info), encrypted signature, public key from client.

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.

确定,所以这是加密如何不对称的作品。我也研究有关使您能够创建与.NET Framework这个密钥对的类。我研究,使你的类做创建这个公共和私有密钥对:

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#做的吗?我理解的理论部分是如何工作的,但我怎么做我只是code描述。我研究了一些例子,但我有一个很难理解他们。

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和服务器鲍勃。我不得不将该程序分成两部分。我有一个很难理解它,如果我给它一个尝试最有可能我会让它正常工作。反正我怎么能这个计划分为服务器端code和客户端code。我知道如何服务器和客户端之间发送的字节。但我不想让它不理解到底是怎么回事工作。也许你们可以告诉我一个简单的例子。

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.

我设法分开code:这里是服务器code:(我的电脑的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();
            }
        }
    }
}

和这里的客户端code:

and here is the client code:

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;
        }
    }
}

我认为这是pretty安全。每当它发送不同的字节数组,虽然发送相同的信息!

I thinks it is pretty secure. Every time it sends a different byte array although sending the same info!

推荐答案

当你注意,你是在加密初学者。如果这是一个有趣的玩具项目,以了解加密,太棒了。如果这是真正的生产code的你要不安全实现它的。您应该使用过的,现成的工具,如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#中不对称加密例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆