Jmp Start

…where the Geek shall Inherit the Word

Posts Tagged ‘.NET’

Do NOT recreate a ctor, use it!

Posted by CKret on July 19, 2012

Stackoverflow is a very popular site for developers.
There are tons of questions and answers and there is a good chance you’ll find the solution to your specific problem if you take the time to search a bit.

This post however is not about the correct answers but more about the ones who on the surface seem correct.

A question was asked and an answer was given.

The answer itself is not bad. It is a working solution. For now.
And that’s the key: for now.

An example (where A is a class in a third party assembly):

public class A
{
  public A()
  {
    Init();
  }

  protected void Init()
  {
    ...
    Initialize everything.
    ...
  }
}

public class B : A
{
  private int theNumber;
  public B(int num)
  {
    Init();

    theNumber = num;
  }
}

The constrcutor of B does exactly what the constructor of A does, calls Init, and some more.
So far so good.

But what happens if the constructor of A in an later update changed to:

public class A
{
  public A()
  {
    Init();
    FixSecurityProblem();
  }

  public void Init()
  {
    ...
    Initialize everything.
    ...
  }

  protected void FixSecurityProblem()
  {
    ...
    Do fix the security problem.
    ...
  }
}

This isn’t a breaking change. The code only introduces some internal security checks not visible to the “outside”.

How does this affect B?
Well. The creator of B would have to add a call to FixSecurityProblem in it’s constructor and distribute the new version to all clients.
Will this work?
Sure, but there will be a lot of headache.

Since all clients might not have the new A,
B has to determine exactly which version is installed and make some decisions based on that.
Then the new version of B has to be distributed to all clients.

An even bigger problem would be if FixSecurityProblem was a private method:

public class A
{
  private void FixSecurityProblem()
  {
    ...
    Do fix the security problem.
    ...
  }
}

Now B would have to call A‘s constructor instead! Which is exactly the point in this post.

Even if someone finds this a valid solution, the fundamental problem here is the negligance of NOT utilizing the existing constructor of A:

public class B : A
{
  private int theNumber;
  public B(int num) : base()
  {
    theNumber = num;
  }
}

This would, for all who have an updated class A, fix the security problem. Whithout any changes to B!
For those who have not updated, changes in B would not affect them anyway!

So, as the title says, “Do NOT recreate a ctor, use it!”.

Posted in .NET, Architecture, C# | Tagged: , , | Leave a Comment »

Proper use of Rfc2898DeriveBytes

Posted by CKret on September 29, 2009

When you need encryption in your application, the recommended way to create the key and Initialization Vector (IV) is to use Rfc2898DeriveBytes. It is located in the namespace System.Security.Cryptography. To encrypt some data you would do something like:

public static byte[] EncryptRfc(byte[] plainText, string password, byte[] salt)
{
  var keyGen = new Rfc2898DeriveBytes(password, salt);
  var key = keyGen.GetBytes(32);
  var iv = keyGen.GetBytes(16);

  var cipher = new RijndaelManaged { Key = key, IV = iv };

  byte[] cipherText;
  using (var encryptor = cipher.CreateEncryptor()) {
    using (var ms = new MemoryStream()) {
      using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) {
        cs.Write(plainText, 0, plainText.Length);
        cs.FlushFinalBlock();
        cipherText = ms.ToArray();
      }
    }
  }
  return cipherText;
}

This is straightforward enough:

  • derive the encryption key and IV from the password and salt.
  • create a new instance of the encryptor with the key and IV.
  • encrypt the plaintext.

If you run this it seems to be quite fast. However, nothing can be further from the truth.

Analysis of Rfc2898DeriveBytes

I created a console application with the above method and called it from main.

Then I profiled the application and analyzed the result.

One method call stood out like a sore thumb:

Function Name Inclusive Samples Exclusive Samples Inclusive Samples % Exclusive Samples %
System.Security.Cryptography.Rfc2898DeriveBytes.GetBytes(int32) 944 0 91,12 0,00

The call to GetBytes took up 91.12% of the execution time!!

“So what!?”, you say.

When encrypting a single batch of data this isn’t really an issue since most of the time the encryption takes longer than generating the key and IV. If you however need to encrypt a lot of different data and the data sizes are small then you will have a lot of overhead like in this case. In the above example encrypting the data took at most 8% of the execution time while generating the key and IV took over 91%.

How does it concern me?

This example takes about 80ms on my computer. That’s not bad but that is a single encryption. If I would encrypt 1000 messages then it would run in 80 seconds. Which of course is unacceptable.

Why does it perform so badly?

Rfc2898DeriveBytes uses a pseudo-random number generator based on HMACSHA1. When calling GetBytes it initializes a new instance of HMAC which takes some time. (More than 50% of the execution time in the above example). Subsequent calls to GetBytes does not need to do this initialization.

What can we do to fix this?

There is a fundamental flaw in the above code example. There’s no need create a new instance of Rfc2898DeriveBytes for each call to encrypt. If you have to send 1000 separate messages to a recipient then you’ll want to use the same key but change the IV for each message. Lift out Rfc2898DeriveBytes from the Encrypt method and pass along the key and IV instead of the password and salt. For each new message you call GetBytes() to generate a new IV.

Conclusion

Using Rfc2898DeriveBytes incorrectly will have a severe performance impact on your application. Taking proper steps to avoid this is easy enough but you should always make sure you understand why things work the way they do.

Posted in .NET, C#, Cryptography, Security | Tagged: , , , , | 5 Comments »