Using secure random to generate a long number - java

I have seeded my secure random object with a long number. Now I want to extract another long number. But there is only a function called nextBytes(byte[] b) which gives a random byte[].
Is there any way to get a long number?
SecureRandom ranGen1 = new SecureRandom();
ranGen1.setSeed(1000);
SecureRandom ranGen2 = new SecureRandom();
ranGen2.setSeed(1000);
byte[] b1= new byte[3];
byte[] b2=new byte[3];
ranGen1.nextBytes(b1);
ranGen2.nextBytes(b2);
int a1=b1[0];
int a2=b1[1];
int a3=b1[2];
int c1=b2[0];
int c2=b2[1];
int c3=b2[2];
System.out.println(a1+", "+a2+", "+a3);//genearated by ranGen1
System.out.println(c1+", "+c2+", "+c3);//generated by ranGen2
System.out.println(ranGen1.nextLong());//genearated by ranGen1
System.out.println(ranGen2.nextLong());//generated by ranGen2
result:
4, -67, 69
4, -67, 69
-3292989024239613972 //this is using nextLong()
-3292989024239613972
The Output for Peter Lawrey's code:(Using secure random)
-7580880967916090810 -7580880967916090810
7364820596437092015 7364820596437092015
6152225453014145174 6152225453014145174
6933818190189005053 6933818190189005053
-2602185131584800869 -2602185131584800869
-4964993377763884762 -4964993377763884762
-3544990590938409243 -3544990590938409243
8725474288412822874 8725474288412822874
-8206089057857703584 -8206089057857703584
-7903450126640733697 -7903450126640733697
They are exaclty the same. How could you get different numbers?
This is the output that I am getting after using Peter Lawrey's second update(I am using windows operating system and he seems to be using some other operaing system which has created the confusion)
SHA1PRNG appears to produce the same values with the same seed
The default PRNG on this system is SHA1PRNG

Revised again, this is the correct answer! (and I should follow my own advice and read the documentation more carefully)
Is this what you're using? If so, it extends Random so it has an inherited nextLong() method. As it overrides next() all the typical Random methods will be using the SecureRandom PRNG method.
(see in the comments why my second answer is incorrect.. or rather unnecessary)
I would suggest creating a long by just composing it out of the next 8 bytes or of two ints (returned by next). There's no problem with doing that and I can't see any reason why you wouldn't be able to touch all the long values (think that either of the two 32-bit halves can have values from 0 to 2^32, with equal probability) or why one would be more probable than another (which would mean it's not pseudo-random).
I do not completely understand why the Random documentation indicates that limitation for nextLong(), but I believe it is a limitation of the linear algorithm that it uses (I think linear algorithms have a much shorter cycle - i.e. when they start repeating numbers - than modern PRNGs). I think that's worth exploring on crypto stack exchange for curiosity.

SecureRandom extends Random, and Random has a nextLong() method: http://docs.oracle.com/javase/6/docs/api/java/util/Random.html#nextLong%28%29

BigInteger randomNumber = new BigInteger(numBits, random);

Note: With Random, a given seed will always produce the same results. With SecureRandom it will not. The seed just adds to the randomness.
Have you ever user secure random? The whole point of seed is to produce the same sequesnce of numbers. This is also the case with secure random. Two secure random numbers seeded with the same value produce same sequence of random numbers.
public static void main(String... args) throws NoSuchProviderException, NoSuchAlgorithmException {
testRNG("NativePRNG");
testRNG("SHA1PRNG");
System.out.println("The default PRNG on this system is " + new SecureRandom().getAlgorithm());
}
private static void testRNG(String prng) throws NoSuchAlgorithmException, NoSuchProviderException {
SecureRandom sr1 = SecureRandom.getInstance(prng, "SUN");
SecureRandom sr2 = SecureRandom.getInstance(prng, "SUN");
sr1.setSeed(1);
sr2.setSeed(1);
for (int i = 0; i < 10; i++) {
if (sr1.nextLong() != sr2.nextLong()) {
System.out.println(prng + " does not produce the same values with the same seed");
return;
}
}
System.out.println(prng + " appears to produce the same values with the same seed");
}
prints
NativePRNG does not produce the same values with the same seed
SHA1PRNG appears to produce the same values with the same seed
The default PRNG on this system is NativePRNG
go and try it first
Good advice, but just trying it doesn't always give you the whole answer in this case.

