Last active
December 16, 2015 17:09
-
-
Save zynick/5468171 to your computer and use it in GitHub Desktop.
Prove that java.util.Random isn't that random after all...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Random; | |
import java.util.concurrent.atomic.AtomicLong; | |
/** | |
* in response to http://jazzy.id.au/default/2010/09/20/cracking_random_number_generators_part_1.html | |
* <p> | |
* the code on that website works 1 out of 4 times because, as mentioned by the | |
* author itself, it isn't complete since he prefer to keep the code easier to | |
* read and understand. | |
* <p> | |
* what i did is just add a 32 bit mask on 2nd random integer when it was cast | |
* to long to ensure the bits remain the same regardless of positive or negative | |
* number generated. | |
* <p> | |
* runnable code: http://ideone.com/pS58fs | |
* | |
* @author zynick | |
*/ | |
public class GuessRandom { | |
// copied from Random source code | |
private static final long multiplier = 0x5DEECE66DL; | |
private static final long addend = 0xBL; | |
private static final long mask = (1L << 48) - 1; | |
public static void main(String[] args) { | |
// give me 2 random integer | |
Random rand = new Random(); | |
int i1 = rand.nextInt(); | |
int i2 = rand.nextInt(); | |
long l1 = i1; | |
long mask32 = (1L << 32) - 1; // 32 bit masking | |
long l2 = i2 & mask32; | |
// find seed | |
long shiftl1 = l1 << 16; | |
long find = 0; | |
for (long i = 0; i < 65536; i++) { | |
find = shiftl1 + i; | |
if ((((find * multiplier + addend) & mask) >>> 16) == l2) { | |
System.out.println("seed found: " + find); | |
break; | |
} | |
} | |
// test seed | |
AtomicLong found = new AtomicLong(find); | |
int predict = next(32, found); | |
predict = next(32, found); | |
int expect = rand.nextInt(); | |
System.out.println("Predict: " + predict + "\nExpect : " + expect); // same! | |
} | |
// copied from Random source code | |
protected static int next(int bits, AtomicLong seed) { | |
long oldseed, nextseed; | |
do { | |
oldseed = seed.get(); | |
nextseed = (oldseed * multiplier + addend) & mask; | |
} while (!seed.compareAndSet(oldseed, nextseed)); | |
return (int) (nextseed >>> (48 - bits)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment