Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*************************************************************************
* *
* CESeCore: CE Security Core *
* *
* This software is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or any later version. *
* *
* See terms of license at gnu.org. *
* *
*************************************************************************/
package org.cesecore.certificates.ca.internal;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.cesecore.config.CesecoreConfiguration;
import org.cesecore.internal.InternalResources;
/**
* Implements a singleton serial number generator using SecureRandom. This generator generates random 8 octec (64 bits) serial numbers.
*
* RFC3280 defines serialNumber be positive INTEGER, and X.690 defines INTEGER consist of one or more octets. X.690 also defines as follows:
*
* If the contents octets of an integer value encoding consist of more than one octet, then the bits of the first octet and bit 8 of the second octet:
* a) shall not all be ones; and b) shall not all be zero.
*
* Therefore, minimum 8 octets value is 0080000000000000 and maximum value is 7FFFFFFFFFFFFFFF."
*
* Therefore, minimum 4 octets value is 00800000 and maximum value is 7FFFFFFF."
*
* X.690:
*
* 8.3 Encoding of an integer value 8.3.1 The encoding of an integer value shall be primitive. The contents octets shall consist of one or more
* octets. 8.3.2 If the contents octets of an integer value encoding consist of more than one octet, then the bits of the first octet and bit 8 of the
* second octet: a) shall not all be ones; and b) shall not all be zero. NOTE – These rules ensure that an integer value is always encoded in the
* smallest possible number of octets. 8.3.3 The contents octets shall be a two's complement binary number equal to the integer value, and consisting
* of bits 8 to 1 of the first octet, followed by bits 8 to 1 of the second octet, followed by bits 8 to 1 of each octet in turn up to and including
* the last octet of the contents octets. NOTE – The value of a two's complement binary number is derived by numbering the bits in the contents
* octets, starting with bit 1 of the last octet as bit zero and ending the numbering with bit 8 of the first octet. Each bit is assigned a numerical
* value of 2N, where N is its position in the above numbering sequence. The value of the two's complement binary number is obtained by summing the
* numerical values assigned to each bit for those bits which are set to one, excluding bit 8 of the first octet, and then reducing this value by the
* numerical value assigned to bit 8 of the first octet if that bit is set to one.
*
* @version $Id: SernoGeneratorRandom.java 23988 2016-07-23 16:03:57Z anatom $
*/
public class SernoGeneratorRandom implements SernoGenerator {
/** Log4j instance */
private static final Logger log = Logger.getLogger(SernoGeneratorRandom.class);
/** Internal localization of logs and errors */
private static final InternalResources intres = InternalResources.getInstance();
/** random generator algorithm, default SHA1PRNG */
private String algorithm = "SHA1PRNG";
/** number of bytes serial number to generate, default 8 */
private int noOctets = 8;
/** random generator */
private SecureRandom random;
/** A handle to the unique Singleton instance. */
private static SernoGeneratorRandom instance = null;
/** lowest possible value we should deliver when getSerno is called */
private BigInteger lowest = new BigInteger("0080000000000000", 16); // Default value for 64 bit serials
/** highest possible value we should deliver when getSerno is called */
private BigInteger highest = new BigInteger("7FFFFFFFFFFFFFFF", 16); // Default value for 64 bit serials
/**
* Creates a serial number generator using SecureRandom
*/
protected SernoGeneratorRandom() {
if (log.isTraceEnabled()) {
log.trace(">SernoGenerator()");
}
this.algorithm = CesecoreConfiguration.getCaSerialNumberAlgorithm();
setSernoOctetSize(CesecoreConfiguration.getCaSerialNumberOctetSize());
init();
if (log.isTraceEnabled()) {
log.trace("=JDK8 try the getInstanceStrong to get a guaranteed strong random number generator.
// Note that this may give you a generator that takes >30 seconds to create a single random number.
// On JDK8/Linux this gives you a NativePRNGBlocking, while SecureRandom.getInstance() gives a NativePRNG.
try {
final Method methodGetInstanceStrong = SecureRandom.class.getDeclaredMethod("getInstanceStrong");
random = (SecureRandom) methodGetInstanceStrong.invoke(null);
log.info("Using SecureRandom.getInstanceStrong() with " + random.getAlgorithm() + " for serialNumber RNG algorithm.");
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new IllegalStateException("SecureRandom.getInstanceStrong() is not available or failed invocation. (This method was added in Java 8.)");
}
} else if (!StringUtils.isEmpty(algorithm) && StringUtils.equalsIgnoreCase(algorithm, "default")) {
// We entered "default" so let's use a good default SecureRandom this should be good enough for just about everyone (on Linux at least)
// On Linux the default Java implementation uses the (secure) /dev/(u)random, but on windows something else
// On JDK8/Linux this gives you a NativePRNG, while SecureRandom.getInstanceStrong() gives a NativePRNGBlocking.
random = new SecureRandom();
log.info("Using default " + random.getAlgorithm() + " serialNumber RNG algorithm.");
}
} catch (NoSuchAlgorithmException e) {
//This state is unrecoverable, and since algorithm is set in configuration requires a redeploy to handle
throw new IllegalStateException("Algorithm " + algorithm + " was not a valid algorithm.", e);
}
if (random == null) {
//This state is unrecoverable, and since algorithm is set in configuration requires a redeploy to handle
throw new IllegalStateException("Algorithm " + algorithm + " was not a valid algorithm.");
}
// Call nextBytes directly after in order to force seeding if not already done. SecureRandom typically seeds on first call.
random.nextBytes(new byte[20]);
}
/**
* Creates (if needed) the serial number generator and returns the object.
*
* @return An instance of the serial number generator.
*/
public static synchronized SernoGenerator instance() {
if (instance == null) {
instance = new SernoGeneratorRandom();
}
return instance;
}
@Override
public synchronized BigInteger getSerno() {
// This is only for testing, of size is set to 0 we will generate random number
// between 1 and 4, this will give collisions often...
if (noOctets == 0) {
Random rand = new Random();
return new java.math.BigInteger(Long.toString(rand.nextInt(4)));
}
final byte[] sernobytes = new byte[noOctets];
boolean ok = false;
BigInteger serno = null;
while (!ok) {
random.nextBytes(sernobytes);
serno = (new java.math.BigInteger(sernobytes)).abs();
// Must be within the range 0080000000000000 - 7FFFFFFFFFFFFFFF
if (checkSernoValidity(serno)) {
ok = true;
} else {
String msg = intres.getLocalizedMessage("sernogenerator.discarding");
log.info(msg);
}
}
return serno;
}
protected boolean checkSernoValidity(final BigInteger serno) {
if ((serno.compareTo(lowest) >= 0) && (serno.compareTo(highest) <= 0)) {
return true;
}
return false;
}
@Override
public int getNoSernoBytes() {
return noOctets;
}
@Override
public void setSeed(final long seed) {
random.setSeed(seed);
}
@Override
public void setAlgorithm(final String algo) throws NoSuchAlgorithmException {
// Since re-initialization is expensive, we only do it if we changed the algo
if (this.algorithm == null || !this.algorithm.equals(algo)) {
this.algorithm = algo;
// We must force re-init after choosing a new algorithm
this.random = null;
init();
}
}
/** Available for testing so we can compare that we actually use what we think
* @return the random generator algorithm as reported by the underlying Java random number generator.
*/
protected String getAlgorithm() {
return random.getAlgorithm();
}
@Override
public void setSernoOctetSize(final int noOctets) {
if (this.noOctets != noOctets) {
// We allow 0 octets for testing
if ((noOctets > 20) && (noOctets != 0)) {
throw new IllegalArgumentException("SernoOctetSize must be between 4 and 20 bytes for this generator.");
}
char[] arr = new char[noOctets*2];
// 00800000 (filled with 0 to the no of octets)
Arrays.fill(arr, '0');
arr[2] = '8';
lowest = new BigInteger(String.valueOf(arr), 16);
// 7FFFFFFF (filled with F to the no of octets)
Arrays.fill(arr, 'F');
arr[0] = '7';
highest = new BigInteger(String.valueOf(arr), 16);
this.noOctets = noOctets;
}
}
}