Encrypt tomcat keystore password

spring boot server.ssl.keystore-password encryption
tomcat encrypt password
java hide keystore password
tomcat certificatekeystorefile
tomcat encrypt ldap password
tomcat 8 ssl configuration
tomcat self-signed certificate
tomcat encryption algorithms

Is there an option to encrypt keystorePass value in tomcat server.xml? I don't want it to be a plain text

    <Connector port="8403" //...
        keystorePass="myPassword" /> 

If someone has access to your server.xml, the plain text value of your keystorePass appearing are only one of your worries.

If someone has access from there, they could do much more harm. Encrypting the password here is really just moving the problem elsewhere as then someone could find the encryption key for this encryption key (a bit like a Russian doll).

If you want to encrypt the password, you have to override the Connector implementation to decrypt the encrypted password so that the real pwd is accessible or available to tomcat.

Chapter 16. Encrypting the Keystore Password in a Tomcat Connector, Configure JaasSecurityDomain MBean. Set the JaasSecurityDomain MBean in the $JBOSS_HOME/server/$PROFILE/deploy/security-service. Encrypting the password here is really just moving the problem elsewhere as then someone could find the encryption key for this encryption key (a bit like a Russian doll). If you want to encrypt the password, you have to override the Connector implementation to decrypt the encrypted password so that the real pwd is accessible or available to tomcat.

There is a better way, than just using the XML encode.

Create an Encryption Class to encrypt and decrypt your password.

And override Http11Nio2Protocol class, something similar to the below code.

 public class Http11Nio2Protocol extends org.apache.coyote.http11.Http11Nio2Protocol {

@Override
public void setKeystorePass(String s) {
    try {
        super.setKeystorePass(new EncryptService().decrypt(s));
    } catch (final Exception e){
        super.setKeystorePass("");
    }
}

}

Note: EncryptService is our own encryption class.

And configure the overridden class in the protocol attribute in server.xml like below.

<Connector port="8443" protocol="<com.mypackage.overridden_Http11Nio2Protocol_class>"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           clientAuth="false" sslProtocol="TLS" 
          keystoreFile="conf/.ssl/keystore.jks"        
           keystorePass="<encrypted_password>"/>

Hope this helps.

Encrypt tomcat keystore password, This means that the keystore/truststore password cannot be passed as an attribute in the connector element of Tomcat's server.xml . A working understanding of  Run this on a single line. In the above example, "abcdefgh" is the Salt and 13 is the iteration count; 'unit-tests-server' is the password of the keystore that you are protecting; and keystore.password is the file in which the encrypted password will be stored.

Faced with same problem. Customer demands to "hide" all passwords.

So, simplest way to pass audit - from Tomcat Wiki.

Go to page http://coderstoolbox.net/string/#!encoding=xml&action=encode&charset=none and encode you pass to XML-view.

Thus - <Connector> element looks like:

<Connector
  port="8443"
  protocol="HTTP/1.1"
  SSLEnabled="true"
  enableLookups="false"
  disableUploadTimeout="true"
  scheme="https"
  secure="true"
  clientAuth="want"
  sslProtocol="TLS"
  keystoreFile="conf/.ssl/keystore.jks"
  keyAlias="tomcat"
  keystorePass="&#99;&#104;&#105;&#107;&#115;"
  truststoreFile="conf/.ssl/trustedstore.jks"
  truststorePass="&#99;&#104;&#105;&#107;&#115;"
/>

How can I encrypt the keystorepass in Tomcat, If someone has access to your server.xml, the plain text value of your keystorePass appearing are only one of your worries. If someone has  To specify the keystore password as plain text on a server component Stop the BMC Atrium Orchestrator services. On the computer for the server component, use a text editor to open the <installationDirectory>/tomcat/conf/server.xml file. Locate the <connector> element that contains the HTTPS protocol information, as shown in the following sample:

We were also facing similar problem but we created our own encryption and decryption logic to tackle this. Here is the code

/* class is used to generate encrypted password */

public class ClientForPasswordGeneration {

