javaencryptionsshsshj

Set allowed transport and MAC ciphers for SSHClient


I'm trying to modify an SSH client using SSHJ so that it only allows certain ciphers. I have properties in a properties file something like this:

sftp.transport.ciphers = aes256-gcm,aes256-ctr,aes256-etcera
sftp.mac.ciphers = hmac-sha3-512,...

Using Jsch limiting ciphers used would be like so:

session.setConfig("cipher.s2c", sftpTransportCiphers);
session.setConfig("cipher.c2s", sftpTransportCiphers);

I've been combing through the docs for SSHJ and at this point I've run around in circles a bit and probably missed something, so best to just ask. I'm not seeing a clean way to take a comma-delimited string and turn it into a list of ciphers as SSHJ would recognize it.

A simple example with SSHJ's SSHClient configured similarly to the JSCH version above would be greatly appreciated.


Solution

  • For future reference/anyone else who wants a quick solution, here's a derived class from DefaultConfig, as suggested by @Robert.

        import net.schmizz.sshj.DefaultConfig;
        import net.schmizz.sshj.common.Factory;
        import net.schmizz.sshj.common.LoggerFactory;
        import net.schmizz.sshj.transport.cipher.*;
        import net.schmizz.sshj.transport.mac.MAC;
        import org.slf4j.Logger;
    
        import java.util.Arrays;
        import java.util.List;
        import java.util.Properties;
        import java.util.stream.Collectors;
    
        public class MyConfig extends DefaultConfig {
            private Logger logger;
    
            public MyConfig() {
                super();
                setLoggerFactory(LoggerFactory.DEFAULT);
            }
    
            @Override
            void setLoggerFactory(LoggerFactory loggerFactory) {
                super.setLoggerFactory(loggerFactory);
                logger = loggerFactory.getLogger(getClass());
            }
    
            public void setTransportCiphers(String input) {
                String[] ciphers = input.trim().split(",");
                List<String> factoryNames = Factory.Named.Util.getNames(getCipherFactories());
    
                List<Factory.Named<Cipher>> transportCiphers = Arrays.stream(ciphers)
                    .filter(factoryNames::contains)
                    .map(cipher -> Factory.Named.Util.get(getCipherFactories(), cipher))
                    .collect(Collectors.toList());
    
                logger.info("Client-side cipher factories set to: {}", transportCiphers);
    
                setCipherFactories(transportCiphers);
            }
    
            public void setMacCiphers(String input) {
                String[] ciphers = input.trim().split(",");
                List<String> factoryNames = Factory.Named.Util.getNames(getMACFactories());
    
                List<Factory.Named<MAC>> macCiphers = Arrays.stream(ciphers)
                    .filter(factoryNames::contains)
                    .map(mac -> Factory.Named.Util.get(getMACFactories(), mac))
                    .collect(Collectors.toList());
    
                logger.info(Client-side MAC factories set to: {}", Factory.Named.Util.getNames(macCiphers));
    
                setMACFactories(macCiphers);
            }
        }