Author: schultz Date: Mon Oct 29 18:11:57 2018 New Revision: 1845157 URL: http://svn.apache.org/viewvc?rev=1845157&view=rev Log: Add EncryptInterceptor for clustering.
Added: tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptorMBean.java tomcat/trunk/test/org/apache/catalina/tribes/group/interceptors/TestEncryptInterceptor.java Modified: tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/LocalStrings.properties tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/cluster-interceptor.xml Added: tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java?rev=1845157&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java (added) +++ tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java Mon Oct 29 18:11:57 2018 @@ -0,0 +1,356 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.tribes.group.interceptors; + +import java.security.GeneralSecurityException; +import java.security.SecureRandom; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.catalina.tribes.Channel; +import org.apache.catalina.tribes.ChannelException; +import org.apache.catalina.tribes.ChannelMessage; +import org.apache.catalina.tribes.Member; +import org.apache.catalina.tribes.group.ChannelInterceptorBase; +import org.apache.catalina.tribes.group.InterceptorPayload; +import org.apache.catalina.tribes.io.XByteBuffer; +import org.apache.catalina.tribes.util.StringManager; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.buf.HexUtils; + +/** + * Adds encryption using a pre-shared key. + * + * The length of the key (in bytes) must be acceptable for the encryption + * algorithm being used. For example, for AES, you must use a key of either + * 16 bytes (128 bits, 24 bytes 192 bits), or 32 bytes (256 bits). + * + * You can supply the raw key bytes by calling {@link #setEncryptionKey(byte[])} + * or the hex-encoded binary bytes by calling + * {@link #setEncryptionKey(String)}. + */ +public class EncryptInterceptor extends ChannelInterceptorBase implements EncryptInterceptorMBean { + + private static final Log log = LogFactory.getLog(EncryptInterceptor.class); + protected static final StringManager sm = StringManager.getManager(EncryptInterceptor.class); + + private static final String DEFAULT_ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding"; + + private String providerName; + private String encryptionAlgorithm = DEFAULT_ENCRYPTION_ALGORITHM; + private byte[] encryptionKeyBytes; + + private Cipher encryptionCipher; + private Cipher decryptionCipher; + + public EncryptInterceptor() { + } + + @Override + public void start(int svc) throws ChannelException { + if(Channel.SND_TX_SEQ == (svc & Channel.SND_TX_SEQ)) { + try { + initCiphers(); + } catch (GeneralSecurityException gse) { + log.fatal(sm.getString("encryptInterceptor.init.failed")); + throw new ChannelException(sm.getString("encryptInterceptor.init.failed"), gse); + } + } + + super.start(svc); + } + + @Override + public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) + throws ChannelException { + try { + byte[] data = msg.getMessage().getBytes(); + + // See #encrypt(byte[]) for an explanation of the return value + byte[][] bytes = encrypt(data); + + XByteBuffer xbb = msg.getMessage(); + + // Completely replace the message + xbb.setLength(0); + xbb.append(bytes[0], 0, bytes[0].length); + xbb.append(bytes[1], 0, bytes[1].length); + + super.sendMessage(destination, msg, payload); + + } catch (IllegalBlockSizeException ibse) { + log.error(sm.getString("encryptInterceptor.encrypt.failed")); + throw new ChannelException(ibse); + } catch (BadPaddingException bpe) { + log.error(sm.getString("encryptInterceptor.encrypt.failed")); + throw new ChannelException(bpe); + } + } + + @Override + public void messageReceived(ChannelMessage msg) { + try { + byte[] data = msg.getMessage().getBytes(); + + data = decrypt(data); + + // Remove the decrypted IV/nonce block from the front of the message + int blockSize = getDecryptionCipher().getBlockSize(); + int trimmedSize = data.length - blockSize; + if(trimmedSize < 0) { + log.error(sm.getString("encryptInterceptor.decrypt.error.short-message")); + throw new IllegalStateException(sm.getString("encryptInterceptor.decrypt.error.short-message")); + } + + XByteBuffer xbb = msg.getMessage(); + + // Completely replace the message with the decrypted one + xbb.setLength(0); + xbb.append(data, blockSize, data.length - blockSize); + + super.messageReceived(msg); + } catch (IllegalBlockSizeException ibse) { + log.error(sm.getString("encryptInterceptor.decrypt.failed"), ibse); + } catch (BadPaddingException bpe) { + log.error(sm.getString("encryptInterceptor.decrypt.failed"), bpe); + } + } + + /** + * Sets the encryption algorithm to be used for encrypting and decrypting + * channel messages. You must specify the <code>algorithm/mode/padding</code>. + * Information on what standard algorithm names are, please see + * {@link https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html}. + * + * Default is <code>AES/CBC/PKCS5Padding</code>. + * + * @param algorithm The algorithm to use. + */ + public void setEncryptionAlgorithm(String algorithm) { + if(null == getEncryptionAlgorithm()) + throw new IllegalStateException(sm.getString("encryptInterceptor.algorithm.required")); + + int pos = algorithm.indexOf('/'); + if(pos < 0) + throw new IllegalArgumentException(sm.getString("encryptInterceptor.algorithm.required")); + pos = algorithm.indexOf('/', pos + 1); + if(pos < 0) + throw new IllegalArgumentException(sm.getString("encryptInterceptor.algorithm.required")); + + encryptionAlgorithm = algorithm; + } + + /** + * Gets the encryption algorithm being used to encrypt and decrypt channel + * messages. + * + * @return The algorithm being used, including the algorithm mode and padding. + */ + public String getEncryptionAlgorithm() { + return encryptionAlgorithm; + } + + /** + * Sets the encryption key for encryption and decryption. The length of the + * key must be appropriate for the algorithm being used. + * + * @param key The encryption key. + */ + public void setEncryptionKey(byte[] key) { + if(null == key) + key = null; + else + encryptionKeyBytes = key.clone(); + } + + /** + * Gets the encryption key being used for encryption and decryption. + * The key is encoded using hex-encoding where e.g. the byte <code>0xab</code> + * will be shown as "ab". The length of the string in characters will + * be twice the length of the key in bytes. + * + * @return The encryption key. + */ + public void setEncryptionKey(String keyBytes) { + if(null == keyBytes) + setEncryptionKey((byte[])null); + else + setEncryptionKey(HexUtils.fromHexString(keyBytes.trim())); + } + + /** + * Gets the encryption key being used for encryption and decryption. + * + * @return The encryption key. + */ + public byte[] getEncryptionKey() { + byte[] key = getEncryptionKeyInternal(); + + if(null != key) + key = key.clone(); + + return key; + } + + private byte[] getEncryptionKeyInternal() { + return encryptionKeyBytes; + } + + /** + * Sets the JCA provider name used for cryptographic activities. + * + * Default is the JVM platform default. + * + * @param provider The name of the JCA provider. + */ + public void setProviderName(String provider) { + providerName = provider; + } + + /** + * Gets the JCA provider name used for cryptographic activities. + * + * Default is the JVM platform default. + * + * @return The name of the JCA provider. + */ + public String getProviderName() { + return providerName; + } + + private void initCiphers() throws GeneralSecurityException { + if(null == getEncryptionKey()) + throw new IllegalStateException(sm.getString("encryptInterceptor.key.required")); + + String algorithm = getEncryptionAlgorithm(); + + String mode = getAlgorithmMode(algorithm); + + if(!"CBC".equalsIgnoreCase(mode)) + throw new IllegalArgumentException(sm.getString("encryptInterceptor.algorithm.requires-cbc-mode", mode)); + + Cipher cipher; + + String providerName = getProviderName(); + if(null == providerName) { + cipher = Cipher.getInstance(algorithm); + } else { + cipher = Cipher.getInstance(algorithm, getProviderName()); + } + + 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); + + IvParameterSpec IV = new IvParameterSpec(iv); + + // If this is a cipher transform of the form ALGO/MODE/PAD, + // take just the algorithm part. + int pos = algorithm.indexOf('/'); + + String bareAlgorithm; + if(pos >= 0) { + bareAlgorithm = algorithm.substring(0, pos); + } else { + bareAlgorithm = algorithm; + } + + SecretKeySpec encryptionKey = new SecretKeySpec(getEncryptionKey(), bareAlgorithm); + + cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, IV); + + encryptionCipher = cipher; + + if(null == providerName) { + cipher = Cipher.getInstance(algorithm); + } else { + cipher = Cipher.getInstance(algorithm, getProviderName()); + } + + cipher.init(Cipher.DECRYPT_MODE, encryptionKey, new IvParameterSpec(iv)); + + decryptionCipher = cipher; + } + + private Cipher getEncryptionCipher() { + return encryptionCipher; + } + + private Cipher getDecryptionCipher() { + return decryptionCipher; + } + + private static String getAlgorithmMode(String algorithm) { + int start = algorithm.indexOf('/'); + if(start < 0) + throw new IllegalArgumentException(sm.getString("encryptInterceptor.algorithm.required")); + int end = algorithm.indexOf('/', start + 1); + if(start < 0) + throw new IllegalArgumentException(sm.getString("encryptInterceptor.algorithm.required")); + + return algorithm.substring(start + 1, end); + } + + /** + * Encrypts the input <code>bytes</code> into two separate byte arrays: + * one for the initial block (which will be the encrypted random IV) + * and the second one containing the actual encrypted payload. + * + * This method returns a pair of byte arrays instead of a single + * concatenated one to reduce the number of byte buffers created + * and copied during the whole operation -- including message re-building. + * + * @param bytes The data to encrypt. + * + * @return The encrypted IV block in [0] and the encrypted data in [1]. + * + * @throws GeneralSecurityException If there is a problem performing the encryption. + */ + private byte[][] encrypt(byte[] bytes) throws IllegalBlockSizeException, BadPaddingException { + Cipher cipher = getEncryptionCipher(); + + // Adding the IV to the beginning of the encrypted data + byte[] iv = cipher.getIV(); + + byte[][] data = new byte[2][]; + data[0] = cipher.update(iv, 0, iv.length); + data[1] = cipher.doFinal(bytes); + + return data; + } + + /** + * Decrypts the input <code>bytes</code>. + * + * @param bytes The data to decrypt. + * + * @return The decrypted data. + * + * @throws GeneralSecurityException If there is a problem performing the decryption. + */ + private byte[] decrypt(byte[] bytes) throws IllegalBlockSizeException, BadPaddingException { + return getDecryptionCipher().doFinal(bytes); + } +} Added: tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptorMBean.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptorMBean.java?rev=1845157&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptorMBean.java (added) +++ tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptorMBean.java Mon Oct 29 18:11:57 2018 @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.tribes.group.interceptors; + +public interface EncryptInterceptorMBean { + + // Config + public int getOptionFlag(); + public void setOptionFlag(int optionFlag); + + public void setEncryptionAlgorithm(String algorithm); + public String getEncryptionAlgorithm(); + public void setEncryptionKey(byte[] key); + public byte[] getEncryptionKey(); + public void setProviderName(String provider); + public String getProviderName(); +} Modified: tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/LocalStrings.properties?rev=1845157&r1=1845156&r2=1845157&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/LocalStrings.properties [UTF-8] (original) +++ tomcat/trunk/java/org/apache/catalina/tribes/group/interceptors/LocalStrings.properties [UTF-8] Mon Oct 29 18:11:57 2018 @@ -73,4 +73,11 @@ throughputInterceptor.report=ThroughputI \n\tRx Speed:{8} MB/sec (since 1st msg)\ \n\tReceived:{9} MB]\n twoPhaseCommitInterceptor.originalMessage.missing=Received a confirmation, but original message is missing. Id:[{0}] -twoPhaseCommitInterceptor.heartbeat.failed=Unable to perform heartbeat on the TwoPhaseCommit interceptor. \ No newline at end of file +twoPhaseCommitInterceptor.heartbeat.failed=Unable to perform heartbeat on the TwoPhaseCommit interceptor. +encryptInterceptor.init.failed=Failed to initialize EncryptInterceptor +encryptInterceptor.encrypt.failed=Failed to encrypt message +encryptInterceptor.decrypt.failed=Failed to decrypt message +encryptInterceptor.decrypt.error.short-message=Failed to decrypt message: premature end-of-message +encryptInterceptor.algorithm.required=Encryption algorithm is required, fully-specified e.g. AES/CBC/PKCS5Padding +encryptInterceptor.key.required=Encryption key is required +encryptInterceptor.algorithm.requires-cbc-mode=EncryptInterceptor only supports CBC cipher modes, not [{0}] \ No newline at end of file Added: tomcat/trunk/test/org/apache/catalina/tribes/group/interceptors/TestEncryptInterceptor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/tribes/group/interceptors/TestEncryptInterceptor.java?rev=1845157&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/catalina/tribes/group/interceptors/TestEncryptInterceptor.java (added) +++ tomcat/trunk/test/org/apache/catalina/tribes/group/interceptors/TestEncryptInterceptor.java Mon Oct 29 18:11:57 2018 @@ -0,0 +1,191 @@ +package org.apache.catalina.tribes.group.interceptors; + +import static org.junit.Assert.*; + +import java.nio.charset.StandardCharsets; +import org.apache.catalina.tribes.Channel; +import org.apache.catalina.tribes.ChannelException; +import org.apache.catalina.tribes.ChannelInterceptor; +import org.apache.catalina.tribes.ChannelMessage; +import org.apache.catalina.tribes.Member; +import org.apache.catalina.tribes.group.ChannelInterceptorBase; +import org.apache.catalina.tribes.group.InterceptorPayload; +import org.apache.catalina.tribes.io.ChannelData; +import org.apache.catalina.tribes.io.XByteBuffer; +import org.apache.tomcat.util.buf.HexUtils; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests the EncryptInterceptor. + * + * Many of the tests in this class use strings as input and output, even + * though the interceptor actually operates on byte arrays. This is done + * for readability for the tests and their outputs. + */ +public class TestEncryptInterceptor { + private static final String encryptionKey128 = HexUtils.toHexString("cafebabedeadbeef".getBytes(StandardCharsets.UTF_8)); + private static final String encryptionKey192 = HexUtils.toHexString("cafebabedeadbeefbeefcafe".getBytes(StandardCharsets.UTF_8)); + private static final String encryptionKey256 = HexUtils.toHexString("cafebabedeadbeefcafebabedeadbeef".getBytes(StandardCharsets.UTF_8)); + + EncryptInterceptor src; + EncryptInterceptor dest; + + @Before + public void setup() { + src = new EncryptInterceptor(); + src.setEncryptionKey(encryptionKey128); + + dest = new EncryptInterceptor(); + dest.setEncryptionKey(encryptionKey128); + + src.setNext(new PipedInterceptor(dest)); + dest.setPrevious(new ValueCaptureInterceptor()); + } + + @Test + public void testBasic() throws Exception { + src.start(Channel.SND_TX_SEQ); + dest.start(Channel.SND_TX_SEQ); + + String testInput = "The quick brown fox jumps over the lazy dog."; + + assertEquals("Basic roundtrip failed", + testInput, + roundTrip(testInput, src, dest)); + } + + @Test + public void testTinyPayload() throws Exception { + src.start(Channel.SND_TX_SEQ); + dest.start(Channel.SND_TX_SEQ); + + String testInput = "x"; + + assertEquals("Tiny payload roundtrip failed", + testInput, + roundTrip(testInput, src, dest)); + } + + @Test + public void testHugePayload() throws Exception { + src.start(Channel.SND_TX_SEQ); + dest.start(Channel.SND_TX_SEQ); + + byte[] bytes = new byte[1073741824]; // 1MiB, all zeros + + assertArrayEquals("Tiny payload roundtrip failed", + bytes, + roundTrip(bytes, src, dest)); + } + + @Test + public void testCustomProvider() throws Exception { + src.setProviderName("SunJCE"); // Explicitly set the provider name + dest.setProviderName("SunJCE"); + src.start(Channel.SND_TX_SEQ); + dest.start(Channel.SND_TX_SEQ); + + String testInput = "The quick brown fox jumps over the lazy dog."; + + assertEquals("Failed to set custom provider name", + testInput, + roundTrip(testInput, src, dest)); + } + + @Test + public void test192BitKey() throws Exception { + src.setEncryptionKey(encryptionKey192); + dest.setEncryptionKey(encryptionKey192); + src.start(Channel.SND_TX_SEQ); + dest.start(Channel.SND_TX_SEQ); + + String testInput = "The quick brown fox jumps over the lazy dog."; + + assertEquals("Failed to set custom provider name", + testInput, + roundTrip(testInput, src, dest)); + } + + @Test + public void test256BitKey() throws Exception { + src.setEncryptionKey(encryptionKey256); + dest.setEncryptionKey(encryptionKey256); + src.start(Channel.SND_TX_SEQ); + dest.start(Channel.SND_TX_SEQ); + + String testInput = "The quick brown fox jumps over the lazy dog."; + + assertEquals("Failed to set custom provider name", + testInput, + roundTrip(testInput, src, dest)); + } + + /** + * Actually go through the interceptor's send/receive message methods. + */ + private static String roundTrip(String input, EncryptInterceptor src, EncryptInterceptor dest) throws Exception { + byte[] bytes = input.getBytes("UTF-8"); + + bytes = roundTrip(bytes, src, dest); + + return new String(((ValueCaptureInterceptor)dest.getPrevious()).getValue(), "UTF-8"); + } + + /** + * Actually go through the interceptor's send/receive message methods. + */ + private static byte[] roundTrip(byte[] input, EncryptInterceptor src, EncryptInterceptor dest) throws Exception { + ChannelData msg = new ChannelData(false); + msg.setMessage(new XByteBuffer(input, false)); + src.sendMessage(null, msg, null); + + return ((ValueCaptureInterceptor)dest.getPrevious()).getValue(); + } + + /** + * Interceptor that delivers directly to a destination. + */ + private static class PipedInterceptor + extends ChannelInterceptorBase + { + private ChannelInterceptor dest; + + public PipedInterceptor(ChannelInterceptor dest) { + if(null == dest) + throw new IllegalArgumentException("Destination must not be null"); + + this.dest = dest; + } + + @Override + public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) + throws ChannelException { + dest.messageReceived(msg); + } + } + + /** + * Interceptor that simply captures the latest message sent to or received by it. + */ + private static class ValueCaptureInterceptor + extends ChannelInterceptorBase + { + private byte[] value; + + @Override + public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) + throws ChannelException { + value = msg.getMessage().getBytes(); + } + + @Override + public void messageReceived(ChannelMessage msg) { + value = msg.getMessage().getBytes(); + } + + public byte[] getValue() { + return value; + } + } +} Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1845157&r1=1845156&r2=1845157&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Mon Oct 29 18:11:57 2018 @@ -131,6 +131,12 @@ the <code>Endpoint</code> rather than a local field that could end up out of sync. (markt) </scode> + <add> + Add EncryptInterceptor to the portfolio of available clustering + interceptors. This adds symmetric encryption of session data + to Tomcat clustering regardless of the type of cluster manager + or membership being used. (schultz) + </add> </changelog> </subsection> <subsection name="Coyote"> Modified: tomcat/trunk/webapps/docs/config/cluster-interceptor.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/cluster-interceptor.xml?rev=1845157&r1=1845156&r2=1845157&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/cluster-interceptor.xml (original) +++ tomcat/trunk/webapps/docs/config/cluster-interceptor.xml Mon Oct 29 18:11:57 2018 @@ -36,7 +36,7 @@ <section name="Introduction"> <p> Apache Tribes supports an interceptor architecture to intercept both messages and membership notifications. - This architecture allows decoupling of logic and opens the way for some very kewl feature add ons. + This architecture allows decoupling of logic and opens the way for some very useful feature add ons. </p> </section> @@ -54,6 +54,7 @@ <li><code>org.apache.catalina.tribes.group.interceptors.FragmentationInterceptor</code></li> <li><code>org.apache.catalina.tribes.group.interceptors.GzipInterceptor</code></li> <li><code>org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor</code></li> + <li><code>org.apache.catalina.tribes.group.interceptors.EncryptInterceptor</code></li> </ul> </section> @@ -196,6 +197,33 @@ </attribute> </attributes> </subsection> + <subsection name="org.apache.catalina.tribes.group.interceptors.EncryptInterceptor Attributes"> + <p> + The EncryptInterceptor adds encryption to the channel messages carrying + session data between nodes. Added in Tomcat 9.0.13. + </p> + <attributes> + <attribute name="encryptionAlgorithm" required="false"> + The encryption algorithm to be used, including the mode and padding. Please see + <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html</a> + for the standard JCA names that can be used. + + The <i>mode</i> is currently required to be <code>CBC</code>. + + The length of the key will specify the flavor of the encryption algorithm + to be used, if applicable (e.g. AES-128 versus AES-256). + + The default algorithm is <code>AES/CBC/PKCS5Padding</code>. + </attribute> + <attribute name="encryptionKey" required="true"> + The key to be used with the encryption algorithm. + + The key should be specified as hex-encoded bytes of the appropriate + length for the algorithm (e.g. 16 bytes / 32 characters / 128 bits for + AES-128, 32 bytes / 64 characters / 256 bits for AES-256, etc.). + </attribute> + </attributes> + </subsection> </section> <section name="Nested Components"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org