3

I need to use basic RSA cryptography in my program so I use the RSACryptoServiceProvider class to do so.

I noticed it generates keys much faster than PyCrypto (Python) for example.

Here are some benchmarks I made:

Execution times (.NET with RSACryptoServiceProvider)

Average generation time for 1024-bit key pair: 111,2 ms Average generation time for 2048-bit key pair: 394,8 ms Average generation time for 3072-bit key pair: 594 ms Average generation time for 4096-bit key pair: 872,4 ms Average generation time for 5120-bit key pair: 3351,4 ms Average generation time for 6144-bit key pair: 4644,2 ms Average generation time for 7168-bit key pair: 10052,8 ms Average generation time for 8192-bit key pair: 16105,8 ms

Execution times (Python with PyCrypto)

Average generation time for 1024-bit key pair: 1.19569948638 s Average generation time for 2048-bit key pair: 2.43145552844 s Average generation time for 3072-bit key pair: 12.8203488201 s Average generation time for 4096-bit key pair: 16.4437521276 s Average generation time for 5120-bit key pair: 58.6469382781 s Average generation time for 6144-bit key pair: 166.814121751 s Average generation time for 7168-bit key pair: 132.13567301 s Average generation time for 8192-bit key pair: 218.305013463 s

Ratio (Python/.NET) :

1024-bit key pair: 10,75 2048-bit key pair: 6,16 3072-bit key pair: 21,58 4096-bit key pair: 18,85 5120-bit key pair: 17,50 6144-bit key pair: 35,92 7168-bit key pair: 13,14 8192-bit key pair: 13,55

As you can see, Python is about 17 times slower than .NET. Is Python really slow or does .NET use some kind of optimization to generate keys?

Tests were run on Windows 7 Ultimate 64-bit with an Intel Core i7 2600.

I used the following code to get these results:

C#

List<List<long>> executionTimes = new List<List<long>>();
int step = 1024;

for (int bits = 1024; bits <= 8192; bits += step) // 1024-bit to 8192-bit key pair
{
    executionTimes.Add(new List<long>());

    for (int i = 0; i < 5; ++i) // Run the test 10 times to compute an average
    {
        Console.WriteLine("Generating " + bits + "-bit key pair...");

        Stopwatch s = Stopwatch.StartNew();
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(bits); // Doesn't actually generate the key pair
        rsa.ExportParameters(true); // Force generation of the key pair
        s.Stop();

        executionTimes[executionTimes.Count - 1].Add(s.ElapsedMilliseconds);

        Console.WriteLine("Key pair generated. Time: " + s.ElapsedMilliseconds.ToString() + " ms\r\n");
    }
}

for (int i = 1; i <= executionTimes.Count; ++i)
    Console.WriteLine("Average generation time for " + (i * step).ToString() + "-bit key pair: " + executionTimes[i - 1].Average().ToString() + " ms");


Console.ReadLine();

Python

import time
from Crypto.PublicKey import RSA

execution_times = list()
step = 1024

for bits in range(1024, 8192 + 1, step): # 1024-bit to 8192-bit key pair
        execution_times.append(list())

        for i in range(5):
                print("Generating " + str(bits) + "-bit key pair...")

                t = time.clock()
                RSA.generate(bits) # Generate key pair
                t = time.clock() - t

                execution_times[len(execution_times) - 1].append(t)

                print("Key pair generated. Time: " + str(t) + " s\r\n");


for i in range(1, len(execution_times) + 1, 1):
        print("Average generation time for " + str(i * step) + "-bit key pair: " + str(sum(execution_times[i - 1]) / len(execution_times[i - 1])) + " s")

Why is C# so much faster at generating keys than Python?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
GuiTeK
  • 1,561
  • 5
  • 20
  • 39
  • 2
    .NET uses a wrapper over the native implementation included with windows. – CodesInChaos May 21 '14 at 12:50
  • @CodesInChaos: I guess the Python implementation is native code, too. – Joey May 21 '14 at 12:51
  • But even pure managed C# code should be much faster than what you give for python. My experience with optimized bigints in C vs. C# is that there is less than a factor 1.5 between equivalent code and a factor 3 if the native code uses 128 bit integers since those are not available in .net. – CodesInChaos May 21 '14 at 13:01
  • @GeorgeStocker Python version: http://pastebin.com/0Zj1Jr3j C# version: http://pastebin.com/jG9BiqK6 – GuiTeK May 21 '14 at 14:54
  • 3
    @GuiTeK The code should be in your question; not in a pastebin. – George Stocker May 21 '14 at 14:57
  • It gets worse when you run it from numerous threads. Try to call OpenSSL binary or wrap an OpenSSLn dll into you .net code to get best results. – pepo May 21 '14 at 15:31

0 Answers0