Related

How can computers generate encryption keys easily?

I wonder how computers can generate keys,especially RSA, easily and quickly. I've been trying to generate 24-bit keys for 2 hours using Java.
My program is using the random function to generate p and q,then if they aren't prime, the program generates new random numbers. Finally, the program calculates e and d. As you can see, my program uses the standard RSA algorithm,but it takes a lot of time.
I thought that the problem might lie in my algorithm, but not only RSA keys, also generating 100-bit prime numbers takes hours even if I use threads. So how can sites ,using HTTPS such as google, can generate these numbers almost in a millisecond?
There is a class named big integer in Java, and it has the method to generate probably random prime. However, if it's probably prime, some packages can't be decrypted.
Not only HTTPS, also some websites can generate 1024-4096 bit keys while I'm struggling to calculate 24-bit keys.
Please explain how it works.
Edit:
Here is my code:
private BigInteger minusOne=new BigInteger("-1");
private BigInteger one=new BigInteger("1");
private BigInteger two=new BigInteger("2");
private BigInteger zero=new BigInteger("0");
private void generateKeys(int keySize){
Random r=new Random();
q=BigInteger.probablePrime(keySize,r);
p=BigInteger.probablePrime(keySize, r);
n=p.multiply(q);
phi=(p.add(minusOne)).multiply(q.add(minusOne));
if(p.equals(q)){
generateKeys(keySize);
return;
}
e=calculate_e();
d=calculate_d();
if(d.equals(minusOne)){
generateKeys(keySize);
return;
}
}
private BigInteger calculate_e(){
Random r=new Random();
BigInteger e;
do{
e=new BigInteger(FindBitSize(phi),r);
}while(!BetweenPrime(e,phi));
if(e.compareTo(phi)==-1 && e.compareTo(one)==1){
return e;
}else{
return calculate_e();
}
}
private BigInteger calculate_d(){
BigInteger k=new BigInteger("0");
while(true){
if(k.multiply(e).mod(phi).equals(one)){
return k;
}
k=k.add(one);
}
}
private boolean BetweenPrime(BigInteger b2,BigInteger b1){
BigInteger d=new BigInteger("1");
while(d.compareTo(b1)==-1 && d.compareTo(b2)==-1){
d=d.add(one);
if(b1.mod(d).equals(zero) && b2.mod(d).equals(zero)){
return false;
}
}
return true;
}
However my problem is not about the code. I just don't understand how computers can calculate too big prime numbers in very short time.
There is a reason your implementation is incredibly slow. You've implemented the literal description, but of course there are algorithms that get you to the finish line much faster.
It is usually not necessary to calculate e. There are some common values for that: 3 (0x3), 17 (0x11), 65537 (0x10001). When as few bits of e as possible are set, then the encryption and signature verification will be very fast when efficient modular exponentiation algorithms are used.
You don't have to set it to a static value if you want encryption and decryption to be equally slow. You can compute it as described in Wikipedia using the greatest common divisor (GCD). Good thing BigInteger already provides an implementation for that:
private BigInteger calculate_e(){
Random r = new Random();
BigInteger e;
do{
e = new BigInteger(phi.bitLength(), r);
} while(!e.gcd(phi).equals(one));
if(e.compareTo(phi)==-1 && e.compareTo(one)==1){
return e;
} else {
return calculate_e();
}
}
calculate_d is a very naive implementation and will only work for very small numbers, because you're trying every single number between 1 and phi. The problem is if phi is something like 20 bits long it would take a million iterations. If phi where 30 bits long it would take a billion iterations. That just doesn't scale. The Wikipedia article on RSA suggests to calculate a modular multiplicative inverse e-1 (mod phi). An algorithm that is capable of that is the Extended Euclidean algorithm. Good thing that BigInteger already implements this:
private BigInteger calculate_d(){
return e.modInverse(phi);
}
Note that Random doesn't produce cryptographically secure random numbers. You really need to use SecureRandom to generate p and q. Also, the keySize is actually the size of n, so it should be:
SecureRandom r = new SecureRandom();
q = BigInteger.probablePrime(keySize/2, r);
p = BigInteger.probablePrime(keySize/2, r);

