2323import java .security .SecureRandom ;
2424import java .security .spec .AlgorithmParameterSpec ;
2525import java .util .Locale ;
26- import java .util .Map ;
27- import java .util .concurrent .ConcurrentHashMap ;
2826import java .util .concurrent .ConcurrentLinkedQueue ;
29- import java .util .concurrent .atomic .AtomicLong ;
3027
3128import javax .crypto .Cipher ;
3229import javax .crypto .NoSuchPaddingException ;
4239import org .apache .catalina .tribes .group .ChannelInterceptorBase ;
4340import org .apache .catalina .tribes .group .InterceptorPayload ;
4441import org .apache .catalina .tribes .io .XByteBuffer ;
45- import org .apache .catalina .tribes .util .CyclicTracker ;
4642import org .apache .catalina .tribes .util .StringManager ;
4743import org .apache .juli .logging .Log ;
4844import org .apache .juli .logging .LogFactory ;
@@ -67,7 +63,6 @@ public class EncryptInterceptor extends ChannelInterceptorBase implements Encryp
6763 private String encryptionAlgorithm = DEFAULT_ENCRYPTION_ALGORITHM ;
6864 private byte [] encryptionKeyBytes ;
6965 private String encryptionKeyString ;
70- private int replayWindowSize = 1024 ;
7166
7267
7368 private BaseEncryptionManager encryptionManager ;
@@ -85,7 +80,7 @@ public void start(int svc) throws ChannelException {
8580 if (Channel .SND_TX_SEQ == (svc & Channel .SND_TX_SEQ )) {
8681 try {
8782 encryptionManager = createEncryptionManager (getEncryptionAlgorithm (), getEncryptionKeyInternal (),
88- getProviderName (), getReplayWindowSize () );
83+ getProviderName ());
8984 } catch (GeneralSecurityException gse ) {
9085 throw new ChannelException (sm .getString ("encryptInterceptor.init.failed" ), gse );
9186 }
@@ -119,12 +114,9 @@ public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPay
119114 throws ChannelException {
120115 try {
121116 byte [] data = msg .getMessage ().getBytes ();
122- byte [] message = new byte [data .length + 8 ];
123- XByteBuffer .toBytes (encryptionManager .getAndIncrementMessageNumber (), message , 0 );
124- System .arraycopy (data , 0 , message , 8 , data .length );
125117
126118 // See #encrypt(byte[]) for an explanation of the return value
127- byte [][] bytes = encryptionManager .encrypt (message );
119+ byte [][] bytes = encryptionManager .encrypt (data );
128120
129121 XByteBuffer xbb = msg .getMessage ();
130122
@@ -147,34 +139,19 @@ public void messageReceived(ChannelMessage msg) {
147139 byte [] data = msg .getMessage ().getBytes ();
148140
149141 data = encryptionManager .decrypt (data );
150- if (data .length < 8 ) {
151- throw new GeneralSecurityException (sm .getString ("encryptInterceptor.decrypt.error.short-message" ));
152- }
153- if (!encryptionManager .checkIncomingMessageNumber (msg .getAddress (), XByteBuffer .toLong (data , 0 ))) {
154- log .error (sm .getString ("encryptInterceptor.decrypt.replay" ));
155- return ;
156- }
157142
158143 XByteBuffer xbb = msg .getMessage ();
159144
160145 // Completely replace the message with the decrypted one
161146 xbb .clear ();
162- xbb .append (data , 8 , data .length - 8 );
147+ xbb .append (data , 0 , data .length );
163148
164149 super .messageReceived (msg );
165150 } catch (GeneralSecurityException gse ) {
166151 log .error (sm .getString ("encryptInterceptor.decrypt.failed" ), gse );
167152 }
168153 }
169154
170- @ Override
171- public void memberDisappeared (Member member ) {
172- if (encryptionManager != null ) {
173- encryptionManager .memberDisappeared (member );
174- }
175- super .memberDisappeared (member );
176- }
177-
178155 /**
179156 * Sets the encryption algorithm to be used for encrypting and decrypting channel messages. You must specify the
180157 * <code>algorithm/mode/padding</code>. Information on standard algorithm names may be found in the
@@ -297,36 +274,6 @@ public String getProviderName() {
297274 return providerName ;
298275 }
299276
300- /**
301- * Returns the number of message sequence numbers remembered for replay detection.
302- *
303- * @return The replay window size
304- */
305- @ Override
306- public int getReplayWindowSize () {
307- return replayWindowSize ;
308- }
309-
310- /**
311- * Sets the number of message sequence numbers remembered for replay detection.
312- *
313- * @param replayWindowSize The replay window size
314- */
315- @ Override
316- public void setReplayWindowSize (int replayWindowSize ) {
317- if (replayWindowSize < 1 ) {
318- throw new IllegalArgumentException (sm .getString ("encryptInterceptor.replayWindow.tooSmall" ));
319- }
320- this .replayWindowSize = replayWindowSize ;
321- }
322-
323- Long getRemovedMemberHeadValue (Member member ) {
324- if (encryptionManager == null ) {
325- return null ;
326- }
327- return encryptionManager .getRemovedMemberHeadValue (member );
328- }
329-
330277 // Copied from org.apache.tomcat.util.buf.HexUtils
331278 // @formatter:off
332279 private static final int [] DEC = {
@@ -373,8 +320,7 @@ private static byte[] fromHexString(String input) {
373320 }
374321
375322 private static BaseEncryptionManager createEncryptionManager (String algorithm , byte [] encryptionKey ,
376- String providerName , int replayWindowSize )
377- throws NoSuchAlgorithmException , NoSuchPaddingException , NoSuchProviderException {
323+ String providerName ) throws NoSuchAlgorithmException , NoSuchPaddingException , NoSuchProviderException {
378324 if (null == encryptionKey ) {
379325 throw new IllegalStateException (sm .getString ("encryptInterceptor.key.required" ));
380326 }
@@ -413,7 +359,8 @@ private static BaseEncryptionManager createEncryptionManager(String algorithm, b
413359 */
414360 if ("NONE" .equals (algorithmMode ) || "ECB" .equals (algorithmMode ) || "PCBC" .equals (algorithmMode ) ||
415361 "CTS" .equals (algorithmMode ) || "KW" .equals (algorithmMode ) || "KWP" .equals (algorithmMode ) ||
416- "CTR" .equals (algorithmMode ) || ("CBC" .equals (algorithmMode ) && "NOPADDING" .equals (algorithmPadding )) ||
362+ "CTR" .equals (algorithmMode ) ||
363+ ("CBC" .equals (algorithmMode ) && "NOPADDING" .equals (algorithmPadding )) ||
417364 ("CFB" .equals (algorithmMode ) && "NOPADDING" .equals (algorithmPadding )) ||
418365 ("GCM" .equals (algorithmMode ) && "PKCS5PADDING" .equals (algorithmPadding )) ||
419366 ("OFB" .equals (algorithmMode ) && "NOPADDING" .equals (algorithmPadding ))) {
@@ -428,18 +375,17 @@ private static BaseEncryptionManager createEncryptionManager(String algorithm, b
428375
429376 } else if (algorithmMode .startsWith ("CFB" ) || algorithmMode .startsWith ("OFB" )) {
430377 // Using a non-default block size. Not supported as insecure and/or inefficient.
431- throw new IllegalArgumentException (sm .getString ("encryptInterceptor.algorithm.unsupported" , algorithm ));
378+ throw new IllegalArgumentException (
379+ sm .getString ("encryptInterceptor.algorithm.unsupported" , algorithm ));
432380
433381 } else if ("GCM" .equals (algorithmMode ) && "NOPADDING" .equals (algorithmPadding )) {
434382 // Needs a specialised encryption manager to handle the differences between GCM and other modes
435- return new GCMEncryptionManager (algorithm , new SecretKeySpec (encryptionKey , algorithmName ), providerName ,
436- replayWindowSize );
383+ return new GCMEncryptionManager (algorithm , new SecretKeySpec (encryptionKey , algorithmName ), providerName );
437384 }
438385
439386 // Use the default encryption manager
440387 try {
441- return new BaseEncryptionManager (algorithm , new SecretKeySpec (encryptionKey , algorithmName ), providerName ,
442- replayWindowSize );
388+ return new BaseEncryptionManager (algorithm , new SecretKeySpec (encryptionKey , algorithmName ), providerName );
443389 } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException ex ) {
444390 throw new IllegalArgumentException (sm .getString ("encryptInterceptor.algorithm.unsupported" , algorithm ), ex );
445391 }
@@ -477,80 +423,24 @@ private static class BaseEncryptionManager {
477423 * SecureRandom is thread-safe, but sharing a single instance will likely be a bottleneck.
478424 */
479425 private final ConcurrentLinkedQueue <SecureRandom > randomPool ;
480- private final AtomicLong messageNumberGenerator = new AtomicLong ();
481- private final Map <Member ,CyclicTracker > receivedMessageNumbersByMember = new ConcurrentHashMap <>();
482- private final Map <Member ,Long > messageNumbersByRemovedMember = new ConcurrentHashMap <>();
483- private final CyclicTracker receivedMessageNumbersForUnknownSender ;
484- private final int replayWindowSize ;
485426
486- BaseEncryptionManager (String algorithm , SecretKeySpec secretKey , String providerName , int replayWindowSize )
427+ BaseEncryptionManager (String algorithm , SecretKeySpec secretKey , String providerName )
487428 throws NoSuchAlgorithmException , NoSuchPaddingException , NoSuchProviderException {
488429 this .algorithm = algorithm ;
489430 this .providerName = providerName ;
490431 this .secretKey = secretKey ;
491- this .replayWindowSize = replayWindowSize ;
492432
493433 cipherPool = new ConcurrentLinkedQueue <>();
494434 Cipher cipher = createCipher ();
495435 blockSize = cipher .getBlockSize ();
496436 cipherPool .offer (cipher );
497437 randomPool = new ConcurrentLinkedQueue <>();
498- receivedMessageNumbersForUnknownSender = new CyclicTracker (replayWindowSize );
499438 }
500439
501440 public void shutdown () {
502441 // Individual Cipher and SecureRandom objects need no explicit tear down
503442 cipherPool .clear ();
504443 randomPool .clear ();
505- receivedMessageNumbersByMember .clear ();
506- messageNumbersByRemovedMember .clear ();
507- }
508-
509- public long getAndIncrementMessageNumber () {
510- return messageNumberGenerator .getAndIncrement ();
511- }
512-
513- public boolean checkIncomingMessageNumber (Member sender , long messageNumber ) {
514- if (sender == null ) {
515- return receivedMessageNumbersForUnknownSender .track (messageNumber );
516- }
517- return receivedMessageNumbersByMember .computeIfAbsent (sender , this ::createTrackerForMember )
518- .track (messageNumber );
519- }
520-
521- public void memberDisappeared (Member member ) {
522- CyclicTracker tracker = receivedMessageNumbersByMember .remove (member );
523- if (tracker != null ) {
524- /*
525- * There is a security trade off here.
526- *
527- * Entries are only removed from this Map if the Member reappears. That means there is a potential DoS
528- * risks due to the growth of this Map. That is considered unlikely as only Members with the encryption
529- * key will be added to this Map and the size of the Map.Entry is minimal.
530- *
531- * If entries are removed from this Map based either on Map size or time, that exposes the risk of a
532- * replay attack using any message the Member may have previously sent.
533- *
534- * The replay attack is viewed as the higher risk, hence there are no limits on the size of this Map.
535- */
536- messageNumbersByRemovedMember .put (member , Long .valueOf (tracker .getHeadValue ()));
537- }
538- }
539-
540- public Long getRemovedMemberHeadValue (Member member ) {
541- return messageNumbersByRemovedMember .get (member );
542- }
543-
544- private CyclicTracker createTrackerForMember (Member member ) {
545- CyclicTracker tracker = new CyclicTracker (replayWindowSize );
546- Long headValue = messageNumbersByRemovedMember .remove (member );
547- if (headValue == null ) {
548- // This is a new member. First valid message will be 0. Therefore set last message to -1.
549- tracker .track (-1 );
550- } else {
551- tracker .track (headValue .longValue ());
552- }
553- return tracker ;
554444 }
555445
556446 private String getAlgorithm () {
@@ -721,9 +611,9 @@ protected AlgorithmParameterSpec generateIV(byte[] ivBytes, int offset, int leng
721611 * number of bits supported 128-bit provide the best security.
722612 */
723613 private static class GCMEncryptionManager extends BaseEncryptionManager {
724- GCMEncryptionManager (String algorithm , SecretKeySpec secretKey , String providerName , int replayWindowSize )
614+ GCMEncryptionManager (String algorithm , SecretKeySpec secretKey , String providerName )
725615 throws NoSuchAlgorithmException , NoSuchPaddingException , NoSuchProviderException {
726- super (algorithm , secretKey , providerName , replayWindowSize );
616+ super (algorithm , secretKey , providerName );
727617 }
728618
729619 @ Override
0 commit comments