Encrypting and Decrypting A String Sent As A Querystring Parameter Using C#

June 24 2015

I recently needed to encrypt/decrypt strings sent as querystring parameters over the wire. The use case happens to be allowing people to unsubscribe from a newsletter by clicking on a hyperlink in their email. The server receives the email as a querystring. Obviously, I don’t want to expose a public service that takes an unencrypted email. So, I encrypt the email as part of the newsletter template. Then decrypt on the web server.

Not rocket science, but worth going over how I did it, as there were a few gotchas.

First, I generated an RSA crypto key as XML, using the code found here:

public class MyCrypto
{
    RSACryptoServiceProvider rsa = null;
    string publicPrivateKeyXML;
    string publicOnlyKeyXML;
    public void AssignNewKey()
    {
        const int PROVIDER_RSA_FULL = 1;
        const string CONTAINER_NAME = "KeyContainer";
        CspParameters cspParams;
        cspParams = new CspParameters(PROVIDER_RSA_FULL);
        cspParams.KeyContainerName = CONTAINER_NAME;
        cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
        cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
        rsa = new RSACryptoServiceProvider(cspParams);
 
        //Pair of public and private key as XML string.
        //Do not share this to other party
        publicPrivateKeyXML = rsa.ToXmlString(true);
 
        //Private key in xml file, this string should be share to other parties
        publicOnlyKeyXML = rsa.ToXmlString(false);
         
    }
}

Then, to encrypt the string in such a way that it could be passed as a querystring, I had to make some changes. First, I changed the encoding to UTF8 and not ASCII. Second, I then base64 encode the string, Third, I URL encode the string:

public string EncryptAndEncode(string text)
{
    string encryptedText;
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.FromXmlString(Resources.Resources.publicKeyXML);
        var bytes = rsa.Encrypt(Encoding.UTF8.GetBytes(text), true);
        encryptedText = Convert.ToBase64String(bytes);
    }
    return HttpUtility.UrlEncode(encryptedText);
}

On the decrypt side, because I’m getting the string as a method in my controller, the URL decoding is handled for me. So, the decrypt looks like this:

private string Decrypt(string text)
{
    string decryptedText;
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.FromXmlString(Resources.Resources.publicPrivateKeyXML);
        var bytes = Convert.FromBase64String(text);
        decryptedText = Encoding.UTF8.GetString(rsa.Decrypt(bytes, true));
    }
    return decryptedText;
}