2 way encryption with MD5 DES

Standard

Data encryption standard (DES) is a old way of encrypting data. It effectively encrypts data to a unreadable string; however it should be noted that it is not secure. The following code is for demonstration purposes only and should not be implemented as a security protocol. DES is a breakable algorithm smaller key, and block size than a advanced encryption standard (AES) algorithm.

Use case

A user is prompted to enter some non sensitive data. For the sake of this example lets assume we have a requirement that the user telephone number must be encrypted. The user enters a phone number and the encode method secures the data for storage in the database. Upon rendering back to the end user the data is translated using the decode method.

public class MD5andDES {

    // A user chosen password used for the PEKeySpec. Once set do not change or all previously encoded data will be lost
    private static final char[] PBEKeyPassword = "nviowefjklaasdlkjweklnvq".toCharArray();

    // Private salt for PBE algorithm
    private static final byte[] PBESALT = {(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12, (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12};

    /**
     * Takes in a string which is then salted with a given password used for the
     * 2 way encryption
     *
     * @param data
     * @return
     * @throws GeneralSecurityException
     * @throws UnsupportedEncodingException
     */
    public static String encode(String data) throws GeneralSecurityException, UnsupportedEncodingException {

        // Get algorithm to use
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");

        // Generates a secretKey object from the provided key specification
        SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PBEKeyPassword));

        // Returns a cipher object that implements the specified transformation
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

        // Initializes cipher with public key
        pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(PBESALT, 20));

