Index: modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
===================================================================
--- modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java (revision 0)
+++ modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java (revision 0)
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ * Licensed 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.
+ */
+
+/*
+ * TODO to add writeObject(ObjectOutputStream) and readObject(ObjectInputStream) for optimal serialization
+ */
+
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.security.InvalidParameterException;
+import java.security.ProviderException;
+import java.security.SecureRandomSpi;
+
+import org.apache.harmony.security.provider.crypto.RandomBitsSupplier;
+import org.apache.harmony.security.provider.crypto.SHA1Impl;
+
+import java.io.Serializable;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+
+
+/**
+ * This 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) algoritms" section, Appendix A,
+ * JavaTM Cryptography Architecure, API Specification&Reference
+ *
+ * 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;
+
+ // miscellanous constans 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 spletting 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 othewise.
+ *
+ * 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("null is passed to the 'seed' argument");
+ }
+
+ 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.
+ *
+ * The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi.
+ *
+ * @param
+ * numBytes - number of bytes to return; should be >= 0.
+ * @return
+ * byte array containing bits in order from left to right
+ * @throws
+ * InvalidParameterException - if numBytes < 0
+ */
+ protected byte[] engineGenerateSeed(int numBytes) {
+
+ byte[] myBytes; // byte[] for bytes returned by "nextBytes()"
+
+ if ( numBytes < 0 ) {
+ throw new NegativeArraySizeException("numBytes=" + numBytes);
+ }
+ 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;
+ }
+
+
+ /**
+ * Writes random bytes into an array suppied.
+ * 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.
+ *
+ * @param
+ * bytes - byte array to be filled in with bytes
+ * @throws
+ * NullPointerException - if null is passed to the "bytes" argument
+ */
+ protected void engineNextBytes(byte[] bytes) {
+
+ 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("null is passed to the 'bytes' argument");
+ }
+
+ 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;
+ }
+ }
+ }
+
+
+}
Index: modules/security/src/main/java/linux/org/apache/harmony/security/provider/crypto/RandomBitsSupplier.java
===================================================================
--- modules/security/src/main/java/linux/org/apache/harmony/security/provider/crypto/RandomBitsSupplier.java (revision 0)
+++ modules/security/src/main/java/linux/org/apache/harmony/security/provider/crypto/RandomBitsSupplier.java (revision 0)
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2006 The Apache Software Software Foundation or its licensors, as applicable.
+ *
+ * Licensed 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.apache.harmony.security.provider.crypto;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+import java.security.ProviderException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+
+
+/**
+ * The static class providing access on Linux paltform
+ * to system means for generating true random bits.
+ *
+ * The source for true random bits is one of Linux's devices "/dev/urandom/" or
+ * "/dev/random" depends on which one is avalable; if both the first is used.
+ *
+ * If no device available the service is not avilable,
+ * that is, provider shouldn't register the algorithm.
+ */
+
+
+public class RandomBitsSupplier implements SHA1_Data {
+
+
+ /**
+ * BufferedInputStream to read from device
+ */
+ private static BufferedInputStream bis = null;
+
+ /**
+ * File to connect to device
+ */
+ private static File randomFile = null;
+
+ /**
+ * value of field is "true" only if a device is available
+ */
+ private static boolean serviceAvailable;
+
+
+ static {
+ AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+
+ for ( int i = 0 ; i < DEVICE_NAMES.length ; i++ ) {
+ File file = new File(DEVICE_NAMES[i]);
+
+ try {
+ if ( file.canRead() ) {
+ bis = new BufferedInputStream(
+ new FileInputStream(file));
+ randomFile = file;
+ return null;
+ }
+ } catch (FileNotFoundException e) {
+ }
+ }
+ return null;
+ }
+ }
+ );
+ serviceAvailable = (bis != null);
+ }
+
+
+ /**
+ * The method is called by provider to determine if a device is available.
+ */
+ static boolean isServiceAvailable() {
+ return serviceAvailable;
+ }
+
+
+ /**
+ * On the Linux platform with "random" devices available,
+ * the method reads random bytes from the device.
+ *
+ * In case of any runtime failure ProviderException gets thrown.
+ */
+ private static synchronized byte[] getLinuxRandomBits(int numBytes) {
+
+ byte[] bytes = new byte[numBytes];
+
+ int total = 0;
+ int bytesRead;
+ int offset = 0;
+ try {
+ for ( ; ; ) {
+
+ bytesRead = bis.read(bytes, offset, numBytes-total);
+
+
+ // the below case should not occur because /dev/random or /dev/urandom is a special file
+ // hence, if it is happened there is some internal problem
+ //
+ if ( bytesRead == -1 ) {
+ throw new ProviderException(
+ "ATTENTION: 'bytesRead == -1' in getLinuxRandomBits()" );
+ }
+
+ total += bytesRead;
+ offset += bytesRead;
+
+ if ( total >= numBytes ) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+
+ // actually there should be no IOException because device is a special file;
+ // hence, there is either some internal problem or, for instance,
+ // device was removed in runtime, or something else
+ //
+ throw new ProviderException(
+ "ATTENTION: IOException in RandomBitsSupplier.getLinuxRandomBits()\n", e );
+ }
+ return bytes;
+ }
+
+
+ /**
+ * The method returns byte array of requested length provided service is available.
+ * ProviderException gets thrown otherwise.
+ *
+ * @param
+ * numBytes - length of bytes requested
+ * @return
+ * byte array
+ * @throws
+ * InvalidArgumentException - if numBytes <= 0
+ */
+ public static byte[] getRandomBits(int numBytes) {
+
+ if ( numBytes <= 0 ) {
+ throw new IllegalArgumentException("numBytes <= 0 : " + numBytes);
+ }
+
+ if ( !serviceAvailable ) {
+ throw new ProviderException(
+ "ATTENTION: service is not available : no random devices");
+ }
+
+ return getLinuxRandomBits(numBytes);
+ }
+
+}