-
Notifications
You must be signed in to change notification settings - Fork 6.1k
BouncyCastle implementation of "AES/CBC/PKCS5Padding" and "AES/GCM/NoPadding" #3779
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
Conversation
1e1eb8e
to
1358da4
Compare
} | ||
|
||
public BouncyCastleAesBytesEncryptor(String password, CharSequence salt) { | ||
this(password, salt, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not use a null IV as this is not safe. We always need to create IV for AES/CBC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This matches the behaviour of the NULL_IV_GENERATOR in AesBytesEncryptor, which is shown in BouncyCastleAesBytesEncryptorEquivalencyTest.bcJceWithoutIvEquivalent(), and Encryptors.queryableText produces this sort of encryptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that is also incorrect (but we cannot change).
NOTE Also note there is a slight difference given AesBytesEncryptor
is package scope and the static methods are a bit more descriptive. Technically though this is still broken and we should not repeat it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so I'll remove that constructor and expect an IV generator in the code. Should I also make it package scope and final and add a method to Encryptors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave it public. I think the static methods in Encryptors need to go eventually. The problem with them is that what is "standard", "stronger", etc changes with time. However we cannot modify these methods and stay passive.
A few additional comments:
|
07925f4
to
18d7a71
Compare
Github was having issues yesterday and seems to not be kicking off Travis... lemme see if I can make a few force pushes to get that going again |
18d7a71
to
cf829a1
Compare
@william-tran Thanks for the updates! Looking at the code it appears my suggestion to use a base class might have caused more code/complexity than intended. I'm wondering if the base class makes sense. Do you think we could try to:
I think the best way we could do this is to create the two classes totally independent of one another (without thinking about the other code). If there are similarities those can be extracted into a package private superclass. If not, then they live in their own classes. |
The whole need for OutputStreams is so that method can return two objects, a properly sized ByteArrayOutputStream and a properly initialized CipherOutputStream, then common code can process those. Both those objects depend on a BlockCipher that doesn't share a common subclass. (though have the same method names). The process method is a bit ugly due to the need to try/catch/finally/close streams so I didn't want to repeat that. While at first glance what you're asking for would seem clearer, it'll result in the 4x duplication (encrypt/decrypt, CBC/GCM) of a lot of complexity. |
@william-tran Thanks for the response. I'm much prefer the duplication of the code to needing to add classes like |
I prefer the previous revision, but what matters the most to me is that it works. We can entirely eliminate the common class by duplicating key generation and OutputStream processing, I only went half way. |
byte[] process(CipherOutputStream cipherOutputStream, ByteArrayOutputStream byteArrayOutputStream, byte[] bytes) { | ||
try { | ||
cipherOutputStream.write(bytes); | ||
cipherOutputStream.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cipherOutputStream
is closed in the finally block on line 69. Is it intentional to close cipherOutputStream
twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second call could go in the catch instead of a finally. close() does a doFinal and releases resources, in case the write() throws exception we should try to release those resources
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved the second close() to the catch block and added comments to clarify things.
b6d8e28
to
9b0a758
Compare
cipherOutputStream.close(); | ||
return byteArrayOutputStream.toByteArray(); | ||
} | ||
catch (IOException e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case this isn't an IOException, we won't attempt to release resources and wrap in IllegalStateException. What about just catching any Exception?
Implments "AES/CBC/PKCS5Padding" and "AES/GCM/NoPadding" Fixes spring-projectsgh-2917
9b0a758
to
b7b4507
Compare
Thanks for the hard work @william-tran! This is now merged into master |
Woohoo! Thanks for guiding this to landing. |
Fixes #2917
I ran a very cursory JMH benchmark on encrypt/decrypt of a 1 MB byte array of random bytes and this implementation is 3x slower than JCE, and for a 1 kB byte array this is 4.7x slower.