        // Returns the cipher encoded to a 64bit string (aka base64 encoded). getBytes() forms a new byte array
        return DatatypeConverter.printBase64Binary(pbeCipher.doFinal(data.getBytes("UTF-8")));
    }

    /**
     * Takes in encrypted data and uses the salt to decrypt it to its original
     * state
     *
     * @param data
     * @return
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public static String decode(String data) throws GeneralSecurityException, IOException {

        // Get algorithm to use
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");

        // Generates a secretKey object from the provided key specification
        SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PBEKeyPassword));

        // Returns a cipher object that implements the specified transformation
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

        // Initializes cipher with public key
        pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(PBESALT, 20));

        // Returns a string of the orignally encrypted data
        return new String(pbeCipher.doFinal(DatatypeConverter.parseBase64Binary((data))), "UTF-8");
    }

}

A complete working copy with test cases is available for checkout on Github.

PBKDF2 with HMAC-SHA1 encryption class

Standard

Sensitive user data must insure confidentiality and integrity. The following class is a example of how to use a password based key derivation function (PBKDF2) algorithm to encode / decode data. Using the createHash method a salt and hash byte array is generated from a instance of the PBKDF2WithHmacSHA1 from the secretKeyFactory. The byte arrays that are returned serve as your encrypted data. You must have both to be able to validate.

Use case

A user signs up for a account on your website. They enter a username / password. The password that is entered is ran against the createHash method. The result (salt, hash) are stored in a database. This is the users login data encrypted. Whenever a user attempts to login with that username, the salt and hash are retrieved from the database and the validatePassword method is called. If the test passes you are assured they are a legitimate user and may proceed.

What is slowEquals?

When a password is validated it requires that slowEquals be true. SlowEquals is a method designed to prevent against timing attacks. What this does is assure that the attacker cannot determine how long it took for the password to fail. It iterates through all values in the byte array regardless if they are equal or not. This prevents the attacker from having enough information compute a off line attack.

public class HmacSHA1 {

    // Used in encryption for how many cycles
    private static final int PBKDF2_ITERATIONS = 2000;
    private static final Integer checkLoops = 10;
    private static final String password = "changeit";

    /**
     * Typical test case to assure that Encoding / Decoding / Encryption work
     * properly
     *
     * @param args
     */
    public static void main(String[] args) {

        System.out.println("Encryption Test\n");
        
        for (int i = 0; i <= checkLoops; i++) {
            
             try {
                // Create has in the form of (salt:hash)
                String hash = createHash(password);
                String[] params = hash.split(":");
                byte[] salt = fromHex(params[0]);
                byte[] hash5 = fromHex(params[1]);

                // Compare our generated bytes to the orignal
                if (validatePassword(password, hash5, salt)) {
                    System.out.println("valid password!");
                }
            } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
                System.out.println("ERROR: " + ex);
            }
        }
    }

    /**
     * Validates a password using a hash.
     *
     * @param password the password to check
     * @param hash
     * @param salt
     * @return true if the password is correct, false if not
     * @throws java.security.NoSuchAlgorithmException
     * @throws java.security.spec.InvalidKeySpecException
     */
    public static boolean validatePassword(char[] password, byte[] hash, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {

        // Compute the hash of the provided password, using the same salt, iteration count, and hash length
        byte[] testHash = pbkdf2(password, salt, PBKDF2_ITERATIONS, hash.length);

        // Compare the hashes in constant time. The password is correct if both hashes match.
        return slowEquals(hash, testHash);
    }

    /**
     * Validates a password using a hash.
     *
     * @param password the password to check
     * @param hash
     * @param salt
     * @return true if the password is correct, false if not
     * @throws java.security.NoSuchAlgorithmException
     * @throws java.security.spec.InvalidKeySpecException
     */
    public static boolean validatePassword(String password, byte[] hash, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {

        return validatePassword(password.toCharArray(), hash, salt);
    }

    /**
     * Computes the PBKDF2 hash of a password.
     *
     * @param password the password to hash.
     * @param salt the salt
     * @param iterations the iteration count (slowness factor)
     * @param bytes the length of the hash to compute in bytes
     * @return the PBDKF2 hash of the password
     */
    private static byte[] pbkdf2(final char[] password, final byte[] salt, final int iterationCount, final int keyLength) {

        try {
            return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(password, salt, iterationCount, keyLength * 8)).getEncoded();
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Returns a salted PBKDF2 hash of the password.
     *
     * @param password the password to hash
     * @return a salted PBKDF2 hash of the password
     * @throws java.security.NoSuchAlgorithmException
     * @throws java.security.spec.InvalidKeySpecException
     */
    public static String createHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
        return createHash(password.toCharArray());
    }

    /**
     * Returns a salted PBKDF2 hash of the password.
     *
     * @param password the password to hash
     * @return a salted PBKDF2 hash of the password in the form of SALT:HASH
     * @throws java.security.NoSuchAlgorithmException
     * @throws java.security.spec.InvalidKeySpecException
     */
    public static String createHash(char[] password) throws NoSuchAlgorithmException, InvalidKeySpecException {

        // Generate a random salt
        byte[] salt = getSalt().getBytes();

        // Hash the password
        byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, 24);

        // Format salt:hash
        return toHex(salt) + ":" + toHex(hash);
    }

    /**
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    private static String getSalt() throws NoSuchAlgorithmException {
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        byte[] salt = new byte[16];
        sr.nextBytes(salt);
        return Arrays.toString(salt);
    }

    /**
     * Converts a byte array into a hexadecimal string.
     *
     * @param array the byte array to convert
     * @return a length*2 character string encoding the byte array
     */
    private static String toHex(byte[] array) {

        BigInteger bi = new BigInteger(1, array);
        String hex = bi.toString(16);
        int paddingLength = (array.length * 2) - hex.length();
        if (paddingLength > 0) {
            return String.format("%0" + paddingLength + "d", 0) + hex;
        } else {
            return hex;
        }
    }

    /**
     * Converts a string of hexadecimal characters into a byte array.
     *
     * @param hex the hex string
     * @return the hex string decoded into a byte array
     */
    public static byte[] fromHex(String hex) {

        byte[] binary = new byte[hex.length() / 2];
        for (int i = 0; i < binary.length; i++) {
            binary[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
        }
        return binary;
    }

    /**
     * Compares two byte arrays in length-constant time. This comparison method
     * is used so that password hashes cannot be extracted from an on-line
     * system using a timing attack and then attacked off-line.
     *
     * @param a the first byte array
     * @param b the second byte array
     * @return true if both byte arrays are the same, false if not
     */
    private static boolean slowEquals(byte[] a, byte[] b) {

        int diff = a.length ^ b.length;
        for (int i = 0; i < a.length && i < b.length; i++) {
            diff |= a[i] ^ b[i];
        }
        return diff == 0;
    }

}

The complete project is available on Github.

Protecting against POODLE attack in Tomcat 7

Standard

What is a POODLE attack?

The internet has been a buzz with security issues this year such as Heartbleed, and Shellshock. POODLE is no different and effects almost every server on the internet. This exploit is done by performing a man in the middle attack and relying on the clients software to fallback to SSL 3.0. The result is an attacker can make around 250 SSL 3.0 requests and decrypt one byte of encrypted data.

What is the solution?

It is very simple to patch the vulnerability in Tomcat 7. This assumes that your CRT and Key file are already configured. Check your server.xml file and assure that you have set the sslEnabledProtocols to the following:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslEnabledProtocols = "TLSv1,TLSv1.1,TLSv1.2" />

Now restart your tomcat server and check if you are secure. Lots of simple tools exist to check your sites security.

JAAS login module in Tomcat 7 example (Part 2)

Standard

Part 1 of this tutorial demonstrated how to implement a login module using JAAS + Tomcat 7. This next segment shows how to create a login form and call the login module.

Folder Structure:

/login.xhtml
/error.xhtml
/protected/index.html (protected via our web.xml file)

Simple JSF login page

The following is a simple form used to submit the username and password to a backing bean called loginBean. The form uses HTML5 passthrough elements, as well as built in JSF validators on the input fields. All errors are displayed using the h:messages output.

<h:form>
    <h3>Please sign in</h3>
    <h:inputText id="username" value="#{loginBean.username}" required="true" requiredMessage="Please enter your username" p:placeholder="Username" p:autofocus="true">
        <f:validateLength maximum="50" minimum="3" />
    </h:inputText>

    <h:inputSecret id="password" value="#{loginBean.password}" required="true" requiredMessage="Enter your password" p:placeholder="Password">
        <f:validateLength maximum="20" minimum="3" />
    </h:inputSecret>

    <h:messages/>

    <h:commandButton type="submit" value="Sign in" id="submit" action="#{loginBean.login()}"/>
</h:form>

Calling the login module

Once the form passes validation the login() action is called. The login action uses the submitted username / password to request a login from the servlet container. This will call the login module created in part 1 of this tutorial. If the request.login() servlet request fails, it throws a LoginException which is caught in the form of a ServletException below. If the login succeeds then the user is redirected to the protected page.

@ManagedBean(name = "loginBean")
@ViewScoped
public class LoginBean implements Serializable {
    
    private static final long serialVersionUID = 1L;

    private String username;
    private String password;

    /**
     *
     * @return
     */
    public String login() {

        try {

            // Get the current servlet request from the facesContext
            FacesContext ctx = FacesContext.getCurrentInstance();
            HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();

            // Do login from the container (will call login module)
            request.login(username, password);

            return "/protected/index.xhtml?faces-redirect=true";

        } catch (ServletException ex) {

            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "An Error Occured: Login failed", null));
            Logger.getLogger(LoginBean.class.getName()).log(Level.SEVERE, null, ex);
        }

        return "login.xhtml";
    }

    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

}

