Key does not exist when trying to decrypt using RSA

4.5k views Asked by At

So, I am creating a simple "web chat", using TcpClient and TcpListener class. I want all data sent to be encrpyted, and I am using AES encryption. So first I have to make sure AES key from server is securely sent to client. I am trying to achieve this, by encrypting AES key with RSA and then sending it to client and there decrypting it with RSA again.

So first of all I created an RSACryptoServiceProvider on server and extracted public key. I sent public key to client and there created RSACryptoServiceProvider and imported that key. When I call Decrpyt method I get an key does not exist exception. This is my code:

Server:

This is sending public key to client.

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

Client:

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

There are 1 answers

3
DanL On BEST ANSWER

Sorry this wasn't small enough to fit in a comment.

You've sent the public key to the client. This will only allow the client to encrypt data to be sent to the server. To decrypt data the client would need a private key (hence your exception)

Sending your public key to someone does not allow you to send them encrypted messages, it allows them to send you encrypted messages securely, so in your example only the client can send an encrypted message.

In your scenario this would mean that the client would need to generate an AES key, encrypt it using the public key it has been been sent and then the server can decrypt it and use the AES key. HOWEVER I would not recommend this as it has many flaws including being very susceptible to a man in the middle attack. This is because we have no way to verify the public key we receive is the one that belongs to the server (some one else could be intercepting and modifying the tcp stream to be inserting their own key pair and thereby gaining access to the AES key and being able to snoop on the rest of the communication).

You should consider looking into using the SslStream class http://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.100).aspx

If you wanted to carry on as you have been then you would need to let the client generate the key and have some mechanism to verify the public key received.

The usually way of verifying public keys is by using certificates (i.e. You have a third party (certificate authority) that both the server and client trusts and that third party has signed the public key to say it does actually belong to the server)

If you don't want to get a certificate that is signed by a trusted certificate authority then you could use a self signed certificate but there is not much benefit over just hardcoding the public key into the client application as you would have to hardcode the certificate thumbprint of the self signed certificate anyway.