prng.utility.NonceFactory Maven / Gradle / Ivy
Show all versions of SecurePRNG-core Show documentation
package prng.utility;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import prng.SecureRandomProvider;
/**
* A factory for nonces where 256-bit security is required.
*
* For such usage a nonce should not be expected to repeat more often than a (0.5 * security-strength)-bit random number is expected to repeat. Due to the
* birthday problem a (0.5 * 256)-bit or 128 bit random number is expected to repeat within 2^64 values.
The time-based UUID comprises a 60 bit clock time,
* a 16 bit sequence number and a 96 bit network ID. The combination of clock time and sequence exceeds the required values before repetition on a particular
* network address.
In order to create nonces that are unique across different processes on the same machine, it is necessary to combine the type 1 UUID
* with a process identifier.
*/
public class NonceFactory {
/** Identifier for this JVM instance (256 bits/32 bytes) */
private static final byte[] IDENTIFIER;
/** Personalization string (256 bit/32 bytes) */
private static final byte[] PERSONALIZATION;
/**
* Create a 256-bit nonce.
*
* @return a 256-bit nonce.
*/
public static byte[] create() {
UUID uuid = TimeBasedUUID.create();
DigestDataOutput dig = new DigestDataOutput("SHA-256");
dig.writeLong(uuid.getMostSignificantBits());
dig.writeLong(uuid.getLeastSignificantBits());
dig.write(IDENTIFIER);
return dig.digest();
}
/**
* Get the application personalization string
*
* @return the personalization string
*/
public static byte[] personalization() {
return PERSONALIZATION.clone();
}
static {
DigestDataOutput dig = new DigestDataOutput("SHA-256");
final RuntimeMXBean runBean = ManagementFactory.getRuntimeMXBean();
// The "name" often contains the process ID, making name and start time
// a unique identifier for this VM.
dig.writeUTF(runBean.getName());
dig.writeLong(runBean.getStartTime());
// If multiple applications are running in the same JVM, the class
// loader and load time will make it unique
dig.writeUTF(NonceFactory.class.getClassLoader().getClass().getName());
dig.writeInt(
System.identityHashCode(NonceFactory.class.getClassLoader()));
dig.writeLong(System.nanoTime());
dig.writeLong(Thread.currentThread().getId());
IDENTIFIER = dig.digest();
// Now create a personalization string. Start with the identifier info
dig = new DigestDataOutput("SHA-512");
dig.writeUTF(runBean.getName());
dig.writeLong(runBean.getStartTime());
dig.writeUTF(NonceFactory.class.getClassLoader().getClass().getName());
dig.writeInt(
System.identityHashCode(NonceFactory.class.getClassLoader()));
dig.writeLong(System.nanoTime());
dig.writeLong(Thread.currentThread().getId());
// input arguments to this instance
List args;
try {
// requires ManagementPermission monitor
args = AccessController.doPrivileged(
(PrivilegedAction>) runBean::getInputArguments);
} catch (SecurityException e) {
SecureRandomProvider.LOG.warn(
"Lacking permission \"ManagementPermission monitor\" - cannot fully personalize nonce factory");
args = null;
}
if (args == null) {
dig.writeInt(-1);
} else {
dig.writeInt(args.size());
for (String s : args) {
dig.writeUTF(s);
}
}
// system and environment properties
Map env;
try {
// requires PropertyPermission * read,write
env = AccessController.doPrivileged(
(PrivilegedAction