blob: 31a1ba102e4c58b1e0045c76562c47e3f6fe4214 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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 java.security;
import java.util.Random;
import org.apache.harmony.security.fortress.Engine;
import org.apache.harmony.security.fortress.Services;
import org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl;
/**
* {@code SecureRandom} is an engine class which is capable of generating
* cryptographically secure pseudo-random numbers.
*/
public class SecureRandom extends Random {
private static final long serialVersionUID = 4940670005562187L;
// The service name.
private static final transient String SERVICE = "SecureRandom";
// Used to access common engine functionality
private static transient Engine engine = new Engine(SERVICE);
private Provider provider;
private SecureRandomSpi secureRandomSpi;
private String algorithm;
private byte[] state;
private byte[] randomBytes;
private int randomBytesUsed;
private long counter;
// Internal SecureRandom used for getSeed(int)
private static transient SecureRandom internalSecureRandom;
/**
* Constructs a new instance of {@code SecureRandom}. An implementation for
* the highest-priority provider is returned. The constructed instance will
* not have been seeded.
*/
public SecureRandom() {
super(0);
Services.refresh();
Provider.Service service = Services.getSecureRandomService();
if (service == null) {
this.provider = null;
this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl();
this.algorithm = "SHA1PRNG";
} else {
try {
this.provider = service.getProvider();
this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null);
this.algorithm = service.getAlgorithm();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Constructs a new instance of {@code SecureRandom}. An implementation for
* the highest-priority provider is returned. The constructed instance will
* be seeded with the parameter.
*
* @param seed
* the seed for this generator.
*/
public SecureRandom(byte[] seed) {
this();
setSeed(seed);
}
/**
* Constructs a new instance of {@code SecureRandom} using the given
* implementation from the specified provider.
*
* @param secureRandomSpi
* the implementation.
* @param provider
* the security provider.
*/
protected SecureRandom(SecureRandomSpi secureRandomSpi,
Provider provider) {
this(secureRandomSpi, provider, "unknown");
}
// Constructor
private SecureRandom(SecureRandomSpi secureRandomSpi,
Provider provider,
String algorithm) {
super(0);
this.provider = provider;
this.algorithm = algorithm;
this.secureRandomSpi = secureRandomSpi;
}
/**
* Returns a new instance of {@code SecureRandom} that utilizes the
* specified algorithm.
*
* @param algorithm
* the name of the algorithm to use.
* @return a new instance of {@code SecureRandom} that utilizes the
* specified algorithm.
* @throws NoSuchAlgorithmException
* if the specified algorithm is not available.
* @throws NullPointerException
* if {@code algorithm} is {@code null}.
*/
public static SecureRandom getInstance(String algorithm)
throws NoSuchAlgorithmException {
if (algorithm == null) {
throw new NullPointerException();
}
synchronized (engine) {
engine.getInstance(algorithm, null);
return new SecureRandom((SecureRandomSpi)engine.spi, engine.provider, algorithm);
}
}
/**
* Returns a new instance of {@code SecureRandom} that utilizes the
* specified algorithm from the specified provider.
*
* @param algorithm
* the name of the algorithm to use.
* @param provider
* the name of the provider.
* @return a new instance of {@code SecureRandom} that utilizes the
* specified algorithm from the specified provider.
* @throws NoSuchAlgorithmException
* if the specified algorithm is not available.
* @throws NoSuchProviderException
* if the specified provider is not available.
* @throws NullPointerException
* if {@code algorithm} is {@code null}.
* @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()}
*/
public static SecureRandom getInstance(String algorithm, String provider)
throws NoSuchAlgorithmException, NoSuchProviderException {
if (provider == null || provider.isEmpty()) {
throw new IllegalArgumentException();
}
Provider p = Security.getProvider(provider);
if (p == null) {
throw new NoSuchProviderException(provider);
}
return getInstance(algorithm, p);
}
/**
* Returns a new instance of {@code SecureRandom} that utilizes the
* specified algorithm from the specified provider.
*
* @param algorithm
* the name of the algorithm to use.
* @param provider
* the security provider.
* @return a new instance of {@code SecureRandom} that utilizes the
* specified algorithm from the specified provider.
* @throws NoSuchAlgorithmException
* if the specified algorithm is not available.
* @throws NullPointerException
* if {@code algorithm} is {@code null}.
* @throws IllegalArgumentException if {@code provider == null}
*/
public static SecureRandom getInstance(String algorithm, Provider provider)
throws NoSuchAlgorithmException {
if (provider == null) {
throw new IllegalArgumentException();
}
if (algorithm == null) {
throw new NullPointerException();
}
synchronized (engine) {
engine.getInstance(algorithm, provider, null);
return new SecureRandom((SecureRandomSpi)engine.spi, provider, algorithm);
}
}
/**
* Returns the provider associated with this {@code SecureRandom}.
*
* @return the provider associated with this {@code SecureRandom}.
*/
public final Provider getProvider() {
return provider;
}
/**
* Returns the name of the algorithm of this {@code SecureRandom}.
*
* @return the name of the algorithm of this {@code SecureRandom}.
*/
public String getAlgorithm() {
return algorithm;
}
/**
* Reseeds this {@code SecureRandom} instance with the specified {@code
* seed}. The seed of this {@code SecureRandom} instance is supplemented,
* not replaced.
*
* @param seed
* the new seed.
*/
public synchronized void setSeed(byte[] seed) {
secureRandomSpi.engineSetSeed(seed);
}
/**
* Reseeds this this {@code SecureRandom} instance with the eight bytes
* described by the representation of the given {@code long seed}. The seed
* of this {@code SecureRandom} instance is supplemented, not replaced.
*
* @param seed
* the new seed.
*/
@Override
public void setSeed(long seed) {
if (seed == 0) { // skip call from Random
return;
}
byte[] byteSeed = {
(byte)((seed >> 56) & 0xFF),
(byte)((seed >> 48) & 0xFF),
(byte)((seed >> 40) & 0xFF),
(byte)((seed >> 32) & 0xFF),
(byte)((seed >> 24) & 0xFF),
(byte)((seed >> 16) & 0xFF),
(byte)((seed >> 8) & 0xFF),
(byte)((seed) & 0xFF)
};
setSeed(byteSeed);
}
/**
* Generates and stores random bytes in the given {@code byte[]} for each
* array element.
*
* @param bytes
* the {@code byte[]} to be filled with random bytes.
*/
@Override
public synchronized void nextBytes(byte[] bytes) {
secureRandomSpi.engineNextBytes(bytes);
}
/**
* Generates and returns an {@code int} containing the specified number of
* random bits (right justified, with leading zeros).
*
* @param numBits
* number of bits to be generated. An input value should be in
* the range [0, 32].
* @return an {@code int} containing the specified number of random bits.
*/
@Override
protected final int next(int numBits) {
if (numBits < 0) {
numBits = 0;
} else {
if (numBits > 32) {
numBits = 32;
}
}
int bytes = (numBits+7)/8;
byte[] next = new byte[bytes];
int ret = 0;
nextBytes(next);
for (int i = 0; i < bytes; i++) {
ret = (next[i] & 0xFF) | (ret << 8);
}
ret = ret >>> (bytes*8 - numBits);
return ret;
}
/**
* Generates and returns the specified number of seed bytes, computed using
* the seed generation algorithm used by this {@code SecureRandom}.
*
* @param numBytes
* the number of seed bytes.
* @return the seed bytes
*/
public static byte[] getSeed(int numBytes) {
if (internalSecureRandom == null) {
internalSecureRandom = new SecureRandom();
}
return internalSecureRandom.generateSeed(numBytes);
}
/**
* Generates and returns the specified number of seed bytes, computed using
* the seed generation algorithm used by this {@code SecureRandom}.
*
* @param numBytes
* the number of seed bytes.
* @return the seed bytes.
*/
public byte[] generateSeed(int numBytes) {
return secureRandomSpi.engineGenerateSeed(numBytes);
}
}