Bug 972 - Slow Encryption in Encryption Libraries
Summary: Slow Encryption in Encryption Libraries
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: 4.x
Hardware: PC Windows
: --- critical
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2011-09-21 15:56 UTC by joe longo
Modified: 2011-10-06 18:03 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

Demo code of slow encryption (560.49 KB, application/x-zip-compressed)
2011-09-21 15:56 UTC, joe longo

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description joe longo 2011-09-21 15:56:51 UTC
Created attachment 461 [details]
Demo code of slow encryption

Encrption code works and is reliable. Performance is adequate on Emulator. On device, encryption performance is very poor. This is a Hard-Stop issue. Our app performs quite well until we activate the encryption, which is a deal-breaker. Response time of a few seconds goes to 90sec encryption overhead on transitions.
Same code works adequately on WP7 with lag times for a call ~2 sec/per encryption job. On iOS,same calls are 10+ secs /call. Demo shows load/save time sample. Due to caching nature of DB, start app once. reset device and start again to see realistic load times. 8 secs on load/12 secs on Save. I have tried all the available encryption libraries (AES is required for our work) best performance in TripleDES. Encryption can be turned off/on  in Project Model; Sterling/EncryptedSerilizer, Line 19. Currently Encrypts. Remove ||iOS to turn off Encryption and see the perf delta.
Comment 1 Sebastien Pouliot 2011-09-27 16:35:41 UTC
Mono's cryptographic stack is entirely managed. It's no bad in a full desktop environment (e.g. simulator) but it fail any comparison to native, hand-coded or hardware accelerated implementations of similar algorithm. However there are some alternatives, from easier to harder:

1) try different options, e.g.

    a) make sure debug is off (as it slow down execution);

    b) use the LLVM compiler (that will ensure debug is off) and it's different targets (you'll have better code generation, which should help performance). YMMV but it's easy

2) review your code, e.g.

    a) why is AesManagedFactory called 3 times ? instead of 1 ? it's perfectly correct to cache it as long as you create new ICryptoTransform (Decryptor/Encryptor) for each invocation.

E.g. If you cache one AesManaged instance (and you should since it's costly to create due to PKCS#5 iterations involved) the number are much better:

	2nd run* before/after
Load:5755		5895
Save:	11297		6147
Load:	0		0
Save:	10559		179
Load:	0		0
Save:	10566		173

* to ensure database was created

    b) your TripleDES code is very different from your AES code, you're likely not comparing the same thing (since key generation is totally different, the one from AES, using PKCS#5, being much better)

    c) your 'stopwatch' is not Reset'ed between the "Load" and "Save" so I think your Save time includes your Load time.

3) go native and bind the CommonCrypto API. AFAIK some devices have hardware acceleration for some algorithms (e.g. AES) and that's unbeatable.

note: we plan to offer access to native crypto in the future, i.e. what iOS offers with CommonCrypto, but there's no ETA for this.

4) ask yourself why...

    a) you're using a 4 characters PIN ? that's 10000 possible values (just a bit over 2^13) if numbers are used (a bit more if any printable characters are available but less than 2^32). An attacker will have no problem pre-computing all possible keys (whatever the cryptographic algorithms and key length you're using)

    b) you're iterating a lot (10000) to create the key/iv from the password/PIN ? you're hurting your users (on mobile devices), not any attacker (which will use much more powerful computers). You could use other strategy (e.g. varying salt and/or iteration count to make it harder to pre-compute all keys)

	2nd run* when 1000 (instead of 10000 iterations are used)

note: the time differences are smaller because the above numbers are using the 'cached' AesManaged (so the iterations are done a single time, not 3 times)

    c) you're using a 256 bits key based on a 4 characters PIN ? e.g. AES 128 bits will be faster (than 256 bits) and still way more secure than the PIN. E.g. 

	2nd run* when a 128 bits key is used (1000 iterations, cached Aes instance)

I don't believe the above suggestions are making the attached code less secure (it's all limited by the PIN) but it makes it much faster.
Comment 2 joe longo 2011-10-06 18:03:36 UTC
The using the AESManaged as a cached item, only doing 1000 interations for IV and reducing the encryption to AES-192, the federal Standard dramatically improved performance. Now encryption performance hit is not notcible. Thankyou.