所以,我正在创建一个简单的#34;网络聊天",使用TcpClient和TcpListener类。我希望所有发送的数据都被加密,我正在使用AES加密。首先,我必须确保从服务器的AES密钥安全地发送到客户端。我试图通过使用RSA加密AES密钥然后将其发送到客户端并再次使用RSA对其进行解密来实现此目的。
首先,我在服务器上创建了一个RSACryptoServiceProvider并提取了公钥。我将公钥发送到客户端,并创建了RSACryptoServiceProvider并导入了该密钥。当我调用Decrpyt方法时,我得到的密钥不存在异常。这是我的代码:
服务器:
这是向客户发送公钥。
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
string privateXml = rsa.ToXmlString(true);
string publicXml = rsa.ToXmlString(false);
Byte[] pubKey = Encoding.UTF8.GetBytes(publicXml);
clientStream.Write(pubKey, 0, pubKey.Length);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); // simetrično kriptiranje
byte[] aesKey = aes.Key;
byte[] encryptedRSA = rsa.Encrypt(aesKey, false);
clientStream.Write(encryptedRSA, 0, encryptedRSA.Length);
客户端:
Byte[] serverPublicKey = new Byte[1024];
Int32 bytes1 = stream.Read(serverPublicKey, 0, serverPublicKey.Length);
string serverKey = Encoding.UTF8.GetString(serverPublicKey, 0, bytes1);
serverKey = serverKey.Replace("\0", "");
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(serverKey);
Byte[] bytes2 = new Byte[128];
String aesKey = null;
stream.Read(bytes2, 0, bytes2.Length);
byte[] decryptedKey = rsa.Decrypt(bytes2, false);
答案 0 :(得分:4)
对不起,这不足以容纳评论。
您已将公钥发送给客户端。这将只允许客户端加密要发送到服务器的数据。要解密数据,客户端需要私钥(因此您的例外)
将您的公钥发送给某人不允许您向他们发送加密邮件,它允许他们安全地向您发送加密邮件,因此在您的示例中,只有客户端才能发送加密邮件。
在您的方案中,这意味着客户端需要生成AES密钥,使用已发送的公钥对其进行加密,然后服务器可以对其进行解密并使用AES密钥。但是我不建议这样做,因为它有许多缺陷,包括在中间攻击中非常容易受到攻击。这是因为我们无法验证我们收到的公钥是否属于服务器(其他人可能正在拦截和修改tcp流以插入自己的密钥对,从而获得对AES密钥的访问权限能够窥探通信的其余部分。)
您应该考虑使用SslStream类http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.100).aspx
如果你想继续像往常一样,那么你需要让客户端生成密钥并使用一些机制来验证收到的公钥。
验证公钥的通常方法是使用证书(即您拥有服务器和客户端信任的第三方(证书颁发机构),并且第三方已签署公钥以表明它确实属于服务器)
如果您不想获得由受信任的证书颁发机构签名的证书,那么您可以使用自签名证书,但是将公钥硬编码到客户端应用程序中并没有太大的好处,就像您必须无论如何,硬编码自签名证书的证书指纹。