How to properly use setSeed() method in SecureRandom to generate RSA primes - java

I want to produce the two prime numbers for RSA key generation. I think in order to increase both primes' randomness, the random may be generated as the following:
SecureRandom r = SecureRandom.getInstance("SHA1PRNG");
r.setSeed(1232);
p = BigInteger.probablePrime(1024, r);
q = BigInteger.probablePrime(1024, r);
My question is: Do you think using SecureRandom will increase the p and q randomness? If so, how can I randomly set the value of setSeed() instead of making it a fixed value ( here i chose 1232)?

As CodesInChaos already shows, the default implementation of the SUN provider automatically seeds itself using the system random number generator. As Java itself doesn't have an (explicit) entropy source it is more or less dependent on the system for its seed.
You should never call setSeed before retrieving data from the "SHA1PRNG" in the SUN provider as that will make your RNG (Random Number Generator) into a Deterministic RNG - it will only use the given seed instead of adding the seed to the state. In other words, it will always generate the same stream of pseudo random bits or values.
The initial call to setSeed may differ per provider. Sometimes it will use the seed as only seed, but it may also just add the seed to the current state. On later Android versions (4.2 onwards) the seed is just added to the random state, so the "SHA1RNG" will stay fully random.
Probably the best way to generate your random number generator is just
SecureRandom r = new SecureRandom();
and let the Java runtime figure out the best one.
If you want to use an explicit algorithm (which is, however, ill-described by SUN/Oracle) then you could use:
SecureRandom r = SecureRandom.getInstance("SHA1PRNG");
as in your code.
Nowadays, it is also possible to use the NIST algorithms using "DRBG" as algorithm description, which you can then configure for the VM using the security properties.
Neither "SHA1PRNG" nor "DRBG" are implementation requirements, and it may differ per runtime / provider which algorithm is used or how they are seeded. I would never use them to re-generate a stream of previously generated bytes or values; please use a stream cipher for that. For instance, you could use a cipher instance Cipher for "AES/CTR/NoPadding" and encrypt zero-valued bytes to get to the key stream.
If you want to add entropy, use:
// just used to make sure that the SecureRandom is seeded by the OS
r.nextBytes(new byte[8]);
r.setSeed(1232);
A constant value or literal doesn't contain much (if any) entropy. Usual sources of entropy are the current time (or even better, System.nanoTime()), mouse movements etc.
For Java 8 there is a new method getInstanceStrong() with the following description:
Returns a SecureRandom object that was selected by using the algorithms/providers specified in the securerandom.strongAlgorithms Security property.
Some situations require strong random values, such as when creating high-value/long-lived secrets like RSA public/private keys. To help guide applications in selecting a suitable strong SecureRandom implementation, Java distributions include a list of known strong SecureRandom implementations in the securerandom.strongAlgorithms Security property.
Which should be used as a replacement for the call to the constructor. Be warned that this may return a blocking RNG, that is: an RNG that may block your thread until sufficient entropy has become available. It may also drain your OS entropy pool blocking other applications, so only use it sparingly.

Related

how to make SecureRandom to be constant using seedBytes in JAVA?

