SHA1PRNG_SecureRandomImplpublic class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serializable, SHA1_DataThis class extends the SecureRandomSpi class implementing all its abstract methods.
To generate pseudo-random bits, the implementation uses technique described in
the "Random Number Generator (RNG) algorithms" section, Appendix A,
JavaTM Cryptography Architecture, API Specification&Reference
The class implements the Serializable interface. |
Fields Summary |
---|
private static final long | serialVersionUID | private static final int[] | END_FLAGS | private static final int[] | RIGHT1 | private static final int[] | RIGHT2 | private static final int[] | LEFT | private static final int[] | MASK | private static final int | HASHBYTES_TO_USE | private static final int | FRAME_LENGTH | private static final int | COUNTER_BASE | private static final int | HASHCOPY_OFFSET | private static final int | EXTRAFRAME_OFFSET | private static final int | FRAME_OFFSET | private static final int | MAX_BYTES | private static final int | UNDEFINED | private static final int | SET_SEED | private static final int | NEXT_BYTES | private static SHA1PRNG_SecureRandomImpl | myRandom | private transient int[] | seed | private transient long | seedLength | private transient int[] | copies | private transient byte[] | nextBytes | private transient int | nextBIndex | private transient long | counter | private transient int | state |
Constructors Summary |
---|
public SHA1PRNG_SecureRandomImpl()Creates object and sets implementation variables to their initial values
// The "seed" array is used to compute both "current seed hash" and "next bytes".
//
// As the "SHA1" algorithm computes a hash of entire seed by splitting it into
// a number of the 512-bit length frames (512 bits = 64 bytes = 16 words),
// "current seed hash" is a hash (5 words, 20 bytes) for all previous full frames;
// remaining bytes are stored in the 0-15 word frame of the "seed" array.
//
// As for calculating "next bytes",
// both remaining bytes and "current seed hash" are used,
// to preserve the latter for following "setSeed(..)" commands,
// the following technique is used:
// - upon getting "nextBytes(byte[])" invoked, single or first in row,
// which requires computing new hash, that is,
// there is no more bytes remaining from previous "next bytes" computation,
// remaining bytes are copied into the 21-36 word frame of the "copies" array;
// - upon getting "setSeed(byte[])" invoked, single or first in row,
// remaining bytes are copied back.
seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
seed[HASH_OFFSET] = H0;
seed[HASH_OFFSET + 1] = H1;
seed[HASH_OFFSET + 2] = H2;
seed[HASH_OFFSET + 3] = H3;
seed[HASH_OFFSET + 4] = H4;
seedLength = 0;
copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
nextBytes = new byte[DIGEST_LENGTH];
nextBIndex = HASHBYTES_TO_USE;
counter = COUNTER_BASE;
state = UNDEFINED;
|
Methods Summary |
---|
protected byte[] | engineGenerateSeed(int numBytes)Returns a required number of random bytes.
The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi.
byte[] myBytes; // byte[] for bytes returned by "nextBytes()"
if (numBytes < 0) {
throw new NegativeArraySizeException(Messages.getString("security.171", numBytes)); //$NON-NLS-1$
}
if (numBytes == 0) {
return new byte[0];
}
if (myRandom == null) {
myRandom = new SHA1PRNG_SecureRandomImpl();
myRandom.engineSetSeed(RandomBitsSupplier
.getRandomBits(DIGEST_LENGTH));
}
myBytes = new byte[numBytes];
myRandom.engineNextBytes(myBytes);
return myBytes;
| protected void | engineNextBytes(byte[] bytes)Writes random bytes into an array supplied.
Bits in a byte are from left to right.
To generate random bytes, the "expansion of source bits" method is used,
that is,
the current seed with a 64-bit counter appended is used to compute new bits.
The counter is incremented by 1 for each 20-byte output.
The method overrides engineNextBytes in class SecureRandomSpi.
int i, n;
long bits; // number of bits required by Secure Hash Standard
int nextByteToReturn; // index of ready bytes in "bytes" array
int lastWord; // index of last word in frame containing bytes
final int extrabytes = 7;// # of bytes to add in order to computer # of 8 byte words
if (bytes == null) {
throw new NullPointerException(
Messages.getString("security.83", "bytes")); //$NON-NLS-1$ //$NON-NLS-2$
}
lastWord = seed[BYTES_OFFSET] == 0 ? 0
: (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1;
if (state == UNDEFINED) {
// no seed supplied by user, hence it is generated thus randomizing internal state
updateSeed(RandomBitsSupplier.getRandomBits(DIGEST_LENGTH));
nextBIndex = HASHBYTES_TO_USE;
} else if (state == SET_SEED) {
System.arraycopy(seed, HASH_OFFSET, copies, HASHCOPY_OFFSET,
EXTRAFRAME_OFFSET);
// possible cases for 64-byte frame:
//
// seed bytes < 48 - remaining bytes are enough for all, 8 counter bytes,
// 0x80, and 8 seedLength bytes; no extra frame required
// 48 < seed bytes < 56 - remaining 9 bytes are for 0x80 and 8 counter bytes
// extra frame contains only seedLength value at the end
// seed bytes > 55 - extra frame contains both counter's bytes
// at the beginning and seedLength value at the end;
// note, that beginning extra bytes are not more than 8,
// that is, only 2 extra words may be used
// no need to set to "0" 3 words after "lastWord" and
// more than two words behind frame
for (i = lastWord + 3; i < FRAME_LENGTH + 2; i++) {
seed[i] = 0;
}
bits = seedLength << 3 + 64; // transforming # of bytes into # of bits
// putting # of bits into two last words (14,15) of 16 word frame in
// seed or copies array depending on total length after padding
if (seed[BYTES_OFFSET] < MAX_BYTES) {
seed[14] = (int) (bits >>> 32);
seed[15] = (int) (bits & 0xFFFFFFFF);
} else {
copies[EXTRAFRAME_OFFSET + 14] = (int) (bits >>> 32);
copies[EXTRAFRAME_OFFSET + 15] = (int) (bits & 0xFFFFFFFF);
}
nextBIndex = HASHBYTES_TO_USE; // skipping remaining random bits
}
state = NEXT_BYTES;
if (bytes.length == 0) {
return;
}
nextByteToReturn = 0;
// possibly not all of HASHBYTES_TO_USE bytes were used previous time
n = (HASHBYTES_TO_USE - nextBIndex) < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
- nextBIndex
: bytes.length - nextByteToReturn;
if (n > 0) {
System.arraycopy(nextBytes, nextBIndex, bytes, nextByteToReturn, n);
nextBIndex += n;
nextByteToReturn += n;
}
if (nextByteToReturn >= bytes.length) {
return; // return because "bytes[]" are filled in
}
n = seed[BYTES_OFFSET] & 0x03;
for (;;) {
if (n == 0) {
seed[lastWord] = (int) (counter >>> 32);
seed[lastWord + 1] = (int) (counter & 0xFFFFFFFF);
seed[lastWord + 2] = END_FLAGS[0];
} else {
seed[lastWord] |= (int) ((counter >>> RIGHT1[n]) & MASK[n]);
seed[lastWord + 1] = (int) ((counter >>> RIGHT2[n]) & 0xFFFFFFFF);
seed[lastWord + 2] = (int) ((counter << LEFT[n]) | END_FLAGS[n]);
}
if (seed[BYTES_OFFSET] > MAX_BYTES) {
copies[EXTRAFRAME_OFFSET] = seed[FRAME_LENGTH];
copies[EXTRAFRAME_OFFSET + 1] = seed[FRAME_LENGTH + 1];
}
SHA1Impl.computeHash(seed);
if (seed[BYTES_OFFSET] > MAX_BYTES) {
System.arraycopy(seed, 0, copies, FRAME_OFFSET, FRAME_LENGTH);
System.arraycopy(copies, EXTRAFRAME_OFFSET, seed, 0,
FRAME_LENGTH);
SHA1Impl.computeHash(seed);
System.arraycopy(copies, FRAME_OFFSET, seed, 0, FRAME_LENGTH);
}
counter++;
int j = 0;
for (i = 0; i < EXTRAFRAME_OFFSET; i++) {
int k = seed[HASH_OFFSET + i];
nextBytes[j] = (byte) (k >>> 24); // getting first byte from left
nextBytes[j + 1] = (byte) (k >>> 16); // getting second byte from left
nextBytes[j + 2] = (byte) (k >>> 8); // getting third byte from left
nextBytes[j + 3] = (byte) (k); // getting fourth byte from left
j += 4;
}
nextBIndex = 0;
j = HASHBYTES_TO_USE < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
: bytes.length - nextByteToReturn;
if (j > 0) {
System.arraycopy(nextBytes, 0, bytes, nextByteToReturn, j);
nextByteToReturn += j;
nextBIndex += j;
}
if (nextByteToReturn >= bytes.length) {
break;
}
}
| protected void | engineSetSeed(byte[] seed)Changes current seed by supplementing a seed argument to the current seed,
if this already set;
the argument is used as first seed otherwise.
The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi.
if (seed == null) {
throw new NullPointerException(
Messages.getString("security.83", "seed")); //$NON-NLS-1$ //$NON-NLS-2$
}
if (state == NEXT_BYTES) { // first setSeed after NextBytes; restoring hash
System.arraycopy(copies, HASHCOPY_OFFSET, this.seed, HASH_OFFSET,
EXTRAFRAME_OFFSET);
}
state = SET_SEED;
if (seed.length != 0) {
updateSeed(seed);
}
| private void | readObject(java.io.ObjectInputStream ois)
seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
nextBytes = new byte[DIGEST_LENGTH];
seedLength = ois.readLong();
counter = ois.readLong();
state = ois.readInt();
seed[BYTES_OFFSET] = ois.readInt();
int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
if (state != NEXT_BYTES) {
for (int i = 0; i < nRemaining; i++) {
seed[i] = ois.readInt();
}
for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
seed[HASH_OFFSET + i] = ois.readInt();
}
} else {
if (seed[BYTES_OFFSET] >= MAX_BYTES) {
// reading next bytes in seed extra frame
seed[FRAME_LENGTH] = ois.readInt();
seed[FRAME_LENGTH + 1] = ois.readInt();
seed[FRAME_LENGTH + 14] = ois.readInt();
seed[FRAME_LENGTH + 15] = ois.readInt();
}
// reading next bytes in seed frame
for (int i = 0; i < FRAME_LENGTH; i++) {
seed[i] = ois.readInt();
}
// reading remaining seed bytes
for (int i = 0; i < nRemaining; i++) {
copies[FRAME_LENGTH + EXTRAFRAME_OFFSET + i] = ois.readInt();
}
// reading copy of current hash
for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
copies[i] = ois.readInt();
}
// reading current hash
for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
seed[HASH_OFFSET + i] = ois.readInt();
}
}
nextBIndex = ois.readInt();
ois.read(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
| private void | updateSeed(byte[] bytes)
// on call: "seed" contains current bytes and current hash;
// on return: "seed" contains new current bytes and possibly new current hash
// if after adding, seed bytes overfill its buffer
SHA1Impl.updateHash(seed, bytes, 0, bytes.length - 1);
seedLength += bytes.length;
| private void | writeObject(java.io.ObjectOutputStream oos)
int[] intData = null;
final int only_hash = EXTRAFRAME_OFFSET;
final int hashes_and_frame = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH;
final int hashes_and_frame_extra = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH
* 2;
oos.writeLong(seedLength);
oos.writeLong(counter);
oos.writeInt(state);
oos.writeInt(seed[BYTES_OFFSET]);
int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
// result may be 0
if (state != NEXT_BYTES) {
// either the state is UNDEFINED or previous method was "setSeed(..)"
// so in "seed[]" to serialize are remaining bytes (seed[0-nRemaining]) and
// current hash (seed[82-86])
intData = new int[only_hash + nRemaining];
System.arraycopy(seed, 0, intData, 0, nRemaining);
System.arraycopy(seed, HASH_OFFSET, intData, nRemaining,
EXTRAFRAME_OFFSET);
} else {
// previous method was "nextBytes(..)"
// so, data to serialize are all the above (two first are in "copies" array)
// and current words in both frame and extra frame (as if)
int offset = 0;
if (seed[BYTES_OFFSET] < MAX_BYTES) { // no extra frame
intData = new int[hashes_and_frame + nRemaining];
} else { // extra frame is used
intData = new int[hashes_and_frame_extra + nRemaining];
intData[offset] = seed[FRAME_LENGTH];
intData[offset + 1] = seed[FRAME_LENGTH + 1];
intData[offset + 2] = seed[FRAME_LENGTH + 14];
intData[offset + 3] = seed[FRAME_LENGTH + 15];
offset += 4;
}
System.arraycopy(seed, 0, intData, offset, FRAME_LENGTH);
offset += FRAME_LENGTH;
System.arraycopy(copies, FRAME_LENGTH + EXTRAFRAME_OFFSET, intData,
offset, nRemaining);
offset += nRemaining;
System.arraycopy(copies, 0, intData, offset, EXTRAFRAME_OFFSET);
offset += EXTRAFRAME_OFFSET;
System.arraycopy(seed, HASH_OFFSET, intData, offset,
EXTRAFRAME_OFFSET);
}
for (int i = 0; i < intData.length; i++) {
oos.writeInt(intData[i]);
}
oos.writeInt(nextBIndex);
oos.write(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
|
|