This concludes the configuration and implementation of JAAS container managed security. The original working copy of the complete project is available on Github.

JAAS login module in Tomcat 7 example (Part 1)

Standard

Implementing a login module using JAAS is an excellent way to secure URL’s in a web application. In this tutorial, it will walk through the steps in configuring JAAS authentication in Tomcat 7 using the form based authentication method.

Before looking at the code is it important to understand the purpose of JAAS authentication. JAAS or Java Authentication and Authorization Service is an optional package designed to work in a pluggable fashion. The JAAS component comes standard with many other servers such as Glassfish, Wildfly, and Jetty. Once the user is authorized, the JAAS component controls access to sensitive resources. In this article we will secure sensitive resources by URL patterns.

Understanding Principals

JAAS relies on users and roles to authorize the access to certain resources. In JAAS, the users and roles are separated into Principals. The separated Principals all represent the Subject identity. The Subject is an entity, such as a person or service. Lets begin by defining our user and roles Principals.

package com.sixthpoint.jaas;

import java.security.Principal;

/**
 * Holds the logged in users name
 *
 * @author sixthpoint
 */
public class UserPrincipal implements Principal {

    private String name;

    /**
     * Initializer
     *
     * @param name
     */
    public UserPrincipal(String name) {
        super();
        this.name = name;
    }

