package org.apache.harmony.security.provider.crypto;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.InvalidParameterException;
import java.security.SecureRandomSpi;
/**
* This class extends the SecureRandomSpi class implementing all its abstract methods. <BR>
* <BR>
* 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 <BR>
* <BR>
* The class implements the Serializable interface.
*/
public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serializable, SHA1_Data {
private static final long serialVersionUID = 283736797212159675L;
// constants to use in expressions operating on bytes in int and long variables:
// END_FLAGS - final bytes in words to append to message;
// see "ch.5.1 Padding the Message, FIPS 180-2"
// RIGHT1 - shifts to right for left half of long
// RIGHT2 - shifts to right for right half of long
// LEFT - shifts to left for bytes
// MASK - mask to select counter's bytes after shift to right
private static final int[] END_FLAGS = { 0x80000000, 0x800000, 0x8000, 0x80 };
private static final int[] RIGHT1 = { 0, 40, 48, 56 };
private static final int[] RIGHT2 = { 0, 8, 16, 24 };
private static final int[] LEFT = { 0, 24, 16, 8 };
private static final int[] MASK = { 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF,
0x000000FF };
// HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])"
// to use to form byte array returning by the "nextBytes(byte[])" method
// Note, that this implementation uses more bytes than it is defined
// in the above specification.
private static final int HASHBYTES_TO_USE = 20;
// value of 16 defined in the "SECURE HASH STANDARD", FIPS PUB 180-2
private static final int FRAME_LENGTH = 16;
// miscellaneous constants defined in this implementation:
// COUNTER_BASE - initial value to set to "counter" before computing "nextBytes(..)";
// note, that the exact value is not defined in STANDARD
// HASHCOPY_OFFSET - offset for copy of current hash in "copies" array
// EXTRAFRAME_OFFSET - offset for extra frame in "copies" array;
// as the extra frame follows the current hash frame,
// EXTRAFRAME_OFFSET is equal to length of current hash frame
// FRAME_OFFSET - offset for frame in "copies" array
// MAX_BYTES - maximum # of seed bytes processing which doesn't require extra frame
// see (1) comments on usage of "seed" array below and
// (2) comments in "engineNextBytes(byte[])" method
//
// UNDEFINED - three states of engine; initially its state is "UNDEFINED"
// SET_SEED call to "engineSetSeed" sets up "SET_SEED" state,
// NEXT_BYTES call to "engineNextByte" sets up "NEXT_BYTES" state
private static final int COUNTER_BASE = 0;
private static final int HASHCOPY_OFFSET = 0;
private static final int EXTRAFRAME_OFFSET = 5;
private static final int FRAME_OFFSET = 21;
private static final int MAX_BYTES = 48;
private static final int UNDEFINED = 0;
private static final int SET_SEED = 1;
private static final int NEXT_BYTES = 2;
private static SHA1PRNG_SecureRandomImpl myRandom;
// Structure of "seed" array:
// - 0-79 - words for computing hash
// - 80 - unused
// - 81 - # of seed bytes in current seed frame
// - 82-86 - 5 words, current seed hash
private transient int[] seed;
// total length of seed bytes, including all processed
private transient long seedLength;
// Structure of "copies" array
// - 0-4 - 5 words, copy of current seed hash
// - 5-20 - extra 16 words frame;
// is used if final padding exceeds 512-bit length
// - 21-36 - 16 word frame to store a copy of remaining bytes
private transient int[] copies;
// ready "next" bytes; needed because words are returned
private transient byte[] nextBytes;
// index of used bytes in "nextBytes" array
private transient int nextBIndex;
// variable required according to "SECURE HASH STANDARD"
private transient long counter;
// contains int value corresponding to engine's current state
private transient int state;
// 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.
/**
* Creates object and sets implementation variables to their initial values
*/
public SHA1PRNG_SecureRandomImpl() {
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;
}
/*
* The method invokes the SHA1Impl's "updateHash(..)" method
* to update current seed frame and
* to compute new intermediate hash value if the frame is full.
*
* After that it computes a length of whole seed.
*/
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;
}
/**
* Changes current seed by supplementing a seed argument to the current seed,
* if this already set;
* the argument is used as first seed otherwise. <BR>
*
* The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi.
*
* @param
* seed - byte array
* @throws
* NullPointerException - if null is passed to the "seed" argument
*/
protected void engineSetSeed(byte[] seed) {
if (seed == null) {
throw new NullPointerException("seed == null");
}
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);
}
}
/**
* Returns a required number of random bytes. <BR>
*
* The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi. <BR>
*
* @param
* numBytes - number of bytes to return; should be >= 0.
*