
org.killbill.billing.util.UUIDs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of catalog-test Show documentation
Show all versions of catalog-test Show documentation
Test Plugin for CatalogPluginApin
/*
* Copyright 2015 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.killbill.billing.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;
/**
* UUIDs helper.
*
* @author kares
*/
public abstract class UUIDs {
public static UUID randomUUID() { return rndUUIDv4(); }
private static UUID rndUUIDv4() {
// ~ return UUID.randomUUID() :
final Random random = threadRandom.get();
final byte[] uuid = new byte[16];
random.nextBytes(uuid);
uuid[6] &= 0x0f; /* clear version */
uuid[6] |= 0x40; /* set to version 4 */
uuid[8] &= 0x3f; /* clear variant */
uuid[8] |= 0x80; /* set to IETF variant */
long msb = 0;
msb = (msb << 8) | (uuid[0] & 0xff);
msb = (msb << 8) | (uuid[1] & 0xff);
msb = (msb << 8) | (uuid[2] & 0xff);
msb = (msb << 8) | (uuid[3] & 0xff);
msb = (msb << 8) | (uuid[4] & 0xff);
msb = (msb << 8) | (uuid[5] & 0xff);
msb = (msb << 8) | (uuid[6] & 0xff);
msb = (msb << 8) | (uuid[7] & 0xff);
long lsb = 0;
lsb = (lsb << 8) | (uuid[8] & 0xff);
lsb = (lsb << 8) | (uuid[9] & 0xff);
lsb = (lsb << 8) | (uuid[10] & 0xff);
lsb = (lsb << 8) | (uuid[11] & 0xff);
lsb = (lsb << 8) | (uuid[12] & 0xff);
lsb = (lsb << 8) | (uuid[13] & 0xff);
lsb = (lsb << 8) | (uuid[14] & 0xff);
lsb = (lsb << 8) | (uuid[15] & 0xff);
return new UUID(msb, lsb);
}
private static final ThreadLocal threadRandom =
new ThreadLocal() {
protected Random initialValue() {
return new LightSecureRandom(); // new SecureRandom();
}
};
/**
* An implementation of SecureRandom inspired by bouncy-castle's own for
* light-weight APIs (JDK 1.0, and J2ME).
*
* Random generation is based on the traditional SHA1 with
* counter. Calling setSeed will always increase the entropy of the hash.
*/
// NOTE: assumes non-concurrent use (generator calls should be synchronized)
private static class LightSecureRandom extends Random {
private static abstract class SeederHolder {
static final SecureRandom seeder;
/* some related info from the JDK itself :
# By default, an attempt is made to use the entropy gathering device
# specified by the "securerandom.source" Security property. If an
# exception occurs while accessing the specified URL:
#
# SHA1PRNG:
# the traditional system/thread activity algorithm will be used.
#
# NativePRNG:
# a default value of /dev/random will be used. If neither
are available, the implementation will be disabled.
# "file" is the only currently supported protocol type.
#
# The entropy gathering device can also be specified with the System
property "java.security.egd". For example:
#
# % java -Djava.security.egd=file:/dev/random MainClass
#
# Specifying this System property will override the
# "securerandom.source" Security property.
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be preferred over
# SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random
*/
static {
SecureRandom random;
// if the securerandom.seed preference is set to file:/dev/urandom
// (default) for Linux, new SecureRandom() returns a NativePRNG,
// which generateSeed()s from /dev/xxx (thus might block terribly)
// ... instead we explicitly use a SHA1PRNG seeder which will only
// seeds itself on initialization (possibly from /dev/urandom)
try {
random = SecureRandom.getInstance("SHA1PRNG");
}
catch (NoSuchAlgorithmException e) {
random = new SecureRandom(); // should never happen
}
seeder = random;
}
}
private final DigestRandomGenerator generator;
LightSecureRandom() {
this( sha1Generator() );
setSeed( SeederHolder.seeder.generateSeed( generator.getDigestLength() ) );
}
LightSecureRandom(final byte[] inSeed) {
this( sha1Generator() );
setSeed(inSeed);
}
private LightSecureRandom(DigestRandomGenerator generator) {
super(0);
this.generator = generator;
}
private static DigestRandomGenerator sha1Generator() {
try {
return new DigestRandomGenerator(MessageDigest.getInstance("SHA-1"));
}
catch (NoSuchAlgorithmException ex) {
throw new AssertionError("unexpeced missing SHA-1 digest", ex);
}
}
@Override
public void setSeed(final long seed) {
if ( seed != 0 ) { // to avoid problems with Random calling setSeed in construction
generator.addSeedMaterial(seed);
}
}
public void setSeed(final byte[] seed) {
generator.addSeedMaterial(seed);
}
@Override
public void nextBytes(byte[] bytes) {
generator.nextBytes(bytes);
}
@Override
public int nextInt() {
final byte[] intBytes = new byte[4];
nextBytes(intBytes);
int result = 0;
for ( int i = 0; i < 4; i++ ) {
result = (result << 8) + (intBytes[i] & 0xff);
}
return result;
}
@Override
protected final int next(int numBits) {
int size = (numBits + 7) / 8;
byte[] bytes = new byte[size];
nextBytes(bytes);
int result = 0;
for (int i = 0; i < size; i++)
{
result = (result << 8) + (bytes[i] & 0xff);
}
return result & ((1 << numBits) - 1);
}
}
private static class DigestRandomGenerator {
private static final long CYCLE_COUNT = 10;
private long stateCounter;
private long seedCounter;
private final MessageDigest digest;
private byte[] state;
private byte[] seed;
private DigestRandomGenerator(MessageDigest digest) {
this.digest = digest;
this.seed = new byte[digest.getDigestLength()];
this.seedCounter = 1;
this.state = new byte[digest.getDigestLength()];
this.stateCounter = 1;
}
int getDigestLength() { return digest.getDigestLength(); }
// NOTE: requires external synchronization
final void addSeedMaterial(byte[] inSeed) {
//synchronized (this) {
digestUpdate(inSeed);
digestUpdate(seed);
seed = digest.digest(); // digestDoFinal(seed);
//}
}
// NOTE: requires external synchronization
final void addSeedMaterial(long rSeed) {
//synchronized (this) {
digestAddCounter(rSeed);
digestUpdate(seed);
seed = digest.digest(); // digestDoFinal(seed);
//}
}
void nextBytes(byte[] bytes) {
nextBytes(bytes, 0, bytes.length);
}
// NOTE: requires external synchronization
final void nextBytes(byte[] bytes, int start, int len) {
//synchronized (this) {
int stateOff = 0;
generateState();
int end = start + len;
for (int i = start; i != end; i++) {
if (stateOff == state.length) {
generateState();
stateOff = 0;
}
bytes[i] = state[stateOff++];
}
//}
}
private void cycleSeed() {
digestUpdate(seed);
digestAddCounter(seedCounter++);
seed = digest.digest(); // digestDoFinal(seed);
}
private void generateState() {
digestAddCounter(stateCounter++);
digestUpdate(state);
digestUpdate(seed);
state = digest.digest(); // digestDoFinal(state);
if ((stateCounter % CYCLE_COUNT) == 0) {
cycleSeed();
}
}
private void digestAddCounter(long seed) {
for (int i = 0; i != 8; i++) {
digest.update((byte) seed);
seed >>>= 8;
}
}
private void digestUpdate(byte[] inSeed) {
digest.update(inSeed, 0, inSeed.length);
}
//private void digestDoFinal(byte[] result) {
// digest.doFinal(result, 0);
//}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy