Home | History | Annotate | Download | only in crypto
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 
     19 package org.apache.harmony.security.provider.crypto;
     20 
     21 import java.io.IOException;
     22 import java.io.ObjectInputStream;
     23 import java.io.ObjectOutputStream;
     24 import java.io.Serializable;
     25 import java.security.InvalidParameterException;
     26 import java.security.SecureRandomSpi;
     27 import libcore.io.Streams;
     28 import libcore.util.EmptyArray;
     29 
     30 /**
     31  * This class extends the SecureRandomSpi class implementing all its abstract methods. <BR>
     32  * <BR>
     33  * To generate pseudo-random bits, the implementation uses technique described in
     34  * the "Random Number Generator (RNG) algorithms" section, Appendix A,
     35  * JavaTM Cryptography Architecture, API Specification&Reference <BR>
     36  * <BR>
     37  * The class implements the Serializable interface.
     38  */
     39 
     40 public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serializable, SHA1_Data {
     41 
     42     private static final long serialVersionUID = 283736797212159675L;
     43 
     44     // constants to use in expressions operating on bytes in int and long variables:
     45     // END_FLAGS - final bytes in words to append to message;
     46     //             see "ch.5.1 Padding the Message, FIPS 180-2"
     47     // RIGHT1    - shifts to right for left half of long
     48     // RIGHT2    - shifts to right for right half of long
     49     // LEFT      - shifts to left for bytes
     50     // MASK      - mask to select counter's bytes after shift to right
     51 
     52     private static final int[] END_FLAGS = { 0x80000000, 0x800000, 0x8000, 0x80 };
     53 
     54     private static final int[] RIGHT1 = { 0, 40, 48, 56 };
     55 
     56     private static final int[] RIGHT2 = { 0, 8, 16, 24 };
     57 
     58     private static final int[] LEFT = { 0, 24, 16, 8 };
     59 
     60     private static final int[] MASK = { 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF,
     61             0x000000FF };
     62 
     63     // HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])"
     64     // to use to form byte array returning by the "nextBytes(byte[])" method
     65     // Note, that this implementation uses more bytes than it is defined
     66     // in the above specification.
     67     private static final int HASHBYTES_TO_USE = 20;
     68 
     69     // value of 16 defined in the "SECURE HASH STANDARD", FIPS PUB 180-2
     70     private static final int FRAME_LENGTH = 16;
     71 
     72     // miscellaneous constants defined in this implementation:
     73     // COUNTER_BASE - initial value to set to "counter" before computing "nextBytes(..)";
     74     //                note, that the exact value is not defined in STANDARD
     75     // HASHCOPY_OFFSET   - offset for copy of current hash in "copies" array
     76     // EXTRAFRAME_OFFSET - offset for extra frame in "copies" array;
     77     //                     as the extra frame follows the current hash frame,
     78     //                     EXTRAFRAME_OFFSET is equal to length of current hash frame
     79     // FRAME_OFFSET      - offset for frame in "copies" array
     80     // MAX_BYTES - maximum # of seed bytes processing which doesn't require extra frame
     81     //             see (1) comments on usage of "seed" array below and
     82     //             (2) comments in "engineNextBytes(byte[])" method
     83     //
     84     // UNDEFINED  - three states of engine; initially its state is "UNDEFINED"
     85     // SET_SEED     call to "engineSetSeed"  sets up "SET_SEED" state,
     86     // NEXT_BYTES   call to "engineNextByte" sets up "NEXT_BYTES" state
     87 
     88     private static final int COUNTER_BASE = 0;
     89 
     90     private static final int HASHCOPY_OFFSET = 0;
     91 
     92     private static final int EXTRAFRAME_OFFSET = 5;
     93 
     94     private static final int FRAME_OFFSET = 21;
     95 
     96     private static final int MAX_BYTES = 48;
     97 
     98     private static final int UNDEFINED = 0;
     99 
    100     private static final int SET_SEED = 1;
    101 
    102     private static final int NEXT_BYTES = 2;
    103 
    104     private static SHA1PRNG_SecureRandomImpl myRandom;
    105 
    106     // Structure of "seed" array:
    107     // -  0-79 - words for computing hash
    108     // - 80    - unused
    109     // - 81    - # of seed bytes in current seed frame
    110     // - 82-86 - 5 words, current seed hash
    111     private transient int[] seed;
    112 
    113     // total length of seed bytes, including all processed
    114     private transient long seedLength;
    115 
    116     // Structure of "copies" array
    117     // -  0-4  - 5 words, copy of current seed hash
    118     // -  5-20 - extra 16 words frame;
    119     //           is used if final padding exceeds 512-bit length
    120     // - 21-36 - 16 word frame to store a copy of remaining bytes
    121     private transient int[] copies;
    122 
    123     // ready "next" bytes; needed because words are returned
    124     private transient byte[] nextBytes;
    125 
    126     // index of used bytes in "nextBytes" array
    127     private transient int nextBIndex;
    128 
    129     // variable required according to "SECURE HASH STANDARD"
    130     private transient long counter;
    131 
    132     // contains int value corresponding to engine's current state
    133     private transient int state;
    134 
    135     // The "seed" array is used to compute both "current seed hash" and "next bytes".
    136     //
    137     // As the "SHA1" algorithm computes a hash of entire seed by splitting it into
    138     // a number of the 512-bit length frames (512 bits = 64 bytes = 16 words),
    139     // "current seed hash" is a hash (5 words, 20 bytes) for all previous full frames;
    140     // remaining bytes are stored in the 0-15 word frame of the "seed" array.
    141     //
    142     // As for calculating "next bytes",
    143     // both remaining bytes and "current seed hash" are used,
    144     // to preserve the latter for following "setSeed(..)" commands,
    145     // the following technique is used:
    146     // - upon getting "nextBytes(byte[])" invoked, single or first in row,
    147     //   which requires computing new hash, that is,
    148     //   there is no more bytes remaining from previous "next bytes" computation,
    149     //   remaining bytes are copied into the 21-36 word frame of the "copies" array;
    150     // - upon getting "setSeed(byte[])" invoked, single or first in row,
    151     //   remaining bytes are copied back.
    152 
    153     /**
    154      *  Creates object and sets implementation variables to their initial values
    155      */
    156     public SHA1PRNG_SecureRandomImpl() {
    157 
    158         seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
    159         seed[HASH_OFFSET] = H0;
    160         seed[HASH_OFFSET + 1] = H1;
    161         seed[HASH_OFFSET + 2] = H2;
    162         seed[HASH_OFFSET + 3] = H3;
    163         seed[HASH_OFFSET + 4] = H4;
    164 
    165         seedLength = 0;
    166         copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
    167         nextBytes = new byte[DIGEST_LENGTH];
    168         nextBIndex = HASHBYTES_TO_USE;
    169         counter = COUNTER_BASE;
    170         state = UNDEFINED;
    171     }
    172 
    173     /*
    174      * The method invokes the SHA1Impl's "updateHash(..)" method
    175      * to update current seed frame and
    176      * to compute new intermediate hash value if the frame is full.
    177      *
    178      * After that it computes a length of whole seed.
    179      */
    180     private void updateSeed(byte[] bytes) {
    181 
    182         // on call:   "seed" contains current bytes and current hash;
    183         // on return: "seed" contains new current bytes and possibly new current hash
    184         //            if after adding, seed bytes overfill its buffer
    185         SHA1Impl.updateHash(seed, bytes, 0, bytes.length - 1);
    186 
    187         seedLength += bytes.length;
    188     }
    189 
    190     /**
    191      * Changes current seed by supplementing a seed argument to the current seed,
    192      * if this already set;
    193      * the argument is used as first seed otherwise. <BR>
    194      *
    195      * The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi.
    196      *
    197      * @param
    198      *       seed - byte array
    199      * @throws
    200      *       NullPointerException - if null is passed to the "seed" argument
    201      */
    202     protected synchronized void engineSetSeed(byte[] seed) {
    203 
    204         if (seed == null) {
    205             throw new NullPointerException("seed == null");
    206         }
    207 
    208         if (state == NEXT_BYTES) { // first setSeed after NextBytes; restoring hash
    209             System.arraycopy(copies, HASHCOPY_OFFSET, this.seed, HASH_OFFSET,
    210                     EXTRAFRAME_OFFSET);
    211         }
    212         state = SET_SEED;
    213 
    214         if (seed.length != 0) {
    215             updateSeed(seed);
    216         }
    217     }
    218 
    219     /**
    220      * Returns a required number of random bytes. <BR>
    221      *
    222      * The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi. <BR>
    223      *
    224      * @param
    225      *       numBytes - number of bytes to return; should be >= 0.
    226      * @return
    227      *       byte array containing bits in order from left to right
    228      * @throws
    229      *       InvalidParameterException - if numBytes < 0
    230      */
    231     protected synchronized byte[] engineGenerateSeed(int numBytes) {
    232 
    233         byte[] myBytes; // byte[] for bytes returned by "nextBytes()"
    234 
    235         if (numBytes < 0) {
    236             throw new NegativeArraySizeException(Integer.toString(numBytes));
    237         }
    238         if (numBytes == 0) {
    239             return EmptyArray.BYTE;
    240         }
    241 
    242         if (myRandom == null) {
    243             myRandom = new SHA1PRNG_SecureRandomImpl();
    244             myRandom.engineSetSeed(RandomBitsSupplier.getRandomBits(DIGEST_LENGTH));
    245         }
    246 
    247         myBytes = new byte[numBytes];
    248         myRandom.engineNextBytes(myBytes);
    249 
    250         return myBytes;
    251     }
    252 
    253     /**
    254      * Writes random bytes into an array supplied.
    255      * Bits in a byte are from left to right. <BR>
    256      *
    257      * To generate random bytes, the "expansion of source bits" method is used,
    258      * that is,
    259      * the current seed with a 64-bit counter appended is used to compute new bits.
    260      * The counter is incremented by 1 for each 20-byte output. <BR>
    261      *
    262      * The method overrides engineNextBytes in class SecureRandomSpi.
    263      *
    264      * @param
    265      *       bytes - byte array to be filled in with bytes
    266      * @throws
    267      *       NullPointerException - if null is passed to the "bytes" argument
    268      */
    269     protected synchronized void engineNextBytes(byte[] bytes) {
    270 
    271         int i, n;
    272 
    273         long bits; // number of bits required by Secure Hash Standard
    274         int nextByteToReturn; // index of ready bytes in "bytes" array
    275         int lastWord; // index of last word in frame containing bytes
    276         final int extrabytes = 7;// # of bytes to add in order to computer # of 8 byte words
    277 
    278         if (bytes == null) {
    279             throw new NullPointerException("bytes == null");
    280         }
    281 
    282         lastWord = seed[BYTES_OFFSET] == 0 ? 0
    283                 : (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1;
    284 
    285         if (state == UNDEFINED) {
    286 
    287             // no seed supplied by user, hence it is generated thus randomizing internal state
    288             updateSeed(RandomBitsSupplier.getRandomBits(DIGEST_LENGTH));
    289             nextBIndex = HASHBYTES_TO_USE;
    290 
    291         } else if (state == SET_SEED) {
    292 
    293             System.arraycopy(seed, HASH_OFFSET, copies, HASHCOPY_OFFSET,
    294                     EXTRAFRAME_OFFSET);
    295 
    296             // possible cases for 64-byte frame:
    297             //
    298             // seed bytes < 48      - remaining bytes are enough for all, 8 counter bytes,
    299             //                        0x80, and 8 seedLength bytes; no extra frame required
    300             // 48 < seed bytes < 56 - remaining 9 bytes are for 0x80 and 8 counter bytes
    301             //                        extra frame contains only seedLength value at the end
    302             // seed bytes > 55      - extra frame contains both counter's bytes
    303             //                        at the beginning and seedLength value at the end;
    304             //                        note, that beginning extra bytes are not more than 8,
    305             //                        that is, only 2 extra words may be used
    306 
    307             // no need to set to "0" 3 words after "lastWord" and
    308             // more than two words behind frame
    309             for (i = lastWord + 3; i < FRAME_LENGTH + 2; i++) {
    310                 seed[i] = 0;
    311             }
    312 
    313             bits = (seedLength << 3) + 64; // transforming # of bytes into # of bits
    314 
    315             // putting # of bits into two last words (14,15) of 16 word frame in
    316             // seed or copies array depending on total length after padding
    317             if (seed[BYTES_OFFSET] < MAX_BYTES) {
    318                 seed[14] = (int) (bits >>> 32);
    319                 seed[15] = (int) (bits & 0xFFFFFFFF);
    320             } else {
    321                 copies[EXTRAFRAME_OFFSET + 14] = (int) (bits >>> 32);
    322                 copies[EXTRAFRAME_OFFSET + 15] = (int) (bits & 0xFFFFFFFF);
    323             }
    324 
    325             nextBIndex = HASHBYTES_TO_USE; // skipping remaining random bits
    326         }
    327         state = NEXT_BYTES;
    328 
    329         if (bytes.length == 0) {
    330             return;
    331         }
    332 
    333         nextByteToReturn = 0;
    334 
    335         // possibly not all of HASHBYTES_TO_USE bytes were used previous time
    336         n = (HASHBYTES_TO_USE - nextBIndex) < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
    337                 - nextBIndex
    338                 : bytes.length - nextByteToReturn;
    339         if (n > 0) {
    340             System.arraycopy(nextBytes, nextBIndex, bytes, nextByteToReturn, n);
    341             nextBIndex += n;
    342             nextByteToReturn += n;
    343         }
    344 
    345         if (nextByteToReturn >= bytes.length) {
    346             return; // return because "bytes[]" are filled in
    347         }
    348 
    349         n = seed[BYTES_OFFSET] & 0x03;
    350         for (;;) {
    351             if (n == 0) {
    352 
    353                 seed[lastWord] = (int) (counter >>> 32);
    354                 seed[lastWord + 1] = (int) (counter & 0xFFFFFFFF);
    355                 seed[lastWord + 2] = END_FLAGS[0];
    356 
    357             } else {
    358 
    359                 seed[lastWord] |= (int) ((counter >>> RIGHT1[n]) & MASK[n]);
    360                 seed[lastWord + 1] = (int) ((counter >>> RIGHT2[n]) & 0xFFFFFFFF);
    361                 seed[lastWord + 2] = (int) ((counter << LEFT[n]) | END_FLAGS[n]);
    362             }
    363             if (seed[BYTES_OFFSET] > MAX_BYTES) {
    364                 copies[EXTRAFRAME_OFFSET] = seed[FRAME_LENGTH];
    365                 copies[EXTRAFRAME_OFFSET + 1] = seed[FRAME_LENGTH + 1];
    366             }
    367 
    368             SHA1Impl.computeHash(seed);
    369 
    370             if (seed[BYTES_OFFSET] > MAX_BYTES) {
    371 
    372                 System.arraycopy(seed, 0, copies, FRAME_OFFSET, FRAME_LENGTH);
    373                 System.arraycopy(copies, EXTRAFRAME_OFFSET, seed, 0,
    374                         FRAME_LENGTH);
    375 
    376                 SHA1Impl.computeHash(seed);
    377                 System.arraycopy(copies, FRAME_OFFSET, seed, 0, FRAME_LENGTH);
    378             }
    379             counter++;
    380 
    381             int j = 0;
    382             for (i = 0; i < EXTRAFRAME_OFFSET; i++) {
    383                 int k = seed[HASH_OFFSET + i];
    384                 nextBytes[j] = (byte) (k >>> 24); // getting first  byte from left
    385                 nextBytes[j + 1] = (byte) (k >>> 16); // getting second byte from left
    386                 nextBytes[j + 2] = (byte) (k >>> 8); // getting third  byte from left
    387                 nextBytes[j + 3] = (byte) (k); // getting fourth byte from left
    388                 j += 4;
    389             }
    390 
    391             nextBIndex = 0;
    392             j = HASHBYTES_TO_USE < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
    393                     : bytes.length - nextByteToReturn;
    394 
    395             if (j > 0) {
    396                 System.arraycopy(nextBytes, 0, bytes, nextByteToReturn, j);
    397                 nextByteToReturn += j;
    398                 nextBIndex += j;
    399             }
    400 
    401             if (nextByteToReturn >= bytes.length) {
    402                 break;
    403             }
    404         }
    405     }
    406 
    407     private void writeObject(ObjectOutputStream oos) throws IOException {
    408 
    409         int[] intData = null;
    410 
    411         final int only_hash = EXTRAFRAME_OFFSET;
    412         final int hashes_and_frame = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH;
    413         final int hashes_and_frame_extra = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH
    414                 * 2;
    415 
    416         oos.writeLong(seedLength);
    417         oos.writeLong(counter);
    418         oos.writeInt(state);
    419         oos.writeInt(seed[BYTES_OFFSET]);
    420 
    421         int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
    422         // result may be 0
    423         if (state != NEXT_BYTES) {
    424 
    425             // either the state is UNDEFINED or previous method was "setSeed(..)"
    426             // so in "seed[]" to serialize are remaining bytes (seed[0-nRemaining]) and
    427             // current hash (seed[82-86])
    428 
    429             intData = new int[only_hash + nRemaining];
    430 
    431             System.arraycopy(seed, 0, intData, 0, nRemaining);
    432             System.arraycopy(seed, HASH_OFFSET, intData, nRemaining,
    433                     EXTRAFRAME_OFFSET);
    434 
    435         } else {
    436             // previous method was "nextBytes(..)"
    437             // so, data to serialize are all the above (two first are in "copies" array)
    438             // and current words in both frame and extra frame (as if)
    439 
    440             int offset = 0;
    441             if (seed[BYTES_OFFSET] < MAX_BYTES) { // no extra frame
    442 
    443                 intData = new int[hashes_and_frame + nRemaining];
    444 
    445             } else { // extra frame is used
    446 
    447                 intData = new int[hashes_and_frame_extra + nRemaining];
    448 
    449                 intData[offset] = seed[FRAME_LENGTH];
    450                 intData[offset + 1] = seed[FRAME_LENGTH + 1];
    451                 intData[offset + 2] = seed[FRAME_LENGTH + 14];
    452                 intData[offset + 3] = seed[FRAME_LENGTH + 15];
    453                 offset += 4;
    454             }
    455 
    456             System.arraycopy(seed, 0, intData, offset, FRAME_LENGTH);
    457             offset += FRAME_LENGTH;
    458 
    459             System.arraycopy(copies, FRAME_LENGTH + EXTRAFRAME_OFFSET, intData,
    460                     offset, nRemaining);
    461             offset += nRemaining;
    462 
    463             System.arraycopy(copies, 0, intData, offset, EXTRAFRAME_OFFSET);
    464             offset += EXTRAFRAME_OFFSET;
    465 
    466             System.arraycopy(seed, HASH_OFFSET, intData, offset,
    467                     EXTRAFRAME_OFFSET);
    468         }
    469         for (int i = 0; i < intData.length; i++) {
    470             oos.writeInt(intData[i]);
    471         }
    472 
    473         oos.writeInt(nextBIndex);
    474         oos.write(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
    475     }
    476 
    477     private void readObject(ObjectInputStream ois) throws IOException,
    478             ClassNotFoundException {
    479 
    480         seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
    481         copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
    482         nextBytes = new byte[DIGEST_LENGTH];
    483 
    484         seedLength = ois.readLong();
    485         counter = ois.readLong();
    486         state = ois.readInt();
    487         seed[BYTES_OFFSET] = ois.readInt();
    488 
    489         int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
    490 
    491         if (state != NEXT_BYTES) {
    492 
    493             for (int i = 0; i < nRemaining; i++) {
    494                 seed[i] = ois.readInt();
    495             }
    496             for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
    497                 seed[HASH_OFFSET + i] = ois.readInt();
    498             }
    499         } else {
    500             if (seed[BYTES_OFFSET] >= MAX_BYTES) {
    501 
    502                 // reading next bytes in seed extra frame
    503                 seed[FRAME_LENGTH] = ois.readInt();
    504                 seed[FRAME_LENGTH + 1] = ois.readInt();
    505                 seed[FRAME_LENGTH + 14] = ois.readInt();
    506                 seed[FRAME_LENGTH + 15] = ois.readInt();
    507             }
    508             // reading next bytes in seed frame
    509             for (int i = 0; i < FRAME_LENGTH; i++) {
    510                 seed[i] = ois.readInt();
    511             }
    512             // reading remaining seed bytes
    513             for (int i = 0; i < nRemaining; i++) {
    514                 copies[FRAME_LENGTH + EXTRAFRAME_OFFSET + i] = ois.readInt();
    515             }
    516             // reading copy of current hash
    517             for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
    518                 copies[i] = ois.readInt();
    519             }
    520             // reading current hash
    521             for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
    522                 seed[HASH_OFFSET + i] = ois.readInt();
    523             }
    524         }
    525 
    526         nextBIndex = ois.readInt();
    527         Streams.readFully(ois, nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
    528     }
    529 }
    530