package net.i2p.crypto; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.LinkedBlockingQueue; import net.i2p.I2PAppContext; import net.i2p.data.Hash; /** * Defines a wrapper for SHA-256 operation. * * As of release 0.8.7, uses java.security.MessageDigest by default. * As of release 0.9.25, uses only MessageDigest. * GNU-Crypto gnu.crypto.hash.Sha256Standalone * is removed as of 0.9.28. */ public final class SHA256Generator { private final LinkedBlockingQueue<MessageDigest> _digests; /** * @param context unused */ public SHA256Generator(I2PAppContext context) { _digests = new LinkedBlockingQueue<MessageDigest>(32); } public static final SHA256Generator getInstance() { return I2PAppContext.getGlobalContext().sha(); } /** * Calculate the SHA-256 hash of the source and cache the result. * @param source what to hash * @return hash of the source */ public final Hash calculateHash(byte[] source) { return calculateHash(source, 0, source.length); } /** * Calculate the hash and cache the result. * @param source what to hash */ public final Hash calculateHash(byte[] source, int start, int len) { MessageDigest digest = acquire(); digest.update(source, start, len); byte rv[] = digest.digest(); release(digest); return Hash.create(rv); } /** * Use this if you only need the data, not a Hash object. * Does not cache. * @param out needs 32 bytes starting at outOffset */ public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) { MessageDigest digest = acquire(); digest.update(source, start, len); try { digest.digest(out, outOffset, Hash.HASH_LENGTH); } catch (DigestException e) { throw new RuntimeException(e); } finally { release(digest); } } private MessageDigest acquire() { MessageDigest rv = _digests.poll(); if (rv != null) rv.reset(); else rv = getDigestInstance(); return rv; } private void release(MessageDigest digest) { _digests.offer(digest); } /** * Return a new MessageDigest from the system libs. * @since 0.8.7, public since 0.8.8 for FortunaStandalone */ public static MessageDigest getDigestInstance() { try { return MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } //private static final int RUNS = 100000; /** * Test the GNU and the JVM's implementations for speed * * Results: 2011-05 eeepc Atom * <pre> * JVM strlen GNU ms JVM ms * Oracle 387 3861 3565 * Oracle 40 825 635 * Harmony 387 8082 5158 * Harmony 40 4137 1753 * JamVM 387 36301 34100 * JamVM 40 7022 6016 * gij 387 125833 4342 * gij 40 22417 988 * </pre> */ /**** public static void main(String args[]) { if (args.length <= 0) { System.err.println("Usage: SHA256Generator string"); return; } byte[] data = args[0].getBytes(); Sha256Standalone gnu = new Sha256Standalone(); long start = System.currentTimeMillis(); for (int i = 0; i < RUNS; i++) { gnu.update(data, 0, data.length); byte[] sha = gnu.digest(); if (i == 0) System.out.println("SHA256 [" + args[0] + "] = [" + Base64.encode(sha) + "]"); gnu.reset(); } long time = System.currentTimeMillis() - start; System.out.println("Time for " + RUNS + " SHA-256 computations:"); System.out.println("GNU time (ms): " + time); start = System.currentTimeMillis(); MessageDigest md; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { System.err.println("Fatal: " + e); return; } for (int i = 0; i < RUNS; i++) { md.reset(); byte[] sha = md.digest(data); if (i == 0) System.out.println("SHA256 [" + args[0] + "] = [" + Base64.encode(sha) + "]"); } time = System.currentTimeMillis() - start; System.out.println("JVM time (ms): " + time); } ****/ }