-
Notifications
You must be signed in to change notification settings - Fork 14
DE25851: Made Encryptor#encrypt thread safe and improved performance … #107
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
c79a499 to
e04f62d
Compare
ddf4272 to
7c980c7
Compare
irinaepshteyn
left a comment
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.
Done reviewing. Please review my comments.
| // Rigorous checks to make sure we've absolutely got the correct instance (with correct alg/key/iv/...) | ||
| if (cachedCipher != null && cachedCipher.isCipherValid(iv, cipherMode, this.secretKeySpec)) { | ||
| return cachedCipher.cipher; | ||
| } |
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.
Caching cipher seems like unnecessary overhead. isCipherValid does comparison on cipherMode (ENCRYPT_MODE or DECRYPT_MODE) and on IV. If the same thread is used continuously to encrypt (or decrypt), the cached cipher will be thrown away each time as new IV is generated for every encryption/decryption operation. If same thread is used to encrypt and then decrypt, cached cypher will be thrown away as mode is different. I can't come up with the use case when cached cypher is actually used.
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.
Apart from maybe allowing flexibility to change the algorithm and not having to change this code, I agree with you. For now, I've changed it to just cache the Cipher instance thread-locally (agnostic of Cipher#init).
| CIPHER_THREAD_LOCAL.set(new CachedCipher(cipherMode, this.secretKeySpec, cipher)); | ||
| return cipher; | ||
| } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | ||
| | InvalidKeyException 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.
It's better to catch a Throwable here and wrap anything that could go wrong with CipherInitializationFailureException
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.
Done
| throw new SymmetricKeyValidationException("Encryption key must be string of length " + KEY_LENGTH_IN_BYTES); | ||
| } | ||
| this.encryptionKey = encryptionKey; | ||
| this.secretKeySpec = new SecretKeySpec(encryptionKey.getBytes(), ALGO); |
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 could unload key length validation to SecretKeySpec(byte[] key, int offset, int len, String algorithm) constructor. It throws IllegalArgumentException if algorithm is null or key is null, empty, or too short, i.e. key.length-offset<len.
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.
Agreed. In the case that the key is longer than 16 bytes, the first 16 will be used (since the offset is 0)
…by using thread local instances of Cipher Signed-off-by: Anurag <[email protected]>
a8e9935 to
eed5941
Compare
Incorporated PR feedback and squashed changes
irinaepshteyn
left a comment
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.
Ready to merge
…by using thread local instances of Cipher
Signed-off-by: Anurag [email protected]