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.
Related
I need to generate the UID (alphanumeric) for my use case but that should be a maximum of 7 characters long as we want UID to be random but manageable, like a PNR (CYB6KL) for example.
Now if I am not wrong, I can generate a random UID that is small, but uniqueness might be compromised because of collisions (birthday paradox), so for 32 bits, 50% collision probability would be around 77k UID generations.
So in essence, I need a way to generate UIDs that are:
Small (max 7 character)
Random
Unique
Don't require lookups for the previous existance.
I will be storing this UID in a database column and it's imperative that the UID is unique. It will NOT be the table's primary key which right now is an autogenerated ID.
I am thinking of something along the lines, but I am not sure about uniqueness.
BigInteger big = new BigInteger(32, new SecureRandom());
return big.toString(32).toUpperCase();
Really appreciate any thoughts that might help on this. Generation must be unique.
Thanks in advance.
You can use a library like hashids for this purpose which implements a bimorphic translation that can encode a numeric value into a string code with a custom alphabet. This should do exactly what you want. If you need this to be traversal-secure, you should use some kind of SecureRandom as source for the underlying numeric value. If not, you could even base this on the auto increment value you already have. The benefit of reusing the primary key is that you can just translate the string code and do a lookup by primary key.
So I tried this line of code in java which generates a random integer that is 40 bytes long. I have no clue if it's secure and I wondered if anyone with a little bit more experience than me could explain.
I would like to know if this is cryptographically secure. meaning is this a secure way of generating a random number that's a BigInteger. If it isn't secure what would be a good way to generate a full cryptographically random BigInteger.
SecureRandom random = new SecureRandom();
BigInteger key_limit = new BigInteger("10000000000000000000000000000000000000000");
int key_length = key_limit.bitLength();
BigInteger key_1 = new BigInteger(key_length, random);
You're rolling your own crypto.
Be prepared to fail. The odds that the code you end up writing will actually be secure are infinitesemal. It is very, very, very easy to make a mistake. These mistakes are almost always extremely hard to test for (for example, your algorithm may leak information based on how long it takes to process different input, thus letting an attacker figure out the key in a matter of hours. Did you plan on writing a test that checks if all attempts to decode anything, be it the actual ciphertext, mangled ciphertext, half of ciphertext, crafted input specifically designed to try to derive key info by checking how long it takes to process, and random gobbledygook all take exactly equally long? Do you know what kind of crafted inputs you need to test for, even?)
On the topic of timing attacks, specifically, once you write BigInteger, you've almost certainly lost the game. It's virtually impossible to write an algorithm based on BI that is impervious to timing attacks.
An expert would keep all key and crypto algorithm intermediates in byte[] form.
So, you're doing it wrong. Do not roll your own crypto, you'll mess it up. Use existing algorithms.
If you really, really, really want to go down this road, you need to learn, a lot, before you even start. Begin by analysing a ton of existing implementations. Try to grok every line, try to grok every move. For example, a password hash checking algorithm might contain this code:
public boolean isEqual(byte[] a, byte[] b) {
if (a.length != b.length) throw new IllegalArgumentException("mismatched lengths");
int len = a.length;
boolean pass = true;
for (int i = 0; i < len; i++) {
if (a[i] != b[i]) pass = false;
}
return pass;
}
and you may simply conclude: Eh. Weird. I guess they copied it from C or something, or they just didn't know they could have removed that method entirely and just replaced it with java.util.Arrays.equals(a, b);. Oh well, it doesn't matter.
and you would be wrong - that's what I mean by understand it all. Assume no mistakes are made. Arrays.equals can be timing-attacked (the amount of time it takes for it to run tells you something: The earlier the mismatch, the faster it returns. This method takes the same time, but only 'works' if the two inputs are equal in length, so it throws instead of returning the seemingly obvious false if that happens).
If you spend that much time analysing them all, you'll have covered this question a few times over.
So, with all that context:
This answer is a bazooka. You WILL blow your foot off. You do not want to write this code. You do not want to do what you are trying to do. BigInteger is the wrong approach.
new BigInteger(8 * 40, secureRandom); will get the job done properly: Generates a random number between (0 and 2^320-1), inclusive, precisely 40 bytes worth. No more, no less.
40 bytes worth of randomness can be generated as follows:
byte[] key = new byte[40];
secureRandom.nextBytes(key);
But this is, really, still a grave error unless you really, really, really know what you are doing (try finding an existing implementation that has some reliable author or has been reviewed by an expert).
You will get a BigInteger containing a securely generated random number that way.
However, that method for calculating the bit length is (to say the least) odd. I don't know about you, but most programmers would find it difficult to work out how many zeros there are in that string. Then, the computation is going to give you a bit count such that 2bits is less than the number.
It would make a lot more sense (to me) to just specify a bit count directly and code it, and add a comment to explain it.
To a first approximation1 2(10*N) is 1000N. However, the former is slightly greater than the latter. That means if your code is intended to give you 40 byte random keys, your computed key length will be off by one.
1 - Experienced programmers remember that ... and inexperienced programmers can use a programmer's calculator.
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
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.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I want to make a simple public-key(asymmetric) encryption. It doesn't have the be secure, I just want to understand the concepts behind them. For instance, I know simple symmetric ciphers can be made with an XOR. I saw in a thread on stackexchange that you need to use trapdoor functions, but I can't find much about them. I want to say, take a group of bytes, and be able to split them someway to get a public/private key. I get the ideas of a shared secret. Say, I generate the random number of 256(not random at all :P), and I split it into 200 and 56. If I do an XOR with 200, I can only decrypt with 200. I want to be able to split numbers random and such to be able to do it asymmetrically.
OK, just a simple demo-idea, based on adding/modulo operation.
Lets say we have a modulo value, for our example 256. This is a public-known, common value.
Let's say you generate a random secret private key in the interval [1-255], for example, pri=133.
Keep secret key in the pocket.
Generate a public key, pub = 256 - pri = 123. This public key (123)
you can share to the world.
Imagine, 3rd party does not know, how to compute the private key from a public. So, they know only public key (123).
Someone from the public wants to send you an encrypted ASCII-byte. He gets his byte, and adds to it the public key by modulo 256 operation:
encrypted = (input_value + pub) % modulto;
For example, I want to send you the letter "X", ASCII code = 88 in encrypted form.
So, I compute:
(88 + 123) % 256 = 211;
I am sending you the value 211 - encrypted byte.
You decrypt it by the same scheme with your private key:
decrypted = (input_value + pri) % 256 = (211 + 133) % 256 = 88;
Of course, using the simple generation pair in this example is weak, because of
the well-known algorithm for generating the private key from the public, and anybody can easily recover the private using the modulo and public.
But, in real cryptography, this algorithm is not known. But, theoretically,
it can be discovered in future.
This is an area of pure mathematics, there's a book called "the mathematics of cyphers" it's quite short but a good introduction. I do suggest you stay away from implementing your own though, especially in Java (you want a compiler that targets a real machine for the kind of maths involved, and optimises accordingly). You should ask about this on the math or computer-science stack-exchanges.
I did get a downvote, so I want to clarify. I'm not being heartless but cyphers are firmly in the domain of mathematics, not programming (even if it is discreet maths, or the mathsy side of comp-sci) it requires a good understanding of algebraic structures, some statistics, it's certainly a fascinating area and I encourage you to read. I do mean the above though, don't use anything you make, the people who "invent" these cyphers have forgotten more than you or I know, implement exactly what they say at most. In Java you ought to expect a really poor throughput btw. Optimisations involving register pressure and allocation pay huge dividends in cypher throughput. Java is stack-based for starters.
Addendum (circa 6 years on)
Java has improved in some areas now (I have a compiler fetish, it's proper weird) however looking back I was right but for the sort-of wrong reasons, Java is much easier to attack through timing, I've seen some great use of relying on tracing compiling techniques to work out what version of software is being used for example. It's also really hard to deal with Spectre which isn't going away any time soon (I like caches.... I feel dirty saying that now)
HOWEVER: above all, don't do this yourself! Toy with it AT MOST - it's very much in the domain of mathematics, and I must say it's probably better done on paper, unless you like admiring a terminal with digits spewn all over it.
http://en.wikipedia.org/wiki/RSA_(algorithm)
Is the standard one on which the (whole) internet is based