/** * Reseeds this random object. The given seed supplements, rather than replaces, the existing * seed. Thus, repeated calls are guaranteed never to reduce randomness. * * @param seed the seed. */ @Override public synchronized void engineSetSeed(byte[] seed) { if (state != null) { digest.update(state); for (int i = 0; i < state.length; i++) { state[i] = 0; } } state = digest.digest(seed); }
/** * Generates a user-specified number of random bytes. * * @param bytes the array to be filled in with random bytes. */ @Override public synchronized void engineNextBytes(byte[] result) { int index = 0; int todo; byte[] output = remainder; if (state == null) { byte[] seed = new byte[DIGEST_SIZE]; SeederHolder.seeder.engineNextBytes(seed); state = digest.digest(seed); } // Use remainder from last time int r = remCount; if (r > 0) { // How many bytes? todo = (result.length - index) < (DIGEST_SIZE - r) ? (result.length - index) : (DIGEST_SIZE - r); // Copy the bytes, zero the buffer for (int i = 0; i < todo; i++) { result[i] = output[r]; output[r++] = 0; } remCount += todo; index += todo; } // If we need more bytes, make them. while (index < result.length) { // Step the state digest.update(state); output = digest.digest(); updateState(state, output); // How many bytes? todo = (result.length - index) > DIGEST_SIZE ? DIGEST_SIZE : result.length - index; // Copy the bytes, zero the buffer for (int i = 0; i < todo; i++) { result[index++] = output[i]; output[i] = 0; } remCount += todo; } // Store remainder for next time remainder = output; remCount %= DIGEST_SIZE; }
/** * This call, used by the constructors, instantiates the SHA digest and sets the seed, if given. */ private void init(byte[] seed) { try { digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { throw new InternalError("internal error: SHA-1 not available.", e); } if (seed != null) { engineSetSeed(seed); } }
/* * readObject is called to restore the state of the random object from * a stream. We have to create a new instance of MessageDigest, because * it is not included in the stream (it is marked "transient"). * * Note that the engineNextBytes() method invoked on the restored random * object will yield the exact same (random) bytes as the original. * If you do not want this behaviour, you should re-seed the restored * random object, using engineSetSeed(). */ private void readObject(j86.java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); try { digest = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { throw new InternalError("internal error: SHA-1 not available.", e); } }
/** * Verifies the validity of checksum field * * @param data the application data * @param offset the offset where the data begins * @param len the length of the application data * @throws GSSException if an error occurs in the checksum calculation */ public final boolean verifySign(byte[] data, int offset, int len) throws GSSException { // debug("\t====In verifySign:====\n"); // debug("\t\t checksum: [" + getHexBytes(checksum) + "]\n"); // debug("\t\t data = [" + getHexBytes(data) + "]\n"); byte[] myChecksum = getChecksum(data, offset, len); // debug("\t\t mychecksum: [" + getHexBytes(myChecksum) +"]\n"); if (MessageDigest.isEqual(checksum, myChecksum)) { // debug("\t\t====Checksum PASS:====\n"); return true; } return false; }
static byte[] doTLS12PRF( byte[] secret, byte[] labelBytes, byte[] seed, int outputLength, String prfHash, int prfHashLength, int prfBlockSize) throws NoSuchAlgorithmException, DigestException { if (prfHash == null) { throw new NoSuchAlgorithmException("Unspecified PRF algorithm"); } MessageDigest prfMD = MessageDigest.getInstance(prfHash); return doTLS12PRF(secret, labelBytes, seed, outputLength, prfMD, prfHashLength, prfBlockSize); }
static byte[] doTLS12PRF( byte[] secret, byte[] labelBytes, byte[] seed, int outputLength, MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize) throws DigestException { if (secret == null) { secret = B0; } // If we have a long secret, digest it first. if (secret.length > mdPRFBlockSize) { secret = mdPRF.digest(secret); } byte[] output = new byte[outputLength]; byte[] ipad; byte[] opad; switch (mdPRFBlockSize) { case 64: ipad = HMAC_ipad64.clone(); opad = HMAC_opad64.clone(); break; case 128: ipad = HMAC_ipad128.clone(); opad = HMAC_opad128.clone(); break; default: throw new DigestException("Unexpected block size."); } // P_HASH(Secret, label + seed) expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes, seed, output, ipad, opad); return output; }
/* * @param digest the MessageDigest to produce the HMAC * @param hmacSize the HMAC size * @param secret the secret * @param secOff the offset into the secret * @param secLen the secret length * @param label the label * @param seed the seed * @param output the output array */ private static void expand( MessageDigest digest, int hmacSize, byte[] secret, int secOff, int secLen, byte[] label, byte[] seed, byte[] output, byte[] pad1, byte[] pad2) throws DigestException { /* * modify the padding used, by XORing the key into our copy of that * padding. That's to avoid doing that for each HMAC computation. */ for (int i = 0; i < secLen; i++) { pad1[i] ^= secret[i + secOff]; pad2[i] ^= secret[i + secOff]; } byte[] tmp = new byte[hmacSize]; byte[] aBytes = null; /* * compute: * * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + * HMAC_hash(secret, A(2) + seed) + * HMAC_hash(secret, A(3) + seed) + ... * A() is defined as: * * A(0) = seed * A(i) = HMAC_hash(secret, A(i-1)) */ int remaining = output.length; int ofs = 0; while (remaining > 0) { /* * compute A() ... */ // inner digest digest.update(pad1); if (aBytes == null) { digest.update(label); digest.update(seed); } else { digest.update(aBytes); } digest.digest(tmp, 0, hmacSize); // outer digest digest.update(pad2); digest.update(tmp); if (aBytes == null) { aBytes = new byte[hmacSize]; } digest.digest(aBytes, 0, hmacSize); /* * compute HMAC_hash() ... */ // inner digest digest.update(pad1); digest.update(aBytes); digest.update(label); digest.update(seed); digest.digest(tmp, 0, hmacSize); // outer digest digest.update(pad2); digest.update(tmp); digest.digest(tmp, 0, hmacSize); int k = Math.min(hmacSize, remaining); for (int i = 0; i < k; i++) { output[ofs++] ^= tmp[i]; } remaining -= k; } }
static byte[] doTLS10PRF( byte[] secret, byte[] labelBytes, byte[] seed, int outputLength, MessageDigest md5, MessageDigest sha) throws DigestException { /* * Split the secret into two halves S1 and S2 of same length. * S1 is taken from the first half of the secret, S2 from the * second half. * Their length is created by rounding up the length of the * overall secret divided by two; thus, if the original secret * is an odd number of bytes long, the last byte of S1 will be * the same as the first byte of S2. * * Note: Instead of creating S1 and S2, we determine the offset into * the overall secret where S2 starts. */ if (secret == null) { secret = B0; } int off = secret.length >> 1; int seclen = off + (secret.length & 1); byte[] secKey = secret; int keyLen = seclen; byte[] output = new byte[outputLength]; // P_MD5(S1, label + seed) // If we have a long secret, digest it first. if (seclen > 64) { // 64: block size of HMAC-MD5 md5.update(secret, 0, seclen); secKey = md5.digest(); keyLen = secKey.length; } expand( md5, 16, secKey, 0, keyLen, labelBytes, seed, output, HMAC_ipad64.clone(), HMAC_opad64.clone()); // P_SHA-1(S2, label + seed) // If we have a long secret, digest it first. if (seclen > 64) { // 64: block size of HMAC-SHA1 sha.update(secret, off, seclen); secKey = sha.digest(); keyLen = secKey.length; off = 0; } expand( sha, 20, secKey, off, keyLen, labelBytes, seed, output, HMAC_ipad64.clone(), HMAC_opad64.clone()); return output; }
static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, byte[] seed, int outputLength) throws NoSuchAlgorithmException, DigestException { MessageDigest md5 = MessageDigest.getInstance("MD5"); MessageDigest sha = MessageDigest.getInstance("SHA1"); return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha); }