8

I want to utilise some form of "simple" encryption that is reasonably secure but very low friction in terms of impact on development process.

Supposing I own both sides of the conversation in a client <> web service situation. My application is a windows phone/win8/silverlight/desktop app and the server is ASP.Net MVC or WebAPI.

In my mind, I want something as simple as:-

<security encryption="off|sometype|someothertype">
    <privatekey>12345MyKey54321</privatekey>
</security>

as some form of configuration parameter on both the client and server. Additionally an authentication routine will return and store some form of public key.

Doing so will enable the 'encryption mode' and result in any http requests being encrypted & hashed in the selected manner using the provided keys. The end result being anything sniffed on the local, proxy or remote machines would not be able to view the data without the key and decryption method. On the server, data is decrypted using the same key before hitting controller actions.

Other than swapping out HttpRequest/WebClient calls for something like EncryptedHttpRequest and adding the appropriate hook on the MVC/WebAPI side of things, all other client code and controller actions would be ignorant to the fact the data was encrypted.

Am I missing something or could setup not be this simple? As far as I have searched there is nothing that offers this level of simplicity so I figure I'm missing some gaping flaw in my logic?

1
  • 1
    The problem is how easy man in the middle attacks are using tools like Fiddler.
    – DannyT
    Commented Aug 16, 2012 at 14:19

2 Answers 2

19

All you are looking for can be achieved by simply using HTTPS. Just buy a certificate (or use a self-signed certificate) and there is your encryption.

Do not re-invent the wheel.

1
8

I've done this successfully. It isn't too difficult and works well. I use it for activating a license for a product. The most important thing is that your truly control the client and server - no one can extract your private key from your code on the client.

Step 1: Create an MVC controller action method that takes no arguments:

[HttpPost]        public ActionResult Activate()        { ... }

Step 2: In the controller just use the HttpRequest.InputStream to get ahold of the bytes sent from the client.

var stream = this.HttpContext.Request.InputStream;

Step 3: Create a CryptoStream to deserialize.

I've included creating both encryption and decryption examples here. The sharedSecret is a byte[] of sufficient length (512 bytes) of random bytes - this is what you protect!

public CryptoStream CreateEncryptionStream(Stream writeStream)
{            
    TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();               
    PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);                
    CryptoStream cryptoStream = new CryptoStream(writeStream, cryptoProvider.CreateEncryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Write);            
    return cryptoStream;        
}        

public CryptoStream CreateDecryptionStream(Stream readStream)        
{            
    TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider();            
    PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null);                
    CryptoStream cryptoStream = new CryptoStream(readStream, cryptoProvider.CreateDecryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Read);            
    return cryptoStream;        
}

Step 4: Use your CryptoStream another stream reader to decrypt.

I use an XmlReader so that all my existing serialization code can work either in the clear (when reading/writing to disk or database on the server) or encrypted (when transmitting).

using (var reader = XmlReader.Create(decryptionStream, settings))                { ... }

Step 5: Formulate a secure response in your controller.

This is doing the reverse of Steps 1-4 to encrypt your response object. Then you just write your encrypted response to a memory stream and return it as a File result. Below, I've shown how I do this for my license response object.

var responseBytes = GetLicenseResponseBytes(licenseResponse);
return File(responseBytes, "application/octet-stream");

private byte[] GetLicenseResponseBytes(LicenseResponse licenseResponse)        
{            
    if (licenseResponse != null)            
    {                
        using (MemoryStream memoryStream = new MemoryStream())                
        {                    
            this._licenseResponseSerializer.Write(memoryStream, licenseResponse);

            return memoryStream.ToArray();                
        }            
    }           
    return null;        
}

Step 6: Implement your client request response.

You can use HttpWebRequest or the WebClient classes to formulate the request. Here's a couple of examples from the code I use.

byte[] postBytes = GetLicenseRequestBytes(licenseRequest);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(licenseServerUrl);
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.Proxy = WebRequest.DefaultWebProxy;
using (Stream requestStream = request.GetRequestStream())
{                
    requestStream.Write(postBytes, 0, postBytes.Length);
}            
return request;

private LicenseResponse ProcessHttpResponse(HttpWebResponse response)
{
    if ((response.StatusCode == HttpStatusCode.OK) && response.ContentType.Contains("application/octet-stream"))
    {
        var stream = response.GetResponseStream();
        if (stream != null)
        {
            var licenseResponse = this._licenseResponseSerializer.Read(stream);
            return licenseResponse;
        }
    }
    return new LicenseResponse(LicensingResult.Error);
}

Summary and Tips

  • Use the streams in the request/responses on the client and server to communicate binary octet-stream data
  • Use CryptoStream along with an encryption algorithm (consider using the strongest encryption possilbe) and a good private key to encrypt data when you serialize/deserialize it.
  • Make sure to check the size and format all incoming data to the client and server (avoid buffer overruns and throw exceptions early)
  • Protect your private key on your client using obfuscation if possible (take a look at the DeepSea obfustactor)
2
  • 2
    Great solution! But Aliostad's answer is more practical and straightforward :) Commented Nov 19, 2012 at 15:57
  • Perfect for embedded linux machine to communicate database with this implementation.
    – NTMS
    Commented Mar 3, 2016 at 8:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.