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);
Related
I am trying to implement the RSA Blind digital signature scheme, using the BigInteger class for generating large prime numbers. Samantha generates the public key, the private key, chooses a message, masks it, then signs it and then Victor verifies the signature.
Problem: As long as I use the modular exponentiation method modPow from the BigInteger class, everything works perfectly (the verification algorithm returns true everytime). However, I have built a custom class where I have implemented several algebraic algorithms on my own; when I switch the modPow call with my modExp method, I keep getting false returns from the verification algorithm (about 50-60 % of the time), even though I should not. If instead of using large, random integers, I set small, hardcoded numbers for testing purposes, I get the correct result.
Question: As a consequence, I am pretty sure that my modExp method is the problem, however I can't seem to find out did I do wrong, even after changing the algorithm several times. What is the problem?
My code so far:
RSA_test() -- Method used for the precomputation step and testing
public static void RSA_test(){
// The Signer (Samantha) picks p and q, 1024 bit primes
Random rng = new SecureRandom();
BigInteger p = BigInteger.probablePrime(1024, rng);
BigInteger q = BigInteger.probablePrime(1024, rng);
/*BigInteger p = BigInteger.valueOf(7);
BigInteger q = BigInteger.valueOf(13);*/
// The RSA modulus is computed
BigInteger n = p.multiply(q);
// phi(n) is computed
BigInteger phiN = (p.subtract(BigInteger.ONE)
.multiply(q.subtract(BigInteger.ONE)));
// Samantha chooses her message, m
BigInteger m = new BigInteger("22");
// Samantha computes her public exponent
BigInteger v;
while(true){
v = new BigInteger(phiN.bitLength(), rng);
if(v.compareTo(BigInteger.ONE) > 0 &&
v.compareTo(phiN) < 0 &&
ModularArithmetic.gcd(v, phiN).equals(BigInteger.ONE))
break;
}
// v = BigInteger.valueOf(5);
// Samantha generates the blinding factor and masks her message
BigInteger r;
while(true){
r = new BigInteger(512, rng);
if(ModularArithmetic.gcd(r, n).equals(BigInteger.ONE))
break;
}
// r = BigInteger.valueOf(10);
BigInteger mBlinded = m.multiply(ModularArithmetic.modExp(r, v, n));
// Samantha signs her message
BigInteger SBlinded = Cryptography.RSASignature(mBlinded, n, phiN, v);
// Samantha removes the blinding factor, obtaining S
BigInteger S = SBlinded.multiply(ModularArithmetic.modInv(r, n));
// Victor verifies the signature
boolean result = Cryptography.RSAVerification(S, m, n, v);
String s = (result == true) ? "The signature has been verified" : "The signature has not been verified";
System.out.println(s);
}
As the signature and verification methods are irrelevant for the question, as I am certain that they are correct, I will omit them. Also, here is my modExp method:
public static BigInteger modExp(BigInteger base, BigInteger exponent, BigInteger modulus){
if(exponent.equals(BigInteger.ZERO))
return (modulus.equals(BigInteger.ONE)) ? BigInteger.ZERO : BigInteger.ONE;
if(base.equals(BigInteger.ONE))
return (modulus.equals(BigInteger.ONE)) ? BigInteger.ZERO : BigInteger.ONE;
if(exponent.equals(BigInteger.ONE))
return base.mod(modulus);
if(modulus.equals(BigInteger.ONE))
return BigInteger.ZERO;
// The case when base does not have a multiplicative inverse
if((modulus.compareTo(BigInteger.ZERO) <= 0) ||
((exponent.compareTo(BigInteger.ZERO) < 0 && !(gcd(base,modulus).compareTo(BigInteger.ONE) == 0))))
throw new ArithmeticException("BigInteger: modulus not positive");
BigInteger result = BigInteger.ONE;
while(exponent.compareTo(BigInteger.ZERO) > 0){
if(exponent.testBit(0))
result = (result.multiply(base).mod(modulus));
exponent = exponent.shiftRight(1);
base = (base.multiply(base)).mod(modulus);
}
return result.mod(modulus);
}
You don't handle negative exponents correctly, except to check that gcd(base, modulus) == 1. The following snippet shows one correct way to do it.
if (exponent.signum() < 0 && gcd(base,modulus).equals(BigInteger.ONE)) {
return modExp(base.modInverse(modulus), exponent.negate(), modulus);
}
Observe that the signum() method may be more convenient for comparing big integers to zero.
I am trying to find a generator which is smaller than 1024 bits.
p is a random 1024 bit prime number.
q is a random 160 bit prime that divides p-1.
I have already found the values of p and q. But the generator always ends up being 0 or 1.
Help is much appreciated.
BigInteger alpha=new BigInteger(1022,rand);//finding a biginteger smaller than 1024 bits
BigInteger modInverseQ= q.modInverse(p); // (q^-1) mod(p)
BigInteger y = p.subtract(one); //p-1
BigInteger z = y.multiply(modInverseQ); //(p-1)*(q^-1)
BigInteger g = alpha.modPow(z, p); // a^(p-1)*(q^-1) mod(p)
int comp = g.compareTo(one); // checking if generator is equal to 1
while(comp == 0) //if generator is 1 find a new generator
{
alpha=new BigInteger(1022,rand);
g = alpha.modPow(z, p);
comp = g.compareTo(one);
}
You could have a look at the implementation of the following class: org.bouncycastle.crypto.generators.DSAParametersGenerator .
It is a class of Bouncy Castle (https://www.bouncycastle.org/java.html), a Java cryptographic provider.
Within it, there are several private methods that could be very useful for what you need.
I tried to get the power of a double value where the exponent is very large (Java BigInteger can contain it (the exponent), for example: 10^30)
That is, I want to find something like 1.75^(10^30) or 1.23^(34234534534222).if the output is too large modify it by getting the modulus by a prime like 10^9+7.
If I want to find a power of an Integer I can use BigInteger.modPow() method which take BigInteger arguments:
( BigInteger modPow(BigInteger exponent, BigInteger m) )
As far as i can go this is what i got in Java
new BigDecimal("1.5").pow(1000); // .pow() can get only integers as a parameter , but i want to pass a big number like a BigInteger
I cannot find an equivalent for that (BigInteger.modPow()) in java for BigDecimal
, or i'm missing that.
Are there any ways to do that - Calculate a large power of a floating point number (a Decimal)?
Example of input and output :
Input : num // or 1.5 or any decimal number. can be an integer also.
exponent : exp // big integer or a Long value
output : num^exp // num to ther power exp
i.e like calculating 1.23^(34234534534222)
if the output is too large modify it by getting the modulus by a prime like 10^9+7
There is a Math.BigDecimal implementation of core mathematical functions which has:
static java.math.BigDecimal powRound(java.math.BigDecimal x, java.math.BigInteger n)
Raise to an integer power and round.
which seems exactly what you need. The fact that there is an external library for it denotes that there is no core implementation of a method like this in java.Math.
As a side note I can say that if your input is considerably small in terms of decimal places (thus no irrational) just like 1.5 you can transform it in 15/10 and do
(15^BigInteger)/(10^BigInteger)
with the modPow(BigInteger exponent, BigInteger m) of BigInteger. This obviously raises the complexity and the numbers to calculate.
There are several caveats. As Gábor Bakos pointed out, the resulting value would most likely contain too many digits to even be represented as a BigDecimal.
Additionally, these number of digits grows quickly, so computing something like 2.034234534534222 is completely out of scope in terms of storage (and, as I assume, in terms of required time).
You mentioned that the value may be computed modulo a large prime when it becomes "too large". Although you did not say what exactly this means, this won't necessarily help you here, because using modulo will not truncate the decimal places. You'll somehow have to limit the precision in which the computation takes place.
However, the most simple implementation using exponentiation by squaring could roughly look like this:
import java.math.BigDecimal;
import java.math.BigInteger;
public class BigDecimalPow {
public static void main(String[] args) {
BigDecimal b = new BigDecimal(1.5);
BigInteger e = new BigInteger("325322");
BigDecimal result = pow(b, e);
System.out.println("Done "+result.scale());
System.out.println(result);
}
/**
* Computes d to the power of e
* #param b The value
* #param e The exponent
* #return The power
*/
private static BigDecimal pow(BigDecimal b, BigInteger e) {
BigDecimal result = BigDecimal.ONE;
BigDecimal p = b;
int skipped = 0;
while (e.compareTo(BigInteger.ZERO) > 0) {
if (e.and(BigInteger.ONE).equals(BigInteger.ONE)) {
if (skipped > 0) {
if (skipped > 29) {
p = pow(p, BigInteger.ONE.shiftLeft(skipped));
} else {
p = p.pow(1 << skipped);
}
skipped = 0;
}
result = result.multiply(p);
}
skipped++;
e = e.shiftRight(1);
System.out.println(e);
}
return result;
}
}
Note: The implementation above is really simple. There most likely is a solution that is more efficient for some cases, or uses the modulo operation to support "larger" numbers. But you simply can not represent (potentially) 34234534534222 decimal places unless you have 34 terabytes of RAM and a JVM with long addressing, so I doubt that there will be a solution that satisfies the requirements that you stated until now - but would upvote+bounty anyone who proved me wrong...
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.
I'm playing with numbers in Java, and want to see how big a number I can make. It is my understanding that BigInteger can hold a number of infinite size, so long as my computer has enough Memory to hold such a number, correct?
My problem is that BigInteger.pow accepts only an int, not another BigInteger, which means I can only use a number up to 2,147,483,647 as the exponent. Is it possible to use the BigInteger class as such?
BigInteger.pow(BigInteger)
Thanks.
You can write your own, using repeated squaring:
BigInteger pow(BigInteger base, BigInteger exponent) {
BigInteger result = BigInteger.ONE;
while (exponent.signum() > 0) {
if (exponent.testBit(0)) result = result.multiply(base);
base = base.multiply(base);
exponent = exponent.shiftRight(1);
}
return result;
}
might not work for negative bases or exponents.
You can only do this in Java by modular arithmetic, meaning you can do a a^b mod c, where a,b,c are BigInteger numbers.
This is done using:
BigInteger modPow(BigInteger exponent, BigInteger m)
Read the BigInteger.modPow documentation here.
The underlying implementation of BigInteger is limited to (2^31-1) * 32-bit values. which is almost 2^36 bits. You will need 8 GB of memory to store it and many times this to perform any operation on it like toString().
BTW: You will never be able to read such a number. If you tried to print it out it would take a life time to read it.
Please be sure to read the previous answers and comments and understand why this should not be attempted on a production level application. The following is a working solution that can be used for testing purposes only:
Exponent greater than or equal to 0
BigInteger pow(BigInteger base, BigInteger exponent) {
BigInteger result = BigInteger.ONE;
for (BigInteger i = BigInteger.ZERO; i.compareTo(exponent) != 0; i = i.add(BigInteger.ONE)) {
result = result.multiply(base);
}
return result;
}
This will work for both positive and negative bases. You might want to handle 0 to the power of 0 according to your needs, since that's technically undefined.
Exponent can be both positive or negative
BigDecimal allIntegersPow(BigInteger base, BigInteger exponent) {
if (BigInteger.ZERO.compareTo(exponent) > 0) {
return BigDecimal.ONE.divide(new BigDecimal(pow(base, exponent.negate())), 2, RoundingMode.HALF_UP);
}
return new BigDecimal(pow(base, exponent));
}
This re-uses the first method to return a BigDecimal with 2 decimal places, you can define the scale and rounding mode as per your needs.
Again, you should not do this in a real-life, production-level system.
java wont let you do BigInteger.Pow(BigInteger) but you can just put it to the max integer in a loop and see where a ArithmeticException is thrown or some other error due to running out of memory.
2^2,147,483,647 has at least 500000000 digit, in fact computing pow is NPC problem, [Pow is NPC in the length of input, 2 input (m,n) which they can be coded in O(logm + logn) and can take upto nlog(m) (at last the answer takes n log(m) space) which is not polynomial relation between input and computation size], there are some simple problems which are not easy in fact for example sqrt(2) is some kind of them, you can't specify true precision (all precisions), i.e BigDecimal says can compute all precisions but it can't (in fact) because no one solved this up to now.
I can suggest you make use of
BigInteger modPow(BigInteger exponent, BigInteger m)
Suppose you have BigInteger X, and BigInteger Y and you want to calculate BigInteger Z = X^Y.
Get a large Prime P >>>> X^Y and do Z = X.modPow(Y,P);
For anyone who stumbles upon this from the Groovy side of things, it is totally possible to pass a BigInteger to BigInteger.pow().
groovy> def a = 3G.pow(10G)
groovy> println a
groovy> println a.class
59049
class java.math.BigInteger
http://docs.groovy-lang.org/2.4.3/html/groovy-jdk/java/math/BigInteger.html#power%28java.math.BigInteger%29
Just use .intValue()
If your BigInteger is named BigValue2, then it would be BigValue2.intValue()
So to answer your question, it's
BigValue1.pow(BigValue2.intValue())