December 30, 2017

JDBC Connections Cheat Sheet

Abstract

This is a quick reference for JDBC connections for common databases. I seem to have to lookup this information a lot, so I figured it be good to have a reference all in one place.

Derby

<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derbyclient</artifactId>
    <version>10.11.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derby</artifactId>
    <version>10.11.1.1</version>
    <scope>test</scope>
</dependency>

Embedded (in-memory)

Class.forName("org.apache.derby.jdbc.EmbeddedDriver");

String connectionUrl
    = "jdbc:derby:C:/My Databases/Derby/Test;user=;password=;create=true";

Connection conn
    = DriverManager.getConnection(connectionUrl);

Remote

Class.forName("org.apache.derby.jdbc.ClientDriver");

String connectionUrl
    = "jdbc:derby://localhost:1527/widget";

String user = "sa";
String pass = "sa";

Connection conn
    = DriverManager.getConnection(connectionUrl, user, pass);

PostgeSQL

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.1.4.jre7</version>
    <scope>test</scope>
</dependency>
Class.forName("org.postgresql.Driver");

String connectionUrl
    = "jdbc:postgresql://localhost:5432/widget";

String user = "widgetapp";
String pass = "widgetapp";

Connection conn
    = DriverManager.getConnection(connectionUrl, user, pass);

Oracle

Download JDBC drivers from http://www.oracle.com/technetwork/database/features/jdbc/index.html

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.4</version>
    <scope>system</scope>
    <systemPath>${basedir}/lib/ojdbc6.jar</systemPath>
</dependency>
Class.forName("oracle.jdbc.driver.OracleDriver");

String SID
    = "xe";

String connectionUrl
    = "jdbc:oracle:thin:@localhost:1521:" + SID;

String user = "hr";
String pass = "hr";

Connection conn
    = DriverManager.getConnection(connectionUrl, user, pass);

Summary

That’s it…enjoy!

December 22, 2017

Java EE Deployment Descriptor and XML Reference

Abstract

This is a quick reference for the most used Java EE deployment descriptors and XML documents. Most developers do not know the versions of these files change with EE versions and that EE servers use the versions of these files to determine what EE standard to apply to your application. So, as you migrate your application to newer application servers, make sure to update the versions of the Java EE deployment descriptors and XML documents to take advantage of the new EE features.

web.xml

<!-- EE 8 -->
<web-app version="4.0"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee  http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
<!-- EE 7 -->
<web-app version="3.1" 
         xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<!-- EE 6 -->
<web-app  version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> 

beans.xml

<!-- EE 8 -->
<beans version="2.0" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" bean-discovery-mode="all">
<!-- EE 7 -->             
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
<!-- EE 6 -->    
<beans 
xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd" -->

Summary

That’s it…enjoy!

Choosing Java Cryptographic Algorithms Part 3 - Public/Private key asymmetric encryption

Abstract

This is the 3rd 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 3rd post details how to implement public/private key, asymmetric, RSA–4096 encryption. 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

Asymmetric Encryption

About

Asymmetric algorithms are based on 2 keys: a public key and a private key. The public key is responsible for encryption and the private key is responsible for decryption. The public key can be freely distributed. With the public key, any client can encrypt a message which only you - with the private key - can decrypt (Asymmetric algorithms, n.d. para. 3).

Asymmetric algorithms are the workhorse of the Internet. Protocols like SSH, OpenPGP, SSL, and TLS rely on asymmetric algorithms (Rouse, 2016, para. 2). Anyone who uses a web browser for something like online banking inherently knows the importance of asymmetric algorithms.

Research done as of today seems to indicate the best and most secure public/private key, asymmetric, encryption algorithm is the following (Sheth, 2017, “Choosing the correct algorithm”, para.2):

  1. Algorithm: RSA
  2. Mode: ECB // It’s really NONE but ECB is needed to get Java to work.
  3. Padding: OAEPWithSHA–512AndMGF1Padding
  4. Key size: 4096 bit

RSA isn’t a block cipher so ECB mode doesn’t make much sense, but, ECB is needed to make Java work even though the mode isn’t used under the covers (Brightwell, 2015). OAEP provides a high level of randomness and padding. Let’s take a look at an example.

Example

Listing 1 is the RsaTest.java unit test. It is a full demonstration on the following:

  1. Generate and store an RSA 4096-bit key
  2. RSA Encryption
  3. RSA Decryption

Listing 2 shows RsaKeyPairProducer.java. This is a helper class which is responsible for producing a new KeyPair. The KeyPair contains both the PublicKey and PrivateKey.

Listing 3 shows RsaPrivateKeyProducer.java. This is a helper class which is responsible for reproducing a PrivateKey from a byte[].

Listing 4 shows RsaPublicKeyProducer.java. This is a helper class which is responsible for reproducing a PublicKey from a byte[].

Listing 5 shows ByteArrayWriter.java and Listing 6 shows ByteArrayReader.java. These are helper classes responsible for reading and writing a byte[] to a file. It’s up to you to determine how to store the byte[] of your keys, but it needs to be stored securely somewhere (file, database, git repository, etc.).

Listing 7 shows RsaEncrypter.java. This is a helper class which is responsible for encryption.

Finally, listing 8 shows RsaDecrypter.java. This is a helper class which is responsible for decryption.

Listing 1 - RsaTest.java class

package org.thoth.crypto.asymmetric;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.thoth.crypto.io.ByteArrayReader;
import org.thoth.crypto.io.ByteArrayWriter;

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

    static Path privateKeyFile;
    static Path publicKeyFile;

    @BeforeClass
    public static void beforeClass() throws Exception {

        // Store the PrivateKey and PublicKey bytes in the ./target
        // diretory. Do this so it will be ignore by source control.
        // We don't want this file committed.
        privateKeyFile
            = Paths.get("./target/RsaPrivate.key").toAbsolutePath();
        publicKeyFile
            = Paths.get("./target/RsaPublic.key").toAbsolutePath();

        // Create KeyPair for RSA
        KeyPair keyPair
            = new RsaKeyPairProducer().produce();

        // Store the PrivateKey bytes. This is what
        // you want to keep absolutely safe
        {
            ByteArrayWriter writer = new ByteArrayWriter(privateKeyFile);
            writer.write(keyPair.getPrivate().getEncoded());
        }

        // Store the PublicKey bytes.  This you
        // can freely distribute so others can
        // encrypt messages which you can then
        // decrypt with the PrivateKey you keep safe.
        {
            ByteArrayWriter writer = new ByteArrayWriter(publicKeyFile);
            writer.write(keyPair.getPublic().getEncoded());
        }
    }


    @Test
    public void encrypt_and_decrypt() throws Exception {
        // setup
        PrivateKey privateKey
            = new RsaPrivateKeyProducer().produce(
                new ByteArrayReader(privateKeyFile).read()
            );

        PublicKey publicKey
            = new RsaPublicKeyProducer().produce(
                new ByteArrayReader(publicKeyFile).read()
            );

        RsaDecrypter decrypter
            = new RsaDecrypter(privateKey);

        RsaEncrypter encrypter
            = new RsaEncrypter(publicKey);

        String toEncrypt
            = "encrypt me";

        // run
        byte[] encryptedBytes
            = encrypter.encrypt(toEncrypt);
        System.out.printf("Encrypted %s%n", new String(encryptedBytes,"UTF-8"));

        String decrypted
            = decrypter.decrypt(encryptedBytes);

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }

}

