尝试使用 RSA 解密时密钥不存在

Posted

技术标签:

【中文标题】尝试使用 RSA 解密时密钥不存在【英文标题】:Key does not exist when trying to decrypt using RSA 【发布时间】:2014-11-29 08:47:35 【问题描述】:

所以,我正在使用 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);

【问题讨论】:

与您的问题无关:如何将公钥发送给客户端?如果不是,我建议生成一个密钥对,将公钥嵌入到客户端代码中,将私钥嵌入到服务器代码(或配置)中。 【参考方案1】:

抱歉,此内容不够小,无法放入评论中。

您已将公钥发送给客户端。这将只允许客户端加密要发送到服务器的数据。要解密数据,客户端需要私钥(因此您的例外)

将您的公钥发送给某人不允许您向他们发送加密消息,它允许他们安全地向您发送加密消息,因此在您的示例中只有客户端可以发送加密消息。

在您的场景中,这意味着客户端需要生成一个 AES 密钥,使用已发送的公钥对其进行加密,然后服务器可以对其进行解密并使用 AES 密钥。但是我不建议这样做,因为它有很多缺陷,包括非常容易受到中间人攻击。这是因为我们无法验证我们收到的公钥是否属于服务器(其他人可能正在拦截和修改 tcp 流以插入他们自己的密钥对,从而获得对 AES 密钥的访问权和能够窥探其余的通信)。

您应该考虑使用 SslStream 类 http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.100).aspx

如果您想像以前一样继续,那么您需要让客户端生成密钥并有一些机制来验证收到的公钥。

验证公钥的通常方法是使用证书(即您有一个服务器和客户端都信任的第三方(证书颁发机构),并且该第三方已经签署了公钥以表明它确实属于服务器)

如果您不想获得由受信任的证书颁发机构签名的证书,那么您可以使用自签名证书,但与您必须将公钥硬编码到客户端应用程序相比并没有太大的好处无论如何都要硬编码自签名证书的证书指纹。

【讨论】:

好吧,这只是为了做功课,所以我真的不想使用证书......你是说我可以在客户端创建 RSA,然后将公钥发送到服务器,然后加密 AES 服务器密钥并将其发送给可以解密的客户端,然后 AES 可以工作吗? 我尝试了这种“我的方式”并且它有效..感谢您的回答! 你可以,但你仍然容易受到中间人攻击。

以上是关于尝试使用 RSA 解密时密钥不存在的主要内容,如果未能解决你的问题,请参考以下文章

全面解决.Net与Java互通时的RSA加解密问题,使用PEM格式的密钥文件

不使用密钥的 RSA 解密

OPENSSL RSA加密与解密

RSA加解密原理

使用 RSA Bouncy Castle 加密/解密无法正常工作

Java 进行 RSA 加解密时不得不考虑到的那些事儿