Generating RSA keys for given modulus and exponent

22,937

I give you some information about RSA. First of all in RSA keys the modulus = p·q where p and q are distinct prime numbers, the modulus length it's the key length. So when you are receiving the exception:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: RSA keys must be at least 512 bits long

This means that your modulus at least must be 512 bits long.

Besides in your code there is also another error, you're using the same exponent for public and private key, but this exponents must be different numbers.

In resume you have to calculate the modulus, public exponent and private exponent with java.math.BigInteger following the RSA key generation algorithm to generate a correct keys. I give you an example from your code:

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

public class Sample {
    public static void main( String args[] ) {

        int keySize = 512;  
        SecureRandom random = new SecureRandom();
        // Choose two distinct prime numbers p and q.
        BigInteger p = BigInteger.probablePrime(keySize/2,random);
        BigInteger q = BigInteger.probablePrime(keySize/2,random);
        // Compute n = pq (modulus)
        BigInteger modulus = p.multiply(q);
        // Compute φ(n) = φ(p)φ(q) = (p − 1)(q − 1) = n - (p + q -1), where φ is Euler's totient function.
        // and choose an integer e such that 1 < e < φ(n) and gcd(e, φ(n)) = 1; i.e., e and φ(n) are coprime.
        BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
        BigInteger publicExponent = getCoprime(m,random);
        // Determine d as d ≡ e−1 (mod φ(n)); i.e., d is the multiplicative inverse of e (modulo φ(n)).
        BigInteger privateExponent = publicExponent.modInverse(m);


        try {                    
            RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
            RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(modulus, privateExponent);

            KeyFactory factory = KeyFactory.getInstance("RSA");

            PublicKey pub = factory.generatePublic(spec);
            PrivateKey priv = factory.generatePrivate(privateSpec); 

            System.out.println("Public Key : "+ byteArrayToHexString( pub.getEncoded() ));
            System.out.println("Private Key : "+ byteArrayToHexString( priv.getEncoded() ));
        }                        
        catch( Exception e ) {   
            System.out.println(e.toString());       
        }                        
    }         

    public static BigInteger getCoprime(BigInteger m, SecureRandom random) {
        int length = m.bitLength()-1;
        BigInteger e = BigInteger.probablePrime(length,random);
        while (! (m.gcd(e)).equals(BigInteger.ONE) ) {
            e = BigInteger.probablePrime(length,random);
        }
        return e;
    }


    public static String byteArrayToHexString(byte[] bytes)          
    {         
        StringBuffer buffer = new StringBuffer();
        for(int i=0; i<bytes.length; i++)
        {                        
            if(((int)bytes[i] & 0xff) < 0x10)       
                buffer.append("0");                               
            buffer.append(Long.toString((int) bytes[i] & 0xff, 16));
        }                        
        return buffer.toString();
    }         
}

Hope this help,

Share:
22,937
vara
Author by

vara

Updated on October 16, 2020

Comments

  • vara
    vara over 3 years

    I have been asked to generate the RSA key using given modulus and exponent values. But I have idea only about generating the keys without specifying the modulus and exponent. Whatever the value I am given is seems to be big integer values. I searched about this in web and worked out some thing, But it could not went through success.

    So if anybody has done this before, can they give me some hints please?

    This is sample program we have tried with given values.

    import java.io.UnsupportedEncodingException;
    import java.math.BigInteger;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.spec.RSAKeyGenParameterSpec;
    import java.security.spec.RSAPrivateKeySpec;
    import java.security.spec.RSAPublicKeySpec;
    
    public class Sample {
            public static void main( String args[] ) {
    
                    BigInteger modulus  = new BigInteger("350871044328208704010580786055405681");
                    BigInteger exponent = new BigInteger("545161406957801571");
    
                    try {                    
                            RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
                            RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(modulus, exponent);
    
                            KeyFactory factory = KeyFactory.getInstance("RSA");
    
                            PublicKey pub = factory.generatePublic(spec);
                            PrivateKey priv = factory.generatePrivate(privateSpec); 
    
                            System.out.println("Public Key : "+ byteArrayToHexString( pub.getEncoded() ));
                            System.out.println("Private Key : "+ byteArrayToHexString( priv.getEncoded() ));
                    }                        
                    catch( Exception e ) {   
                            System.out.println(e.toString());       
                    }                        
            }         
            public static String byteArrayToHexString(byte[] bytes)          
            {         
                    StringBuffer buffer = new StringBuffer();
                    for(int i=0; i<bytes.length; i++)
                    {                        
                            if(((int)bytes[i] & 0xff) < 0x10)       
                                    buffer.append("0");                               
                            buffer.append(Long.toString((int) bytes[i] & 0xff, 16));
                    }                        
                    return buffer.toString();
            }         
    }
    

    ERROR:

    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: RSA keys must be at least 512 bits long