0% found this document useful (0 votes)
538 views

RSA Encryption in Java

This document discusses RSA encryption in Java. It begins by explaining asymmetric encryption and how RSA solves the problem of securely transmitting an encryption key. It then covers generating an RSA key pair in Java, including specifying a key length, saving the public and private keys to files, and using the keys to encrypt and decrypt messages. Code examples are provided for each step.

Uploaded by

Niteshwar Kumar
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
538 views

RSA Encryption in Java

This document discusses RSA encryption in Java. It begins by explaining asymmetric encryption and how RSA solves the problem of securely transmitting an encryption key. It then covers generating an RSA key pair in Java, including specifying a key length, saving the public and private keys to files, and using the keys to encrypt and decrypt messages. Code examples are provided for each step.

Uploaded by

Niteshwar Kumar
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 5

RSA encryption in Java

We introduced the notion of asymmetric encryption, in which a key needed


to encrypt data is made public, but the corresponding key needed to decrypt it
is kept private, for example in a file on the server to which clients connect. In
principle, such a system solves the problem of how to send a temporary
encryption key securely to the server when opening a secure connection *. A
very common asymmetric encryption system is RSA, named after inventors
Rivest, Shamir & Adleman.
*
If we just used a symmetric encryption system such as AES on its own, we'd have the
problem of how the two parties agree on the key in advance. This is sometimes possible,
but usually, we want to transmit a temporary key at the moment of connecting. Generally,
we use an asymmetric encryption system such as RSA to transmit the secret key, then for
the rest of the conversation, use a regular symmetric encryption system using that secret
key.

Basic algorithm and terminology

RSA encryption and decryption are essentially mathematical operations. They


are what are termed exponentiation, modulo a particular number. Because of
this, RSA keys actually consist of numbers involved in this calculation, as
follows:

 the public key consists of the modulus and a public exponent;


 the private key consists of that same modulus plus a private
exponent.

Those interested in more details of the RSA algorithm should see this separate


page.

Creating an RSA key pair in Java

As a one-off process, we need to generate an RSA key pair that from then on,
we'll use for all conversations between our clients and server.

Creating an RSA key pair essentially consists of picking a modulus, which is


based on two random primes intended to be unique to that key pair, picking a
public exponent (in practice, the common exponent 65537 is often used), then
calculating the corresponding private exponent given the modulus and public
exponent. Java provides the KeyPairGenerator class for performing this task. The
essential idea is as follows:

 we create an instance of KeyPairGenerator suitable for generating RSA


keys;
 we initialise the generator, telling it the bit length of the modulus that
we require (see below);
 we call genKeyPair(), which eventually returns a KeyPair object;
 we call getPublic() and getPrivate() on the latter to pull out the public
and private keys.

The code looks as follows:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");


kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();

Notice that we specify a key length of 2048 bits. Common values are 1024 or
2048. Choosing an RSA key length is a tradeoff between security and
performance.

We now have two Key objects. Whilst we could immediately use these to start


encrypting and decrypting, in most practical uses, we want to store these two
keys for later use. For that, we use aKeyFactory to pull out the components
(modulus and exponents) of the keys.

Saving the public and private key

In practice, we need to store the public and private keys somewhere. Typically,
the private key will be placed on our server, and the public key distributed to
clients. To store the key, we simply need to pull out the modulus and the public
and private exponents, then write these numbers to some file (or put in
whatever convenient place).

The Key interface allows us to pretend for a second that we don't need to worry


about the algorithm-specific details of keys. But unfortunately, in practice we
do. So there also exist "key specification" classes
— RSAPublicKeySpec and RSAPrivateKeySpec in this case— with transparent
methods for pulling out the parameters that make up the key. Then,
a KeyFactory allows us to translate between Keys and their corresponding
specification. It's a bit clumsy, but the code ends up as follows:

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


RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(),
RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(),
RSAPrivateKeySpec.class);

saveToFile("public.key", pub.getModulus(),
pub.getPublicExponent());
saveToFile("private.key", priv.getModulus(),
priv.getPrivateExponent());

To save the moduli and exponents to file, we can just use boring old
serialisation, since the modulus and exponents are just BigInteger objects:

public void saveToFile(String fileName,


BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}

In our example, we end up with two files: public.key, which is distributed with


out clients (it can be packed into the jar, or whatever); meanwhile, private.key,
is kept secret on our server. Of course, we needn't even bother saving the keys
to a file: they're just numbers, and we could embed them as constant strings in
our code, then pass those strings to the constructor of BigInteger. Saving the
keys to file simply makes it a bit easier to manage keys in some cases (for
example, we might change keys periodically and distribute new key files to the
clients; distributing a few bytes is often more practical than distributing the
entire code base).

Now we've got a mechanism to generate a key pair and save those keys for the
future, we're ready to consider how to actually perform RSA
encryption/decryption, reading in the key files we generated.
RSA.java
Below is the syntax highlighted version of RSA.java from §7.8 Intractability.

/*************************************************************************
* Compilation: javac RSA.java
* Execution: java RSA N
*
* Generate an N-bit public and private RSA key and use to encrypt
* and decrypt a random message.
*
* % java RSA 50
* public = 65537
* private = 553699199426609
* modulus = 825641896390631
* message = 48194775244950
* encrpyted = 321340212160104
* decrypted = 48194775244950
*
* Known bugs (not addressed for simplicity)
* -----------------------------------------
* - It could be the case that the message >= modulus. To avoid, use
* a do-while loop to generate key until modulus happen to be exactly N
bits.
*
* - It's possible that gcd(phi, publicKey) != 1 in which case
* the key generation fails. This will only happen if phi is a
* multiple of 65537. To avoid, use a do-while loop to generate
* keys until the gcd is 1.
*
*************************************************************************/

import java.math.BigInteger;
import java.security.SecureRandom;

public class RSA {


private final static BigInteger one = new BigInteger("1");
private final static SecureRandom random = new SecureRandom();

private BigInteger privateKey;


private BigInteger publicKey;
private BigInteger modulus;

// generate an N-bit (roughly) public and private key


RSA(int N) {
BigInteger p = BigInteger.probablePrime(N/2, random);
BigInteger q = BigInteger.probablePrime(N/2, random);
BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));
modulus = p.multiply(q);
publicKey = new BigInteger("65537"); // common value in practice =
2^16 + 1
privateKey = publicKey.modInverse(phi);
}

BigInteger encrypt(BigInteger message) {


return message.modPow(publicKey, modulus);
}

BigInteger decrypt(BigInteger encrypted) {


return encrypted.modPow(privateKey, modulus);
}

public String toString() {


String s = "";
s += "public = " + publicKey + "\n";
s += "private = " + privateKey + "\n";
s += "modulus = " + modulus;
return s;
}

public static void main(String[] args) {


int N = Integer.parseInt(args[0]);
RSA key = new RSA(N);
System.out.println(key);

// create random message, encrypt and decrypt


BigInteger message = new BigInteger(N-1, random);

//// create message by converting string to integer


// String s = "test";
// byte[] bytes = s.getBytes();
// BigInteger message = new BigInteger(s);

BigInteger encrypt = key.encrypt(message);


BigInteger decrypt = key.decrypt(encrypt);
System.out.println("message = " + message);
System.out.println("encrpyted = " + encrypt);
System.out.println("decrypted = " + decrypt);
}
}

You might also like