Cryptographie asymétrique exemple en C#
J'ai besoin d'envoyer des données à un serveur sur une connexion TCP. J'ai fait beaucoup de recherches et je comprends la partie théorique. Basé sur ce que j'ai fait des recherches je veux faire ce qui suit:
Remarque il y a un client et un serveur: (nous supposons que les clés publiques de client ou de serveur peut être obtenue par n'importe qui)
-
client crée sa clé publique et privée. Il est en mesure de chiffrer avec sa clé privée et de déchiffrer avec sa clé publique.
-
serveur crée ses clés publiques et privées. la clé privée est utilisée pour déchiffrer les messages et la clé publique est utilisée pour chiffrer les messages. (remarque est l'inverse avec le client)
-
le client est la clé publique du serveur. le client sera alors en mesure de chiffrer les messages avec cette clé, et le seul qui sera en mesure de déchiffrer le message serait la clé privée du serveur.
-
depuis le serveur doit être certain que le message vient de ce client, le client va crypter son nom (signature) avec sa clé privée.
-
de sorte que le client message contient des données: les données à envoyer au client à clé publique, le nom du client chiffré avec le client est la clé privée.
-
le client va chiffrer le message avec la clé publique du serveur. le client devra ensuite envoyer le message au serveur.
-
le serveur va décrypter le message qu'il vient de recevoir, avec sa clé privée.
-
une fois que le message est déchiffré il contient les données (informations), signature cryptée, de la clé publique du client.
-
enfin, le serveur déchiffre la signature du client avec la clé publique contenue dans le message pour vérifier que le message est à partir de ce client.
OK donc, c'est comment la cryptographie asymétrique œuvres. J'ai aussi fait des recherches sur les classes qui vous permettent de créer cette paires de clés avec le .NET framework. Les classes que j'ai fait des recherches qui vous permettent de vous faire créer cette publics et privés paires de clés sont:
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
donc maintenant mes problèmes vient sur comment puis-je utiliser un de ces classes de le faire avec C#? Je comprends comment la partie théorique fonctionne, mais comment dois-je faire ce que je viens de décrire avec code. J'ai fait des recherches pour d'autres exemples, mais je vais avoir du mal à les comprendre.
voici un exemple que j'ai trouvé qui je crois n'est ce que j'ai décrit:
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();
}
}
}
}
Dans ce programme, je crois que le client est Alice et le serveur est Bob. Je dois briser ce programme en deux parties. Je vais avoir du mal à le comprendre, et si je tente le plus probable, je vais le faire fonctionner. De toute façon comment puis-je diviser ce programme dans un code côté serveur et côté client code. Je sais comment envoyer des octets entre le serveur et le client. Mais je ne veux pas le faire fonctionner sans comprendre ce qui se passe. peut-être que les gars, vous pouvez me montrer un exemple facile.
MODIFIER
J'ai réussi à séparer le code: voici le code du serveur (adresse ip de mon ordinateur qui est arrivé à être 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();
}
}
}
}
et voici le code de client:
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;
}
}
}
Je pense que c'est assez sécurisé. Chaque fois qu'il envoie un autre tableau d'octets, même si l'envoi de la même info!
- Il semble que vous être en train de réinventer le protocole SSL (ou au moins, votre tâche pourrait être accomplie à l'aide de SSL). Une raison quelconque vous ne voulez pas utiliser SSL ?
- Je ne sais pas, il sera bon de savoir comment utiliser les clés privées et publiques avec le code pas seulement à comprendre la partie théorique... Peut-être que vous avez raison, je devrais utiliser ssl mais je n'ai jamais utilisé ce feather. Je suis nouveau dans le monde de la cryptographie...
- Je ne veux pas vous les gars pour modifier cet exemple. Il sera agréable de recevoir un sassier exemple. J'ai posté cet exemple juste pour vous montrer ce que je cherchais. Je veux juste comprendre comment cela fonctionne et de le faire fonctionner avec le code c'est ça...
- Vote pour fermer ce qu'il n'a pas vraiment poser une question. Peut-être que le code pourrait être publié sur la revue de code site. Mais comme il est la seule réponse possible est d'expliquer totalement la cryptographie asymétrique (y compris la façon d'orthographier correctement) et de la sécurité des transports.
- Je veux dire: "Étape 1: le client crée sa clé publique et privée. Il est en mesure de chiffrer avec sa clé privée et de déchiffrer avec sa clé publique." grande, ce qui est totalement faux déjà. Ne pas utiliser le texte ci-dessus à titre d'exemple.
Vous devez vous connecter pour publier un commentaire.
Comme vous le notez, vous êtes un débutant à la crypto. Si c'est un jouet amusant projet à apprendre à propos de la cryptographie, de la grande. Si c'est vrai code de production vous allez mettre en œuvre de manière non sécurisée. Vous devriez être en utilisant off-the-shelf des outils comme SSL/HTTPS/whatever pour résoudre ce problème plutôt que de le faire mal soi-même.
Je vais profiter de cette occasion pour souligner les domaines où vos croquis est mortellement faible.
OK. Comment? C'est l'étape la plus importante. La sécurité de l'ensemble du système repose sur cette étape, et vous avez complètement passées sous silence la façon dont il fonctionne. Comment le client d'obtenir la clé publique du serveur? Ce qui empêche une personne mal d'appeler le client en lui disant "hey client, je suis le serveur. Voici ma clé publique!" Et maintenant, le client est le chiffrement des messages qui ne peuvent être déchiffrées par les méchants. Le malfaiteur a la vraie clé publique du serveur, de sorte que le malfaiteur, re-crypte le message avec la vraie clé publique et l'envoie sur. Votre système est ainsi compromise. Le cryptosystème à clé publique est sûr uniquement si on est sûr de la clé dans le mécanisme de change. (Et raisonnable question est alors: si vous avez une clé sécurisée dans le mécanisme de change, pourquoi ne pas utiliser simplement pour échanger le message en premier lieu?)
Le client doit chiffrer un hachage du message en entier comme la signature, et pas seulement une partie du message. De cette façon, le serveur a la preuve que l'ensemble du message est de la part du client.
C'est extrêmement inefficace. Mieux, c'est pour le serveur et le client pour convenir d'une clé d'un cryptosystème symétrique. Les clés peuvent être transmises entre le serveur et le client à l'aide de la clé publique cryptosystème. Le serveur et le client ont maintenant une clé secrète partagée qu'ils peuvent utiliser pour cette session de communication.
Comment sur la terre, n'est que l'aider à quelque chose? Je veux vous envoyer un message. Vous voulez savoir de qui il vient. Je vous envoie une photocopie de mon permis de conduire, de sorte que vous pouvez comparer la signature de la licence avec la signature sur le message. Comment savez-vous que je vous ai envoyé mon pilotes de licence et non une photocopie de quelqu'un d'autre? Cela ne résout pas le problème de l'authentification client à tous. Encore une fois, vous avez besoin pour résoudre la clé du problème de distribution. Le système dépend de l'existence d'une clé sécurisée infrastructure de distribution, que vous n'avez pas spécifié.
De poster une réponse, car il serait trop long pour un commentaire, et il n'est pas spécifiquement pour répondre à votre question.
Comme mentionné dans le commentaire par driis, vous devriez vraiment compter sur des solutions existantes qui sont considérés comme étant en sécurité. Cela dit, votre protocole ne ont des problèmes de sécurité:
De Communication est généralement dans les deux sens, cependant, vous ne semblent adresse de communication à sens unique (du serveur vers le client). Cela ne fait pas beaucoup de sens, puisque vous dites que vous allez utiliser le protocole TCP est un protocole en lui-même.
Les étapes 4 et 5 sont buggy: puisque vous envoyer la clé publique du client à l'intérieur du message, n'importe qui peut créer une paire et chiffrer l'identification des clients à l'aide de cette paire. À partir de votre description le serveur n'a pas de connaissances de la part du client touches, ce qui rend cette signature ne rien faire, mais de s'assurer de l'intégrité du message - plus précisément, c'est de ne pas en aucune façon faire l'identification du client digne de confiance.
Une pièce d'identité, vous n'avez d'autres conditions préalables; le serveur a à connaître le client de la clé publique à l'avance ou si elle doit être en mesure de faire confiance à la réclamation du client à être lui-même à l'aide d'un de confiance 3ème partie. C'est ce que les certificats et les certificats de confiance chaînes sont sur: si le client présente un certificat délivré par la 3ème partie de X et approuve le serveur X, alors on peut supposer que le client est bien celui qu'il prétend être.
SSL fondamentalement prend en charge deux modes:
Soit uniquement le serveur d'identité est vérifiée et, tout client peut communiquer avec elle; l'identité du client n'est pas vérifiée, seulement que (après la connexion a été négocié) c'est toujours le même client qui communique avec le serveur. C'est l'utilisation typique pour les achats en ligne etc. - vous (le client) la confiance, le serveur et créer une connexion de confiance, mais le serveur ne sais pas qui vous êtes.
Les deux sens de l'authentification peut être effectuée à l'aide de certificats client. Le serveur a à connaître et à faire confiance, soit le certificat du client directement ou l'émetteur du certificat du client pour négocier la connexion se fait correctement. Dans ce scénario, le serveur ne fait en effet savoir qui est le client, mais la condition préalable comme mentionné ci-dessus doit être remplie.