RFR 8066397 Remove network-related seed initialization code in ThreadLocal/SplittableRandom
Peter Levart
peter.levart at gmail.com
Thu Dec 4 18:15:16 UTC 2014
On 12/04/2014 10:40 AM, Paul Sandoz wrote:
> Hi,
>
> I think we may be over-rotating a little on this.
>
> There is already a mechanism to create a cryptographically strong seed by setting a system property and using SecureRandom. That has a high initialization cost, but i think under those circumstances that cost is acceptable (it may well be possible to reduce that cost but i consider that to be a separate issue).
>
> For the default case what we need is something with low initialization cost that is *good enough* for the majority of cases e.g. documents the lower bound of cryptographic strength.
>
> I like Doug's approach to hide this under TLR, i think that fits well with the "good enough" aspect (cross seeding can be documented as an @implNote). But I still marginally prefer a public static method as well, and SecureRandom seems an appropriate choice (although it could easily be exposed on System or Runtime).
>
> Paul.
Right. I think the cleanest is to provide an internal public API
(modules will effectively hide it from user code) and then expose it if
desired by delegation or just use it internally. For JDK8u, the approach
to disable the API for user code could use similar trick as Unsafe. If
anyone wants to bother with reflection, let him do it. We can't prevent
that in JDK8 no matter how deep the implementation is buried.
Here's the 3rd iteration of SystemRandom:
http://cr.openjdk.java.net/~plevart/jdk9-dev/SystemRandom/webrev.03/
I managed to make LoadLibrary work (I used LoadLibraryA - the ANSI variant).
The API is back to getBytes() instance method and a getInstance() static
method that lazily initializes a singleton instance. This way the
initialization is clearly separated from use. Initialization is expected
to fail if the system does not support the interface (/dev/urandom or
ADVAPI32!RtlGenRandom), but use should always succeed unless there's
something wrong with the state of the operating system (testing will
show if my assumptions are correct).
The enclosed test results (on 64 bit Linux, i7 PC):
SystemRandomTest... (8 bytes / invocation)
1st invocation: 116368 ns, result: [47, -68, 15, -28, 76, -11, -70, -10]
Following 1000000 invocations: 0.624066896 s, (624 ns/invocation)
On 32 bit Windows 7 (VirtualBox guest on the same Linux host):
SystemRandomTest... (8 bytes / invocation)
1st invocation: 1329219 ns, result: [31, -5, 62, -34, -82, -69, 69, 80]
Following 1000000 invocations: 1.137231408 s, (1137 ns/invocation)
The initialization latency on Windows is higher that with code in
webrev.02, but sill lower that when using MS Crypto API. I think that's
because now the ADVAPI32.DLL is loaded lazily as part of singleton
initialization, in webrev.02 it was loaded as part of libjava.dll, since
it was linked with it, so the measurement did not include the
ADVAPI32.DLL loading time.
We can now play in Java and use a strategy that releases the singleton
after some time (thinking WeakReference) and ADVAPI32.DLL will be
effectively unloaded and unmapped from the process address space. The
same goes with UNIX variant and it's file descriptor open from
/dev/urandom file...
I think webrev.03 is ready for testing.
Regards, Peter
>
> On Dec 4, 2014, at 9:20 AM, Peter Levart <peter.levart at gmail.com> wrote:
>
>> On 12/04/2014 12:32 AM, Martin Buchholz wrote:
>>> On Wed, Dec 3, 2014 at 2:15 PM, Doug Lea <dl at cs.oswego.edu> wrote:
>>>
>>>> No public API because systemSeed need only be implemented
>>>> inside TLR, for its initial seed. Then the others can get their seeds
>>>> using ThreadLocalRandom.current().nextLong(), unless
>>>> java.util.secureRandomSeed is set (which I didn't illustrate above).
>>>> In other words, across all non-secure generators, you only need
>>>> one system-generated seed.
>>> That's good enough for seeding other non-cryptographically secure
>>> PRNGs, but if you want each caller to get a
>>> cryptographically secure random number, you need to avoid correlations
>>> between them that would arise when you use a non-CS PRNG to generate
>>> them from a single CS seed.
>> Unless java.util.Random is retrofitted to allocate new cryptographically secure seed for each new instance. In such case expression:
>>
>> new java.util.Random().nextLong()
>>
>> ...could be used to gather secure seed. Perhaps even SplittableRandom could allocate new seed from secure source for each new instance (only in public constructor - not when it is split()ed)...
>>
>> What makes those workarounds unsuitable is failure mode. Gathering secure seed is inherently coupled with possible failure which must be communicated explicitly to the consumer. But one must not be bothered with failure in situations where security is not a necessary ingredient.
>>
>> So for non-CS PRNGs, cross-seeding is a possible solution, but it's nicer for all of them to just use a common (internal) API.
>>
>> As far as public API is concerned, there already is one: SecureRandom.generateSeed(). It's as good as SystemRandom (uses same primary means) and has a nice cross-platform fallback (ThreadedSeedGenerator). It's only drawback is that it comes with all the baggage of security providers (Java and MS Crypto API on Windows). But that's ok for user code perhaps.
>>
>> So what we have here is two desires:
>> - we want a resource-friendly / with as little dependencies as possible way to generate some unique seed, with implicit fall-back which need not be secure
>> - we want a resource-friendly / with as little dependencies as possible way to generate secure random bytes that can be pseudo-random, but still secure, with explicit failure mode
>>
>> I'll try to address this dichotomy in the next iteration of the API.
>>
>> Regards, Peter
>>
>> P.S. Is anyone interested in generating truly random bytes?
>>
>> http://www.cryptography.com/public/pdf/Intel_TRNG_Report_20120312.pdf
>>
>> https://software.intel.com/en-us/tags/35970
>>
More information about the core-libs-dev
mailing list