-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Mark,
On 11/22/18 17:52, Mark Thomas wrote:
> On 22/11/2018 22:32, Christopher Schultz wrote:
>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
>>
>> Mark,
>>
>> On 11/22/18 16:43, Mark Thomas wrote:
>>> On 22/11/2018 19:17, Christopher Schultz wrote:
>>>> Mark,
>>>>
>>>> On 11/22/18 05:21, Mark Thomas wrote:
>>>>> On 21/11/2018 22:39, Christopher Schultz wrote:
>>>>>> Mark,
>>>>>>
>>>>> <snip/>
>>>>
>>>>>>> I thought you were using CBC so a missing block (a
>>>>>>> message being one or more blocks) means that the next
>>>>>>> message can't be decrypted.
>>>>>>
>>>>>> CBC *is* being used, but the cipher is reset after each
>>>>>> message, and a new IV is being randomly generated for
>>>>>> that purpose. There is no state-carryover between
>>>>>> messages. At least, there shouldn't be.
>>>>
>>>>> Ah. Thanks for the explanation. I should have looked at
>>>>> the code. That should all work then.
>>>>
>>>>> I'll try and find some time today to figure out what is
>>>>> causing the error messages I am seeing.
>>>>
>>>> Thanks, I'd appreciate a second set of eyes.
>>>>
>>>> I can't seem to find any problems with it. The only
>>>> "problems" I ended up finding were poorly-written tests :)
>>>
>>> syncs on encrypt() and decrypt() seem to have done the trick.
>>> That was just a quick hack to confirm a suspicion - it isn't
>>> the right long term fix.
>>>
>>> If we want this to be performant under load I'd lean towards
>>> using a Queue for encryption ciphers and another for decryption
>>> ciphers along the lines of the way SessionIdGeneratorBase
>>> handles SecureRandom.
>>>
>>> We should probably handle SecureRandom the same way.
>>>
>>> I'll start working on a patch.
>>
>> Hmm... I was under the impression that the message-sending
>> operations were single-threaded (and similar with the receiving
>> operations).
>
> There are locks in other Interceptors which are consistent with
> them being multi-threaded.
>
>> I've read that calling Cipher.init() is expensive, but since
>> it's being done for every outgoing (and incoming) message,
>> perhaps there is no reason to re-use Cipher objects. I'd be
>> interested to see a micro-benchmark showing whether all that
>> complexity (Cipher object pool) is really worth it. It probably
>> isn't, given that the code without that complexity would be super
>> clear and compact.
>
> Good point. I'll try that. It will depend on how expensive creating
> the object is.
>
> Even with the pools the code is pretty clean but I take the point
> that it would be (even) cleaner without.
>
> I have a patch ready to go but I'll do some work on the benchmark
> first.
I have a patch below. Passes all my unit-tests, but I don't have any
multi-threaded ones written at this point.
I'd appreciate a review before I commit. I'm going to change the
cipher-pool-size to be configurable via an XML attribute, etc.
- -chris
=== CUT ===
> ### Eclipse Workspace Patch 1.0 #P tomcat-trunk Index:
> java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java
>
>
===================================================================
> ---
> java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java
> (revision 1847118) +++
> java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java
> (working copy) @@ -20,7 +20,7 @@ import
> java.security.InvalidAlgorithmParameterException; import
> java.security.InvalidKeyException; import
> java.security.SecureRandom; - +import
> java.util.concurrent.ArrayBlockingQueue; import
> javax.crypto.BadPaddingException; import javax.crypto.Cipher;
> import javax.crypto.IllegalBlockSizeException; @@ -63,8 +63,7 @@
> private String encryptionKeyString; private SecretKeySpec
> secretKey;
>
> - private Cipher encryptionCipher; - private Cipher
> decryptionCipher; + private ArrayBlockingQueue<Cipher>
> cipherQueue;
>
> public EncryptInterceptor() { } @@ -113,6 +112,9 @@ } catch
> (InvalidAlgorithmParameterException iape) {
> log.error(sm.getString("encryptInterceptor.encrypt.failed")); throw
> new ChannelException(iape); + } catch (InterruptedException
> ie) { +
> log.error(sm.getString("encryptInterceptor.cipher-borrow.failed"),
> ie); + throw new ChannelException(ie); } }
>
> @@ -138,6 +140,8 @@
> log.error(sm.getString("encryptInterceptor.decrypt.failed"), ike);
> } catch (InvalidAlgorithmParameterException iape) {
> log.error(sm.getString("encryptInterceptor.decrypt.failed"),
> iape); + } catch (InterruptedException ie) { +
> log.error(sm.getString("encryptInterceptor.cipher-borrow.failed"),
> ie); } }
>
> @@ -297,12 +301,15 @@ setSecretKey(new
> SecretKeySpec(getEncryptionKeyInternal(), algorithmName));
>
> String providerName = getProviderName(); - if(null ==
> providerName) { - encryptionCipher =
> Cipher.getInstance(algorithm); - decryptionCipher =
> Cipher.getInstance(algorithm); - } else { -
> encryptionCipher = Cipher.getInstance(algorithm,
> getProviderName()); - decryptionCipher =
> Cipher.getInstance(algorithm, getProviderName()); + + int
> queueSize = 10; // TODO: Parameter + cipherQueue = new
> ArrayBlockingQueue<>(queueSize); + for(int i=0; i<queueSize;
> ++i) { + if(null == providerName) { +
> cipherQueue.add(Cipher.getInstance(algorithm)); + } else
> { + cipherQueue.add(Cipher.getInstance(algorithm,
> getProviderName())); + } } }
>
> @@ -314,12 +321,20 @@ return secretKey; }
>
> - private Cipher getEncryptionCipher() { - return
> encryptionCipher; + private Cipher getEncryptionCipher() throws
> InterruptedException { + return cipherQueue.take(); + }
> + + private void returnEncryptionCipher(Cipher cipher) throws
> InterruptedException { + cipherQueue.put(cipher); }
>
> - private Cipher getDecryptionCipher() { - return
> decryptionCipher; + private Cipher getDecryptionCipher() throws
> InterruptedException { + return cipherQueue.take(); + }
> + + private void returnDecryptionCipher(Cipher cipher) throws
> InterruptedException { + cipherQueue.put(cipher); }
>
> /** @@ -341,27 +356,35 @@ * @throws BadPaddingException Declared
> but should not occur during encryption * @throws
> InvalidAlgorithmParameterException If the algorithm is invalid *
> @throws InvalidKeyException If the key is invalid + * @throws
> InterruptedException If there is a problem obtaining or returning a
> pooled Cipher object */ - private byte[][] encrypt(byte[] bytes)
> throws IllegalBlockSizeException, BadPaddingException,
> InvalidKeyException, InvalidAlgorithmParameterException { -
> Cipher cipher = getEncryptionCipher(); + private byte[][]
> encrypt(byte[] bytes) throws IllegalBlockSizeException,
> BadPaddingException, InvalidKeyException,
> InvalidAlgorithmParameterException, InterruptedException { +
> Cipher cipher = null; + + try { + cipher =
> getEncryptionCipher();
>
> - byte[] iv = new byte[cipher.getBlockSize()]; +
> byte[] iv = new byte[cipher.getBlockSize()];
>
> - // Always use a random IV For cipher setup. - //
> The recipient doesn't need the (matching) IV because we will
> always - // pre-pad messages with the IV as a nonce. -
> new SecureRandom().nextBytes(iv); + // Always use a
> random IV For cipher setup. + // The recipient doesn't
> need the (matching) IV because we will always + //
> pre-pad messages with the IV as a nonce. + new
> SecureRandom().nextBytes(iv);
>
> - IvParameterSpec IV = new IvParameterSpec(iv); +
> IvParameterSpec IV = new IvParameterSpec(iv);
>
> - cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(), IV); +
> cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(), IV);
>
> - // Prepend the IV to the beginning of the encrypted data -
> byte[][] data = new byte[2][]; - data[0] = iv; -
> data[1] = cipher.doFinal(bytes); + // Prepend the IV to
> the beginning of the encrypted data + byte[][] data =
> new byte[2][]; + data[0] = iv; + data[1] =
> cipher.doFinal(bytes);
>
> - return data; + return data; + } finally
> { + if(null != cipher) +
> returnEncryptionCipher(cipher); + } }
>
> /** @@ -376,18 +399,26 @@ * expected number of padding
> bytes * @throws InvalidAlgorithmParameterException If the algorithm
> is invalid * @throws InvalidKeyException If the key is invalid +
> * @throws InterruptedException If there is a problem obtaining or
> returning a pooled Cipher object */ - private byte[]
> decrypt(byte[] bytes) throws IllegalBlockSizeException,
> BadPaddingException, InvalidKeyException,
> InvalidAlgorithmParameterException { - Cipher cipher =
> getDecryptionCipher(); + private byte[] decrypt(byte[] bytes)
> throws IllegalBlockSizeException, BadPaddingException,
> InvalidKeyException, InvalidAlgorithmParameterException,
> InterruptedException { + Cipher cipher = null;
>
> - int blockSize = cipher.getBlockSize(); + try { +
> cipher = getDecryptionCipher();
>
> - // Use first-block of incoming data as IV -
> IvParameterSpec IV = new IvParameterSpec(bytes, 0, blockSize); -
> cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), IV); +
> int blockSize = cipher.getBlockSize();
>
> - // Decrypt remainder of the message. - return
> cipher.doFinal(bytes, blockSize, bytes.length - blockSize); +
> // Use first-block of incoming data as IV +
> IvParameterSpec IV = new IvParameterSpec(bytes, 0, blockSize); +
> cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), IV); + +
> // Decrypt remainder of the message. + return
> cipher.doFinal(bytes, blockSize, bytes.length - blockSize); +
> } finally { + if(null != cipher) +
> returnDecryptionCipher(cipher); + } }
>
>
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/
iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlv3NiwACgkQHPApP6U8
pFjUgxAAlLmx1gMAez+x/jKWl/VbrW6SXbg6jnBSbC0rHXgde1mq/EyHd4KioE0S
fseYt672OSdxIk+yrN0ZZjWfjofkkc32pZm2ap2n23DjTD8yujgGP2ttCvEvK+zr
CQVhBw3Xgfn5UJeMedTlT50ciJOGDko7W3H7fIvsIuElWd3qULEs0T8rFUktKHlB
EgxPEDcum0YX+jyq8W6LNuYma9IQFZQGjLLcorjqaEvtNRbXC08NwReLWSUW/Qeq
EnXPv7jPxXuoN769uB9Jk1HvWxlMeFU0C6rLw5M+/NiQmj4F1sSYtaptAggHwmiI
rcDbN+NNatTOTInsP/pVpjMB3Yzv8S9c5gBLuflCQiSOggFgjGPE5ncXeRZlkZcX
J+31AXR66OM5n7hsdveLWJByQUIie/HVF7KWGnPE4Z9W+qVOD14T5JN8lRnAyYY3
LdvzQV5kkw3ANhjWiATZ9iBCp24RIUqbKpntY/tikBrHAkYOHfceIDbAYRlgciYT
iCG5Jlxlgymg+0VRm1eED70aSvWBUqOn+zB5EPa1zGkbW13/6TIE33armni/PI2L
3uerYAWOsIdann8y1TOgCjIBrYtj2OhnwtncWD7J5Tnl5pTXqMBu13OnrzzDQP1X
uYLXYhHytiEkK8eO2OKOy3ceIDa7dxdoamFEYDK2OG86EX7+KcE=
=s8xU
-----END PGP SIGNATURE-----
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]