Listing 2 - RsaKeyPairProducer.java class

package org.thoth.crypto.asymmetric;

import java.security.KeyPair;
import java.security.KeyPairGenerator;

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

    /**
     * Generates a new RSA-4096 bit {@code KeyPair}.
     *
     * @return {@code KeyPair}, never null
     * @throws RuntimeException All exceptions are caught
     * and re-thrown as {@code RuntimeException}
     */
    public KeyPair produce() {
        KeyPairGenerator keyGen;
        try {
            keyGen = KeyPairGenerator.getInstance("RSA");
            //keyGen.initialize(3072);
            keyGen.initialize(4096);
            return keyGen.generateKeyPair();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 3 - RsaPrivateKeyProducer.java class

package org.thoth.crypto.asymmetric;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;

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

    /**
     * Regenerates a previous RSA {@code PrivateKey}.
     *
     * @param encodedByteArrayForPrivateKey The bytes this method
     * will use to regenerate a previously created {@code PrivateKey}
     *
     * @return {@code PrivateKey}, never null
     * @throws RuntimeException All exceptions are caught
     * and re-thrown as {@code RuntimeException}
     */
    public PrivateKey produce(byte[] encodedByteArrayForPrivateKey) {
        try {
            PrivateKey privateKey = KeyFactory.getInstance("RSA")
                .generatePrivate(new PKCS8EncodedKeySpec(encodedByteArrayForPrivateKey));

            return privateKey;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 4 - RsaPublicKeyProducer.java class

package org.thoth.crypto.asymmetric;

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

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

    /**
     * Regenerates a previous RSA {@code PublicKey}.
     *
     * @param encodedByteArrayForPublicKey The bytes this method
     * will use to regenerate a previously created {@code PublicKey}
     *
     * @return {@code PublicKey}, never null
     * @throws RuntimeException All exceptions are caught
     * and re-thrown as {@code RuntimeException}
     */
    public PublicKey produce(byte[] encodedByteArrayForPublicKey) {
        try {
            PublicKey publicKey = KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(encodedByteArrayForPublicKey));

            return publicKey;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 5 - ByteArrayWriter.java class

package org.thoth.crypto.io;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;

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

    protected Path outputFile;

    private void initOutputFile(Path outputFile) {
        this.outputFile = outputFile;
    }

    private void initOutputDirectory() {
        Path outputDirectory = outputFile.getParent();
        if (!Files.exists(outputDirectory)) {
            try {
                Files.createDirectories(outputDirectory);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public ByteArrayWriter(Path outputFile) {
        initOutputFile(outputFile);
        initOutputDirectory();
    }

    public void write(byte[] bytesArrayToWrite) {
        try (
            OutputStream os
                = Files.newOutputStream(outputFile);

            PrintWriter writer
                =  new PrintWriter(os);
        ){
            for (int i=0; i<bytesArrayToWrite.length; i++) {
                if (i>0) {
                    writer.println();
                }
                writer.print(bytesArrayToWrite[i]);
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 6 - ByteArrayReader.java class

package org.thoth.crypto.io;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Scanner;

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

    protected Path inputFile;

    public ByteArrayReader(Path inputFile) {
        this.inputFile = inputFile;
    }

    public byte[] read() {
        try (
            Scanner scanner
                =  new Scanner(inputFile);

            ByteArrayOutputStream baos
                = new ByteArrayOutputStream();
        ){
            while (scanner.hasNext()) {
                baos.write(Byte.parseByte(scanner.nextLine()));
            }
            
            baos.flush();
            return baos.toByteArray();

        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 7 - RsaEncrypter.java class

package org.thoth.crypto.asymmetric;

import java.security.PublicKey;
import javax.crypto.Cipher;

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

    protected RsaCipher cipher;

    public RsaEncrypter(PublicKey key) {
        this.cipher = new RsaCipher(Cipher.ENCRYPT_MODE, key);
    }

    public byte[] encrypt(String message) {
        try {
            return cipher
                    .update(message.getBytes("UTF-8"))
                    .doFinal()
            ;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Listing 8 - RsaDecrypter.java class

package org.thoth.crypto.asymmetric;

import java.security.PrivateKey;
import javax.crypto.Cipher;

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

    protected RsaCipher cipher;

    public RsaDecrypter(PrivateKey key) {
        this.cipher = new RsaCipher(Cipher.DECRYPT_MODE, key);
    }

    public String decrypt(byte[] message) {
        try {
            return new String(
                cipher.update(message).doFinal()
                , "UTF-8"
            );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

Summary

Encryption isn’t easy. And easy examples will result in implementations with security vulnerabilities for your application. If you need a public/private key, asymmetric, encryption algorithm, use RSA/ECB/OAEPWithSHA–512AndMGF1Padding, with a 4096 bit key.

References

Sheth, M. (2017, April 18). Encryption and Decryption in Java Cryptography. Retrieved from https://www.veracode.com/blog/research/encryption-and-decryption-java-cryptography.

  • Best algorithms, modes, and paddings
  • Use 4096-bit key

Brightwell, W., poncho. (2015, May 4). Is ECB mode safe to use with RSA encryption?. Retrieved from https://crypto.stackexchange.com/questions/25420/is-ecb-mode-safe-to-use-with-rsa-encryption.

  • ECB isn’t applicable; Java doesn’t use it under the covers.
  • RSA uses randomness and the padding to avoid ECB issue of the same plaintext generating the same ciphertext

Marilena. (2016, November 29). Java - Asymmetric Cryptography example. Retrieved from https://www.mkyong.com/java/java-asymmetric-cryptography-example/.

  • Writing the public/private keys to file
  • Reading the public/private keys from file
  • Encrypt & Decrypt

Key size. (2017, October 12). Wikipedia. Retrieved from https://en.wikipedia.org/wiki/Key_size.

  • 2048-bit keys are sufficient until 2030
  • An RSA key length of 3072 bits should be used if security is required beyond 2030

user4982. (2013, November 4). How are IVs used in association with RSA Encryption?. Retrieved from https://crypto.stackexchange.com/questions/11403/how-are-ivs-used-in-association-with-rsa-encryption.

  • IV values are not used with RSA

Choosing Java Cryptographic Algorithms Part 2 - Single key symmetric encryption

Abstract

This is the 2nd 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 2nd post details how to implement single key, symmetric, AES-256 encryption. 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.

NOTE As of Java 1.8.0_161, unlimited cryptography is enabled by default. This means if you are using Java 1.8.0_161 or later, you do not need to install Java Cryptography Extension (JCE) Unlimited Strength separately. See the Java 1.8.0_161 release notes

Acknowledgments

Thanks to Peter Jakobsen. In March 2022, he identified an error in my Aes#encrypt() method. The error caused encryption/decryption process to fail when the string being encrypted was greater than 15 characters long. I did not have unit test for this case.

At the time, I did not have availability to look into this problem. Peter posted the question to https://stackoverflow.com/questions/71422498/javax-crypto-aeadbadtagexception-tag-mismatch-when-password-length-16. Additional thanks to Topaco on Stack Overflow for providing comments.

In November 2022, I was able to update my Aes class to address the problem Peter identified. Using the Template Method Design Pattern, I now have two sub-classes of Aes demonstrating both the multiple-part and single-part encryption operations. I have updated this blog to reflect these new classes.

Download

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

Symmetric Encryption

About

Symmetric encryption algorithms are based on a single key. This one key is used for both encryption and decryption. As such, symmetric algorithms should only be used where strict controls are in place to protect the key.

Symmetric algorithms are commonly used for encryption and decryption of data in secured environments. A good example of this is securing Microservice communication. If an OAuth-2/JWT architecture is out of scope, the API Gateway can use a symmetric algorithm’s single key to encrypt a token. This token is then passed to other Microservices. The other Microservices use the same key to decrypt token. Another good example are hyperlinks embedded in emails. The hyperlinks in emails contain an encoded token which allow automatic login request processing when the hyperlink is clicked. This token is a strongly encrypted value generated by a symmetric algorithm so it can only be decoded on the application server. And of course, anytime passwords or credentials of any kind need to be protected, a symmetric algorithm is used to encrypt them and the bytes can later be decrypted with the same key.

Research done as of today seems to indicate the best and most secure single key, symmetric, encryption algorithm is the following (Sheth, 2017, “Choosing the correct algorithm”, para.2):

  1. Algorithm: AES
  2. Mode: GCM
  3. Padding: PKCS5Padding
  4. Key size: 256 bit
  5. IV size: 96 bit

AES-256 uses a 256-bit key which requires installation of the Java Cryptography Extension (JCE) Unlimited Strength package. Let’s take a look at an example.

NOTE The Java Cryptography Extension (JCE) Unlimited Strength package is required for 256-bit keys. If it’s not installed, 128-bit keys are the max.

Example

If you don’t already have it, download and install the Java Cryptography Extension (JCE) Unlimited Strength package. It is required to use 256-bit keys. Otherwise, the example below must be updated to use a 128-bit key.

Listing 1 and Listing 2 are the unit tests AesUsingSinglePartEncryptionTest.java and AesUsingMultiplePartEncryptionTest.java. Both unit tests are full demonstrations of the following:

  1. Generate and store an AES 256-bit key
  2. AES Encryption
  3. AES Decryption

One demonstrates multiple-part encryption and the other demonstrates single-part encryption. The difference between the two is how the Cipher#update and Cipher#doFinal methods are used to get the encrypted bytes.

Listing 3 shows AesSecretKeyProducer.java. This is a helper class which is responsible for producing a new key or reproducing an existing key from a byte[].

Listing 4 shows ByteArrayWriter.java and Listing 5 shows ByteArrayReader.java. These are helper classes responsible for reading and writing a byte[] to a file. It’s up to you to determine how to store the byte[] of your key, but it needs to be stored securely somewhere (file, database, git repository, etc.).

Listing 6 shows Aes.java. This is a helper class which is responsible for both encryption and decryption. It is implemented as an abstract class so it can not be instantiated directly. Instead, one of its sub-classes need to be used. There are 2 sub-classes, one to demonstrate the single-part encryption operation and the other to demonstrate the multiple-part encryption operation.

NOTE In reality, you probably won’t need an abstract class. Instead you’ll most likely create 1 class which uses the encryption operation (single-part or multiple-part) you want to use.

Listing 7 shows AesUsingSinglePartEncryption.java. This extends the Aes class and implements the getEncryptedBytes() method. Its implementation demonstrates the single-part encryption operation, which uses a single call to Cipher#doFinal(byte[]) to get the encrypted bytes.

Listing 8 shows AesUsingMultiplePartEncryption.java. This extends the Aes class and implements the getEncryptedBytes() method. Its implementation demonstrates the multiple-part encryption operation which makes multiple calls to Cipher#update(byte[]) and then a final call to Cipher#doFinal(). All the encrypted bytes are store along the way and returned after the call to Cipher#doFinal().

Listing 1 - AesUsingSinglePartEncryptionTest.java class

package org.thoth.crypto.symmetric;

import java.io.ByteArrayOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Optional;
import javax.crypto.SecretKey;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.thoth.crypto.io.ByteArrayReader;
import org.thoth.crypto.io.ByteArrayWriter;

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

    static Path secretKeyFile;

    @BeforeClass
    public static void beforeClass() throws Exception {
        // Store the SecretKey bytes in the ./target diretory. Do
        // this so it will be ignore by source control.  We don't
        // want this file committed.
        secretKeyFile
            = Paths.get("./target/Aes256.key").toAbsolutePath();

        // Generate a SecretKey for the test
        SecretKey secretKey
            = new AesSecretKeyProducer().produce();

        // Store the byte[] of the SecretKey.  This is the
        // "private key file" you want to keep safe.
        ByteArrayWriter writer = new ByteArrayWriter(secretKeyFile);
        writer.write(secretKey.getEncoded());
    }


    @Test
    public void encrypt_and_decrypt_using_same_Aes256_instance_long() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingSinglePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me1, encrypt me2, encrypt me3, encrypt me4, encrypt me5, encrypt me6, encrypt me7, encrypt me8, encrypt me9, encrypt me10";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.empty());

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    
    @Test
    public void encrypt_and_decrypt_using_same_Aes256_instance_short() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.empty());

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }


    public void encrypt_and_decrypt_with_aad_using_same_Aes256_instance_short() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me aad";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.of("JUnit AAD"));

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.of("JUnit AAD"));

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    public void encrypt_and_decrypt_with_aad_using_same_Aes256_instance_long() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me aad 1, encrypt me aad 2, encrypt me aad 3, encrypt me aad 4, encrypt me aad 5, encrypt me aad 6, encrypt me aad 7, encrypt me aad 8, encrypt me aad 9, encrypt me aad 10";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.of("JUnit AAD"));

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.of("JUnit AAD"));

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }


    @Test
    public void encrypt_and_decrypt_using_different_Aes256_instance_long()
    throws Exception {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aesForEncrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        Aes aesForDecrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me1, encrypt me2, encrypt me3, encrypt me4, encrypt me5, encrypt me6, encrypt me7, encrypt me8, encrypt me9, encrypt me10";

        // run
        byte[] encryptedBytes
            = aesForEncrypt.encrypt(toEncrypt, Optional.empty());

        ByteArrayOutputStream baos
            = new ByteArrayOutputStream();
        baos.write(encryptedBytes);

        String decrypted
            = aesForDecrypt.decrypt(baos.toByteArray(), Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    
    @Test
    public void encrypt_and_decrypt_using_different_Aes256_instance_short()
    throws Exception {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aesForEncrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        Aes aesForDecrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "eNcryPt Me";

        // run
        byte[] encryptedBytes
            = aesForEncrypt.encrypt(toEncrypt, Optional.empty());

        ByteArrayOutputStream baos
            = new ByteArrayOutputStream();
        baos.write(encryptedBytes);

        String decrypted
            = aesForDecrypt.decrypt(baos.toByteArray(), Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    @Test
    public void foo() {
        String s = "ABC";
        int chunkSize = 5;
        String[] chunks = s.split("(?<=\\G.{" + chunkSize + "})");
        System.out.println(Arrays.toString(chunks));
    }
}

Listing 2 - AesUsingMultiplePartEncryptionTest.java class

package org.thoth.crypto.symmetric;

import java.io.ByteArrayOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Optional;
import javax.crypto.SecretKey;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.thoth.crypto.io.ByteArrayReader;
import org.thoth.crypto.io.ByteArrayWriter;

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

    static Path secretKeyFile;

    @BeforeClass
    public static void beforeClass() throws Exception {
        // Store the SecretKey bytes in the ./target diretory. Do
        // this so it will be ignore by source control.  We don't
        // want this file committed.
        secretKeyFile
            = Paths.get("./target/Aes256.key").toAbsolutePath();

        // Generate a SecretKey for the test
        SecretKey secretKey
            = new AesSecretKeyProducer().produce();

        // Store the byte[] of the SecretKey.  This is the
        // "private key file" you want to keep safe.
        ByteArrayWriter writer = new ByteArrayWriter(secretKeyFile);
        writer.write(secretKey.getEncoded());
    }


    @Test
    public void encrypt_and_decrypt_using_same_Aes256_instance_long() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me1, encrypt me2, encrypt me3, encrypt me4, encrypt me5, encrypt me6, encrypt me7, encrypt me8, encrypt me9, encrypt me10";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.empty());

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    
    @Test
    public void encrypt_and_decrypt_using_same_Aes256_instance_short() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.empty());

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }


    public void encrypt_and_decrypt_with_aad_using_same_Aes256_instance_short() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me aad";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.of("JUnit AAD"));

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.of("JUnit AAD"));

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    public void encrypt_and_decrypt_with_aad_using_same_Aes256_instance_long() {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aes
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me aad 1, encrypt me aad 2, encrypt me aad 3, encrypt me aad 4, encrypt me aad 5, encrypt me aad 6, encrypt me aad 7, encrypt me aad 8, encrypt me aad 9, encrypt me aad 10";

        // run
        byte[] encryptedBytes
            = aes.encrypt(toEncrypt, Optional.of("JUnit AAD"));

        String decrypted
            = aes.decrypt(encryptedBytes, Optional.of("JUnit AAD"));

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }


    @Test
    public void encrypt_and_decrypt_using_different_Aes256_instance_long()
    throws Exception {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aesForEncrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        Aes aesForDecrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "encrypt me1, encrypt me2, encrypt me3, encrypt me4, encrypt me5, encrypt me6, encrypt me7, encrypt me8, encrypt me9, encrypt me10";

        // run
        byte[] encryptedBytes
            = aesForEncrypt.encrypt(toEncrypt, Optional.empty());

        ByteArrayOutputStream baos
            = new ByteArrayOutputStream();
        baos.write(encryptedBytes);

        String decrypted
            = aesForDecrypt.decrypt(baos.toByteArray(), Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    
    @Test
    public void encrypt_and_decrypt_using_different_Aes256_instance_short()
    throws Exception {
        // setup
        SecretKey secretKey
            = new AesSecretKeyProducer().produce(
                new ByteArrayReader(secretKeyFile).read()
            );

        Aes aesForEncrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        Aes aesForDecrypt
            = new AesUsingMultiplePartEncryption(secretKey);

        String toEncrypt
            = "eNcryPt Me";

        // run
        byte[] encryptedBytes
            = aesForEncrypt.encrypt(toEncrypt, Optional.empty());

        ByteArrayOutputStream baos
            = new ByteArrayOutputStream();
        baos.write(encryptedBytes);

        String decrypted
            = aesForDecrypt.decrypt(baos.toByteArray(), Optional.empty());

        // assert
        Assert.assertEquals(toEncrypt, decrypted);
    }
    
    @Test
    public void foo() {
        String s = "ABC";
        int chunkSize = 5;
        String[] chunks = s.split("(?<=\\G.{" + chunkSize + "})");
        System.out.println(Arrays.toString(chunks));
    }
}

Listing 3 - AesSecretKeyProducer.java class

package org.thoth.crypto.symmetric;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

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

    /**
     * Generates a new AES-256 bit {@code SecretKey}.
     *
     * @return {@code SecretKey}, never null
     * @throws RuntimeException All exceptions are caught and re-thrown as {@code RuntimeException}
     */
    public SecretKey produce() {
        KeyGenerator keyGen;
        try {
            keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(256);
            SecretKey secretKey = keyGen.generateKey();
            return secretKey;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }


    /**
     * Generates an AES-256 bit {@code SecretKey}.
     *
     * @param encodedByteArray The bytes this method will use to regenerate a previously created {@code SecretKey}
     *
     * @return {@code SecretKey}, never null
     * @throws RuntimeException All exceptions are caught and re-thrown as {@code RuntimeException}
     */
    public SecretKey produce(byte [] encodedByteArray) {
        try {
            return new SecretKeySpec(encodedByteArray, "AES");
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 4 - ByteArrayWriter.java class

package org.thoth.crypto.io;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;

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

    protected Path outputFile;

    private void initOutputFile(Path outputFile) {
        this.outputFile = outputFile;
    }

    private void initOutputDirectory() {
        Path outputDirectory = outputFile.getParent();
        if (!Files.exists(outputDirectory)) {
            try {
                Files.createDirectories(outputDirectory);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public ByteArrayWriter(Path outputFile) {
        initOutputFile(outputFile);
        initOutputDirectory();
    }

    public void write(byte[] bytesArrayToWrite) {
        try (
            OutputStream os
                = Files.newOutputStream(outputFile);

            PrintWriter writer
                =  new PrintWriter(os);
        ){
            for (int i=0; i<bytesArrayToWrite.length; i++) {
                if (i>0) {
                    writer.println();
                }
                writer.print(bytesArrayToWrite[i]);
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 5 - ByteArrayReader.java class

package org.thoth.crypto.io;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Scanner;

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

    protected Path inputFile;

    public ByteArrayReader(Path inputFile) {
        this.inputFile = inputFile;
    }

    public byte[] read() {
        try (
            Scanner scanner
                =  new Scanner(inputFile);

            ByteArrayOutputStream baos
                = new ByteArrayOutputStream();
        ){
            while (scanner.hasNext()) {
                baos.write(Byte.parseByte(scanner.nextLine()));
            }
            
            baos.flush();
            return baos.toByteArray();

        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Listing 6 - Aes.java class

package org.thoth.crypto.symmetric;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Optional;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;

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

    // If you don't have the Java Cryptography Extension
    // (JCE) Unlimited Strength packaged installed, use
    // a 128 bit KEY_SIZE.
    public static int KEY_SIZE = 256;
    
    public static int IV_SIZE = 12; // 12bytes * 8 = 96bits
    public static int TAG_BIT_SIZE = 128;
    public static String ALGORITHM_NAME = "AES";
    public static String MODE_OF_OPERATION = "GCM";
    public static String PADDING_SCHEME = "PKCS5Padding";

    protected SecretKey secretKey;
    protected SecureRandom secureRandom;

    protected Aes(SecretKey secretKey) {
        this.secretKey = secretKey;
        this.secureRandom = new SecureRandom();
    }


    public byte[] encrypt(String message, Optional<String> aad) {
        try {
            // Transformation specifies algortihm, mode of operation and padding
            Cipher c = Cipher.getInstance(
                String.format("%s/%s/%s",ALGORITHM_NAME,MODE_OF_OPERATION,PADDING_SCHEME)
            );

            // Generate IV
            byte iv[] = new byte[IV_SIZE];
            secureRandom.nextBytes(iv); // SecureRandom initialized using self-seeding

            // Initialize GCM Parameters
            GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_SIZE, iv);

            // Init for encryption
            c.init(Cipher.ENCRYPT_MODE, secretKey, spec, secureRandom);

            // Add AAD tag data if present
            aad.ifPresent(t -> {
                try {
                    c.updateAAD(t.getBytes("UTF-8"));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });

            // I demonstrate 2 different ways of getting the
            // encrypted bytes. See the 2 sub-classes which
            // implement the method of this abstract class.
            ByteArrayOutputStream baos = getEncryptedBytes(message, c);
            
            // Concatinate IV and encrypted bytes.  The IV is needed later
            // in order to to decrypt.  The IV value does not need to be
            // kept secret, so it's OK to encode it in the return value
            //
            // Create a new byte[] the combined length of IV and encryptedBytes
            byte[] ivPlusEncryptedBytes = new byte[iv.length + baos.size()];
            // Copy IV bytes into the new array
            System.arraycopy(iv, 0, ivPlusEncryptedBytes, 0, iv.length);
            // Copy encryptedBytes into the new array
            System.arraycopy(baos.toByteArray(), 0, ivPlusEncryptedBytes, iv.length, baos.size());

            // Return
            return ivPlusEncryptedBytes;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public String decrypt(byte[] ivPlusEncryptedBytes, Optional<String> aad) {

        try {
            // Get IV
            byte iv[] = new byte[IV_SIZE];
            System.arraycopy(ivPlusEncryptedBytes, 0, iv, 0, IV_SIZE);

            // Initialize GCM Parameters
            GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_SIZE, iv);

            // Transformation specifies algortihm, mode of operation and padding
            Cipher c = Cipher.getInstance(
                String.format("%s/%s/%s",ALGORITHM_NAME,MODE_OF_OPERATION,PADDING_SCHEME)
            );

            // Get encrypted bytes
            byte [] encryptedBytes = new byte[ivPlusEncryptedBytes.length - IV_SIZE];
            System.arraycopy(ivPlusEncryptedBytes, IV_SIZE, encryptedBytes, 0, encryptedBytes.length);

            // Init for decryption
            c.init(Cipher.DECRYPT_MODE, secretKey, spec, secureRandom);

            // Add AAD tag data if present
            aad.ifPresent(t -> {
                try {
                    c.updateAAD(t.getBytes("UTF-8"));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });

            // Add message to decrypt
            c.update(encryptedBytes);

            // Decrypt
            byte[] decryptedBytes
                = c.doFinal();

            // Return
            return new String(decryptedBytes, "UTF-8");

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    
    /**
     * An abstract method to be implemented by a subclass following the 
     * Gang of four <a href="https://www.digitalocean.com/community/tutorials/template-method-design-pattern-in-java">Template Method Design Pattern</a>.
     * This method is to use the {@link Cipher} provided to return the 
     * encrypted bytes of the {@link message} parameter.
     * 
     * @param message The String to be encrypted.
     * @param cipher  The Cipher object used to encrypt the message.
     * @return
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws IOException 
     */
    abstract ByteArrayOutputStream getEncryptedBytes(String message, Cipher cipher) throws BadPaddingException, IllegalBlockSizeException, IOException;
}

Listing 7 - AesUsingSinglePartEncryption.java class

package org.thoth.crypto.symmetric;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;

/**
 *
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class AesUsingSinglePartEncryption extends Aes {


    public AesUsingSinglePartEncryption(SecretKey secretKey) {
        super(secretKey);
    }
    

    /**
     * This method demonstrates how to perform a  single-part encryption
     * operation by using the {@link Cipher#doFinal(byte[]) } method to 
     * get all of the encrypted bytes.
     * 
     * @param message The message to encrypt.
     * @param c The {@link Cipher} used to get the encrypted bytes.
     * @return
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws IOException 
     */
    @Override
    ByteArrayOutputStream getEncryptedBytes(String message, Cipher c) throws BadPaddingException, IllegalBlockSizeException, IOException {
        // Create output array to hold all the encrypted bytes
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
         
        // Perform single-part encryption.
        baos.write(
            c.doFinal(message.getBytes("UTF-8"))
        );
        
        return baos;
    }
}

Listing 8 - AesUsingMultiplePartEncryption.java class

package org.thoth.crypto.symmetric;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;

/**
 *
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class AesUsingMultiplePartEncryption extends Aes {


    public AesUsingMultiplePartEncryption(SecretKey secretKey) {
        super(secretKey);
    }
    

    /**
     * This method demonstrates how to perform a  multiple-part encryption
     * operation by using the {@link Cipher#update(byte[]) } and the 
     * {@link Cipher#doFinal() } methods to get all of the encrypted
     * bytes. This method <b>simulates</b> the operation by dividing the
     * {@link message} parameter into many strings and operating on those
     * strings individually. In reality you would probably never do this, but
     * it's an easy way to demonstrate to perform a  multiple-part encryption.
     * 
     * @param message The message to encrypt. This method will <b>simulate</b>
     * multiple-part encryption by <b>unnecessarily</b> dividing this string into many strings.
     * @param c The {@link Cipher} used to get the encrypted bytes.
     * @return
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws IOException 
     */
    @Override
    ByteArrayOutputStream getEncryptedBytes(String message, Cipher c) throws BadPaddingException, IllegalBlockSizeException, IOException {
        // Create output array to hold all the encrypted bytes
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
        // Chunk the message into many strings to simulate multiple-part encryption
        int chunkSize = 5;
        String[] chunks = message.split("(?<=\\G.{" + chunkSize + "})");
        
        // Add each chunk to a multiple-part encryption.
        // Don't forget to collect the encypted bytes
        // along the way!
        for (String chunk : chunks) {
            baos.write(
                c.update(chunk.getBytes("UTF-8"))
            );
        }
        
        // Finish multi-part encryption. Again,
        // Don't forget to collect the encypted bytes
        // along the way!
        baos.write(
            c.doFinal()
        );
        
        return baos;
    }
}

Summary

Encryption isn’t easy. And easy examples will result in implementations with security vulnerabilities for your application. If you need a single key, symmetric, encryption algorithm, use cipher AES/GCM/PKCS5Padding with a 256 bit key and a 96 bit IV.

References

Java Cryptography Extension (JCE) Unlimited Strength. (n.d.). Retrieved from http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html.

Sheth, M. (2017, April 18). Encryption and Decryption in Java Cryptography. Retrieved from https://www.veracode.com/blog/research/encryption-and-decryption-java-cryptography.

cpast[ Says GCM IV is 96bit which is 96/8 = 12 bytes]. (2015, June 4). Encrypting using AES-256, can I use 256 bits IV [Web log comment]. Retrieved from https://security.stackexchange.com/questions/90848/encrypting-using-aes-256-can-i-use-256-bits-iv.

Bodewes[ Says GCM IV is strongly recommended to be 12 bytes (12*8 = 96) but can be of any size. Other sizes will require additional calculations], M. (2015, July 7). Ciphertext and tag size and IV transmission with AES in GCM mode [Web log comment]. Retrieved from https://crypto.stackexchange.com/questions/26783/ciphertext-and-tag-size-and-iv-transmission-with-aes-in-gcm-mode.

Figlesquidge. (2013, October 18). What’s the difference between a ‘cipher’ and a ‘mode of operation’? [Web log comment]. Retrieved from https://crypto.stackexchange.com/questions/11132/what-is-the-difference-between-a-cipher-and-a-mode-of-operation.

Toust, S. (2013, February 4). Why does the recommended key size between symmetric and asymmetric encryption differ greatly?. Retrieved from https://crypto.stackexchange.com/questions/6236/why-does-the-recommended-key-size-between-symmetric-and-asymmetric-encryption-di.

Karonen, I. (2012, October 5). What is the main difference between a key, an IV and a nonce?. Retrieved from https://crypto.stackexchange.com/questions/3965/what-is-the-main-difference-between-a-key-an-iv-and-a-nonce.

Block cipher mode of operation. (2017, November 6). Wikipedia. Retrieved from https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_.28IV.29

Jakobsen, Peter. (2022, March 10). javax.crypto.AEADBadTagException: Tag mismatch! when password.length >= 16 - Stack Overflow [Web log post]. Retrieved from https://stackoverflow.com/questions/71422498/javax-crypto-aeadbadtagexception-tag-mismatch-when-password-length-16.

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!

October 02, 2017

My JavaOne Session (2017)

Materials

GitHub (thoth-jaspic): JASPIC Research EE 6+

GitHub (thoth-security-api): Security API Research EE 8+

PowerPoint: Modern Application and Microservices Security from EE6 JASPIC to the EE8 Security API

Session

Session ID: CON5954

Session Title: Modern Application and Microservices Security from EE6 JASPIC to the EE8 Security API

Room: Moscone West - Room 2024

DATE: Tuesday, 10/03/17

Time: 09:30:00 AM

Proposal

Abstract

EE6 added the Java Authentication Service Provider Interface for Containers (JASPIC) to the EE specification. JASPIC is a flexible and customizable way for EE servers and applications to generate a Principal and roles for securing application. Unfortunately, JASPIC has been a specification few knew about. But with EE8, microservices, and focus on the new EE Security API, JASPIC is starting to get attention. This session will look at JASPIC and the EE Security API from a modern application & microservices security perspective. This session will first demonstrate how to secure the major EE components (Servlet, JSP, JSF, JAX-RS, JAX-WS) with JASPIC. Then it will demonstrate how security will change migrating to EE 8 and the EE Security API.

Summary

EE6 added the Java Authentication Service Provider Interface for Containers (JASPIC) to the EE specification. JASPIC is a flexible and customizable way for EE servers and applications to generate a Principal and roles for securing application. Unfortunately, JASPIC has been a specification few knew about. But with EE8, microservices, and focus on the new EE Security API, JASPIC is starting to get attention. This session will look at JASPIC and the EE Security API from a modern application & microservices security perspective. This session will first demonstrate how to secure the major EE components (Servlet, JSP, JSF, JAX-RS, JAX-WS) with JASPIC. Then it will demonstrate how security will change migrating to EE 8 and the EE Security API.

The EE security model has been one the biggest obstacles I’ve faced convincing organizations to stop using 3rd party proprietary frameworks. The assumption is that EE security is limited to BASIC, FORM, DIGEST and these do not fit the complex needs applications have when it comes to authentication and authorization. Specifically in modern application architecture, where there is typically a single-sign on, identity management layer protecting all applications within an organization, the Java EE standard is seen as unable to integrate with this layer so a 3rd party proprietary framework is needed to fill in the gaps with Java EE. But, since EE 6, Java has had the JASPIC specification. JASPIC already “fills this gap” within an EE standard, but hardly anyone knows about it. It wasn’t until EE 8 and the new EE Security API that I learned about JASPIC. Now JASPIC is low-level and a bit difficult to use, but the EE Security API will be built on top of JASPIC, so it’s a specification development teams need to know about. Both of these standards need to be evangelized and good example applications need to be made available which show how they are used to secure all the major EE components (Servlet, JSP, JSF, JAX-RS, JAX-WS, etc.). If developers know robust security exists with the EE specification and have examples showing how to secure the code they are developing, I believe more teams will stick with the standard vs 3rd party proprietary frameworks.

Pictures

billboard
billboard
room
room

July 13, 2017

Java Bean Validation Basics

Abstract

This post summarizes some quick and easy examples for the most common things you would want to do with the Java Beans Validation API (JSR 349, JSR 303). Remember, Beans Validation is independent of Java EE. Although it is built in as part of a Java EE compliant server, the API can also be used just as easily in a Java SE application. All these examples use Java SE.

Table of Contents

  1. Basics
  2. Custom Message Template
  3. Custom Message Template with Variable Replacement
  4. Custom Property Validator
  5. Custom Class Validator
  6. GroupSequence (Short Circuit)

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_65_x64
  • NetBeans 8.2
  • Maven 3.0.5 (Bundled with NetBeans)
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.2.Final</version>
</dependency>
<dependency>
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>2.2.4</version>
</dependency>
<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.el</artifactId>
    <version>2.2.4</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

Download

Visit my GitHub page https://github.com/mjremijan to see all of my open source projects. The code for this post is located at: https://github.com/mjremijan/thoth-beanvalidation

Basics

This example shows the basics of bean validation using the built-in, standard constraints and the built-in, standard validators.

Listing 1.1 - Bean to validate

package org.thoth.beanvalidation.basics;

import javax.validation.constraints.NotNull;

public class Widget {

    @NotNull
    protected String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Listing 1.2 - How to validate

package org.thoth.beanvalidation.basics;

import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class WidgetTest {

    protected Validator validator;

    @Before
    public void before() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void violations_size() {
        // setup
        Widget w = new Widget();

        // action
        Set<ConstraintViolation<Widget>> violations
            = validator.validate(w);

        // assert
        Assert.assertEquals(1, violations.size());
    }

    @Test
    public void violation_message() {
        // setup
        Widget w = new Widget();

        // action
        Set<ConstraintViolation<Widget>> violations
            = validator.validate(w);

        // assert
        ConstraintViolation<Widget> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("may not be null", v.getMessage());
    }

    @Test
    public void violation_messageTemplate() {
        // setup
        Widget w = new Widget();

        // action
        Set<ConstraintViolation<Widget>> violations
            = validator.validate(w);

        // assert
        ConstraintViolation<Widget> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("{javax.validation.constraints.NotNull.message}", v.getMessageTemplate());
    }

    @Test
    public void violation_propertyPath() {
        // setup
        Widget w = new Widget();

        // action
        Set<ConstraintViolation<Widget>> violations
            = validator.validate(w);

        // assert
        ConstraintViolation<Widget> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("name", v.getPropertyPath().toString());
    }
}

Custom Message Template

This example shows how the built-in, standard constraints can be customized with a custom error message instead of using the built-in, standard error messages.

Listing 2.1 - ValidationMessages.properties

Candy.name.NotNull=A candy name is required.

Listing 2.2 - Bean to validate

package org.thoth.beanvalidation.custommessage;

import javax.validation.constraints.NotNull;

public class Candy {

    @NotNull(message = "{Candy.name.NotNull}")
    protected String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Listing 2.3 - How to validate

package org.thoth.beanvalidation.custommessage;

import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

public class CandyTest {

    protected static Validator validator;

    @BeforeClass
    public static void before() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void notnull_violation_message() {
        // setup
        Candy candy = new Candy();

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(candy);

        // assert
        ConstraintViolation<Candy> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("A candy name is required.", v.getMessage());
    }

    @Test
    public void notnull_violation_messageTemplate() {
        // setup
        Candy candy = new Candy();

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(candy);

        // assert
        ConstraintViolation<Candy> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("{Candy.name.NotNull}", v.getMessageTemplate());
    }
}

Custom Message Template with Variable Replacement

This example shows how the built-in, standard constraints can be configured with a custom error message which has variable values in the message which are replaced by bean validation at runtime. Examples of variables which can be replaced are the actual value which was validate and the min and max properties of a @Size constraint.

Listing 3.1 - ValidationMessages.properties

Candy.name.Size.message=The candy name "${validatedValue}" is invalid. It must be between {min} and {max} characters long

Listing 3.2 - Bean to validate

package org.thoth.beanvalidation.variablereplacement;

import javax.validation.constraints.Size;

public class Candy {
    private String name;

    @Size(message = "{Candy.name.Size.message}", min=5, max=10)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Listing 3.3 - How to validate

package org.thoth.beanvalidation.variablereplacement;

import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.thoth.beanvalidation.variablereplacement.Candy;

public class CandyTest {

    protected static Validator validator;

    @BeforeClass
    public static void before() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }


    @Test
    public void does_the_constraint_have_the_correct_messageTemplate() {
        // setup
        Candy candy = new Candy();
        candy.setName("");

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(candy);

        // assert
        ConstraintViolation<Candy> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("{Candy.name.Size.message}", v.getMessageTemplate());
    }

    @Test
    public void is_the_message_correct_if_size_is_too_small() {
        // setup
        Candy candy = new Candy();
        candy.setName("foo");

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(candy);

        // assert
        ConstraintViolation<Candy> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("The candy name \"foo\" is invalid. It must be between 5 and 10 characters long", v.getMessage());
    }

    @Test
    public void is_the_message_correct_if_size_is_too_big() {
        // setup
        Candy candy = new Candy();
        candy.setName("123456789|1");

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(candy);

        // assert
        ConstraintViolation<Candy> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("The candy name \"123456789|1\" is invalid. It must be between 5 and 10 characters long", v.getMessage());
    }
}

Custom Property Validator

This example shows how to create your own constraint and your own validator for a property of a class.

Listing 4.1 - ValidationMessages.properties

org.thoth.beanvalidation.propertyvalidator.Excludes.message=The value "${validatedValue}" is one of {value} which is forbidden.

Listing 4.2 - Constraint annotation

package org.thoth.beanvalidation.propertyvalidator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;

@Target({
    ElementType.TYPE, ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ExcludesValidator.class})
@Documented
public @interface Excludes {

    String message() default "{org.thoth.beanvalidation.propertyvalidator.Excludes.message}";

    Class[] groups() default {};

    Class[] payload() default {};

    String[] value() default {};
}

Listing 4.3 - Constraint validator

package org.thoth.beanvalidation.propertyvalidator;

import java.util.Arrays;
import java.util.List;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class ExcludesValidator
    implements ConstraintValidator< Excludes, String> {

    private List<String> excludeTheseValues;

    @Override
    public void initialize(Excludes arg) {
        String[] strarr = arg.value();
        if (strarr == null) {
            strarr = new String[]{};
        }
        excludeTheseValues = Arrays.asList(strarr);
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext cvc) {
        if (excludeTheseValues.contains(value)) {
            return false;
        } else {
            return true;
        }
    }
}

Listing 4.4 - Bean to validate

package org.thoth.beanvalidation.propertyvalidator;

public class Candy {
    private String name;

    public Candy(String name) {
        this.name = name;
    }

    @Excludes({"foo", "bar", "shrubbery"})
    public String getName() {
        return name;
    }
}

Listing 4.5 - How to validate

package org.thoth.beanvalidation.propertyvalidator;

import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;

public class CandyTest {

    protected static Validator validator;

    @BeforeClass
    public static void before() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }


    @Test
    public void a_non_excludeded_name_should_not_give_you_a_constraint_violation() {
        // setup
        Candy candy = new Candy("hershey");

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(candy);

        // assert
        assertEquals(0, violations.size());
    }


    @Test
    public void do_you_get_a_constraint_violation_if_you_use_excluded_name_foo() {
        // setup
        Candy candy = new Candy("foo");

        // action
        ConstraintViolation<Candy> violation
            = validator.validate(candy).iterator().next();

        // assert
        assertEquals("{org.thoth.beanvalidation.propertyvalidator.Excludes.message}", violation.getMessageTemplate());
        assertEquals("The value \"foo\" is one of [foo, bar, shrubbery] which is forbidden.", violation.getMessage());
    }


    @Test
    public void do_you_get_a_constraint_violation_if_you_use_excluded_name_bar() {
        // setup
        Candy candy = new Candy("bar");

        // action
        ConstraintViolation<Candy> violation
            = validator.validate(candy).iterator().next();

        // assert
        assertEquals("{org.thoth.beanvalidation.propertyvalidator.Excludes.message}", violation.getMessageTemplate());
        assertEquals("The value \"bar\" is one of [foo, bar, shrubbery] which is forbidden.", violation.getMessage());
    }


    @Test
    public void do_you_get_a_constraint_violation_if_you_use_excluded_name_shrubbery() {
        // setup
        Candy candy = new Candy("shrubbery");

        // action
        ConstraintViolation<Candy> violation
            = validator.validate(candy).iterator().next();

        // assert
        assertEquals("{org.thoth.beanvalidation.propertyvalidator.Excludes.message}", violation.getMessageTemplate());
        assertEquals("The value \"shrubbery\" is one of [foo, bar, shrubbery] which is forbidden.", violation.getMessage());
    }
}

Custom Class Validator

This example shows how to create your own constraint and your own validator which applies to an entire class.

Listing 5.1 - ValidationMessages.properties

org.thoth.beanvalidation.classvalidator.IdentificationExists.message=At least one of social security number, drivers license number, or passport number must exist.

Listing 5.2 - Constraint annotation

package org.thoth.beanvalidation.classvalidator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {IdentificationExistsValidator.class})
@Documented
public @interface IdentificationExists {

    String message() default "{org.thoth.beanvalidation.classvalidator.IdentificationExists.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Listing 5.3 - Constraint validator

package org.thoth.beanvalidation.classvalidator;

import java.util.Objects;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class IdentificationExistsValidator implements ConstraintValidator<IdentificationExists, Identification> {

    @Override
    public void initialize(IdentificationExists a) {}

    @Override
    public boolean isValid(Identification t, ConstraintValidatorContext cvc) {
        boolean invalid =
            Objects.equals(t.getDriversLicenseNumber(), null)
            &&
            Objects.equals(t.getPassportNumber(), null)
            &&
            Objects.equals(t.getSocialSecurityNumber(), null)
        ;
        return !invalid;
    }
}

Listing 5.4 - Bean to validate

package org.thoth.beanvalidation.classvalidator;

@IdentificationExists
public class Identification {
    protected String socialSecurityNumber;
    protected String driversLicenseNumber;
    protected String passportNumber;

    public String getSocialSecurityNumber() {
        return socialSecurityNumber;
    }

    public void setSocialSecurityNumber(String socialSecurityNumber) {
        this.socialSecurityNumber = socialSecurityNumber;
    }

    public String getDriversLicenseNumber() {
        return driversLicenseNumber;
    }

    public void setDriversLicenseNumber(String driversLicenseNumber) {
        this.driversLicenseNumber = driversLicenseNumber;
    }

    public String getPassportNumber() {
        return passportNumber;
    }

    public void setPassportNumber(String passportNumber) {
        this.passportNumber = passportNumber;
    }
}

Listing 5.5 - How to validate

package org.thoth.beanvalidation.classvalidator;

import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class IdentificationTest {

protected Validator validator;

    @Before
    public void before() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void violation_if_all_are_missing() {
        // setup
        Identification id = new Identification();

        // action
        Set<ConstraintViolation<Identification>> violations
            = validator.validate(id);

        // assert
        ConstraintViolation<Identification> v
            = violations.stream().findFirst().get();
        Assert.assertEquals("At least one of social security number, drivers license number, or passport number must exist.", v.getMessage());
    }

    @Test
    public void no_violation_if_social_security_number_exists() {
        // setup
        Identification id = new Identification();
        id.setSocialSecurityNumber("a");

        // action
        Set<ConstraintViolation<Identification>> violations
            = validator.validate(id);

        // assert
        Assert.assertEquals(0, violations.size());
    }

    @Test
    public void no_violation_if_drivers_license_number_exists() {
        // setup
        Identification id = new Identification();
        id.setDriversLicenseNumber("a");

        // action
        Set<ConstraintViolation<Identification>> violations
            = validator.validate(id);

        // assert
        Assert.assertEquals(0, violations.size());
    }

    @Test
    public void no_violation_if_passport_number_exists() {
        // setup
        Identification id = new Identification();
        id.setPassportNumber("a");

        // action
        Set<ConstraintViolation<Identification>> violations
            = validator.validate(id);

        // assert
        Assert.assertEquals(0, violations.size());
    }
}

GroupSequence (Short Circuit)

This example shows how to use @GroupSequence as a short circuit when doing validation. This means if the 1st round of validations do not pass, then validation is “short circuited” and the 2nd round of validations is not performed.

By default, all bean validation constraints are put into a “Default” group sequence. However, by putting a @GroupSequence on a class (like shown below) the “Default” group sequence is redefined just for that class. With the @GroupSequence on a class below, what it basically does is that during beans validation the 1st operation is to validate all constraints in the class that aren’t specifically assigned a group. That would be the @NotNull constraint first. If all of those are OK, then the 2nd operation is to validate all constraints that are in the Second.class group. That would be the @Size constraint. If all of those are OK, then 3rd operation is to validate all of the constraints that are in the Third.class group. That would be the @Pattern constraint. If at any time a group fails to validate, validation is “short circuited” and validation goes no farther.

Listing 6.1 - Bean to validate

package org.thoth.beanvalidation.groupsequence;

import javax.validation.GroupSequence;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@GroupSequence({Candy.class, Candy.Second.class, Candy.Third.class})
public class Candy {

    protected interface Second {}
    protected interface Third {}

    private String name;

    @NotNull()
    @Size(min=4, max=10, groups = Second.class )
    @Pattern(regexp = "[a-z]", groups = Third.class)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Listing 6.2 - How to validate

package org.thoth.beanvalidation.groupsequence;

import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;

public class CandyTest {

    private Validator validator;

    @Before
    public void before() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void short_circuits_first_if_null() {
        // setup
        Candy w = new Candy();

        // action
        Set<ConstraintViolation<Candy>> violations
            //= validator.validate(w, CheckGroupSequence.class);
            = validator.validate(w);

        // assert
        assertEquals(1, violations.size());
        assertEquals("may not be null", violations.iterator().next().getMessage());
    }


    @Test
    public void short_circut_if_size_is_in_violation() {
        // setup
        Candy w = new Candy();
        w.setName("foo");

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(w);

        // assert
        assertEquals(1, violations.size());
        assertEquals("size must be between 4 and 10", violations.iterator().next().getMessage());
    }


    @Test
    public void short_circuit_if_pattern_is_in_violation() {
        // setup
        Candy w = new Candy();
        w.setName("SHRUBBERY");

        // action
        Set<ConstraintViolation<Candy>> violations
            = validator.validate(w);

        // assert
        assertEquals(1, violations.size());
        assertEquals("must match \"[a-z]\"", violations.iterator().next().getMessage());
    }
}

Summary

Beans validation is a powerful API, especially since it can be used within a Java EE server or in stand-alone Java SE applications. This is just a very short summary of the basics of the beans validation API, but, typically, it is enough to cover most questions developers have about how to use it.