Math.random() v/s Random class [duplicate]

This question already has answers here:
Math.random() versus Random.nextInt(int)
(4 answers)
Closed 7 years ago.
The Math class in Java has a method, Math.random() which returns a pseudorandom number between 0 and 1.
There is also a class java.util.Random which has various methods like nextInt(), nextFloat(), nextDouble(), nextLong()etc.
My question is that if I want to get a random number in a range (say, 30-70), then which way should I go? The factors under consideration are speed and randomness.
If you look at the implementation of Math.random(), you'll see that it uses an instance of the Random class :
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
Therefore the randomness would be the same.
That said, since you need an int and not a double, you'd better use the nextInt method of the Random class, since it would save you the multiplication and casting of a double to int.
Random rnd = new Random();
int num = rnd.nextInt(41)+30;
I personally would go with the random class, because, in my opinion, it's way easier to use and to influence with parameters, for example for a random number between 30-79
Random r = new Random(); int i = r.nextInt(40)+30;
I hope that helped at least a bit
Math.random() does rely on the Random class. Depending on the case and data type you are using you can use either. For an int Random.nextInt() would probably be the best choice.
Speaking of randomness, a more secure random class is SecureRandom. SecureRandom does not rely on the system time unlike Random, so if your application has a security element to it definitely use SecureRandom. Same method names, except
SecureRandom secureRandom = new SecureRandom() instead of
Random random = new Random().

Stable mapping of an integer to a random number

