December 20, 2017

Choosing Java Cryptographic Algorithms Part 1 - Hashing

Abstract

This is the 1st of a three-part blog series covering Java cryptographic algorithms. The series covers how to implement the following:

  1. Hashing with SHA–512
  2. Single-key symmetric encryption with AES–256
  3. Public/Private key asymmetric encryption with RSA–4096

This 1st post details how to implement SHA–512 hashing. Let’s get started.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • Java 1.8.0_152_x64
  • NetBeans 8.2 (Build 201609300101)
  • Maven 3.0.5 (Bundled with NetBeans)

Download

Visit my GitHub Page to see all of my open source projects. The code for this post is located in project: thoth-cryptography

Hashing

About

Hashing is a one-way cryptographic algorithm which takes in a message of any length and outputs a repeatable, fixed-length, and one-way digest (hash) of the message. Being one-way, it’s supposed to be impossible to regenerate the original message from the hash. Identical messages will always generate the same hash.

A hash can be used to authenticate an original message. A common use of hashing is validating passwords. Instead of storing the password itself, the hash of the password is stored. To verify a password, the stored hash is compared with a new hash of an incoming password during a login process.

Because identical messages generate the same hash, a salt value is used to make the hash more secure (Salt, 2017, para. 1). Consider a case where the same password is used by multiple users. A salt value combined with the original password allows for unique hash values. This is important because if the hashed values are ever compromised, identical hashes let a hacker know those passwords are the same.

SHA–512

Research done as of today seems to indicate the best and most secure algorithm for hashing is SHA–512, which uses 64-bit words (Secure Hash Algorithms, 2017, para.2). Let’s take a look at an example.

NOTE Don’t use MD5 as a secure hash. It has many vulnerabilities (MD5, 2017, para. 1). Limit MD5 use to checksums and data verification.

Example

Listing 1 is the ShaTest.java unit test demonstrating how to hash. Listing 2 is the Sha.java class which does the hash.

Listing 1 - ShaTest.java class

package org.thoth.security.hash;

import java.util.Optional;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class ShaTest {

    @Test
    public void test_hash_with_optional_to_hex() throws Exception {
        // setup
        String username = "mjremijan";
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asHex
            = sha.hashToHex(password, Optional.of(username));

        // assert
        Assert.assertEquals(
              "F38CD5290D11B20159E36740843A8D93CFDFA395CF594F328613EF5C7BA42D9EAC00BF3EE47B7E8CE1587040B36365F05C8E15E9392C288A1D7C4CFB66097848"
            , asHex);
    }

    @Test
    public void test_hash_without_optional_to_hex() throws Exception {
        // setup
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asHex
            = sha.hashToHex(password, Optional.empty());

        // assert
        Assert.assertEquals(
              "516A1FE9D87FE5B953D91B48B1A2FFA5AE5F670914C1B6FE0835D8877918DC4E8BC8FB8CCD520DBA940C21B4F294DFD1B4EFF2E06AB110C6A06E35068251C1DD"
            , asHex);
    }


    @Test
    public void test_hash_with_optional_to_base64() throws Exception {
        // setup
        String username = "mjremijan";
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asBase64
            = sha.hashToBase64(password, Optional.of(username));

        // assert
        Assert.assertEquals(
              "84ZVKQ0RSGFZ42DAHDQNK8/FO5XPWU8YHHPVXHUKLZ6SAL8+5HT+JOFYCECZY2XWXI4V6TKSKIODFEZ7ZGL4SA=="
            , asBase64);
    }


    @Test
    public void test_hash_without_optional_to_base64() throws Exception {
        // setup
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asBase64
            = sha.hashToBase64(password, Optional.empty());

        // assert
        Assert.assertEquals(
              "UWOF6DH/5BLT2RTISAL/PA5FZWKUWBB+CDXYH3KY3E6LYPUMZVINUPQMIBTYLN/RTO/Y4GQXEMAGBJUGGLHB3Q=="
            , asBase64);
    }
}

