bcgit / pc-dart

Pointy Castle - Dart Derived Bouncy Castle APIs
MIT License
230 stars 115 forks source link

Question about AES/CBC speed #173

Open hootyjeremy opened 1 year ago

hootyjeremy commented 1 year ago

I am interested in using this package but when I test encrypting 100mb with AES/CBC, it takes about 7 seconds in release mode on my machine. I know that speed on machines are relative so I have a gist of the example code here which will print elapsed time:

https://gist.github.com/hootyjeremy/97ccfe7b1203ac5160b4544a237b9b5a

image

I can understand that this is software implemented AES and not aesni, but does this seem extremely slow for anybody else? Even that it is a software implementation, I wouldn't expect more than 0.5 to 1 seconds to encrypt 100mb.

Can anybody verify if I am getting acceptable speeds with this package or if this is an anomaly?

maxjaglak commented 1 year ago

Hello, you’re not alone :)

I use a similar implementation as you do and I also get similar results.

I’m getting around ~9 mb/s on my laptop (AES/CBC, 256 bits key, running flutter app in release mode, encryption itself in separate isolate), less than that on some slower phones, meanwhile AES/CBC in Java/Kotlin (same modes, same params, same devices) encrypts at 200-300+ mb/s (desktop) and 80+ mb/s (phones).

I have also tested the deprecated AESFastEngine engine. It can encrypt at ~20 mb/s on my machine.

Do we know what is the bottleneck in the current implementation of AESEngine?

hootyjeremy commented 1 year ago

Ah, I think I get it now after digging into the source code. aes.dart uses only one T-table, _T0, while aes_fast.dart uses four _t0, _t1, _t2, and _t3 where 1, 2, and 3 are rotated versions of _t0. This gains a performance increase, apparently. The other package I was testing, which has pretty quick throughput, also does this. I will try aes_fast.dart and check the results. I didn't try it at first because of the warning that it was susceptible to side-channel attacks.

Check out section 5 Implementation aspects of the rijndael block cipher for more info. (this is a pdf) https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf

edit: I see that you are saying that aes_fast is also slow. Have you tried the package called "cryptography" yet? That's the fastest one I've come across. Does that give you faster speeds than aes_fast.dart?

hootyjeremy commented 1 year ago

How did you get aes_fast.dart to work? I can't seem to get it to work.

Also, what package are you using for Java/Kotlin? BouncyCastle or something else?

I have created gist for the "cryptography" package example if you want to try it. It will encrypt 100mb the same way as the gist provided in the original post for pointycastle (https://gist.github.com/hootyjeremy/97ccfe7b1203ac5160b4544a237b9b5a). I can't seem to get aes_fast.dart to work right now so I can't compare it to this other package.

"cryptography" package by dint.dev... https://gist.github.com/hootyjeremy/038f434e57aa4fd5765b7c63e70da7f3

Does that package provide faster results than aes_fast.dart for you?

maxjaglak commented 1 year ago

I’ve modified your AES/CBC gist to run with AESFastEngine: https://gist.github.com/maxjaglak/65896f380d10027568c50b475d605d52

it gives me following results: //AES / CBC / pointy castle / AESFastEngine size: 100 mb time.elapsed: 0:00:03.209223 speed 29.72 [mbps]

For comparison, same test, but with standard AESEngine, from Pointy Castle: size: 100 mb time.elapsed: 0:00:12.970145 speed 7.35 [mbps]

with your cryptography test: //AES / CBC / https://pub.dev/packages/cryptography size: 100 mb time: 0:00:02.424923 speed 39.34 [mbps] (a little bit faster than AESFastEngine from Pointy Castle)

With java/kotlin I use javax.crypto API.

I guess I will end up writing native code for AES encryption / decryption (java / swift / other) and keep Pointy Castle as a fallback for platforms where I don’t have native implementation.

hootyjeremy commented 1 year ago

Thanks for the benchmarks. I'm not yet sure why pointycastle's implementation is slower than cryptography's. I'm looking at that one right now and maybe I'll find something. The good thing about pointycastle is that padding is optional with aescbc which means I can process chunks and just pad the last block but the cryptography package pads it all in one shot and doesn't let you do chunks as far as I can tell. But I'm starting to work on a PR for that one if I can figure out how to make padding optional for Aes Cbc.

I would like to be able to use aesni first and then fallback to a software implementation but I haven't found any packages that use CBC with aesni. Sodium will do aesni but only uses GCM which is fine except that it doesn't have a software fallback. But I've only found that the software implementations for GCM are even slower than CBC so I don't even want to use GCM.

If you don't mind my asking, what is the difference in writing it natively vs. with dart? Why is that faster if flutter/dart is said to compile to native code?

maxjaglak commented 1 year ago

If you don't mind my asking, what is the difference in writing it natively vs. with dart? Why is that faster if flutter/dart is said to compile to native code?

I guess it’s about code optimization itself. I mean just compiling to native code doesn’t mean it’s optimal. javax.crypto uses implementation of different providers, so its performance is dependent on what is actually being used. I’ve found some posts that explains a little: https://stackoverflow.com/questions/6101565/is-there-a-practical-way-to-determine-which-jce-crypto-providers-are-in-use https://docs.oracle.com/en/java/javase/16/docs/api/java.base/javax/crypto/package-summary.html https://stackoverflow.com/a/3048593/5178627

I’m not sure what speed you require in your implementation, but for my use cases, javax.crypto + “whatever is selected by default” is usually enough. On iOS / macOS, you could use CryptoKit, which uses hardware acceleration; on newer machines it can reach 2000+ mb/s with AES GCM.

But I've only found that the software implementations for GCM are even slower than CBC so I don't even want to use GCM.

For CBC vs GCM, check this post: https://security.stackexchange.com/a/184307

hootyjeremy commented 1 year ago

Thanks for the info. I'll give these a read.