Just a note about Java’s SecureRandom interface:

You should not use

byte[] nonce = SecureRandom.getSeed(16);

as this method will block on the OS-provided hardware-backed RNG. What this means in the real world is that you’ll be stuck wiggling your mouse while you wait for unit tests to finish running.

Instead,

byte[] nonce = new byte[16];
new SecureRandom() // grabs first non-blocking hardware backed RNG
	.nextBytes(nonce);

Technically, nextBytes() can still block, but you’ll have to specifically pick a blocking RNG algorithm when allocating the SecureRandom object.