I need a stable and fast one way mapping function of an integer to a random number.
By "stable" I mean that the same integer should always map to the same random number.
And by "random number" I actually mean "some number which behaves like random".
e.g.
1 -> 329423
2 -> -12398791234
3 -> -984
4 -> 42342435
...
If I had enough memory (and time) I would ideally use:
for( int i=Integer.MIN_VALUE; i<Integer.MAX_VALUE; i++ ){
map[i]=i;
}
shuffle( map );
I could use some secure hash function like MD5 or SHA but these are to slow for my purposes and I don't need any crypto/security properties.
I only need this in one way. So I will never have to translate the random number back to its integer.
Background: (For those who want to know more)
I'm planing to use this to invalidate a complete cache over a given amount of time. The invalidation is done "randomly" on access of the cache member with an increasing chance while time passes. I need this to be stable so that isValid( entry ) does not "flicker" and for consistent testing.
The input to this function will be the java hash of the key of the entry which typically is in the range of "1000"-"15000" (but can contain some other stuff, too) and comes in bulks.
The invalidation is done on the condition of:
elapsedTime / timeout * Integer.MAX_VALUE > abs( random( key.hashCode() ) )
EDIT: (this is to long for a comment so I put it here)
I tried gexicide's answer and it turns out this isn't random enough. Here is what I tried:
for( int i=0; i<12000; i++ ){
int hash = (""+i).hashCode();
Random rng = new Random( hash );
int random = rng.nextInt();
System.out.printf( "%05d, %08x, %08x\n", i, hash, random );
}
The output starts with:
00000, 00000030, bac2c591
00001, 00000031, babce6a4
00002, 00000032, bace836b
00003, 00000033, bac8a47e
00004, 00000034, baab49de
00005, 00000035, baa56af1
00006, 00000036, bab707b7
00007, 00000037, bab128ca
00008, 00000038, ba93ce2a
00009, 00000039, ba8def3d
00010, 0000061f, 98048199
and it goes on in this way.
I could use SecureRandom instead:
for( int i=0; i<12000; i++ ){
SecureRandom rng = new SecureRandom( (""+i).getBytes() );
int random = rng.nextInt();
System.out.printf( "%05d, %08x\n", i, random );
}
which indeed looks pretty random but this is not stable anymore and 10 times slower than the method above.
Although you never specified it as a requirement you'll probably want a full 1:1 mapping. This is because the number of possible input values is small. Any output that can occur for more than one input implies another output which can never happen at all. If you have output values which are impossible then you have a skewed distribution.
Of course, if your input is skewed then your output will be skewed anyway, and there's not much you can do about that.
Anyway; this makes it a unique int to int hash.
Simply apply a couple of trivial, independent 1:1 mapping functions until things are suitably distributed. You've already isolated one transform from the Random class, but I suggest mixing it with some other transforms like shifts and XORs to avoid individual weaknesses of different algorithms.
For example:
public static int mapInteger( int value ){
value *= 1664525;
value += 1013904223;
value ^= value >>> 12;
value ^= value << 25;
value ^= value >>> 27;
value *= 1103515245;
value += 12345;
return value;
}
If that's good enough then you can make it faster by deleting lines at random (I suggest you keep at least one multiply) until it's not good enough anymore, and then add the last deleted line back in.
Use a Random and seed it with your number:
Random generator = new Random(i);
return generator.nextInt();
As your testing exposes, the problem with this method is that such a seed creates a very poor random number in the first iteration. To increase the quality of the result, we need to run the random generator a few times; this will fill up the state of the random generator with pseudo-random values and will increase the quality of the following values.
To make sure that the random generator spreads the values enough, use it a few times before outputting the number. This should make the resulting number more pseudo-random:
Random generator = new Random(i);
for(int i = 0; i < 5; i++) generator.nextInt();
return generator.nextInt();
Try different values, maybe 5 is enough.
The answer of gexicide is the correct (and the most simple) one. Just one note:
Running this 1,000,000 times on my system takes about 70ms. (Which is pretty fast.)
But it involves at least two object creations and feeds the GC. It would be better
if this could be done on the stack and not using object creation at all.
Looking at the sources of Random class it shows that there is some code to make
it callable multiple times and to make it threadsafe which can be removed.
So I ended up with a reimplementation in one method:
public static int mapInteger( int value ){
// initial scramble
long seed = (value ^ multiplier) & mask;
// shuffle three times. This is like calling rng.nextInt() 3 times
seed = (seed * multiplier + addend) & mask;
seed = (seed * multiplier + addend) & mask;
seed = (seed * multiplier + addend) & mask;
// fit size
return (int)(seed >>> 16);
}
(multiplier, addend and mask are some constants used by Random)
Running this 1,000,000 times gives the same result but takes only 5ms and is therefor 10 times faster.
BTW: This happens to be another piece of code from The Old Man - again. See Donald Knuth,
The Art of Computer Programming, Volume 2, Section 3.2.1

Random Number In A Range

I have an app I am writing for iOS and Android. On startup I am trying to get a random number between 1 and 6.
iOS (Objective-C):
int random = rand() % (6 - 1) + 1;
Android (Java):
Random random = new Random();
int num = random.nextInt(6)+1;
In both cases they return 3 every time.
From other questions I have read, people are having the same issue because they are looping through randoms and keep reinstantiating the Random object. But I just want one random number, so I am only instantiating it once.
So, how can I get either of these pieces of code to get a number 1-6 instead of just 3?
For the Objective-C part, I can tell you that you have to seed the random, like this:
srand(time(0)); // seed it using the current time
And for the Java part, the new Random() constructor automatically seeds it in the default JVM for desktop applications, but not on Android. On Android, it uses a default seed value.
Random rand = new Random(System.nanoTime());
In Objective-C, you could alternately use the recommended arc4random() function that does not need to be seeded. You would use it like this:
int random = (arc4random() % 5) + 1;
A huge benefit of this function over rand() is that is has twice the range of rand(), thus allowing for "more random" numbers.
The best solution is to use arc4random_uniform if possible, it is available in iOS 4.3 and above. It eliminates bias that is usually introduced by the mod operator.
+ (u_int32_t)randomInRangeLo:(u_int32_t)loBound toHi:(u_int32_t)hiBound {
int32_t range = hiBound - loBound + 1;
return loBound + arc4random_uniform(range);
}
Note that no seeding is necessary and it produces cryptographic quality random numbers.
Not sure about Random on Android, but in other cases, you probably want to seed the Random instance with something reasonably unique, like the system time.
Random r = new Random(System.currentTimeMillis());
I tried the Java part and it works OK for me, but you can try to instantiate Random using time as a seed:
java.util.Date d = new java.util.Date();
Random random = new Random(d.getTime());
int num = random.nextInt(6)+1;
System.out.println(num);

