简体   繁体   中英

How do I transmit a SecureString (or similar) across the network without exposing the plaintext?

I have an application with a "secret" (eg password)

I don't want to store this secret locally in a user-accessible context file, so I'm planning to retrieve it on-demand from the server over HTTPS

I also don't want it visible in memory (eg from a crash log), for obvious reasons, so I'm storing the secret in a SecureString

However, when I serialise the SecureString, the result just shows the length of the plaintext string, eg {"Length":4}

If I transmit the password in plaintext, though, then it will be visible in the retrieved JSON in memory, even if subsequently store it in a SecureString

Is there any way to serialize a SecureString, or to receive the JSON and convert a plaintext string to a SecureString without needing an intermediate regular String that would be stored in memory?

In this scenario, I have to store/send the actual password, rather than, for example, a one-time-use key as I'd prefer: that's beyond my control here. I need the actual plaintext password to access another service, so the usual "Hash it then compare the hash" doesn't apply either

Here is a worked example of using RSA encryption to send a string to someone whose public key you have. In your question you want the server to send a message (password) to the client and for the client to securely use that password without having to worry about logging etc in the middle. For this to work you need to have the client create the private key file and send the public key file to the server which can then communicate back securely.

There are probably libraries that make this way easier.

[Test]
public void TestEncryption()
{
    /////////////// Create Key Files ////////////////
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(4096);

    //Create the key files on disk and distribute them to sender / reciever
    var publicKey =  provider.ToXmlString(false);
    var privateKey =  provider.ToXmlString(true);

    /////////////// Actual Test ////////////////

    //send with the public key
    byte[] sent = Send("hey",publicKey);

    //cannot receive with public key
    var ex = Assert.Throws<CryptographicException>(()=>Receive(sent, publicKey));
    StringAssert.Contains("Key does not exist",ex.Message);

    //but can with private key
    Assert.AreEqual("hey", Receive(sent,privateKey));
}

private Byte[] Send(string send, string publicKey)
{
    using (RSACryptoServiceProvider rsaSender = new RSACryptoServiceProvider())
    {
        rsaSender.FromXmlString(publicKey);
        return rsaSender.Encrypt(Encoding.ASCII.GetBytes(send), false);
    }
}

private object Receive(byte[] sent, string privateKey)
{
    using (RSACryptoServiceProvider rsaReceiver = new RSACryptoServiceProvider())
    {
        rsaReceiver.FromXmlString(privateKey);
        return Encoding.ASCII.GetString(rsaReceiver.Decrypt(sent, false));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM