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.
Related
Is there any ready-made Java library for operations over BigInteger and BigDecimal objects?
I'd like to use square root and ++ operators.
Thank you
P.S. BigInteger.add() should be used instead of ++, I got it.
What about square root from BigInteger?
BigInteger is immutable. That makes something like the ++-operator on it conceptually impossible. You can not change the value of a given BigInteger, just like you can't do it with String.
Incrementing
You always have to create a new BigInteger that holds the incremented value (you can then of course store the reference to that BigInteger in the same variable).
Edit: As pointed out in the comment, "incrementing" would look like:
BigInteger result = a.add(BigInteger.ONE);
or
a = a.add(BigInteger.ONE);
Note that both lines do not change the value of the BigInteger which a originally points to. The last line creates a new BigInteger and stores the reference to it in a.
Calculating the Square
You can calculate the square of a BigInteger like this:
BigInteger a = BigInteger.valueOf(2);
BigInteger a_square = a.multiply(a); // a^2 == a * a
or
BigInteger a_square = a.pow(2);
Square Root
The code is taken from https://gist.github.com/JochemKuijpers/cd1ad9ec23d6d90959c549de5892d6cb .
It uses simple bisection and a clever upper bound. Note that a.shiftRight(x) is equivalent to a / 2^x (only for non-negative numbers, but that is all we deal with, anyway)
BigInteger sqrt(BigInteger n) {
BigInteger a = BigInteger.ONE;
BigInteger b = n.shiftRight(5).add(BigInteger.valueOf(8));
while (b.compareTo(a) >= 0) {
BigInteger mid = a.add(b).shiftRight(1);
if (mid.multiply(mid).compareTo(n) > 0) {
b = mid.subtract(BigInteger.ONE);
} else {
a = mid.add(BigInteger.ONE);
}
}
return a.subtract(BigInteger.ONE);
}
Using Operators Instead of Methods
Operator overloading like in C++ is not possible in Java.
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);
Something strange is going on with BigInteger. I'm trying to implement my own RSA for an assignment.
The code is as follows, and work great with small numbers.
If I choose p=11, q=5, e=7 and d=23 then the output on the terminal is
Original message is: 19
Encryption of message is: 24
Decryption of message is: 19
If I change the numbers with bigger ones, though, it does not work anymore. The following code:
import java.math.BigInteger;
class RSAdumb{
public static void main(String[] args) {
BigInteger m = new BigInteger("19");
BigInteger p = new BigInteger("99989");
BigInteger q = new BigInteger("99991");
BigInteger n = p.multiply(q);
BigInteger e = new BigInteger("65537");
BigInteger d = new BigInteger("4232182107");
BigInteger c = m.modPow(e,n); //Returns a BigInteger whose value is (this^e mod n)
BigInteger check = c.modPow(d,n);
System.out.println("Original message is: "+m.toString());
System.out.println("Encryption of message is: "+c.toString());
System.out.println("Decryption of message is: "+check.toString());
}
}
Outputs this:
Original message is: 19
Encryption of message is: 5609974360
Decryption of message is: 2710593036
I already checked, twice, that the numbers are good for RSA. Precisely
e*d = 4232182107 * 65537 = 1 mod 9998000099
where
9998000099 = 99989 * 99991 (both primes)
Now, from my understanding BigInteger should be unlimited so it should not be a boundary issue... than what could be? I can always implement this with small numbers for my assignment but it's quite ridiculous...
The requirement for e and d isn't that their product is congruent to 1 (mod n), it's that their product must be congruent to 1 (mod φ(n)), according to the Wikipedia page on RSA.
That is the totient function, which for the 2 primes multiplied is (p - 1)(q - 1), or 997800120.
The result of ed (mod φ(n)) is not 1, it's 32589339.
The reason that your smaller numbers worked is because φ(n) for 5 and 11 is 4 * 10 = 40, and 7 * 23 (mod 40) is 1.
You will need to choose a proper d constant for your larger numbers. This is the modular inverse of e with respect to φ(n), which can be calculated with BigInteger's modInverse method.
BigInteger phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
BigInteger d = e.modInverse(phi);
This reveals d to be 2598113033. Using d yields the proper output.
Original message is: 19
Encryption of message is: 5609974360
Decryption of message is: 19
You've made an error calculating the private exponent d.
First you need to calculate phi of n: φ(n) = φ(p)φ(q) = (p − 1)(q − 1) = n - (p + q -1)
BigInteger phi = n.subtract(p.add(q).subtract(BigInteger.ONE));
and then you need to take the modular inverse of e with phi as the modulus to get d:
d = e.modInverse(phi);
which results in d = 2598113033.
For reference: Wikipedia
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 have two simple java codes.The first one defines constant power as power = a.pow(b);
import java.math.BigInteger;
public class FermatOne
{
public static void main(String[] args)
{
BigInteger a = new BigInteger ("2");
BigInteger k = new BigInteger ("15");
BigInteger c = new BigInteger ("1");
int b = 332192810;
BigInteger n = new BigInteger ("2");
BigInteger power;
power = a.pow(b);
BigInteger exponent;
exponent = k.multiply(power);
BigInteger mod;
mod = exponent.add(c);
BigInteger result = n.modPow(exponent,mod);
System.out.println("Result is ==> " + result);
}
}
The second one defines constant power as power = BigInteger.ONE.shiftLeft(b)
import java.math.BigInteger;
public class FermatOne
{
public static void main(String[] args)
{
BigInteger k = new BigInteger ("15");
BigInteger c = new BigInteger ("1");
int b = 332192810;
BigInteger n = new BigInteger ("2");
BigInteger power;
power = BigInteger.ONE.shiftLeft(b);
BigInteger exponent;
exponent = k.multiply(power);
BigInteger mod;
mod = exponent.add(c);
BigInteger result = n.modPow(exponent,mod);
System.out.println("Result is ==> " + result);
}
}
Setting the memory flag -Xmx1024m in the command line the first code works fine , but for the second code I am getting error : java.lang.OutOfMemoryError :Java heap space
My question : What should I change in the second code to avoid java.lang.OutOfMemoryError ?
You're trying to calculate a number like 2 ^ (15 * 2 ^ 332192809). I don't know if you could even fit such a number in the universe!! Or maybe, the answer is simply... 42 ? ;-)
On a more serious note, you'll really have trouble, calculating this number. Encoded in bits, 15 * 2 ^ 332192810 would require almost a gigabyte by itself. Then raising 2 to that power again, I don't want to know...
On a more serious note, when you dig into the implementation of java.math.BigInteger, I think that you just run into such an error faster with the left shift, as that is implemented much more efficiently, than the power method. Having said this, have you tried to force garbage collection in your code, using System.gc()?
UPDATE: My original reasoning might've been wrong. 2 ^ 332192809 can be calculated with 1GB. And the overall result might be "modded" efficiently by java.math.BigInteger, although I believe that this calculation might take a while...
It's just a guess, but BigInteger.ONE.shiftLeft(332192810); will internally create an int array of length x + 10381025. Since an int is 4 bytes big you'll get about 40 mega bytes of data just for that one call. I assume the other calls copy that data around and thus you get that high a memory consumption.