I have a kotlin android application and I need to use seed bytes to generate a secure random. how can I make the secure random to give the same number for the same seed bytes?
this is my code:
val seedBytes = byteArrayOf(116,-64,24,11,126,59,70,-12,68,-39,-33,65,-38,-88,-75,87,97,-112,-22,-64,12,44,-2,-41,-28,-52,82,107,-109,-66,47,41,-59,-44,-114,-95,80,-83,37,107,27,-93,-38,-116,37,-60,-97,98,-102,-61,-50,-83,69,27,11,-12,116,26,59,21,116,69,-90,-19);
val RANDOM = SecureRandom(seedBytes);
println(RANDOM) // => I want this print to always be the same
but right now for example one time I get
java.security.SecureRandom#c708450
and the other time I get
java.security.SecureRandom#de2e6b1
Your not getting a value from the random, but printing the instance of the random you have created. You cannot make this the same each time however if you call nextInt() for example it will be the same in both cases.
You've done it. You're a bit confused about that output.
System.out.println(someObj)
This is just syntax sugar for System.out.println(someObj.toString());.
The default toString() implementation, as found in java.lang.Object, is this:
public String toString() {
return this.getClass().getName() + "#" + printAsHex(System.identityHashCode(this));
}
In other words, that #c708450 stuff is the system's identity hash code for your SecureRandom instance. This is, vastly oversimplifying, it's memory address. The point is: If you have 2 identical references, the number is the same. That's all it does, it is otherwise meaningless, and every object in the system has this, it has nothing whatsoever to do with Random / SecureRandom, and the location in heap memory where the SecureRandom instance is at, has zero effect on the random numbers it spits out. In other words, that #foo thing is not the seed value. It is a number that has no meaning at all, other than when it is the same as another identity hash code.
The API of Random does not offer a way to get the seed value, nor to get the 'distance' from it. Therefore, it is not immediately obvious how one would ascertain that two separate instances of SecureRandom are going to produce the same sequence forever.
However, in practice, just invoke .nextInt() 100 times on both and if the same 100 numbers fall out? Rest assured.
Thus, if you want to print a 'footprint' of where your secure random is it, print a few invokes of .nextInt() or .nextByte(). This is more involved than just System.out.println(theSecureRandomInstance) - there is no easy way out; you'll have to write a method that does this (and be aware that this will advance the sequence, of course. You also can't shove em back in, either).
So the solution for me was to extend the android's SecureRandom and then re implement it with the java original code that permits generating same secure random with the same seed. it is not possible to do it with Android's built in Secure random because the possibility to create the same random with the same seed has been deprecated in Android N and was removed in Android P

SHA3-512 to Generate Keys in Java

