From fc1d41b1e1ebedaa791d9dda6c41a559eded2b35 Mon Sep 17 00:00:00 2001 From: Bert Massop Date: Sat, 5 Oct 2024 17:15:06 +0200 Subject: [PATCH 1/5] Remove pooling for SHA256 digests SHA256 digests are cheap to construct nowadays. The pooling mechanism is complex and microbenchmarks show that it actually reduces performance. Remove the pooling, but keep the return digest method for compatibility. --- src/freenet/crypt/SHA256.java | 51 ++++++++--------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/src/freenet/crypt/SHA256.java b/src/freenet/crypt/SHA256.java index e68a8e0fa10..70cac7aea4e 100644 --- a/src/freenet/crypt/SHA256.java +++ b/src/freenet/crypt/SHA256.java @@ -35,19 +35,13 @@ 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; +import org.tanukisoftware.wrapper.WrapperManager; /** * @author Jeroen C. van Gelderen (gelderen@cryptix.org) @@ -55,7 +49,8 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING public class SHA256 { /** Size (in bytes) of this hash */ private static final int HASH_SIZE = 32; - private static final Queue> digests = new ConcurrentLinkedQueue<>(); + + private static final Provider mdProvider = Util.mdProviders.get("SHA-256"); /** * It won't reset the Message Digest for you! @@ -78,54 +73,30 @@ 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(); + } catch (NoSuchAlgorithmException e) { + WrapperManager.stop(NodeInitException.EXIT_CRAPPY_JVM); + throw new RuntimeException(e); } - WrapperManager.stop(NodeInitException.EXIT_CRAPPY_JVM); - throw new RuntimeException(); } /** - * 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() { From 6eb3a172710f0b03efaf27c998187e62dcf150fd Mon Sep 17 00:00:00 2001 From: Bert Massop Date: Sat, 5 Oct 2024 17:19:56 +0200 Subject: [PATCH 2/5] Assume the SHA-256 digest is supported This is already checked during construction of Util.mdProviders, there is no need to do the WrapperManager.stop() dance here because this will never happen. --- src/freenet/crypt/SHA256.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/freenet/crypt/SHA256.java b/src/freenet/crypt/SHA256.java index 70cac7aea4e..07671b92cf1 100644 --- a/src/freenet/crypt/SHA256.java +++ b/src/freenet/crypt/SHA256.java @@ -39,9 +39,7 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING import java.security.NoSuchAlgorithmException; import java.security.Provider; -import freenet.node.NodeInitException; import freenet.support.io.Closer; -import org.tanukisoftware.wrapper.WrapperManager; /** * @author Jeroen C. van Gelderen (gelderen@cryptix.org) @@ -75,14 +73,12 @@ public static void hash(InputStream is, MessageDigest md) throws IOException { /** * Create a new SHA-256 MessageDigest - * Either succeed or stop the node. */ public static MessageDigest getMessageDigest() { try { return MessageDigest.getInstance("SHA-256", mdProvider); } catch (NoSuchAlgorithmException e) { - WrapperManager.stop(NodeInitException.EXIT_CRAPPY_JVM); - throw new RuntimeException(e); + throw new IllegalStateException("SHA-256 not supported", e); } } From 2b962e2b2eb298951975ccb6cab6714f6990df44 Mon Sep 17 00:00:00 2001 From: Bert Massop Date: Sat, 5 Oct 2024 17:44:24 +0200 Subject: [PATCH 3/5] Remove all uses of SHA256.returnMessageDigest Since the removal of SHA256 digest pooling, SHA256.returnMessageDigest has become a no-op function. Remove all of its uses. --- src/freenet/client/Metadata.java | 8 +- .../client/async/KeyListenerTracker.java | 9 +- .../async/SplitFileFetcherKeyListener.java | 4 +- src/freenet/clients/fcp/ClientPut.java | 2 - src/freenet/crypt/HashType.java | 11 +- src/freenet/keys/CHKBlock.java | 1 - src/freenet/keys/ClientCHKBlock.java | 24 +-- src/freenet/keys/ClientKSK.java | 24 +-- src/freenet/keys/ClientSSK.java | 36 ++-- src/freenet/keys/InsertableClientSSK.java | 175 +++++++++--------- src/freenet/keys/Key.java | 1 - src/freenet/keys/NodeSSK.java | 4 +- src/freenet/keys/SSKBlock.java | 28 ++- src/freenet/node/FNPPacketMangler.java | 10 +- src/freenet/node/LocationManager.java | 2 - src/freenet/node/MasterKeys.java | 3 - .../updater/MainJarDependenciesChecker.java | 4 +- src/freenet/pluginmanager/PluginManager.java | 9 +- .../store/saltedhash/CipherManager.java | 20 +- src/freenet/support/io/BucketTools.java | 39 ++-- test/freenet/crypt/HMAC_legacy.java | 24 +-- 21 files changed, 179 insertions(+), 259 deletions(-) diff --git a/src/freenet/client/Metadata.java b/src/freenet/client/Metadata.java index 7aa86ba1054..0a9645bf50e 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 72efa9769dd..b62ff0a0443 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 656b1a28e47..339c36691c1 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 223740ebc80..61e24810259 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 29baf984117..d4f19e2ad1a 100644 --- a/src/freenet/crypt/HashType.java +++ b/src/freenet/crypt/HashType.java @@ -6,9 +6,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import org.bitpedia.util.TigerTree; - import freenet.support.Logger; +import org.bitpedia.util.TigerTree; public enum HashType { // warning: keep in sync with Util.mdProviders! @@ -46,7 +45,6 @@ public final MessageDigest get() { return new TigerTree(); } if(name().equals("SHA256")) { - // Use the pool return freenet.crypt.SHA256.getMessageDigest(); } else { try { @@ -58,9 +56,10 @@ public final MessageDigest get() { } } + /** + * @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/keys/CHKBlock.java b/src/freenet/keys/CHKBlock.java index f3940e9322e..ec8fbe481f7 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 a9f57c6f9ba..50b0febb7c4 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 deeef38bfcc..168e844007d 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 c3ab0d74898..9387b2a53d5 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 8f67544f2be..2ff8a138212 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 18011111272..0bb9a12fce9 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 e5ed87e2277..6173191f089 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 4447b95b03e..a59af2f63a3 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 7ca688b37cb..ce34e0cb1d0 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 ea92c912d77..a232c378922 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 1f48752cd7d..249f2a312b6 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 1a5daea3bc6..6369d348863 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 c15ba8f1a6d..dc00d9a8fd5 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; @@ -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 { @@ -1337,13 +1336,11 @@ private String getFileDigest(File file, String digest) throws PluginNotFoundExce MessageDigest hash = null; 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; + hash = SHA256.getMessageDigest(); } else { hash = MessageDigest.getInstance(digest); } @@ -1357,8 +1354,6 @@ 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); } finally { diff --git a/src/freenet/store/saltedhash/CipherManager.java b/src/freenet/store/saltedhash/CipherManager.java index 1ffddf4c4ff..8ef928fd3c3 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 8277deacb2f..910765051cf 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 81280ee4bcf..5f19c01dfa3 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); } } From bef6ca01026889ba04e1d87fe6b2b7744428c2b7 Mon Sep 17 00:00:00 2001 From: Bert Massop Date: Sat, 5 Oct 2024 18:06:58 +0200 Subject: [PATCH 4/5] Reduce SHA256 to a compatibility wrapper around HashType.SHA256 HashType had a special case around SHA256 but this is no longer needed since these digests are no longer pooled. Simplify and generalize the solution by having HashType create all digests, and reducing SHA256 to a compatibility wrapper offering a few convenience functions. --- src/freenet/crypt/HashType.java | 38 +++++++++++++-------------------- src/freenet/crypt/SHA256.java | 14 ++---------- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/freenet/crypt/HashType.java b/src/freenet/crypt/HashType.java index d4f19e2ad1a..bc48369b37d 100644 --- a/src/freenet/crypt/HashType.java +++ b/src/freenet/crypt/HashType.java @@ -5,14 +5,14 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.Provider; -import freenet.support.Logger; import org.bitpedia.util.TigerTree; 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), @@ -25,34 +25,26 @@ 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")) { - 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); } } diff --git a/src/freenet/crypt/SHA256.java b/src/freenet/crypt/SHA256.java index 07671b92cf1..1f2cfbca4b8 100644 --- a/src/freenet/crypt/SHA256.java +++ b/src/freenet/crypt/SHA256.java @@ -36,8 +36,6 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; import freenet.support.io.Closer; @@ -45,10 +43,6 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * @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 Provider mdProvider = Util.mdProviders.get("SHA-256"); /** * It won't reset the Message Digest for you! @@ -75,11 +69,7 @@ public static void hash(InputStream is, MessageDigest md) throws IOException { * Create a new SHA-256 MessageDigest */ public static MessageDigest getMessageDigest() { - try { - return MessageDigest.getInstance("SHA-256", mdProvider); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("SHA-256 not supported", e); - } + return HashType.SHA256.get(); } /** @@ -96,6 +86,6 @@ public static byte[] digest(byte[] data) { } public static int getDigestLength() { - return HASH_SIZE; + return HashType.SHA256.hashLength; } } From 73041752b6c6e482d0d472de923b7e1cfefc7849 Mon Sep 17 00:00:00 2001 From: Bert Massop Date: Sat, 5 Oct 2024 18:18:57 +0200 Subject: [PATCH 5/5] Remove SHA-256 special case in PluginManager --- src/freenet/pluginmanager/PluginManager.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/freenet/pluginmanager/PluginManager.java b/src/freenet/pluginmanager/PluginManager.java index dc00d9a8fd5..4e083107f65 100644 --- a/src/freenet/pluginmanager/PluginManager.java +++ b/src/freenet/pluginmanager/PluginManager.java @@ -40,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; @@ -1180,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); @@ -1331,19 +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; String result; try { - if ("SHA-256".equals(digest)) { - hash = SHA256.getMessageDigest(); - } else { - hash = MessageDigest.getInstance(digest); - } // We compute the hash // http://java.sun.com/developer/TechTips/1998/tt0915.html#tip2 fis = new FileInputStream(file); @@ -1355,7 +1350,7 @@ private String getFileDigest(File file, String digest) throws PluginNotFoundExce } result = HexUtil.bytesToHex(hash.digest()); } 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);