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. 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.

Sign up to request clarification or add additional context in comments.

1 Comment

Using Fiddler it is easy to decrypt the HTTPS communication. docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS
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 Comments

Great solution! But Aliostad's answer is more practical and straightforward :)
Perfect for embedded linux machine to communicate database with this implementation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.