KeyStore and TrustStore

  1. Technically a KeyStore and a TrustStore are of same. They just serve different purposes based on what they contain.
  2. A KeyStore is simply a database or repository or a collection of Certificates or Secret Keys or key pairs. When a KeyStore contains only certificates, you call it a TrustStore.
  3. When you also have Private Keys associated with their corresponding Certificate chain (Key Pair or asymmetric keys), it is called a KeyStore.
  4. Your truststore will be in your JAVA_HOME—> JRE –>lib—> security–> cacerts
  5. ‘cacerts’ is a truststore. A trust store is used to authenticate peers. A keystore is used to authenticate yourself in mutual authentication
  6. cacerts is where Java stores public certificates of root CAs. Java uses cacerts to authenticate the servers.
    Keystore is where Java stores the private keys of the clients so that it can share it to the server when the server requests client authentication.
  7. Keystore is used to store private key and identity certificates that a specific program should present to both parties (server or client) for verification.
    Truststore is used to store certificates from Certified Authorities (CA) that verify the certificate presented by the server in SSL connection.
  8. Mutual authentication requires Keystore and Truststore whereas Server-Client authentication requires truststore to store Certificates from CA.


List the content of your keystore file

keytool -v -list -keystore .keystore

specific alias, you can also specify it in the command

keytool -list -keystore .keystore -alias foo

Importing Certificate to Truststore

keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias Root -import -file Trustedcaroot.txt

When the client communicates with the server over HTTPS either browser or REST call, the server doesn’t care who the client is, as long as they have the correct credentials. This is what happens in Login forms(Asymmetric communication followed by Symmetric Communication).

Two-way SSL is used for places where you only want the server to accept connections from a restricted number of users. It helps to mitigate the risk of fraud in online transactions. Two-way SSL authentication (also known as “mutual authentication”, or “TLS/SSL with client certificates”) where two parties authenticate
each other through verifying provided digital certificates, so that both parties are assured of the other’s identity.

In One-way SSL, where the browser (the client) establishes an SSL connection to a secure web site and the server’s certificate is checked, creating SSL authentication in RESTful web services. The browser either relies on itself or the operating system providing a list of certs that have been designated as trusted Certificate Authorities (CA).

In context to java, Java Key Store is used to store the certs and keys.It must be password protected and entries in it must have an “alias” that is unique. If an alias is not specified, “mykey” is used by default.

KeyStores provide credentials, TrustStores verify credentials.Clients will use certificates stored in their TrustStores to verify identities of servers. They will present certificates stored in their KeyStores to servers requiring them.

The JDK ships with a tool called Keytool. It manages a JKS of cryptographic keys, X.509 certificate chains, and trusted certificates.

//Importing a truststore which could be used by client for server certificate verification
>> keytool -import -v -trustcacerts -keystore client_truststore.jks -storepass apassword -alias server -file foo.snaplogic.com.cert

//Importing a keystore which could be used by client when server asks of identity certificate
>> keytool -importkeystore -srckeystore client-certificate.p12 -srcstoretype pkcs12 -destkeystore client_keystore.jks -deststoretype jks -deststorepass apassword

// Viewing list of servcer certificates in Client Truststore  
>> keytool -list -v -keystore client_truststore.jks

We can now complete configuration of the REST SSL Account by uploading our client_truststore.jks and client_keystore.jks KeyStore files

One way SSL

  1. Client requests for some protected data from the server on HTTPS protocol. This initiates SSL/TLS handshake process.
  2. Server returns its public certificate to the client along with server hello message.
  3. Client validates/verifies the received certificate. Client verifies the certificate through certification authority (CA) for CA signed certificates.
  4. SSL/TLS client sends the random byte string that enables both the client and the server to compute the secret key to be used for encrypting subsequent message data. The random byte string itself is encrypted with the server’s public key.
  5. After agreeing on this secret key, client and server communicate further for actual data transfer by encrypting/decrypting data using this key.

Two way SSL

  1. Client requests a protected resource over HTTPS protocol and the SSL/TSL handshake process begins.
  2. Server returns its public certificate to the client along with server hello.
  3. Client validates/verifies the received certificate. Client verifies the certificate through certification authority (CA) for CA signed certificates.
  4. If Server certificate was validated successfully, client will provide its public certificate to the server.
  5. Server validates/verifies the received certificate. Server verifies the certificate through certification authority (CA) for CA signed certificates.
  6. After completion of handshake process, client and server communicate and transfer data with each other encrypted with the secret keys shared between the two during handshake.

In the below code there might arise a question why we need to do hashing and extract the final secret key from it. The importance of this step could be felt incase we are storing passwords in DBs instead of directly using actual secret key and hashing, the hashing by using message digest adds more strength.

EncryptUtil.java

package com.mugil.org;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;

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

    public static void setKey(String myKey) {
        MessageDigest sha = null;
        try {
            //Byte Arrays are secured compared to storing in String as it is immutable
            key = myKey.getBytes("UTF-8");

            /*
              MessageDigest class represents a cryptographic hash function which can calculate a
              message digest from binary data.A hash function is a mathematical function that 
              converts a numerical input value into another compressed numerical value.The input to 
              the hash function is of arbitrary length but output is always of fixed length.
              Values returned by a hash function are called message digest or simply hash values.
            */

            /*
              Code will work without below two lines but hashing adds more strength to secret key
              AES needs a 128/192/256 bits key. If you don't hash your key and only trim the input it
              would only use the first 16/24/32 Bytes. So generating a Hash is the only reasonable way.
             */
            sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);

            /*Use SHA-1 to generate a hash from your key and trim the result to 128 bit (16 bytes).*/
            key = Arrays.copyOf(key, 16);

            /*Taking Key that would be used for Encrytion */
            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, String secret) {
        try {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
        } catch (Exception e) {
            System.out.println("Error while decrypting: " + e.toString());
        }
        return null;
    }
}

SimpleEncryption.java

package com.mugil.org;

public class SimpleEncryption {
    public static void main(String[] args) {
        final String secretKey = "ItSecretKey";

        String originalString = "You Nailed It!!!";
        String encryptedString = EncryptUtil.encrypt(originalString, secretKey) ;
        String decryptedString = EncryptUtil.decrypt(encryptedString, secretKey) ;

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

You Nailed It!!!
lFY4a0e0BRVfcfko56Lpe78iUfPoZm5wkq/zv0hrFco=
You Nailed It!!!