The next version of Visual Studio “Orcas” and the .NET Framework brings a few changes to the BCL too, not just fancy WPF editors and such.
While implementing encryption support for my BitTorrent based product I noticed how the BCL lacks a few classes that I’d expect to be there, considering how good in general is support for encryption. The examples include at least some kind of Diffie-Hellman key exchange, RC4 (despite its shortcomings) and most notably BigInteger – infinite precision integer class (which is already implemented in J# as well as in IronPython). I also noticed how managed AES implementation was unexpectedly slow compared to the test wrapper I built for the native implementation already present in the Windows API (XP and later, Windows Server 2003 and later).
I’m glad to report that all of these (sans RC4 support, but that’s not a problem as the algorithm is trivial to implement) are fixed/introduced in the next version of the .NET Framework.
The simplest improvement to use is to replace managed AES encryption with an unmanaged one. The benefits are huge, as I’ll demonstrate with the following short application. I am still puzzled as to why is managed implementation so much slower and can only guess that it’s because managed implementation allows for variability in block size while unmanaged doesn’t. Have a look at this short code snippet (requires March CTP of “Orcas” or newer):
namespace CryptoTest
{
class Program
{
const int BLOCK_SIZE = 128;
const int KEY_SIZE = 256;
const int DATA_SIZE = 1024 * 1024 * 32;
static void Main(string[] args)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] iv = new byte[BLOCK_SIZE/8];
rng.GetNonZeroBytes(iv);
byte[] key = new byte[KEY_SIZE/8];
rng.GetNonZeroBytes(key);
ICryptoTransform encryptorManaged = GetEncryptor(iv, key,
new RijndaelManaged());
ICryptoTransform encryptorUnmanaged = GetEncryptor(iv, key,
new AesCryptoServiceProvider());
byte[] data = new byte[DATA_SIZE];
rng.GetBytes(data);
Measure(data, encryptorManaged, true);
Measure(data, encryptorUnmanaged, false);
Console.ReadKey();
}
private static void Measure(byte[] data, ICryptoTransform transform,
bool isManaged)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Encrypt(data, transform);
sw.Stop();
Console.WriteLine("Encrypting {0}MB took {1} ms with the {2} transform",
DATA_SIZE / (1024 * 1024), sw.ElapsedMilliseconds,
isManaged ? "managed" : "unmanaged");
}
private static void Encrypt(byte[] data, ICryptoTransform transform)
{
const int CHUNK = 1024;
byte[] throwAway = new byte[CHUNK];
for (int i = 0; i < data.Length; i += CHUNK)
transform.TransformBlock(data, i, CHUNK, throwAway, 0);
}
private static ICryptoTransform GetEncryptor(byte[] iv, byte[] key,
SymmetricAlgorithm sa)
{
sa.BlockSize = BLOCK_SIZE;
sa.Mode = CipherMode.CBC;
sa.KeySize = KEY_SIZE;
sa.Key = key;
sa.IV = iv;
sa.Padding = PaddingMode.Zeros;
return sa.CreateEncryptor();
}
}
}
The test consists of encrypting 32MB of random data. Both encryptors are initialized with exactly the same initialization vector (IV), key, mode, padding and block size. As you can see, since both RijndaelManaged and AesCryptoServiceProvider derive from SymmetricAlgorithm, the latter is a drop-in replacement for the former.
The results are clear – on average, the unmanaged implementation is between 2.1 and 2.4 times faster than the unmanaged one! This is really important if you have a lot of data to encrypt/decrypt.
“Orcas” is shaping up to be a fine release indeed.
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5