1. Overview
1.概述
When launching the Java Virtual Machine (JVM), there are various properties we can define that will alter how our JVM behaves. One such property is java.security.egd.
在启动Java虚拟机(JVM)时,我们可以定义各种属性来改变JVM的行为方式。其中一个属性是java.security.egd.。
In this tutorial, we’ll examine what it is, how to use it, and what effect it has.
在本教程中,我们将研究它是什么,如何使用它,以及它有什么效果。
2. What Is java.security.egd?
2.什么是java.security.egd?
As a JVM property, we can use java.security.egd to affect how the SecureRandom class initializes.
作为一个JVM属性,我们可以使用java.security.egd来影响SecureRandom类如何初始化。
Like all JVM properties, we declare it using the -D parameter in our command line when launching the JVM:
像所有的JVM属性一样,我们在启动JVM时在命令行中使用-D参数来声明它。
java -Djava.security.egd=file:/dev/urandom -cp . com.baeldung.java.security.JavaSecurityEgdTester
Typically, if we’re running Java 8 or later and are running on Linux, then our JVM will use file:/dev/urandom by default.
通常,如果我们运行的是Java 8或更高版本,并且在Linux上运行,那么我们的JVM将默认使用file:/dev/urandom。
3. What Effect Does java.security.egd Have?
3.java.security.egd有什么影响?
When we make our first call to read bytes from SecureRandom we cause it to initialize and read the JVM’s java.security configuration file. This file contains a securerandom.source property:
当我们第一次调用从SecureRandom读取字节时,我们使它初始化并读取JVM的java.security配置文件。 该文件包含一个securerandom.source属性。
securerandom.source=file:/dev/random
Security Providers such as the default sun.security.provider.Sun read this property when initializing.
安全提供者,如默认的sun.security.provider.Sun在初始化时读取此属性。
When we set our java.security.egd JVM property, the Security Provider may use it to override the one configured in securerandom.source.
当我们设置我们的java.security.egd JVM属性时,安全提供者可以使用它来覆盖securerandom.source中配置的属性。
Together, java.security.egd and securerandom.source control which entropy gathering device (EGD) will be used as the main source of seed data when we use SecureRandom to generate random numbers.
当我们使用java.security.egd和securerandom.source控制哪个熵收集设备(EGD)将被用作种子数据的主要来源,以生成随机数。
Up to Java 8, we find java.security in $JAVA_HOME/jre/lib/security, but in later implementations, it’s in $JAVA_HOME/conf/security.
在Java 8之前,我们在java.security中找到$JAVA_HOME/jre/lib/security,但在后来的实现中,它在$JAVA_HOME/conf/security。
Whether or not the egd option has any effect depends on the Security Provider’s implementation.
egd选项是否有任何影响,取决于安全提供者的实现。
4. What Values Can java.security.egd Take?
4.java.security.egd可以取什么值?
We can specify java.security.egd in a URL format with values such as:
我们可以在URL格式中指定java.security.egd,其数值为:。
- file:/dev/random
- file:/dev/urandom
- file:/dev/./urandom
Whether this setting has any effect, or any other value makes a difference, depends on the platform and the version of Java we’re using, and how our JVM’s security has been configured.
该设置是否有任何影响,或任何其他值是否有区别,取决于我们使用的平台和Java版本,以及我们的JVM的安全性是如何被配置的。
On Unix-based operating systems (OS), /dev/random is a special file path that appears in the filesystem as a normal file, but reads from it actually interact with the OS’s device driver for random number generation. Some device implementations also provide access via /dev/urandom and even /dev/arandom URIs.
在基于Unix的操作系统(OS)上,/dev/random是一个特殊的文件路径,在文件系统中作为一个正常的文件出现,但从它的读取实际上是与OS的设备驱动程序互动,以生成随机数。一些设备实现也通过/dev/urandom,甚至/dev/arandom URI提供访问。
5. What’s So Special About file:/dev/./urandom?
5.file:/dev/./urandom有什么特别之处?
First, let’s understand the difference between the files /dev/random and /dev/urandom:
首先,让我们了解一下文件/dev/random和/dev/urandom:之间的区别。
- /dev/random gathers entropy from various sources; /dev/random will block until it has enough entropy to satisfy our read request with unpredictable data
- /dev/urandom will derive pseudo-randomness from whatever is available, without blocking.
When we first use SecureRandom, our default Sun SeedGenerator initializes.
当我们第一次使用SecureRandom时,我们默认的SunSeedGenerator会初始化。
When we use either of the special values file:/dev/random or file:/dev/urandom, we cause the Sun SeedGenerator to use a native (platform) implementation.
当我们使用特殊值file:/dev/random或file:/dev/urandom时,我们导致Sun SeedGenerator使用一个本地(平台)实现。
Provider implementations on Unix may block by still reading from /dev/random. In Java 1.4, some implementations were discovered to have this issue. The bug was subsequently fixed under Java 8’s JDK Enhancement Proposal (JEP 123).
Unix上的提供者实现可能会因为仍然从/dev/random读取而阻塞。在Java 1.4中,一些实现被发现有这个问题。这个错误随后在Java 8的JDK增强建议(JEP 123)中得到了修复。
Using a URL such as file:/dev/./urandom, or any other value, causes the SeedGenerator to treat it as the URL to the seed source we want to use.
使用诸如file:/dev/.urandom这样的URL,或者任何其他的值,都会导致SeedGenerator将其视为我们要使用的种子源的URL。
On Unix-like systems, our file:/dev/./urandom URL resolves to the same non-blocking /dev/urandom file.
在类Unix系统中,我们的file:/dev/./urandom URL解析到同一个非阻塞的/dev/urandom文件。
However, we don’t always want to use this value. On Windows, we don’t have this file, so our URL fails to resolve. This triggers a final mechanism to generate randomness and can delay our initialization by around 5 seconds.
然而,我们并不总是想使用这个值。在Windows上,我们没有这个文件,所以我们的URL无法解析。这就触发了最后的机制来产生随机性,并会使我们的初始化延迟5秒左右。
6. The Evolution of SecureRandom
6.SecureRandom的演变
The effect of java.security.egd has changed through the various Java releases.
java.security.egd的作用在不同的 Java 版本中都有所改变。
So, let’s see some of the more significant events that impacted the behavior of SecureRandom:
因此,让我们看看影响SecureRandom行为的一些更重要的事件。
- Java 1.4
- /dev/random blocking issue raised under JDK-4705093: Use /dev/urandom rather than /dev/random if it exists
- Java 5
- Fix for JDK-4705093
- Adds NativePRNG algorithm to respect the java.security.egd setting, but we need to manually configure it
- If SHA1PRNG is used, then it may block if we use anything other than file:/dev/urandom. In other words, it may block if we use file:/dev/./urandom
- Fix for JDK-4705093
- Java 8
- JEP123: Configurable Secure Random-Number Generation
- Adds new SecureRandom implementation, which respects the security properties
- Adds a new getInstanceStrong() method, for platform-native strong random numbers. Great for generating high-value and long-lived secrets, such as RSA private/public key pairs
- we no longer need the file:/dev/./urandom workaround
- JEP123: Configurable Secure Random-Number Generation
- Java 9
- JEP273: DRBG-Based SecureRandom Implementations
- Implements three Deterministic Random Bit Generator (DRBG) mechanisms as described in Recommendation for Random Number Generation Using Deterministic Random Bit Generators
- JEP273: DRBG-Based SecureRandom Implementations
Understanding how SecureRandom has changed gives us an insight into the likely effect of the java.security.egd property.
了解SecureRandom的变化,让我们了解java.security.egd属性的可能影响。
7. Testing the Effect of java.security.egd
7.测试java.security.egd的效果
The best way to be certain of the effect of a JVM property is to try it. So, let’s see the effect of java.security.egd by running some code to create a new SecureRandom and timing how long it takes to get some random bytes.
要确定JVM属性的效果,最好的办法就是去尝试。因此,让我们看看java.security.egd的效果,运行一些代码来创建一个新的SecureRandom,并计时获得一些随机字节的时间。
First, let’s create a JavaSecurityEgdTester class with a main() method. We’ll time our call to secureRandom.nextBytes() using System.nanoTime() and display the results:
首先,让我们创建一个JavaSecurityEgdTester类,其中有一个main()方法。我们将使用System.nanoTime()对secureRandom.nextBytes()的调用计时,并显示结果。
public class JavaSecurityEgdTester {
public static final double NANOSECS = 1000000000.0;
public static void main(String[] args) {
SecureRandom secureRandom = new SecureRandom();
long start = System.nanoTime();
byte[] randomBytes = new byte[256];
secureRandom.nextBytes(randomBytes);
double duration = (System.nanoTime() - start) / NANOSECS;
System.out.println("java.security.egd = " + System.getProperty("java.security.egd") + " took " + duration + " seconds and used the " + secureRandom.getAlgorithm() + " algorithm");
}
}
Now, let’s run a JavaSecurityEgdTester test by launching a new Java instance and specifying a value for the java.security.egd property:
现在,让我们运行一个JavaSecurityEgdTester测试,启动一个新的Java实例并为java.security.egd属性指定一个值。
java -Djava.security.egd=file:/dev/random -cp . com.baeldung.java.security.JavaSecurityEgdTester
Let’s check the output to see how long our test took and which algorithm was used:
让我们检查一下输出,看看我们的测试花了多长时间,以及使用了哪种算法。
java.security.egd=file:/dev/random took 0.692 seconds and used the SHA1PRNG algorithm
Since our System Property is only read at initialization, let’s launch our class in a new JVM for each different value of java.security.egd:
由于我们的系统属性只在初始化时被读取,让我们在一个新的 JVM 中为 java.security.egd 的每个不同值启动我们的类。
java -Djava.security.egd=file:/dev/urandom -cp . com.baeldung.java.security.JavaSecurityEgdTester
java -Djava.security.egd=file:/dev/./urandom -cp . com.baeldung.java.security.JavaSecurityEgdTester
java -Djava.security.egd=baeldung -cp . com.baeldung.java.security.JavaSecurityEgdTester
On Windows using Java 8 or Java 11, tests with the values file:/dev/random or file:/dev/urandom give sub-second times. Using anything else, such as file:/dev/./urandom, or even baeldung, makes our tests take over 5 seconds!
在使用Java 8或Java 11的Windows上,使用file:/dev/random或file:/dev/urandom的值进行测试,可以得到亚秒的时间。使用其他任何东西,例如file:/dev/.urandom,甚至baeldung,都会使我们的测试花费超过 5 秒!。
See our earlier section for an explanation of why this happens. On Linux, we might get different results.
请参阅我们前面的章节以了解为什么会发生这种情况。在Linux上,我们可能会得到不同的结果。
8. What About SecureRandom.getInstanceStrong()?
8.关于SecureRandom.getInstanceStrong()?
Java 8 introduced a SecureRandom.getInstanceStrong() method. Let’s see how that affects our results.
Java 8引入了一个SecureRandom.getInstanceStrong()方法。让我们看看这对我们的结果有何影响。
First, let’s replace our new SecureRandom() with SecureRandom.getInstanceStrong():
首先,让我们用SecureRandom.getInstanceStrong()替换我们的new SecureRandom()。
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
Now, let’s run the tests again:
现在,让我们再次运行这些测试。
java -Djava.security.egd=file:/dev/random -cp . com.baeldung.java.security.JavaSecurityEgdTester
When run on Windows, the value of the java.security.egd property has no discernible effect when we use SecureRandom.getInstanceStrong(). Even an unrecognized value gives us a fast response.
在Windows上运行时,当我们使用SecureRandom.getInstanceStrong()时,java.security.egd属性的值没有明显的影响。即使是一个未被识别的值也会给我们带来快速的响应。
Let’s check our output again and notice the under 0.01 seconds time. Let’s also observe that the algorithm is now Windows-PRNG:
让我们再次检查我们的输出,注意到不到0.01秒的时间。我们也来观察一下,现在的算法是Windows-PRNG。
java.security.egd=baeldung took 0.003 seconds and used the Windows-PRNG algorithm
Note that the PRNG in the names of the algorithms stands for Pseudo-Random Number Generator.
请注意,算法名称中的PRNG是指伪随机数发生器。
9. Seeding the Algorithm
9.播种算法
Because random numbers are used heavily in cryptography for secure keys, they need to be unpredictable.
因为随机数在密码学中被大量用于安全密钥,所以它们需要是不可预测的。
So, how we seed our algorithms directly affects the predictability of the random numbers they produce.
因此,我们如何为我们的算法播种,直接影响到它们产生的随机数的可预测性。
To generate unpredictability, SecureRandom implementations use entropy gathered from accumulated input to seed their algorithms. This comes from IO devices such as mice and keyboards.
为了产生不可预测性,SecureRandom实现使用从累积输入中收集的熵来作为其算法的种子。这来自于IO设备,如鼠标和键盘。
On Unix-like systems, our entropy is accumulated in the file /dev/random.
在类似Unix的系统中,我们的熵被积累在/dev/random文件中。
There’s no /dev/random file on Windows. Setting -Djava.security.egd to either file:/dev/random or file:/dev/urandom causes the default algorithm (SHA1PRNG) to seed using the native Microsoft Crypto API.
在 Windows 上没有 /dev/random 文件。 将 -DJA.security.egd 设置为 file:/dev/random 或 file:/dev/urandom 导致默认算法(SHA1PRNG)使用本地 Microsoft Crypto API 来播种。
10. What About Virtual Machines?
10.关于虚拟机?
Sometimes, our application may be running in a virtual machine that has little or no entropy gathering in /dev/random.
有时,我们的应用程序可能在一个虚拟机中运行,该虚拟机在/dev/random中很少或没有熵的收集。
Virtual machines have no physical mouse or keyboard to generate data, so the entropy in /dev/random accumulates much more slowly. This may cause our default SecureRandom call to block until there is enough entropy for it to generate an unpredictable number.
虚拟机没有物理鼠标或键盘来生成数据,所以/dev/random中的熵积累得更慢。这可能会导致我们默认的SecureRandom调用阻塞,直到有足够的熵让它生成一个不可预测的数字。
There are steps we can take to mitigate this. When running a VM in RedHat Linux, for example, the system administrator can configure a virtual IO random number generator, virtio-rng. This reads entropy from the physical machine that it’s hosted on.
我们可以采取一些措施来缓解这种情况。例如,当在RedHat Linux中运行一个虚拟机时,系统管理员可以配置一个虚拟IO随机数发生器,virtio-rng。这从它所托管的物理机上读取熵。
11. Troubleshooting Tips
11.故障处理提示
If our application hangs when it, or its dependencies, generates SecureRandom numbers, consider java.security.egd — in particular, when we run on Linux, and if we’re running on pre-Java 8.
如果我们的应用程序在生成SecureRandom数字时挂起,请考虑java.security.egd–特别是当我们在Linux上运行时,以及如果我们在Java 8之前运行时。
Our Spring Boot applications often use embedded Tomcat. This uses SecureRandoms to generate session keys. When we see Tomcat’s “Creation of SecureRandom instance” operation taking 5 seconds or more, we should try different values for java.security.egd.
我们的Spring Boot应用程序经常使用嵌入式Tomcat。这使用SecureRandoms来生成会话密钥。当我们看到Tomcat的 “创建SecureRandom实例 “操作耗时5秒或更多时,我们应该尝试不同的java.security.egd.的值。
12. Conclusion
12.结语
In this tutorial, we learned what the JVM property java.security.egd is, how to use it, and what effect it has. We also discovered that its effects can vary based on the platform we’re running on, and the version of Java we’re using.
在本教程中,我们了解了 JVM 属性 java.security.egd 是什么,如何使用它,以及它有什么作用。我们还发现,它的效果会因我们所运行的平台和所使用的 Java 版本而有所不同。
As a final note, we can read more about SecureRandom and how it works in the SecureRandom section of the JCA Reference Guide and the SecureRandom API Specification and be aware of some of the myths about urandom.
最后,我们可以在《JCA参考指南》的SecureRandom部分和SecureRandom API规范中阅读更多关于SecureRandom以及它如何工作的信息,并注意一些关于urandom的神话。
As usual, the code can be found over on GitHub.
像往常一样,代码可以在GitHub上找到over。