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