    /**
     * Set the name of the user
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Get the name of the user
     *
     * @return
     */
    @Override
    public String getName() {
        return name;
    }
}
package com.sixthpoint.jaas;

import java.security.Principal;

/**
 * Holds a single role name that the user is in
 *
 * @author sixthpoint
 */
public class RolePrincipal implements Principal {

    private String name;

    /**
     * Initializer
     *
     * @param name
     */
    public RolePrincipal(String name) {
        super();
        this.name = name;
    }

    /**
     * Set the role name
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Get the role name
     *
     * @return
     */
    @Override
    public String getName() {
        return name;
    }
}

Note the simplicity of the Principals. They both are similar and only require a name for referencing.

The Custom Login Module

The Login module must implement the javax.security.auth.spi.LoginModule interface. It is by inheritance that it will override the following methods:

  • initialize() – all options are loaded at this time, options can be configured in the jaas.conf file later in the tutorial
  • login() – used to perform verification logic
  • commit() – invoked after successful authentication from the login() method
  • abort() – called if something goes wrong with the login() or commit() methods
  • logout() – clears the Subject

The login module accepts the inputs from the end user and verifies they are valid through the login() method. The verification can be made in any number of ways: checking a database, a LDAP, remote API, etc. It is up to the developer to define the requirements for verification. For the purpose of this tutorial we are only verifying that the end user has entered values for the username / password. Once the verification is successful; roles are attached to the verified user. These roles are used for restricting access to resource locations in the web.xml. If an error occurs during the verification process or the assigning of roles the login() method must throw a LoginException. This will be gracefully handled by our application later in the tutorial.

The commit() method is invoked after a successful verification from the login() method. A UserPrincipal and all RolePrincipals associated with the verified user are stored in the Subject. The Subject is accessible in the javax.security.auth.Subject instance for the container managed security.

The final two methods are self explanatory. The logout() method clears all the subjects principals (user information). The abort() method nullifies the inputs (username / password), and principals if the commit failed but the user is authenticated. However, if the user is not verified or the commit() did succeed, then a standard logout() is performed.

public class CustomLoginModule implements LoginModule {

    private CallbackHandler handler;
    private Subject subject;
    private UserPrincipal userPrincipal;
    private RolePrincipal rolePrincipal;
    private List<String> userGroups;
    private Map options;
    private Map sharedState;

    // Configurable option
    private boolean debug = false;

    // Logger used to output debug information
    private static final Logger logger = Logger.getLogger(CustomLoginModule.class.getName());

    // User credentials
    private String username = null;
    private String password = null;

    private boolean isAuthenticated = false;
    private boolean commitSucceeded = false;

    /**
     * Constructor
     */
    public CustomLoginModule() {
        super();
    }

    /**
     * Initializer
     *
     * @param subject
     * @param callbackHandler
     * @param sharedState
     * @param options
     */
    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {

        // Store the handler
        this.handler = callbackHandler;

        // Subject reference holds the principals
        this.subject = subject;

        this.options = options;
        this.sharedState = sharedState;

        // Setup a logging class / state
        if ("true".equalsIgnoreCase((String) options.get("debug"))) {
            ConsoleHandler consoleHandler = new ConsoleHandler();
            logger.addHandler(consoleHandler);
            debug = true;
        }
    }

