-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

All,

Can I get a technical review for (a) appropriateness and (b) technical
implementation of the attached cluster interceptor? Let's assume for a
moment that encryption is something worth adding to clustering and not
argue that point.

It should be straightforward. Knowing virtually nothing about the way
that Tribes works, implementing this as an interceptor seemed like the
least invasive (and easiest!) way to add encryption to clustering.

The only question I have about what I've actually written is what to
do about the cipher IV? Both sides of the conversation need to know
the IV in order to communicate. Should I just add another member to
the class for the IV and require that users specify both the key AND
the IV?

Thanks,
- -chris
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlvPKqsACgkQHPApP6U8
pFgGSxAAy1vj8FY7uzcvstimHwUGKd6dJkFiKRxygY30Lp3bHor5O4GKoWP4eWwJ
l0rl0ojvhgLzHwPB/+Cdm1gpZD2cSSiqyz3V6eGlt8oq8mm3M4lCMqZqXckNHYG5
cSRHXPIO0XaoCrUR2KA4NRS207OXTUYZe7ihPb0Bblev5SE/S/vIArRs+1Gybdi+
zYXY4XwBUHRHu2PzWy6c0HFPP3hDJ85I3Mn4O/uqZgh01eRRpsfvbmros45znTfc
frKqBeT3O/+dwNOX9HhshnIW92U8dyYto70CsKdtPrsVXpY9kQH3zOc3vC+UN2qf
jJZYie32mHjg22JDrYOqFpfAhTQi9r4xUMzprMVjTk93p34SxvmZNbLBVi/Li6OA
PdthMBpHiAQp+bLVGSU4UbHdEG9t/Ixp8RodWJzxGWtduy3/GGCsifQke5H6yBf5
Kb3Rux4u/3mKwn0PZL8HljUgEZCge3g1+KOX1qL9Uw5TCKm4YIF744C1P7piSllR
GW3UxamATH4qmZ/ccAUJVBgdQQYPjVKAc0tAvCVBZSxf6+OB8D5HfA/A8f8N7Fzj
wBVPbcW5d4OjFpjEshOtehb74q1WAGhg1+rUkPbd1Nkd/WTQN8YXXayN0+TE28gm
LPSv8RSsAEWFLzh/TiY8BNzdehEaHID6R6h5q7io9JNMbtljhgQ=
=nSgU
-----END PGP SIGNATURE-----
/*
 * 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.Key;
import javax.crypto.Cipher;
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.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.
 */
public class EncryptInterceptor extends ChannelInterceptorBase {

    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 Key encryptionKey;

    private Cipher encryptionCipher;
    private Cipher decryptionCipher;

    public EncryptInterceptor() {
    }

    @Override
    public void start(int svc) throws ChannelException {
        super.start(svc);

        if(Channel.SND_TX_SEQ == svc) {
            try {
                initCiphers();
            } catch (GeneralSecurityException gse) {
                log.fatal(sm.getString("encryptInterceptor.init.failed"));
                throw new 
ChannelException(sm.getString("encryptInterceptor.init.failed"), gse);
            }
        }
    }

    @Override
    public void sendMessage(Member[] destination, ChannelMessage msg, 
InterceptorPayload payload)
            throws ChannelException {
        try {
            byte[] data = msg.getMessage().getBytes();

            data = encrypt(data);

            msg.getMessage().trim(msg.getMessage().getLength());
            msg.getMessage().append(data,0,data.length);

            super.sendMessage(destination, msg, payload);

        } catch (GeneralSecurityException gse) {
            log.error(sm.getString("encryptInterceptor.encrypt.failed"));
            throw new ChannelException(gse);
        }
    }


    @Override
    public void messageReceived(ChannelMessage msg) {
        try {
            byte[] data = msg.getMessage().getBytes();

            data = decrypt(data);

            msg.getMessage().trim(msg.getMessage().getLength());
            msg.getMessage().append(data,0,data.length);

            super.messageReceived(msg);
        } catch (GeneralSecurityException gse) {
            log.error(sm.getString("encryptInterceptor.decrypt.failed"), gse);
        }
    }

    public void setEncryptionAlgorithm(String algorithm) {
        encryptionAlgorithm = algorithm;
    }

    public String getEncryptionAlgorithm() {
        return encryptionAlgorithm;
    }

    public void setEncryptionKey(byte[] key) {
        encryptionKey = new SecretKeySpec(key, getEncryptionAlgorithm());
    }

    public void setEncryptionKey(String keyBytes) {
        setEncryptionKey(HexUtils.fromHexString(keyBytes));
    }

    private Key getEncryptionKey() {
        return encryptionKey;
    }

    public void setProviderName(String provider) {
        providerName = provider;
    }

    public String getProviderName() {
        return providerName;
    }

    private void initCiphers() throws GeneralSecurityException {
        if(null == getEncryptionAlgorithm())
            throw new 
IllegalStateException(sm.getString("encryptInterceptor.algorithm.required"));
        if(null == getEncryptionKey())
            throw new 
IllegalStateException(sm.getString("encryptInterceptor.key.required"));

        Cipher cipher = Cipher.getInstance(getEncryptionAlgorithm(), 
getProviderName());

        IvParameterSpec IV = null; // TODO: determine how to solve the IV 
problem

        cipher.init(Cipher.ENCRYPT_MODE, getEncryptionKey(), IV);

        encryptionCipher = cipher;

        cipher = Cipher.getInstance(getEncryptionAlgorithm(), 
getProviderName());

        cipher.init(Cipher.DECRYPT_MODE, getEncryptionKey(), IV);

        decryptionCipher = cipher;
    }

    private Cipher getEncryptionCipher() {
        return encryptionCipher;
    }

    private byte[] encrypt(byte[] bytes) throws GeneralSecurityException {
        return getEncryptionCipher().doFinal(bytes);
    }

    private Cipher getDecryptionCipher() throws GeneralSecurityException {
        return decryptionCipher;
    }

    private byte[] decrypt(byte[] bytes) throws GeneralSecurityException {
        return getDecryptionCipher().doFinal(bytes);
    }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to