Rotten performance of RSACryptoServiceProvider.Ver

2019-07-21 07:54发布

问题:

Is the performance of VerifyData so bad that the function is practically useless, or am I doing something very wrong in the code below?

open System
open System.Security.Cryptography

let keySize     = 1024  // bits
let testDataLen = 1000
let iterations  = 100
let hashAlg     = "SHA1"

let timer f =
    let start = DateTime.Now
    f() |> ignore
    let finish = DateTime.Now
    finish - start


let bench () = 
    use rsaSP = new RSACryptoServiceProvider(keySize)
    let rnd = Random()
    let data = Array.create testDataLen 0uy
    rnd.NextBytes data

    let signature = rsaSP.SignData(data, hashAlg)

    let isValid = [for i in 1..iterations -> rsaSP.VerifyData(data, hashAlg, signature)]
                  |> List.forall id
    if not isValid then failwith "Bad signature."

printfn "%d iterations took %A" iterations (timer bench)

100 calls to VerifyData takes a full 3 seconds on a 2.1 GHz Dual-Core on 32 bit XP.

I've also tried replacing the "SHA1" string with a SHA1CryptoServiceProvider object that is reused (no new instantiations in the loop), but that makes no difference.

0.03 seconds for a single VerifyData call - what's going on here?

Edit/Update: Just tried writing F# functions, using BigInteger.ModPow, my own padding function and SHA1CryptoServiceProvider.ComputeHash. The 100 iterations finish in 0.07 seconds, which is 40 times faster than RSACryptoServiceProvider. (Those results must have been wrong. Will revise later.)

回答1:

Delay while calling RSACryptoServiceProvider SignData or VerifyData methods



回答2:

There's not just SHA1 hashing taking place, but also an asymmetric RSA operation, and this one is relatively slow (however, 30 msec is still a bit slow for a single 1024-bit operation).

Did you try alternative crypto implementations that use their own cryptographic primitives, such as BouncyCastle or our SecureBlackbox? Try doing this to check what performance they show on your system.

Also we noticed that some basic crypto operations take much more time on certain quite powerful processors (QuadCore) than on older DualCore (say speed of AES is 6 Mb/s on QuadCore against 30 Mb/s on DualCore notebook). I.e. system architecture affects speed of managed code somehow.



回答3:

I switched timing to use System.Diagnostics.Stopwatch, to make sure you weren't suffering from bad resolution. Running your code on my dual-core laptop of 2 years it takes on average 270 milliseconds with 100 iterations.

I timed just the looping part, that takes around 70 milliseconds, so the bulk of the work is done prior to looping. Breaking it down further, it is actually SignData that is the hog here, it takes around 210 milliseconds even though it is called only once in the benchmark.

Of course, we are using different machines, but 70 milliseconds is what you got out of your own verifying code?

Changes to timer:

let timer f =
    let sw = System.Diagnostics.Stopwatch()
    sw.Start()
    f() |> ignore
    sw.Stop()
    sw.ElapsedMilliseconds

Sample breakdown:

Construct cryptoprovider took 0
Create test array took 0
rnd.NextBytes took 0
rsaSP.SignData took 211
VerifyData took 75
100 iterations took 287L