Generate 8-byte number in Java

I'm a little bit confused, how to do this. I know I can use Random class to generate random numbers, but I don't know how to specify and generate 8-byte number?
Thanks,
Vuk
You should note that the java.util.Random class uses a 48-bit seed, so not all 8-byte values (sequences of 64 bits) can be generated using this class. Due to this restriction I suggest you use SecureRandom and the nextBytes method in this situation.
The usage is quite similar to the java.util.Random solution.
SecureRandom sr = new SecureRandom();
byte[] rndBytes = new byte[8];
sr.nextBytes(rndBytes);
Here is the reason why a 48-bit seed is not enough:
The Random class implements a pseudo random generator which means that it is deterministic.
The current "state" of the Random determines the future sequence of bits.
Since it has 248 states, it can't have more than 248 possible future sequences.
Since an 8-byte value has 264 different possibilities, some of these possibilities will never be read from the Random object.
Based on #Peter Lawreys excellent answer (it deserves more upvotes!): Here is a solution for creating a java.util.Random with 2×48-bit seed. That is, a java.util.Random instance capable of generating all possible longs.
class Random96 extends Random {
int count = 0;
ExposedRandom extra48bits;
class ExposedRandom extends Random {
public int next(int bits) { // Expose the next-method.
return super.next(bits);
}
}
#Override
protected int next(int bits) {
if (count++ == 0)
extra48bits = new ExposedRandom();
return super.next(bits) ^ extra48bits.next(bits) << 1;
}
}
I agree with #aioobe' point about Random using a 48-bit seed. SecureRandom is a better solution. However to answer the OP's questions of how to use the Random class and still allow for all possible 8-byte values is to reset the seed periodically.
int counter = 0;
Random rand = new Random();
Random rand2 = new Random();
if (++counter == 0) rand = new Random(); // reset every 4 billion values.
long randomLong = rand.nextLong() ^ rand2.nextLong() << 1;
Random only allows a sequence of 2^47 long values. By using two Random generators, one which keeps jumping around in the sequence, you get two 2^47 * 2^47 possible values. The use of << 1 is to avoid the impact of having both randoms having the same seed (in which case ^ would produce 0 for 4 billion values in a row)
It can be done either with byte array of length 8:
byte[] byteArray = new byte[8];
random.nextBytes(byteArray);
or with a variable of type long (which represents 8-byte numbers):
long randomLong = random.nextLong();
The long type is an 8 byte signed integer, so Random.nextLong() seems to do what you want. Or if you need a byte array as result:
byte[] result = new byte[8];
Random.nextBytes(result);
A little adjusting from the code here:
import java.util.Random;
/** Generate 10 random integers in the range 0..99. */
public final class RandomByte {
public static final void main(String... aArgs){
log("Generating 10 random integers in range 0..255.");
//note a single Random object is reused here
Random randomGenerator = new Random();
for (int idx = 1; idx <= 10; ++idx){
int randomInt = randomGenerator.nextInt(256);
// int randomInt = randomGenerator.nextBytes(256);
log("Generated : " + randomInt);
}
log("Done.");
}
private static void log(String aMessage){
System.out.println(aMessage);
}
}
Some further reading: Math.random() versus Random.nextInt(int)

Categories

Resources