0

I have a class with a bunch of fields that need to be encrypted before being saved, something like this;

class MyClass
{
   public string CustomerName{ get; set; }
   public string Address1{ get; set; }
   public string Address2{ get; set; }
   public string Town{ get; set; }
   public string Postcode{ get; set; }

   // updated
   public DateTime RegistrationDate { get; set; } // don't encrypt
}

What's the most performant approach to encrypt the fields in this object? What about if we had to encrypt 100 or 1000 of these objects? (can we leverage TPL?)

UPDATE:
Some of the fields might not need encryption, so I don't want to encrypt the entire class.
.NET4 is acceptable.

Mark Cooper
  • 6,738
  • 5
  • 54
  • 92
  • 1
    How 'encrypted' do they need to be? If you're using SQL server, have you considered encryption at the database level? – Paddy Jun 13 '12 at 10:10
  • 2
    Take a look at [SecureString](http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx) (.NET 2.0+) for when it's in memory - doesn't really help you with saving but it's still useful. – Bridge Jun 13 '12 at 10:11
  • http://stackoverflow.com/questions/202011/encrypt-decrypt-string-in-net – Darren Jun 13 '12 at 10:12
  • You need to define what your metric is first. Some that is good for 1 1000 objects with less strength encryption might not be suitable for 100 objects requiring stronger encryption. – Preet Sangha Jun 13 '12 at 10:12
  • Can I suggest a quick reading about encryption performance and security which fits perfectly here? https://krebsonsecurity.com/2012/06/how-companies-can-beef-up-password-security/ – Palantir Jun 13 '12 at 10:13
  • 2
    I think on a modern hardware and software, 1000 objects would be processed in no time. Maybe you need to worry if you foresee processing of millions of such objects – Midhat Jun 13 '12 at 10:13
  • 1
    @Bridge you learn something every day! I never knew this existed - cool! – MoonKnight Jun 13 '12 at 10:14
  • @Killercam doesn't really help for saving it, but it's good for protecting strings in memory. There's lots of handy bits in the framework people don't know about (including me of course) :-) – Bridge Jun 13 '12 at 10:16
  • @all - not using SQL server, so can't use TDE. SecureString is a good hint, but doesn't help this situation. We are already seeing problems with 1000 objects (takes 60s+). Have tried a few things, but want to validate. – Mark Cooper Jun 13 '12 at 10:18
  • Do you save these objects in a relational db or serialized to a file? – Eren Ersönmez Jun 13 '12 at 10:18
  • @Preet - the requirements are currently undefined, we are able to define the policy. My initial thoughts are for AES_128 using a 1024 bit key, but I don't want to steer the answers if a better approach is available. – Mark Cooper Jun 13 '12 at 10:19
  • @Eren - it could be either. I'd like a solution that is database agnostic. – Mark Cooper Jun 13 '12 at 10:20
  • Mark, I think you are getting your concepts mixed up as there is no such thing as AES-128 with a 1024 bit key. – President James K. Polk Jun 13 '12 at 10:26
  • @gregs - quite possibly, apologies - I'm no expert on encryption hence the question ;-) – Mark Cooper Jun 13 '12 at 10:29
  • 1
    I'll bet you can guess how many bits are in an AES-128 key. Here a hint: Who is buried in Grant's tomb? ;) – President James K. Polk Jun 13 '12 at 10:35

2 Answers2

0

Assuming that you finally want encrypted fields no matter you application layers, you have to time it on your own in order to get results for your system and configuration. In general your can use parallel tasks for compression as in the following sample code:

    RijndaelManaged csp = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 };
    // TODO: define Key and IV
    Stopwatch encryptionTime = Stopwatch.StartNew();
    Parallel.For(0, 1000, i =>
        {
            string fieldValue = "abcdef...";
            byte[] fieldBytes = UTF8Encoding.UTF8.GetBytes(fieldValue);
            byte[] fieldEncrypred;
            using (var ms = new MemoryStream())
            using (var cs = new CryptoStream(ms, csp.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(fieldBytes, 0, fieldBytes.Length);
                cs.FlushFinalBlock();
                fieldEncrypred = ms.ToArray();
            }
        });
    encryptionTime.Stop();
    Console.WriteLine(encryptionTime.Elapsed.TotalMilliseconds);

You can modify the above to cover your needs and perform your own tests.

For the above sample you will need:

using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
0

First, serialize the whole object (e.g. using protobuf-net), and then encrypt the serialized bytes using CryptoStream.

If the resulting bytes are generally small (e.g. less than 256KB), you can store them in a varbinary(MAX) field in a sql database. If they are generally larger, you'd be better off storing them as files in the filesystem.

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • Thanks for taking time to provide an answer. I'd like to do the fields individually rather than the whole object. There might be some fields that don't need to be encrypted. Question edited appropriately. – Mark Cooper Jun 13 '12 at 10:33