    public static void main(String[] args) {
        //final String secretKey = "ssshhhhhhhhhhh!!!!";
        final String secretKey = PasswordKey.getEncryptionKey();
        GenerateLogic object = new GenerateLogic();

        String password = PasswordField.readPassword("Enter password: ");

        String encryptPassword = object.encrypt(password, secretKey);
        System.out.println("Encrypted Password:");
        System.out.println(encryptPassword);

    }

}

Another Class

class EraserThread implements Runnable {
    private boolean stop;

    /**
     * @param The
     *            prompt displayed to the user
     */
    public EraserThread(String prompt) {
        System.out.print(prompt);
    }

    /**
     * Begin masking...display asterisks (*)
     */
    public void run() {
        stop = true;
        while (stop) {

            System.out.print("\010*");

            try {

                Thread.currentThread().sleep(1);
                // System.out.println("current thread::" + Thread.currentThread());
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
    }

    /**
     * Instruct the thread to stop masking
     */
    public void stopMasking() {
        this.stop = false;
    }

}

Logic which generated hashed code

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class GenerateLogic {
    private static SecretKeySpec secretKey;
    private static byte[] key;

    public static void setKey(String myKey) {
        MessageDigest sha = null;
        try {
            key = myKey.getBytes("UTF-8");
            sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16);
            secretKey = new SecretKeySpec(key, "AES");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public static String encrypt(String strToEncrypt, String secret) {
        try {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
        } catch (Exception e) {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;
    }

    public static String decrypt(String strToDecrypt) {
        try {
            //System.out.println("decryptedString methods");
            //String secret = "ssshhhhhhhhhhh!!!!";
            String secret = PasswordKey.getEncryptionKey();
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            //System.out.println("testing string values::" + new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt))));
            return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
        } catch (Exception e) {
            System.out.println("Error while decrypting: " + e.toString());
        }
        return null;
    }

    public static void main(String[] args) {
        final String secretKey = "ssshhhhhhhhhhh!!!!";

        String originalString = "changeit";
        String encryptedString = GenerateLogic.encrypt(originalString, secretKey);
        String decryptedString = GenerateLogic.decrypt(encryptedString);

        System.out.println(originalString);
        System.out.println(encryptedString);
        System.out.println(decryptedString);
    }

}

This is where we extended the class org.apache.coyote.http11.Http11Nio2Protocol which is present in tomcat-coyote-8.0.29.jar which is present in lib folder of tomcat 8. So while compiling these classes tomcat-coyote-8.0.29.jar should be present.

public class Http11Nio2Protocol extends org.apache.coyote.http11.Http11Nio2Protocol {

    @Override
    public void setKeystorePass(String s) {
        try {
            super.setKeystorePass(new GenerateLogic().decrypt(s));
        } catch (final Exception e) {
            super.setKeystorePass("");
        }
    }

}

This is where user has to enter password in cmd which should be hashed

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PasswordField {

    /**
     * @param prompt
     *            The prompt to display to the user
     * @return The password as entered by the user
     */
    public static String readPassword(String prompt) {
        EraserThread et = new EraserThread(prompt);
        Thread mask = new Thread(et);
        mask.start();

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String password = "";

        try {
            password = in.readLine();

        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        // stop masking
        et.stopMasking();
        // return the password entered by the user
        return password;
    }
}

This is where you keep your password key. You should change it.

public class PasswordKey {

    private static String ENCRYPTION_KEY = "myKeysecretkey";

    protected static String getEncryptionKey()
    {
        return ENCRYPTION_KEY;
    }

}

compile above classes to generate class files with below command in cmd. Remember tomcat-coyote-8.0.29.jar should be present in same folder where all the java files are present.

javac  -cp ".;tomcat-coyote-8.0.29.jar" *.java

Make a jar with the generated class file using this command in cmd

jar -cvf  PasswordEncryptor.jar  *.class

This will create a jar file PasswordEncryptor.jar

Paste the generated PasswordEncryptor.jar in lib folder of Tomcat8. i.e. apache-tomcat-8.5.9\lib

Now go to this location and type below command to generate the hashed password.

java -cp ".;PasswordEncryptor.jar" ClientForPasswordGeneration

Now go to apache-tomcat-8.5.9\conf and edit server.xml

Use the hashed password in keystorpasss of certificate

<Connector port="9443" protocol="Http11Nio2Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
        keystoreFile="C:\Certificates\SSLCert.cert" keystorePass="nOS74yuWW4s18TsL2UJ51A=="/>

Notice the protocol is the custom class name.

Hope this will help you.

Thanks

Apache Tomcat 7 (7.0.104), I have see post to encrypt password in web.xml, will same steps work for keystorepass in "appserver/conf/server.xml" keystoreFile="${catalina.home}/​conf/tomcat.key" I looked into ways to encrypt the server.xml keystore and found this:  Encrypt the admin’s password Tomcat comes with a nice little app called the Web Application Manager, which makes it easy to deploy a new war-file. To be able to use the application you have to add an account with the role of “manager-gui”. This is done by adding the following two lines to the conftomcat-users.xml file:

Here's a handy Perl one-liner to XML encode a password:

$ perl -pe 's/(.)/"&#".ord($1).";"/eg;' <<< 'secret'
# &#115;&#101;&#99;&#114;&#101;&#116;

Why the keystore password in , Why the keystore password in server.xml cannot be encrypted and must be Because the clear text password to the keystore is needed by Tomcat in Instead of obfuscating, encoding or trying to encrypt the password it is  Enter the Password to Encrypt including the Pass Phrase. Copy the Generated SecureTomcatJDBC.jar into the $CATALINA_HOME/lib directory. Replace the Factory element in Context.xml with factory=“SecureTomcatDataSourceImpl”. Replace the Encrypted Password in place of Clear Text Password password="ENCRYPTED PASSWORD”.

A simple, step-by-step guide to Apache Tomcat SSL configuration , In order for public key encryption to provide secure communication, one more more of After you choose the keystore password, you will enter the information​  Let’s discuss each step briefly and enforce the password encryption policy for the Tomcat Manager. Here we will discuss about using SHA-256 and MD5 hash algorithms to encrypt the tomcat manager password in Tomcat 8.5.6 and Tomcat 6/7. Step 1. We have to define the password encryption algorithm in the Realm section of server.xml, as in the

Specifying a keystore password, This topic describes how to specify a keystore password on any of the server Due to a limitation of the underlying Tomcat engine, the keypass used Tool, as described in Using the Maintenance Tool to encrypt a password. How to encrypt passwords in the Tomcat server.xml file – Matthew Skelton By default, Tomcat stores passwords in server.xml in clear text, which can lead to obvious security lapses. The easiest way to mitigate against user account compromise is to use a password digest (SHA, MD2 or MD5 are supported).

Mechanism to encrypt the keystore passwords in, Out of the box, keystore passwords in server.xml of Tomcat of Remedy components (midtier, Smart Reporting, MyIT/Smart IT, Remedy SSO) are  Create a Java Keystore (.JKS) from Let's Encrypt Certificates Application server like Jetty, Glassfish or Tomcat need a keystore (.jks) in order to properly handling the certificates. These three simple steps will create a valid keystore file for your application server using the Let's Encrypt service.

Comments
  • Where were you thinking of storing the encryption key to unlock the password to unlock the keystorePass? Just out of interest.
  • I am aware that this is not a simple question. I am asking to know if there is a standard solution.
  • No, there's on standard solution other than maybe overriding the Connector as I mentioned below, but that's in no way a standard solution and more of a down right hack.
  • A small correction - as connectors are final (at least at tomcat 7) it is the protocol one needs to override
  • Could I please Ask you please which protocol one needs to override? and how?
  • I disagree with the above. The whole point of security is a layered defense. In the cloud for example, it is possible to encrypt data and then enable access to the encryption keys via IAM (on aws). Keeping passwords on disk in plain text is just bad security. Such secrets should only ever be in process memory in their decrypted form.
  • Yes, this is exactly what we did. See my comment on the accepted answer.
  • I tried this solution but I get the error: java.lang.ClassNotFoundException: listener.Http11Nio2Protocol.
  • I have implemented that It does not read the method setKeystorePass!!
  • It's not a solutions, It's just encode/decode like Base64/Hex. We should show the password. But nice idea. thanks!