Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about AES/CBC speed #173

Open
hootyjeremy opened this issue Sep 27, 2022 · 7 comments
Open

Question about AES/CBC speed #173

hootyjeremy opened this issue Sep 27, 2022 · 7 comments
Labels
question Further information is requested

Comments

@hootyjeremy
Copy link

hootyjeremy commented Sep 27, 2022

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?

@hootyjeremy hootyjeremy changed the title Is AES/CBC slow? (sample included) Question about AES/CBC speed Sep 27, 2022
@maxjaglak
Copy link

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
Copy link
Author

hootyjeremy commented Oct 4, 2022

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
Copy link
Author

hootyjeremy commented Oct 4, 2022

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
Copy link

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
Copy link
Author

hootyjeremy commented Oct 6, 2022

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
Copy link

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
Copy link
Author

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

@Ephenodrom Ephenodrom added the question Further information is requested label Mar 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants