Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove pooling and other special cases for SHA-256 digests #985

Merged
merged 5 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/freenet/client/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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();
}

/**
Expand Down
9 changes: 3 additions & 6 deletions src/freenet/client/async/KeyListenerTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@
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;
import freenet.keys.Key;
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;
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 1 addition & 3 deletions src/freenet/client/async/SplitFileFetcherKeyListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions src/freenet/clients/fcp/ClientPut.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,13 @@ 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);
} finally {
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) + '.');

Expand Down
47 changes: 19 additions & 28 deletions src/freenet/crypt/HashType.java
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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.
}
}
57 changes: 7 additions & 50 deletions src/freenet/crypt/SHA256.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 ([email protected])
*/
public class SHA256 {
/** Size (in bytes) of this hash */
private static final int HASH_SIZE = 32;
private static final Queue<SoftReference<MessageDigest>> digests = new ConcurrentLinkedQueue<>();

/**
* It won't reset the Message Digest for you!
Expand All @@ -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<MessageDigest> 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;
}
}
1 change: 0 additions & 1 deletion src/freenet/keys/CHKBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
24 changes: 8 additions & 16 deletions src/freenet/keys/ClientCHKBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
24 changes: 10 additions & 14 deletions src/freenet/keys/ClientKSK.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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);
}
}

Expand Down
Loading