From f6d39849e84847d55f3ca890a8d4db12be7930c0 Mon Sep 17 00:00:00 2001 From: gregw Date: Fri, 17 Jul 2020 12:19:22 +0200 Subject: [PATCH] Improves #5053 by giving option of secure or pseudo random Allow random to be passed in and can default to a weak pseudo random. --- .../client/util/DigestAuthentication.java | 30 +++++++++++++++---- .../client/util/MultiPartContentProvider.java | 13 ++------ .../jetty/plus/webapp/PlusConfiguration.java | 5 +--- .../websocket/client/masks/RandomMasker.java | 26 +++++++++++++--- 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java index 37ce42b6968..53b9bcd4d89 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java @@ -26,6 +26,7 @@ import java.security.SecureRandom; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.client.HttpClient; @@ -46,19 +47,32 @@ import org.eclipse.jetty.util.TypeUtil; */ public class DigestAuthentication extends AbstractAuthentication { - private static final SecureRandom random = new SecureRandom(); + private final Random random; private final String user; private final String password; - /** + /** Construct a DigestAuthentication with a {@link SecureRandom} nonce. * @param uri the URI to match for the authentication * @param realm the realm to match for the authentication * @param user the user that wants to authenticate * @param password the password of the user */ public DigestAuthentication(URI uri, String realm, String user, String password) + { + this(uri, realm, user, password, new SecureRandom()); + } + + /** + * @param uri the URI to match for the authentication + * @param realm the realm to match for the authentication + * @param user the user that wants to authenticate + * @param password the password of the user + * @param random the Random generator to use for nonces, or null for a weak algorithm. + */ + public DigestAuthentication(URI uri, String realm, String user, String password, Random random) { super(uri, realm); + this.random = random; this.user = user; this.password = password; } @@ -217,9 +231,15 @@ public class DigestAuthentication extends AbstractAuthentication private String newClientNonce() { - byte[] bytes = new byte[8]; - random.nextBytes(bytes); - return toHexString(bytes); + if (random != null) + { + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + return toHexString(bytes); + } + + long pseudoRandom = System.nanoTime() ^ System.identityHashCode(new Object()); + return Long.toHexString(pseudoRandom); } private String toHexString(byte[] bytes) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java index 9110d5d86a8..6b907b6de69 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java @@ -23,12 +23,10 @@ import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; -import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.client.AsyncContentProvider; @@ -70,7 +68,6 @@ public class MultiPartContentProvider extends AbstractTypedContentProvider imple private static final Logger LOG = Log.getLogger(MultiPartContentProvider.class); private static final byte[] COLON_SPACE_BYTES = new byte[]{':', ' '}; private static final byte[] CR_LF_BYTES = new byte[]{'\r', '\n'}; - private static final Random random = new SecureRandom(); private final List parts = new ArrayList<>(); private final ByteBuffer firstBoundary; @@ -102,13 +99,9 @@ public class MultiPartContentProvider extends AbstractTypedContentProvider imple private static String makeBoundary() { StringBuilder builder = new StringBuilder("JettyHttpClientBoundary"); - int length = builder.length(); - while (builder.length() < length + 16) - { - long rnd = random.nextLong(); - builder.append(Long.toString(rnd < 0 ? -rnd : rnd, 36)); - } - builder.setLength(length + 16); + builder.append(Long.toString(System.identityHashCode(builder), 36)); + builder.append(Long.toString(System.identityHashCode(Thread.currentThread()), 36)); + builder.append(Long.toString(System.nanoTime(), 36)); return builder.toString(); } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java index 1744c227bc3..00503ffc968 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.plus.webapp; -import java.security.SecureRandom; -import java.util.Random; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; @@ -40,7 +38,6 @@ import org.eclipse.jetty.webapp.WebAppContext; public class PlusConfiguration extends AbstractConfiguration { private static final Logger LOG = Log.getLogger(PlusConfiguration.class); - private static final Random __random = new SecureRandom(); private Integer _key; @@ -101,7 +98,7 @@ public class PlusConfiguration extends AbstractConfiguration { try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(wac.getClassLoader())) { - _key = __random.nextInt(); + _key = (int)(this.hashCode() ^ System.nanoTime()); Context context = new InitialContext(); Context compCtx = (Context)context.lookup("java:comp"); compCtx.addToEnvironment(NamingContext.LOCK_PROPERTY, _key); diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/masks/RandomMasker.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/masks/RandomMasker.java index 5a9126a8021..d4e47222594 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/masks/RandomMasker.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/masks/RandomMasker.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.websocket.client.masks; -import java.security.SecureRandom; import java.util.Random; import org.eclipse.jetty.websocket.common.WebSocketFrame; @@ -29,7 +28,7 @@ public class RandomMasker implements Masker public RandomMasker() { - this(new SecureRandom()); + this(null); } public RandomMasker(Random random) @@ -40,8 +39,27 @@ public class RandomMasker implements Masker @Override public void setMask(WebSocketFrame frame) { - byte[] mask = new byte[4]; - random.nextBytes(mask); + byte[] mask; + if (random != null) + { + mask = new byte[4]; + random.nextBytes(mask); + } + else + { + // This is a weak random, but sufficient for a mask. + // Using a SecureRandom would result in lock contention + // Using a Random is as more predictable than this algorithm + // Using a onetime random is essentially a system time. + int pseudoRandom = (int)(System.identityHashCode(frame.hashCode()) ^ System.nanoTime()); + mask = new byte[] + { + (byte)pseudoRandom, + (byte)(pseudoRandom >> 8), + (byte)(pseudoRandom >> 16), + (byte)(pseudoRandom >> 24), + }; + } frame.setMask(mask); } }