diff --git a/src/freenet/client/Metadata.java b/src/freenet/client/Metadata.java index 7aa86ba105..0a9645bf50 100644 --- a/src/freenet/client/Metadata.java +++ b/src/freenet/client/Metadata.java @@ -737,9 +737,7 @@ public static byte[] getCryptoKey(byte[] hash) { MessageDigest md = SHA256.getMessageDigest(); md.update(hash); md.update(SPLITKEY); - byte[] buf = md.digest(); - SHA256.returnMessageDigest(md); - return buf; + return md.digest(); } public static byte[] getCrossSegmentSeed(HashResult[] hashes, byte[] hashThisLayerOnly) { @@ -758,9 +756,7 @@ public static byte[] getCrossSegmentSeed(byte[] hash) { MessageDigest md = SHA256.getMessageDigest(); md.update(hash); md.update(CROSS_SEGMENT_SEED); - byte[] buf = md.digest(); - SHA256.returnMessageDigest(md); - return buf; + return md.digest(); } /** diff --git a/src/freenet/client/async/KeyListenerTracker.java b/src/freenet/client/async/KeyListenerTracker.java index 72efa9769d..b62ff0a044 100644 --- a/src/freenet/client/async/KeyListenerTracker.java +++ b/src/freenet/client/async/KeyListenerTracker.java @@ -6,13 +6,13 @@ import static java.lang.String.format; import java.security.MessageDigest; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.List; import freenet.crypt.RandomSource; import freenet.crypt.SHA256; @@ -20,7 +20,6 @@ import freenet.keys.KeyBlock; import freenet.keys.NodeSSK; import freenet.node.SendableGet; -import freenet.node.SendableRequest; import freenet.support.ByteArrayWrapper; import freenet.support.LogThresholdCallback; import freenet.support.Logger; @@ -469,9 +468,7 @@ private byte[] saltKey(byte[] key) { MessageDigest md = SHA256.getMessageDigest(); md.update(key); md.update(globalSalt); - byte[] ret = md.digest(); - SHA256.returnMessageDigest(md); - return ret; + return md.digest(); } protected void hintGlobalSalt(byte[] globalSalt2) { diff --git a/src/freenet/client/async/SplitFileFetcherKeyListener.java b/src/freenet/client/async/SplitFileFetcherKeyListener.java index 656b1a28e4..339c36691c 100644 --- a/src/freenet/client/async/SplitFileFetcherKeyListener.java +++ b/src/freenet/client/async/SplitFileFetcherKeyListener.java @@ -204,9 +204,7 @@ private byte[] localSaltKey(Key key) { MessageDigest md = SHA256.getMessageDigest(); md.update(key.getRoutingKey()); md.update(localSalt); - byte[] ret = md.digest(); - SHA256.returnMessageDigest(md); - return ret; + return md.digest(); } /** The segment bloom filters should only need to be written ONCE, and can all be written at diff --git a/src/freenet/clients/fcp/ClientPut.java b/src/freenet/clients/fcp/ClientPut.java index 223740ebc8..61e2481025 100644 --- a/src/freenet/clients/fcp/ClientPut.java +++ b/src/freenet/clients/fcp/ClientPut.java @@ -236,7 +236,6 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ is = data.getInputStream(); SHA256.hash(is, md); } catch (IOException e) { - SHA256.returnMessageDigest(md); Logger.error(this, "Got IOE: " + e.getMessage(), e); throw new MessageInvalidException(ProtocolErrorMessage.COULD_NOT_READ_FILE, "Unable to access file: " + e, identifier, global); @@ -244,7 +243,6 @@ public ClientPut(FCPConnectionHandler handler, ClientPutMessage message, FCPServ Closer.close(is); } foundHash = md.digest(); - SHA256.returnMessageDigest(md); if(logMINOR) Logger.minor(this, "FileHash result : we found " + Base64.encode(foundHash) + " and were given " + Base64.encode(saltedHash) + '.'); diff --git a/src/freenet/crypt/HashType.java b/src/freenet/crypt/HashType.java index 29baf98411..bc48369b37 100644 --- a/src/freenet/crypt/HashType.java +++ b/src/freenet/crypt/HashType.java @@ -5,15 +5,14 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.Provider; import org.bitpedia.util.TigerTree; -import freenet.support.Logger; - public enum HashType { // warning: keep in sync with Util.mdProviders! - SHA1(1, 20), - MD5(2, 16), + SHA1(1, "SHA1", 20), + MD5(2, "MD5", 16), SHA256(4, "SHA-256", 32), SHA384(8, "SHA-384", 48), SHA512(16, "SHA-512", 64), @@ -26,41 +25,33 @@ public enum HashType { public final String javaName; public final int hashLength; - private HashType(int bitmask, int hashLength) { - this.bitmask = bitmask; - this.javaName = super.name(); - this.hashLength = hashLength; - } + private final Provider provider; - private HashType(int bitmask, String name, int hashLength) { + HashType(int bitmask, String name, int hashLength) { this.bitmask = bitmask; this.javaName = name; this.hashLength = hashLength; + this.provider = javaName != null ? Util.mdProviders.get(javaName) : null; } public final MessageDigest get() { - if(javaName == null) { - if(this.name().equals("ED2K")) - return new Ed2MessageDigest(); - if(this.name().equals("TTH")) - return new TigerTree(); + if (this == ED2K) { + return new Ed2MessageDigest(); + } + if (this == TTH) { + return new TigerTree(); } - if(name().equals("SHA256")) { - // Use the pool - return freenet.crypt.SHA256.getMessageDigest(); - } else { - try { - return MessageDigest.getInstance(javaName, Util.mdProviders.get(javaName)); - } catch (NoSuchAlgorithmException e) { - Logger.error(HashType.class, "Internal error; please report:", e); - } - return null; + try { + return MessageDigest.getInstance(javaName, provider); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Unsupported digest algorithm " + javaName, e); } } + /** + * @deprecated message digests are no longer pooled, there is no need to recycle them + */ + @Deprecated public final void recycle(MessageDigest md) { - if(this.equals(SHA256)) { - freenet.crypt.SHA256.returnMessageDigest(md); - } // Else no pooling. } } diff --git a/src/freenet/crypt/SHA256.java b/src/freenet/crypt/SHA256.java index e68a8e0fa1..1f2cfbca4b 100644 --- a/src/freenet/crypt/SHA256.java +++ b/src/freenet/crypt/SHA256.java @@ -35,27 +35,14 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING import java.io.IOException; import java.io.InputStream; -import java.lang.ref.SoftReference; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import org.tanukisoftware.wrapper.WrapperManager; - -import freenet.node.Node; -import freenet.node.NodeInitException; -import freenet.support.Logger; import freenet.support.io.Closer; /** * @author Jeroen C. van Gelderen (gelderen@cryptix.org) */ public class SHA256 { - /** Size (in bytes) of this hash */ - private static final int HASH_SIZE = 32; - private static final Queue> digests = new ConcurrentLinkedQueue<>(); /** * It won't reset the Message Digest for you! @@ -78,57 +65,27 @@ public static void hash(InputStream is, MessageDigest md) throws IOException { } } - private static final Provider mdProvider = Util.mdProviders.get("SHA-256"); - /** * Create a new SHA-256 MessageDigest - * Either succeed or stop the node. */ public static MessageDigest getMessageDigest() { - try { - SoftReference item = null; - while (((item = digests.poll()) != null)) { - MessageDigest md = item.get(); - if (md != null) { - return md; - } - } - return MessageDigest.getInstance("SHA-256", mdProvider); - } catch(NoSuchAlgorithmException e2) { - //TODO: maybe we should point to a HOWTO for freejvms - Logger.error(Node.class, "Check your JVM settings especially the JCE!" + e2); - System.err.println("Check your JVM settings especially the JCE!" + e2); - e2.printStackTrace(); - } - WrapperManager.stop(NodeInitException.EXIT_CRAPPY_JVM); - throw new RuntimeException(); + return HashType.SHA256.get(); } /** - * Return a MessageDigest to the pool. - * Must be SHA-256 ! + * No-op function retained for backwards compatibility. + * + * @deprecated message digests are no longer pooled, there is no need to return them */ + @Deprecated public static void returnMessageDigest(MessageDigest md256) { - if(md256 == null) - return; - String algo = md256.getAlgorithm(); - if(!(algo.equals("SHA-256") || algo.equals("SHA256"))) - throw new IllegalArgumentException("Should be SHA-256 but is " + algo); - md256.reset(); - digests.add(new SoftReference<>(md256)); } public static byte[] digest(byte[] data) { - MessageDigest md = null; - try { - md = getMessageDigest(); - return md.digest(data); - } finally { - returnMessageDigest(md); - } + return getMessageDigest().digest(data); } public static int getDigestLength() { - return HASH_SIZE; + return HashType.SHA256.hashLength; } } diff --git a/src/freenet/keys/CHKBlock.java b/src/freenet/keys/CHKBlock.java index f3940e9322..ec8fbe481f 100644 --- a/src/freenet/keys/CHKBlock.java +++ b/src/freenet/keys/CHKBlock.java @@ -81,7 +81,6 @@ public CHKBlock(byte[] data2, byte[] header2, NodeCHK key, boolean verify, byte md.update(headers); md.update(data); byte[] hash = md.digest(); - SHA256.returnMessageDigest(md); if(key == null) { chk = new NodeCHK(hash, cryptoAlgorithm); } else { diff --git a/src/freenet/keys/ClientCHKBlock.java b/src/freenet/keys/ClientCHKBlock.java index a9f57c6f9b..50b0febb7c 100644 --- a/src/freenet/keys/ClientCHKBlock.java +++ b/src/freenet/keys/ClientCHKBlock.java @@ -9,12 +9,6 @@ import java.security.Provider; import java.util.Arrays; -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - import freenet.crypt.BlockCipher; import freenet.crypt.CTRBlockCipher; import freenet.crypt.JceLoader; @@ -33,6 +27,11 @@ import freenet.support.io.ArrayBucketFactory; import freenet.support.io.BucketTools; import freenet.support.math.MersenneTwister; +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; /** * @author amphibian @@ -142,7 +141,6 @@ public Bucket decodeOld(BucketFactory bf, int maxLength, boolean dontCompress) t byte[] dkey = key.cryptoKey; // Check: IV == hash of decryption key byte[] predIV = md256.digest(dkey); - SHA256.returnMessageDigest(md256); md256 = null; // Extract the IV byte[] iv = Arrays.copyOf(hbuf, 32); if(!Arrays.equals(iv, predIV)) @@ -496,9 +494,7 @@ public static ClientCHKBlock encodeNew(byte[] data, int dataLength, MessageDiges // Now calculate the final hash md256.update(header); byte[] finalHash = md256.digest(cdata); - - SHA256.returnMessageDigest(md256); - + // Now convert it into a ClientCHK ClientCHK finalKey = new ClientCHK(finalHash, encKey, asMetadata, cryptoAlgorithm, compressionAlgorithm); @@ -570,9 +566,7 @@ public static ClientCHKBlock encodeNewNoJCA(byte[] data, int dataLength, Message // Now calculate the final hash md256.update(header); byte[] finalHash = md256.digest(cdata); - - SHA256.returnMessageDigest(md256); - + // Now convert it into a ClientCHK ClientCHK finalKey = new ClientCHK(finalHash, encKey, asMetadata, cryptoAlgorithm, compressionAlgorithm); @@ -631,9 +625,7 @@ public static ClientCHKBlock innerEncode(byte[] data, int dataLength, MessageDig // Now calculate the final hash md256.update(header); byte[] finalHash = md256.digest(data); - - SHA256.returnMessageDigest(md256); - + // Now convert it into a ClientCHK key = new ClientCHK(finalHash, encKey, asMetadata, cryptoAlgorithm, compressionAlgorithm); diff --git a/src/freenet/keys/ClientKSK.java b/src/freenet/keys/ClientKSK.java index deeef38bfc..168e844007 100644 --- a/src/freenet/keys/ClientKSK.java +++ b/src/freenet/keys/ClientKSK.java @@ -5,16 +5,16 @@ /** A KSK. We know the private key from the keyword, so this can be both * requested and inserted. */ + import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import freenet.support.math.MersenneTwister; - import freenet.crypt.DSAPrivateKey; import freenet.crypt.DSAPublicKey; import freenet.crypt.Global; import freenet.crypt.SHA256; +import freenet.support.math.MersenneTwister; public class ClientKSK extends InsertableClientSSK { @@ -44,19 +44,15 @@ public static InsertableClientSSK create(FreenetURI uri) { public static ClientKSK create(String keyword) { MessageDigest md256 = SHA256.getMessageDigest(); + byte[] keywordHash = md256.digest(keyword.getBytes(StandardCharsets.UTF_8)); + MersenneTwister mt = new MersenneTwister(keywordHash); + DSAPrivateKey privKey = new DSAPrivateKey(Global.DSAgroupBigA, mt); + DSAPublicKey pubKey = new DSAPublicKey(Global.DSAgroupBigA, privKey); + byte[] pubKeyHash = md256.digest(pubKey.asBytes()); try { - byte[] keywordHash = md256.digest(keyword.getBytes(StandardCharsets.UTF_8)); - MersenneTwister mt = new MersenneTwister(keywordHash); - DSAPrivateKey privKey = new DSAPrivateKey(Global.DSAgroupBigA, mt); - DSAPublicKey pubKey = new DSAPublicKey(Global.DSAgroupBigA, privKey); - byte[] pubKeyHash = md256.digest(pubKey.asBytes()); - try { - return new ClientKSK(keyword, pubKeyHash, pubKey, privKey, keywordHash); - } catch (MalformedURLException e) { - throw new Error(e); - } - } finally { - SHA256.returnMessageDigest(md256); + return new ClientKSK(keyword, pubKeyHash, pubKey, privKey, keywordHash); + } catch (MalformedURLException e) { + throw new Error(e); } } diff --git a/src/freenet/keys/ClientSSK.java b/src/freenet/keys/ClientSSK.java index c3ab0d7489..9387b2a53d 100644 --- a/src/freenet/keys/ClientSSK.java +++ b/src/freenet/keys/ClientSSK.java @@ -74,27 +74,23 @@ public ClientSSK(String docName, byte[] pubKeyHash, byte[] extras, DSAPublicKey if(cryptoKey.length != CRYPTO_KEY_LENGTH) throw new MalformedURLException("Decryption key wrong length: "+cryptoKey.length+" should be "+CRYPTO_KEY_LENGTH); MessageDigest md = SHA256.getMessageDigest(); + if (pubKey != null) { + byte[] pubKeyAsBytes = pubKey.asBytes(); + md.update(pubKeyAsBytes); + byte[] otherPubKeyHash = md.digest(); + if (!Arrays.equals(otherPubKeyHash, pubKeyHash)) + throw new IllegalArgumentException(); + } + this.cryptoKey = cryptoKey; + md.update(docName.getBytes(StandardCharsets.UTF_8)); + byte[] buf = md.digest(); try { - if (pubKey != null) { - byte[] pubKeyAsBytes = pubKey.asBytes(); - md.update(pubKeyAsBytes); - byte[] otherPubKeyHash = md.digest(); - if (!Arrays.equals(otherPubKeyHash, pubKeyHash)) - throw new IllegalArgumentException(); - } - this.cryptoKey = cryptoKey; - md.update(docName.getBytes(StandardCharsets.UTF_8)); - byte[] buf = md.digest(); - try { - Rijndael aes = new Rijndael(256, 256); - aes.initialize(cryptoKey); - aes.encipher(buf, buf); - ehDocname = buf; - } catch (UnsupportedCipherException e) { - throw new Error(e); - } - } finally { - SHA256.returnMessageDigest(md); + Rijndael aes = new Rijndael(256, 256); + aes.initialize(cryptoKey); + aes.encipher(buf, buf); + ehDocname = buf; + } catch (UnsupportedCipherException e) { + throw new Error(e); } if(ehDocname == null) throw new NullPointerException(); diff --git a/src/freenet/keys/InsertableClientSSK.java b/src/freenet/keys/InsertableClientSSK.java index 8f67544f2b..2ff8a13821 100644 --- a/src/freenet/keys/InsertableClientSSK.java +++ b/src/freenet/keys/InsertableClientSSK.java @@ -3,11 +3,6 @@ * http://www.gnu.org/ for further details of the GPL. */ package freenet.keys; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; -import org.bouncycastle.crypto.signers.DSASigner; -import org.bouncycastle.crypto.signers.HMacDSAKCalculator; - import java.io.IOException; import java.math.BigInteger; import java.net.MalformedURLException; @@ -29,6 +24,10 @@ import freenet.support.api.Bucket; import freenet.support.compress.InvalidCompressionCodecException; import freenet.support.math.MersenneTwister; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import org.bouncycastle.crypto.signers.DSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; /** A ClientSSK that has a private key and therefore can be inserted. */ public class InsertableClientSSK extends ClientSSK { @@ -120,100 +119,96 @@ public ClientSSKBlock encode( } // Pad it MessageDigest md256 = SHA256.getMessageDigest(); - try { - byte[] data; - // First pad it - if (compressedData.length != SSKBlock.DATA_LENGTH) { - // Hash the data - if (compressedData.length != 0) - md256.update(compressedData); - byte[] digest = md256.digest(); - MersenneTwister mt = new MersenneTwister(digest); - data = Arrays.copyOf(compressedData, SSKBlock.DATA_LENGTH); - if (compressedData.length > data.length) { - throw new RuntimeException("compressedData.length = " + compressedData.length + " but data.length=" - + data.length); - } - Util.randomBytes(mt, data, compressedData.length, SSKBlock.DATA_LENGTH - compressedData.length); - } else { - data = compressedData; + byte[] data; + // First pad it + if (compressedData.length != SSKBlock.DATA_LENGTH) { + // Hash the data + if (compressedData.length != 0) + md256.update(compressedData); + byte[] digest = md256.digest(); + MersenneTwister mt = new MersenneTwister(digest); + data = Arrays.copyOf(compressedData, SSKBlock.DATA_LENGTH); + if (compressedData.length > data.length) { + throw new RuntimeException("compressedData.length = " + compressedData.length + " but data.length=" + + data.length); } + Util.randomBytes(mt, data, compressedData.length, SSKBlock.DATA_LENGTH - compressedData.length); + } else { + data = compressedData; + } - // Implicit hash of data - byte[] origDataHash = md256.digest(data); + // Implicit hash of data + byte[] origDataHash = md256.digest(data); - Rijndael aes; - try { - aes = new Rijndael(256, 256); - } catch (UnsupportedCipherException e) { - throw new Error("256/256 Rijndael not supported!"); - } + Rijndael aes; + try { + aes = new Rijndael(256, 256); + } catch (UnsupportedCipherException e) { + throw new Error("256/256 Rijndael not supported!"); + } - // Encrypt data. Data encryption key = H(plaintext data). + // Encrypt data. Data encryption key = H(plaintext data). - aes.initialize(origDataHash); - PCFBMode pcfb = PCFBMode.create(aes, origDataHash); + aes.initialize(origDataHash); + PCFBMode pcfb = PCFBMode.create(aes, origDataHash); - pcfb.blockEncipher(data, 0, data.length); + pcfb.blockEncipher(data, 0, data.length); - byte[] encryptedDataHash = md256.digest(data); + byte[] encryptedDataHash = md256.digest(data); - // Create headers + // Create headers - byte[] headers = new byte[SSKBlock.TOTAL_HEADERS_LENGTH]; - // First two bytes = hash ID - int x = 0; - headers[x++] = (byte) (KeyBlock.HASH_SHA256 >> 8); - headers[x++] = (byte) (KeyBlock.HASH_SHA256); - // Then crypto ID - headers[x++] = (byte) (Key.ALGO_AES_PCFB_256_SHA256 >> 8); - headers[x++] = Key.ALGO_AES_PCFB_256_SHA256; - // Then E(H(docname)) - // Copy to headers - System.arraycopy(ehDocname, 0, headers, x, ehDocname.length); - x += ehDocname.length; - // Now the encrypted headers - byte[] encryptedHeaders = Arrays.copyOf(origDataHash, SSKBlock.ENCRYPTED_HEADERS_LENGTH); - int y = origDataHash.length; - short len = (short) compressedData.length; - if (asMetadata) - len |= 32768; - encryptedHeaders[y++] = (byte) (len >> 8); - encryptedHeaders[y++] = (byte) len; - encryptedHeaders[y++] = (byte) (compressionAlgo >> 8); - encryptedHeaders[y++] = (byte) compressionAlgo; - if (encryptedHeaders.length != y) - throw new IllegalStateException("Have more bytes to generate encoding SSK"); - aes.initialize(cryptoKey); - pcfb.reset(ehDocname); - pcfb.blockEncipher(encryptedHeaders, 0, encryptedHeaders.length); - System.arraycopy(encryptedHeaders, 0, headers, x, encryptedHeaders.length); - x += encryptedHeaders.length; - // Generate implicit overall hash. - md256.update(headers, 0, x); - md256.update(encryptedDataHash); - byte[] overallHash = md256.digest(); - // Now sign it - DSASigner dsa = new DSASigner(new HMacDSAKCalculator(new SHA256Digest())); - dsa.init(true, new DSAPrivateKeyParameters(privKey.getX(), Global.getDSAgroupBigAParameters())); - BigInteger[] sig = dsa.generateSignature(Global.truncateHash(overallHash)); - // Pack R and S into 32 bytes each, and copy to headers. - // Then create and return the ClientSSKBlock. - byte[] rBuf = truncate(sig[0].toByteArray(), SSKBlock.SIG_R_LENGTH); - byte[] sBuf = truncate(sig[1].toByteArray(), SSKBlock.SIG_S_LENGTH); - System.arraycopy(rBuf, 0, headers, x, rBuf.length); - x += rBuf.length; - System.arraycopy(sBuf, 0, headers, x, sBuf.length); - x += sBuf.length; - if (x != SSKBlock.TOTAL_HEADERS_LENGTH) - throw new IllegalStateException("Too long"); - try { - return new ClientSSKBlock(data, headers, this, !logMINOR); - } catch (SSKVerifyException e) { - throw (AssertionError)new AssertionError("Impossible encoding error").initCause(e); - } - } finally { - SHA256.returnMessageDigest(md256); + byte[] headers = new byte[SSKBlock.TOTAL_HEADERS_LENGTH]; + // First two bytes = hash ID + int x = 0; + headers[x++] = (byte) (KeyBlock.HASH_SHA256 >> 8); + headers[x++] = (byte) (KeyBlock.HASH_SHA256); + // Then crypto ID + headers[x++] = (byte) (Key.ALGO_AES_PCFB_256_SHA256 >> 8); + headers[x++] = Key.ALGO_AES_PCFB_256_SHA256; + // Then E(H(docname)) + // Copy to headers + System.arraycopy(ehDocname, 0, headers, x, ehDocname.length); + x += ehDocname.length; + // Now the encrypted headers + byte[] encryptedHeaders = Arrays.copyOf(origDataHash, SSKBlock.ENCRYPTED_HEADERS_LENGTH); + int y = origDataHash.length; + short len = (short) compressedData.length; + if (asMetadata) + len |= 32768; + encryptedHeaders[y++] = (byte) (len >> 8); + encryptedHeaders[y++] = (byte) len; + encryptedHeaders[y++] = (byte) (compressionAlgo >> 8); + encryptedHeaders[y++] = (byte) compressionAlgo; + if (encryptedHeaders.length != y) + throw new IllegalStateException("Have more bytes to generate encoding SSK"); + aes.initialize(cryptoKey); + pcfb.reset(ehDocname); + pcfb.blockEncipher(encryptedHeaders, 0, encryptedHeaders.length); + System.arraycopy(encryptedHeaders, 0, headers, x, encryptedHeaders.length); + x += encryptedHeaders.length; + // Generate implicit overall hash. + md256.update(headers, 0, x); + md256.update(encryptedDataHash); + byte[] overallHash = md256.digest(); + // Now sign it + DSASigner dsa = new DSASigner(new HMacDSAKCalculator(new SHA256Digest())); + dsa.init(true, new DSAPrivateKeyParameters(privKey.getX(), Global.getDSAgroupBigAParameters())); + BigInteger[] sig = dsa.generateSignature(Global.truncateHash(overallHash)); + // Pack R and S into 32 bytes each, and copy to headers. + // Then create and return the ClientSSKBlock. + byte[] rBuf = truncate(sig[0].toByteArray(), SSKBlock.SIG_R_LENGTH); + byte[] sBuf = truncate(sig[1].toByteArray(), SSKBlock.SIG_S_LENGTH); + System.arraycopy(rBuf, 0, headers, x, rBuf.length); + x += rBuf.length; + System.arraycopy(sBuf, 0, headers, x, sBuf.length); + x += sBuf.length; + if (x != SSKBlock.TOTAL_HEADERS_LENGTH) + throw new IllegalStateException("Too long"); + try { + return new ClientSSKBlock(data, headers, this, !logMINOR); + } catch (SSKVerifyException e) { + throw (AssertionError)new AssertionError("Impossible encoding error").initCause(e); } } diff --git a/src/freenet/keys/Key.java b/src/freenet/keys/Key.java index 1801111127..0bb9a12fce 100644 --- a/src/freenet/keys/Key.java +++ b/src/freenet/keys/Key.java @@ -134,7 +134,6 @@ public synchronized double toNormalizedDouble() { md.update((byte)(TYPE >> 8)); md.update((byte)TYPE); byte[] digest = md.digest(); - SHA256.returnMessageDigest(md); md = null; cachedNormalizedDouble = Util.keyDigestAsNormalizedDouble(digest); return cachedNormalizedDouble; } diff --git a/src/freenet/keys/NodeSSK.java b/src/freenet/keys/NodeSSK.java index e5ed87e227..6173191f08 100644 --- a/src/freenet/keys/NodeSSK.java +++ b/src/freenet/keys/NodeSSK.java @@ -107,9 +107,7 @@ private static byte[] makeRoutingKey(byte[] pkHash, byte[] ehDocname) { MessageDigest md256 = SHA256.getMessageDigest(); md256.update(ehDocname); md256.update(pkHash); - byte[] key = md256.digest(); - SHA256.returnMessageDigest(md256); - return key; + return md256.digest(); } @Override diff --git a/src/freenet/keys/SSKBlock.java b/src/freenet/keys/SSKBlock.java index 4447b95b03..a59af2f63a 100644 --- a/src/freenet/keys/SSKBlock.java +++ b/src/freenet/keys/SSKBlock.java @@ -3,9 +3,6 @@ * http://www.gnu.org/ for further details of the GPL. */ package freenet.keys; -import org.bouncycastle.crypto.params.DSAPublicKeyParameters; -import org.bouncycastle.crypto.signers.DSASigner; - import java.math.BigInteger; import java.security.MessageDigest; import java.util.Arrays; @@ -16,6 +13,8 @@ import freenet.support.Fields; import freenet.support.HexUtil; import freenet.support.Logger; +import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.crypto.signers.DSASigner; /** * SSKBlock. Contains a full fetched key. Can do a node-level verification. Can @@ -138,21 +137,16 @@ public SSKBlock(byte[] data, byte[] headers, NodeSSK nodeKey, boolean dontVerify System.arraycopy(headers, x, bufS, 0, SIG_S_LENGTH); x+=SIG_S_LENGTH; - MessageDigest md = null; byte[] overallHash; - try { - md = SHA256.getMessageDigest(); - md.update(data); - byte[] dataHash = md.digest(); - // All headers up to and not including the signature - md.update(headers, 0, headersOffset + ENCRYPTED_HEADERS_LENGTH); - // Then the implicit data hash - md.update(dataHash); - // Makes the implicit overall hash - overallHash = md.digest(); - } finally { - SHA256.returnMessageDigest(md); - } + MessageDigest md = SHA256.getMessageDigest(); + md.update(data); + byte[] dataHash = md.digest(); + // All headers up to and not including the signature + md.update(headers, 0, headersOffset + ENCRYPTED_HEADERS_LENGTH); + // Then the implicit data hash + md.update(dataHash); + // Makes the implicit overall hash + overallHash = md.digest(); // Now verify it BigInteger r = new BigInteger(1, bufR); diff --git a/src/freenet/node/FNPPacketMangler.java b/src/freenet/node/FNPPacketMangler.java index 7ca688b37c..ce34e0cb1d 100644 --- a/src/freenet/node/FNPPacketMangler.java +++ b/src/freenet/node/FNPPacketMangler.java @@ -3,6 +3,10 @@ * http://www.gnu.org/ for further details of the GPL. */ package freenet.node; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; + import java.io.File; import java.net.InetAddress; import java.nio.charset.StandardCharsets; @@ -48,10 +52,6 @@ import freenet.support.io.InetAddressComparator; import freenet.support.io.NativeThread; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.concurrent.TimeUnit.SECONDS; - /** * @author amphibian * @@ -1760,7 +1760,6 @@ private int getInitialMessageID(byte[] identity) { // Similar to JFK keygen, should be safe enough. md.update("INITIAL0".getBytes(StandardCharsets.UTF_8)); byte[] hashed = md.digest(); - SHA256.returnMessageDigest(md); return Fields.bytesToInt(hashed, 0); } @@ -1771,7 +1770,6 @@ private int getInitialMessageID(byte[] identity, byte[] otherIdentity) { // Similar to JFK keygen, should be safe enough. md.update("INITIAL1".getBytes(StandardCharsets.UTF_8)); byte[] hashed = md.digest(); - SHA256.returnMessageDigest(md); return Fields.bytesToInt(hashed, 0); } diff --git a/src/freenet/node/LocationManager.java b/src/freenet/node/LocationManager.java index ea92c912d7..a232c37892 100644 --- a/src/freenet/node/LocationManager.java +++ b/src/freenet/node/LocationManager.java @@ -694,8 +694,6 @@ public void run() { announceLocChange(true, true, false); node.writeNodeFile(); } - - SHA256.returnMessageDigest(md); } catch (Throwable t) { Logger.error(this, "Caught "+t, t); } finally { diff --git a/src/freenet/node/MasterKeys.java b/src/freenet/node/MasterKeys.java index 1f48752cd7..249f2a312b 100644 --- a/src/freenet/node/MasterKeys.java +++ b/src/freenet/node/MasterKeys.java @@ -164,7 +164,6 @@ public static MasterKeys read(File masterKeysFile, Random hardRandom, String pas MasterKeys ret = new MasterKeys(clientCacheKey, databaseKey, tempfilesMasterSecret, flags); clear(data); clear(hash); - SHA256.returnMessageDigest(md); System.err.println("Read old master keys file"); if(mustWrite) { ret.changePassword(masterKeysFile, password, hardRandom); @@ -243,7 +242,6 @@ private static MasterKeys readOldFormat(DataInputStream dis, int length, Random MasterKeys ret = new MasterKeys(clientCacheKey, databaseKey, tempfilesMasterSecret, flags); clear(data); clear(hash); - SHA256.returnMessageDigest(md); return ret; } @@ -303,7 +301,6 @@ private void write(File masterKeysFile, String newPassword, Random hardRandom) t md.update(data, hashedStart, data.length-hashedStart); byte[] hash = md.digest(); - SHA256.returnMessageDigest(md); md = null; baos.write(hash, 0, HASH_LENGTH); data = baos.toByteArray(); diff --git a/src/freenet/node/updater/MainJarDependenciesChecker.java b/src/freenet/node/updater/MainJarDependenciesChecker.java index 1a5daea3bc..6369d34886 100644 --- a/src/freenet/node/updater/MainJarDependenciesChecker.java +++ b/src/freenet/node/updater/MainJarDependenciesChecker.java @@ -36,8 +36,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.tanukisoftware.wrapper.WrapperManager; - import freenet.client.FetchException; import freenet.crypt.SHA256; import freenet.keys.FreenetURI; @@ -53,6 +51,7 @@ import freenet.support.io.FileUtil.CPUArchitecture; import freenet.support.io.FileUtil.OperatingSystem; import freenet.support.io.NativeThread; +import org.tanukisoftware.wrapper.WrapperManager; /** * Parses the dependencies.properties file and ensures we have all the @@ -1665,7 +1664,6 @@ public static boolean validFile(File filename, byte[] expectedHash, long size, b MessageDigest md = SHA256.getMessageDigest(); SHA256.hash(fis, md); byte[] hash = md.digest(); - SHA256.returnMessageDigest(md); fis.close(); fis = null; if(Arrays.equals(hash, expectedHash)) { diff --git a/src/freenet/pluginmanager/PluginManager.java b/src/freenet/pluginmanager/PluginManager.java index c15ba8f1a6..4e083107f6 100644 --- a/src/freenet/pluginmanager/PluginManager.java +++ b/src/freenet/pluginmanager/PluginManager.java @@ -32,8 +32,6 @@ import java.util.jar.JarFile; import java.util.jar.Manifest; -import org.tanukisoftware.wrapper.WrapperManager; - import freenet.client.HighLevelSimpleClient; import freenet.clients.fcp.ClientPut; import freenet.clients.http.PageMaker.THEME; @@ -42,7 +40,7 @@ import freenet.config.InvalidConfigValueException; import freenet.config.NodeNeedRestartException; import freenet.config.SubConfig; -import freenet.crypt.SHA256; +import freenet.crypt.HashType; import freenet.keys.FreenetURI; import freenet.l10n.BaseL10n.LANGUAGE; import freenet.l10n.NodeL10n; @@ -68,6 +66,7 @@ import freenet.support.io.Closer; import freenet.support.io.FileUtil; import freenet.support.io.NativeThread.PriorityLevel; +import org.tanukisoftware.wrapper.WrapperManager; public class PluginManager { @@ -1181,7 +1180,7 @@ private void verifyDigest(PluginDownLoader pluginDownLoader, File pluginFile) if (digest == null) { return; } - String testsum = getFileDigest(pluginFile, "SHA-1"); + String testsum = getFileDigest(pluginFile); if (!(digest.equalsIgnoreCase(testsum))) { Logger.error(this, "Checksum verification failed, should be " + digest + " but was " + testsum); throw new PluginNotFoundException("Checksum verification failed, should be " + digest + " but was " + testsum); @@ -1332,21 +1331,14 @@ private long extractTimestamp(String filename) { return cachedFiles; } - private String getFileDigest(File file, String digest) throws PluginNotFoundException { + private String getFileDigest(File file) throws PluginNotFoundException { final int BUFFERSIZE = 4096; - MessageDigest hash = null; + MessageDigest hash = HashType.SHA1.get(); FileInputStream fis = null; BufferedInputStream bis = null; - boolean wasFromDigest256Pool = false; String result; try { - if ("SHA-256".equals(digest)) { - hash = SHA256.getMessageDigest(); // grab digest from pool - wasFromDigest256Pool = true; - } else { - hash = MessageDigest.getInstance(digest); - } // We compute the hash // http://java.sun.com/developer/TechTips/1998/tt0915.html#tip2 fis = new FileInputStream(file); @@ -1357,10 +1349,8 @@ private String getFileDigest(File file, String digest) throws PluginNotFoundExce hash.update(buffer, 0, len); } result = HexUtil.bytesToHex(hash.digest()); - if (wasFromDigest256Pool) - SHA256.returnMessageDigest(hash); } catch(Exception e) { - throw new PluginNotFoundException("Error while computing hash '"+digest+"' of the downloaded plugin: " + e, e); + throw new PluginNotFoundException("Error while computing hash of the downloaded plugin: " + e, e); } finally { Closer.close(bis); Closer.close(fis); diff --git a/src/freenet/store/saltedhash/CipherManager.java b/src/freenet/store/saltedhash/CipherManager.java index 1ffddf4c4f..8ef928fd3c 100644 --- a/src/freenet/store/saltedhash/CipherManager.java +++ b/src/freenet/store/saltedhash/CipherManager.java @@ -77,21 +77,17 @@ byte[] getDigestedKey(byte[] plainKey) { } MessageDigest digest = SHA256.getMessageDigest(); - try { - digest.update(plainKey); - digest.update(salt); - - byte[] hashedRoutingKey = digest.digest(); - assert hashedRoutingKey.length == 0x20; + digest.update(plainKey); + digest.update(salt); - synchronized (digestRoutingKeyCache) { - digestRoutingKeyCache.put(key, hashedRoutingKey); - } + byte[] hashedRoutingKey = digest.digest(); + assert hashedRoutingKey.length == 0x20; - return hashedRoutingKey; - } finally { - SHA256.returnMessageDigest(digest); + synchronized (digestRoutingKeyCache) { + digestRoutingKeyCache.put(key, hashedRoutingKey); } + + return hashedRoutingKey; } /** diff --git a/src/freenet/support/io/BucketTools.java b/src/freenet/support/io/BucketTools.java index 8277deacb2..910765051c 100644 --- a/src/freenet/support/io/BucketTools.java +++ b/src/freenet/support/io/BucketTools.java @@ -14,10 +14,7 @@ import java.util.List; import java.util.Random; -import freenet.support.math.MersenneTwister; - import freenet.crypt.AEADCryptBucket; - import freenet.crypt.EncryptedRandomAccessBucket; import freenet.crypt.EncryptedRandomAccessBuffer; import freenet.crypt.MasterSecret; @@ -30,6 +27,7 @@ import freenet.support.api.LockableRandomAccessBuffer; import freenet.support.api.RandomAccessBucket; import freenet.support.api.RandomAccessBuffer; +import freenet.support.math.MersenneTwister; /** * Helper functions for working with Buckets. @@ -276,27 +274,22 @@ public static byte[] hash(Bucket data) throws IOException { InputStream is = data.getInputStreamUnbuffered(); try { MessageDigest md = SHA256.getMessageDigest(); - try { - long bucketLength = data.size(); - long bytesRead = 0; - byte[] buf = new byte[BUFFER_SIZE]; - while ((bytesRead < bucketLength) || (bucketLength == -1)) { - int readBytes = is.read(buf); - if (readBytes < 0) - break; - bytesRead += readBytes; - if (readBytes > 0) - md.update(buf, 0, readBytes); - } - if ((bytesRead < bucketLength) && (bucketLength > 0)) - throw new EOFException(); - if ((bytesRead != bucketLength) && (bucketLength > 0)) - throw new IOException("Read " + bytesRead + " but bucket length " + bucketLength + " on " + data + '!'); - byte[] retval = md.digest(); - return retval; - } finally { - SHA256.returnMessageDigest(md); + long bucketLength = data.size(); + long bytesRead = 0; + byte[] buf = new byte[BUFFER_SIZE]; + while ((bytesRead < bucketLength) || (bucketLength == -1)) { + int readBytes = is.read(buf); + if (readBytes < 0) + break; + bytesRead += readBytes; + if (readBytes > 0) + md.update(buf, 0, readBytes); } + if ((bytesRead < bucketLength) && (bucketLength > 0)) + throw new EOFException(); + if ((bytesRead != bucketLength) && (bucketLength > 0)) + throw new IOException("Read " + bytesRead + " but bucket length " + bucketLength + " on " + data + '!'); + return md.digest(); } finally { if(is != null) is.close(); } diff --git a/test/freenet/crypt/HMAC_legacy.java b/test/freenet/crypt/HMAC_legacy.java index 81280ee4bc..5f19c01dfa 100644 --- a/test/freenet/crypt/HMAC_legacy.java +++ b/test/freenet/crypt/HMAC_legacy.java @@ -129,26 +129,14 @@ public static void main(String[] args) { } public static byte[] macWithSHA256(byte[] K, byte[] text, int macbytes) { - MessageDigest sha256 = null; - try { - sha256 = SHA256.getMessageDigest(); - HMAC_legacy hash = new HMAC_legacy(sha256); - return hash.mac(K, text, macbytes); - } finally { - if(sha256 != null) - SHA256.returnMessageDigest(sha256); - } + MessageDigest sha256 = SHA256.getMessageDigest(); + HMAC_legacy hash = new HMAC_legacy(sha256); + return hash.mac(K, text, macbytes); } public static boolean verifyWithSHA256(byte[] K, byte[] text, byte[] mac) { - MessageDigest sha256 = null; - try { - sha256 = SHA256.getMessageDigest(); - HMAC_legacy hash = new HMAC_legacy(sha256); - return hash.verify(K, text, mac); - } finally { - if(sha256 != null) - SHA256.returnMessageDigest(sha256); - } + MessageDigest sha256 = SHA256.getMessageDigest(); + HMAC_legacy hash = new HMAC_legacy(sha256); + return hash.verify(K, text, mac); } }