Is it possible to use SHA3-512(a subset of keccak available in Java9) to generate keys in Java?
I have searched through a lot of noise and documentation to try to figure this out.
Currently it seems SHA3-512 is available as a hash for MessageDigest but not for generating keys. My code below tries to generate keys predictably(for wallet purposes like BIP32 but beyond currency to blockchain uses)
https://github.com/devssh/BlockchainFullNode/blob/d2978e598b4cdecdf4b3337713b2c3e839a6b181/src/main/java/app/model/Keyz.java#L111-L128
public static String GenerateSeed() throws Exception {
SecureRandom random = new SecureRandom();
byte[] seed = random.generateSeed(512);
return Base64.getEncoder().encodeToString(seed);
}
public static Keyz GenerateKey(String seedString) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator keyGen1 = KeyPairGenerator.getInstance("ECDSA");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
SecureRandom random1 = SecureRandom.getInstance("SHA1PRNG");
random1.setSeed(Base64.getDecoder().decode(seedString));
keyGen1.initialize(ecSpec, random1);
KeyPair keyPair1 = keyGen1.generateKeyPair();
PublicKey pub1 = keyPair1.getPublic();
PrivateKey priv1 = keyPair1.getPrivate();
//Keyz is a simple model that stores the 3 fields below and overrides equals and hashcode on those fields
return new Keyz("random", pub1, priv1);
}
As you can see, it uses SHA1PRNG to predictably generate keypair deterministically(I am fine with the security concerns on this) so that the keys can be recreated deterministically.
Here is a JUnit test to make sure the keys are deterministic(works for SHA1PRNG, needs to work in SHA3PRNG). Ideally what is needed is a SHA3-512 TRNG in the GenerateSeed and a SHA3PRNG in the GenerateKey. Since the keygenerator needs a SecureRandom I would be surprised if java.Security.SecureRandom is still on something as insecure as SHA1PRNG.
https://github.com/devssh/BlockchainFullNode/blob/d2978e598b4cdecdf4b3337713b2c3e839a6b181/test/main/java/app/model/KeyzTest.java#L16-L22
#Test
public void shouldReturnDeterministicKeys() throws Exception {
String seedString = GenerateSeed();
Keyz random1 = GenerateKey(seedString);
Keyz random2 = GenerateKey(seedString);
//This assertion works as we override equals and hashcode
assertEquals(random1, random2);
}
Can someone please let me know if they figured a way to get this to work
It seems what you are looking for is not available out of the box:
Note that SHA1 and SHA1PRNG are not equivalent. While the former is a hash algorithm, the latter is a pseudo random generation algorithm (that uses SHA1 to update its internal state, of course.) One trivial result of this difference is, SHA1 outputs a fixed size of bits, where SHA1PRNG outputs as many bits as you like.
Because of this difference, SHA3-512 cannot be used as PRNG directly, although it is available in Java. What you need to do is, implement a PRNG algorithm using SHA3-512 (this part is really tricky, since generating a pseudo random stream is quite difficult.) and register it through your custom Security Provider (like Bouncy Castle does) with some name MySHA3PRNG. After that, you can get an instance of it with name MySHA3PRNG as you do for SHA1PRNG. The rest remains as-is.
A major problem with this tricky part might be as follows: Quoting from here,
The paper "Sponge-based pseudo-random number generators" talks about just that and it also describes a clean and efficient way to construct a re-seedable PRNG with a (Keccak) sponge function. What you'll get is a PRNG based on a cryptographic hash function… with the usual security implications.
For example: the paper explicitly states that you should reseed regularly with sufficient entropy to prevent an attacker from going backwards on the period of the PRNG (which is probably what you've been hearing about).
However, what you need is a PRNG algorithm that does not need to be re-seeded. I hope you have sufficient theoretical background to prove that your custom PRNG algorithm is secure.
Good luck!

AES random key generation

I see many examples where the secret key is generated this way:
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(KEY_LEN);
SecretKey secretKey = generator.generateKey();
I'm in doubt if there's a difference (even conceptual) with the following:
byte[] material = new byte[KEY_LEN / Byte.SIZE];
SecureRandom.getInstanceStrong().nextBytes(material);
SecretKey secretKey = new SecretKeySpec(material, "AES");
Stated that both methods are 3 lines, is there some practical impact in preferring the first over the second?
Thanks
You could look at the actual source code for generateKey() to see the difference but ultimately they are both going to do the same steps to generate an AES key. I would argue the latter
byte[] material = new byte[KEY_LEN / Byte.SIZE];
SecureRandom.getInstanceStrong().nextBytes(material);
SecretKey secretKey = new SecretKeySpec(material, "AES");
is a little more brittle for the average coder, requiring them to understand the SecureRandom class. If you eliminate the second line altogether the code runs just fine with an all zero key, an obvious vulnerability that's also easy for an attacker to check. Also, using generateKey() can produce a properly formatted key if the algorithm has some particular requirements. For example, the now obsolete DES and Triple DES algorithms had a weird parity bit in each byte that some DES implementations expected to see.
There are many reasons why you would want to use the KeyGenerator method, which was designed for the purpose:
readability: generateKey tells you exactly what the algorithm is doing;
portability: e.g. when choosing a different algorithm);
correctness: SecretKeySpec may not validate the key entirely;
security: you would leave the key material exposed in the material variable, which may not be cleared or even garbage collected after the key is not required anymore;
hardware support: importing key material is often not supported for hardware devices; keys should be generated on the device itself (using a specialized KeyFactory implementation).
There is no reason at all to use the second method. If you want to use a very specific random number generator for generating the key then you can use one of the specialized init methods but beware that this may not be compatible with hardware devices.
The two code examples seem to be doing the same and as already answered usually they are.
However using security devices (e. g. HSM, smartcards or other crypto devices) by default they won't allow exposing the key bytes so you would be able to generate a key from arbitritrary byte array only in very limited cases..

Implementing a Pseudorandom Generator using AES