Listing 2 - Sha.java class

package org.thoth.security.hash;

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

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class Sha {

    public String hashToHex(String hashMe, Optional<String> salt)
    throws NoSuchAlgorithmException, UnsupportedEncodingException {
        byte[] bytes
            = hash(hashMe, salt);

        StringBuilder sp
            = new StringBuilder();

        for (int i = 0; i < bytes.length; i++) {
            sp.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }

        return sp.toString().toUpperCase();
    }

    public String hashToBase64(String hashMe, Optional<String> salt)
    throws NoSuchAlgorithmException, UnsupportedEncodingException {
        return Base64.getEncoder().encodeToString(
            hash(hashMe, salt)
        ).toUpperCase();
    }

    public byte[] hash(String hashMe, Optional<String> salt)
    throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md
            = MessageDigest.getInstance("SHA-512");

        md.update(hashMe.getBytes("UTF-8"));
        salt.ifPresent(s -> {
            try { md.update(s.getBytes("UTF-8")); } catch (Exception e) {throw new RuntimeException(e);}
        });

        return md.digest();
    }
}

Summary

Hashing is pretty easy. Choose a strong hashing algorithm like SHA–512 for securing your application data. Avoid MD5 for securing data. Stay current as to which algorithms are strong and safe. Update your application if you are using an older algorithm which has vulnerabilities or is compromised.

References

Salt (cryptography). (2017, November 3). Wikipedia. Retrieved from https://en.wikipedia.org/wiki/Salt_(cryptography).

Secure Hash Algorithms. (2017, November 25). Wikipedia. Retrieved from https://en.wikipedia.org/wiki/Secure_Hash_Algorithms.

MD5. (2017, November 22). Wikipedia. Retrieved from https://en.wikipedia.org/wiki/MD5.

October 13, 2017

Double click a Windows batch file (*.bat, *.cmd) and keep the command prompt open

Abstract

This is a quick tip about Windows batch files (.bat, .cmd). I often use these files to setup different development environments; setting environment variables, update %PATH%, different %JAVA_HOME%, etc. Sometimes it can be a challenge to do this, not lose these settings, and keep the command prompt (DOS window) open all at the same time. This is a technique I found which seems to do all this reliably.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Example

This is an example run.cmd file. The basic idea is when you double-click this file, the script will actually call itself again which you can see in the :cmd section. After the script calls itself again, the :run section is where you put the details of your script.

Listing 1 - run.cmd

@echo off

REM Check the value of the 1st command line argument.
REM If the value is empty, go to the 'cmd' section
IF "%~1" == ""    GOTO cmd

REM Check the value of the 1st command line argument.
REM If the value is "run", go to the 'run' section
IF "%~1" == "run" GOTO run

REM If the 1st command line argument is not empty,
REM but not the value "run" then just 'end' because
REM this script doesn't know how to handle it.
ECHO Command line argument "%1" is not understood.
GOTO end

:cmd
REM In this section, use the %0 value in order to 
REM have this script call itself again.  By calling
REM itself with `cmd /K` you get a command prompt 
REM (DOS window) which won't automatically close
REM when this script is finished executing.
ECHO In the 'cmd' section
ECHO Script file=%0
cmd /K "%0 run"
GOTO end

:run
REM In this section, this is where you want to put
REM the work of your script.  You can execute whatever
REM you need and even call other scripts.  The
REM command prompt window will remain open because
REM of what the 'cmd' section does.
ECHO In the 'run' section

SET SOME_PROPERTY=foo
ECHO SOME_PROPERTY=%SOME_PROPERTY%

ECHO call env.cmd
call "%~dp0\env.cmd"

ECHO ENV_PROPERTY_1=%ENV_PROPERTY_1%
ECHO ENV_PROPERTY_2=%ENV_PROPERTY_2%
ECHO ENV_PROPERTY_3=%ENV_PROPERTY_3%

:end

Summary

That’s it. Really easy. Enjoy!