    /**
     *
     * @return @throws LoginException
     */
    @Override
    public boolean login() throws LoginException {

        // If no handler is specified throw a error
        if (handler == null) {
            throw new LoginException("Error: no CallbackHandler available to recieve authentication information from the user");
        }

        // Declare the callbacks based on the JAAS spec
        Callback[] callbacks = new Callback[2];
        callbacks[0] = new NameCallback("login");
        callbacks[1] = new PasswordCallback("password", true);

        try {

            //Handle the callback and recieve the sent inforamation
            handler.handle(callbacks);
            username = ((NameCallback) callbacks[0]).getName();
            password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());

            // Debug the username / password
            if (debug) {
                logger.log(Level.INFO, "Username: {0}", username);
                logger.log(Level.INFO, "Password: {0}", password);
            }

            // We should never allow empty strings to be passed
            if (username == null || username.isEmpty() || password == null || password.isEmpty()) {
                throw new LoginException("Data specified had null values");
            }

            // Validate against our database or any other options (this check is a example only)
            if (username != null && password != null) {

                // Assign the user roles
                userGroups = this.getRoles();
                isAuthenticated = true;

                return true;
            }

            throw new LoginException("Authentication failed");

        } catch (IOException | UnsupportedCallbackException e) {
            throw new LoginException(e.getMessage());
        }

    }

    /**
     * Adds the username / roles to the principal
     *
     * @return @throws LoginException
     */
    @Override
    public boolean commit() throws LoginException {

        if (!isAuthenticated) {
            return false;
        } else {

            userPrincipal = new UserPrincipal(username);
            subject.getPrincipals().add(userPrincipal);

            if (userGroups != null && userGroups.size() > 0) {
                for (String groupName : userGroups) {
                    rolePrincipal = new RolePrincipal(groupName);
                    subject.getPrincipals().add(rolePrincipal);
                }
            }

            commitSucceeded = true;

            return true;
        }
    }

    /**
     * Terminates the logged in session on error
     *
     * @return @throws LoginException
     */
    @Override
    public boolean abort() throws LoginException {
        if (!isAuthenticated) {
            return false;
        } else if (isAuthenticated && !commitSucceeded) {
            isAuthenticated = false;
            username = null;
            password = null;
            userPrincipal = null;
        } else {
            logout();
        }
        return true;
    }

    /**
     * Logs the user out
     *
     * @return @throws LoginException
     */
    @Override
    public boolean logout() throws LoginException {
        isAuthenticated = false;
        isAuthenticated = commitSucceeded;
        subject.getPrincipals().clear();
        return true;
    }

    /**
     * Returns list of roles assigned to authenticated user.
     *
     * @return
     */
    private List<String> getRoles() {

        List<String> roleList = new ArrayList<>();
        roleList.add("admin");

        return roleList;
    }

}

 

Structuring the web application

Enabling the module above requires 3 files to be configured. Once complete this will secure access to the specified folder on the Java web application.

Begin by editing the context.xml file and defining the JAAS realm. This example uses the default JAASRealm for defining the user and role Principal classes which we defined above as UserPrincipal and RolePrincipal. The appName attribute is used to define which security module Tomcat will look to use.

<Context antiJARLocking="true" path="" reloadable="true">
    <Realm appName="CustomLogin" className="org.apache.catalina.realm.JAASRealm" roleClassNames="com.sixthpoint.jaas.RolePrincipal" userClassNames="com.sixthpoint.jaas.UserPrincipal"/>
</Context>

Finally, for the web application to load the security configuration a jaas.config file must be defined. This file will inform Tomcat what class file to load when processing login requests. Note that CustomLogin mirrors our appName in the context.xml. The CustomLoginModule is referenced from our java class above.

CustomLogin {
    com.sixthpoint.jaas.CustomLoginModule required debug=true;
};

Tomcat needs to know where the application security configuration file is located (jaas.config). A JVM argument needs to be added to the catalina.sh file. On server startup the server will load the custom login module.

JAVA_OPTS="-Djava.security.auth.login.config==$CATALINA_BASE/conf/jaas.config"

Securing Resource Locations

To prevent access to certain resource location the web.xml needs modification. Any number of security constraints can be added to map to resource locations. The auth-constraint can have multiple roles as shown.

<!-- URL constraints -->
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Admin</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>staff</role-name>
    </auth-constraint>
    <user-data-constraint>
        <!-- transport-guarantee can be CONFIDENTIAL, INTEGRAL, or NONE -->
        <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
</security-constraint>
<!-- What roles are allowed -->
<security-role>
    <role-name>admin</role-name>
    <role-name>staff</role-name>
</security-role>
<!-- Force login by form -->
<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <form-login-page>/login.xhtml</form-login-page>
        <form-error-page>/error.xhtml</form-error-page>
    </form-login-config>
</login-config>

This concludes the setup / configuration of JAAS on a java web application. The next tutorial demonstrates how to implement a JSF login page with JAAS.

A full copy of the complete project is available on Github.