"A pseudorandom generator (PRG) is a deterministic algorithm that takes a short uniformly distributed string, known as the seed, and outputs a longer string that cannot be efficiently distinguished from a uniformly distributed string of that length." [1]
It is my understanding that we can create pseudorandom generators using stream ciphers. For instance, SCAPI, a Secure Multiparty Computation API, uses RC4 in the following example to create an output of a fixed number of bytes (check out.length):
//Create secret key and out byte array
...
//Create prg using the PrgFactory
PseudorandomGenerator prg = PrgFactory.getInstance().getObject("RC4");
SecretKey secretKey = prg.generateKey(256); //256 is the key size in bits.
//set the key
Prg.setKey(secretKey);
//get PRG bytes. The caller is responsible for allocating the out array.
//The result will be put in the out array.
prg.getPRGBytes(out.length, out);
Indeed, pseudorandom generators are particulary useful in some cryptographic protocols (i.e. this protocol) where we need to create a pseudorandom output of bytes, usually of a very large size, fast.
I have actually implemented this protocol using the SCAPI snippet shown above for the PRG part. Yet the authors, instead of using RC4 for their PRG, they use AES128 in CTR mode. Which makes sense since RC4 is known to be broken and since AES can be easily used as stream cipher.
I want to implement a pseudorandom generator using AES in CTR in the same fashion as the snippet above, but I'm unable to do so. My problem is not using AES in CTR, there are countless examples online. My problem is the out.length part. I don't know how to implement a PRG using AES (or any other cipher for that matter) in a way where I get to choose the exact number of output bytes, like the example above. How can I do this?
Before someone mentions that a hash function can do the same job: Indeed, this is basically a hash function but the problem in this particular protocol is that we need very large outputs (i.e. 32MB) where a hash function usually has a fixed output of (192, 256, 512 bits).
Finally, this question is not a duplicate to this one, because the latter is about implementing any kind of PRG in Python where this is one is about implementing an AES_CTR based PRG in Java.
Some useful links:
SCAPI's API
SCAPI's source code on PRGs
In CTR mode you just cut off the bytes you don't need (from the right hand side) of the block encrypt over the last counter. You can create the key stream by performing AES-CTR over the right number (out.length) of zero valued bytes as well.

Achieve more randomness through user input in Java

I want to achieve more randomness in my key generation implemented in java since the key strength is depending on it.
I want to use the java.security.KeyPairGenerator to create private and public keys.
A seed can be defined with the SecureRandom object.
SecureRandom random = new SecureRandom();
byte[] rand = new byte[8]; // or only one byte
Imagine I create the random byte[] as follows:
// new KeyPress registered
long currentTime = System.currentTimeMillis();
long time = currentTime - lastTime;
lastTime = currentTime;
byte = time % Byte.MAX_VALUE;
// add byte to array or to the SecureRandom object
random.setSeed(byte);
The initialize method allows to add the seed to the generator object. This should increase
the randomness of the keys.
// adds the seed to the generator
keyGen.initialize(4096, random);
The question is shall I set the seed of the key generator after all user inputs or after for example 8 bytes?
I know that the randomness gained here depends on the precision of the system clock. But I assume that the currentTimeMillis() method is precise.
Do you think this is a solution for more randomness?
Or do you think this does not change anything?
EDIT 1 03.12.13
First, thank you for your comments and thoughts!
#Quincunx "I would say that SecureRandom is probably random enough."
Enough for what? I mean I think it depends on what you need it for. Right?
And the question was how can I even increase the randomness?!
#IT-Pro yeah, I could use the square of the time, but I think the user input is more random, right?
Did you mean by saying after user input to collect an array of bytes and pass it after the user finished all his inputs to the generator?
EDIT 2 03.12.13
#Erickson
I think what you are saying is not true!
"these system level devices are already gathering entropy from key presses"
Can you please share a link to this?
You might have some more understanding in this topic than me, but please, if you say something like that I would like to read some more details about it!
This isn't necessary. It won't hurt your security, but it will hurt the readability—and credibility—of your code.
Providers of SecureRandom will seed the generator for you. The SUN provider and other quality providers will use a source of entropy from the underlying system, like /dev/random or /dev/urandom; these system level devices are already gathering entropy from key presses and other, less predictable source, or even from truly random physical processes.
So, I would suggest that you not bother. At best, key press timing will only give you a bit or two of entropy per key press, and that's only if the system source hasn't already included that event.
You could always take the cube root of currentTimeMillis()*currentTimeMillis()
That's a pretty random seed.
And yes. It seems that after user input is the best solution.

Categories

Resources