Shane Chism

RSA Encryption/Decryption/Key-Gen Class


Description


This class is a portable and user friendly way to implement an RSA encryption and decryption scheme into a pre-existing (or in development) Java program.

The class is designed to accommodate programs that use pre-generated keys as well as programs that need keys created at runtime. Moreover, this class is particularly suited to programs that symmetrically encrypt a block of data (such as in AES) and then need to transmit the key to decode that data in a way that cannot be easily intercepted by a third party.

You can read about the advantages of the RSA Algorithm on Wikipedia.

As a possible point of interest, the RSA algorithim encrypts and decrypts on the equations denoted below. Note that c is the cipher text, m is the plain text, and n is the modulus:

c = m^e mod n
m = c^d mod n

For details on the keys, as well as the values for e and d, see the RSA Key Generation Tool.

Usage


There are two different ways, in terms of key generation, that you can implement in the RSA class. In the first method you specify your own keys. This is useful if you want to hard-code your private key into a server which will be receiving the Java transmission. Conversely, you can let the class generate its own RSA keys based on the size of the message (by the RSA algorithm, the generated modulus must exceed the size of the message).

When looking at the implementations, and the code itself, please make sure you're familiar with Java's BigInteger API as this is the format required by many of the RSA class' APIs.

This implementation has the user setting their own keys:
import java.math.*;
 
class RSATest {

	public static void main( String[] args ){

		// Invoke the RSA class, ensuring that the RSA class is in the same
		// directory as your invoking class.
		RSA rsa = new RSA();

		// The RSA class creates a "session key" when the RSA object is
		// created. This is a completely optional value that can be used
		// in the encoding of text using a symmetric key encryption, such
		// as AES. Alternatively, instead of using the RSA class created
		// session key, you can use a value of your own for the encryption.
		// NOTE: YOUR MESSAGE *MUST* BE A HEXADECIMAL STRING IN ORDER
		// FOR ENCRYPTION/KEY GENERATION TO  WORK.
		String message = rsa.getSessionKey();
		
		// Set our keys needed by RSA. They need to be in BigInteger format
		// NOTE: In order to save space, the keys provided here are smaller
		// than they should be in your implementation. Know that running this program
		// in its current state will FAIL, because the default session key size
		// is 256 bits, far exceeding what's provided below.
		BigInteger publicKey = new BigInteger( "65537" );
		BigInteger privateKey = new BigInteger( "1265385473" );
		BigInteger modulus = new BigInteger( "1891728589" );
		
		// The setRSAKeys() method will set the internal keys used by the RSA
		// function for encryption and decryption.
		rsa.setRSAKeys( publicKey, privateKey, modulus );

		// encrypt( String message ) will encrypt a hexadecimal string
		// using the generated, or specified, RSA keys.
		BigInteger encryptedMessage = rsa.encrypt( message );
		
		System.out.println( "[RSA Generated Values]" );
		System.out.println( "Original Message =\n|" + message + "|" );
		System.out.println( "Cipher Text =\n|" + encryptedMessage + "|" );
		
		// decrypt( BigInteger encryptedMessage ) will decrypt a BigInteger (RSA
		// encrypted number) into its hexadecimal equivalent.
		System.out.println( "Decrypted Text =\n|" + rsa.decrypt( encryptedMessage ) + "|" );

	}

}


This implementation, on the other hand, inputs the message (in this case a session key as generated by the RSA class) and allows the program to create the keys:
import java.math.*;
 
class RSATest {

	public static void main( String[] args ){

		// Invoke the RSA class, ensuring that the RSA class is in the same
		// directory as your invoking class.
		RSA rsa = new RSA();

		// The RSA class creates a "session key" when the RSA object is
		// created. This is a completely optional value that can be used
		// in the encoding of text using a symmetric key encryption, such
		// as AES. Alternatively, instead of using the RSA class created
		// session key, you can use a value of your own for the encryption.
		// NOTE: YOUR MESSAGE *MUST* BE A HEXADECIMAL STRING IN ORDER
		// FOR ENCRYPTION/KEY GENERATION TO  WORK.
		String message = rsa.getSessionKey();
		
		// This function creates the RSA keys (public, private, and modulus)
		// based on the size of the message (the modulus must exceed the message
		// in size). Alternatively, you can invoke generateRSAKeys( int bitStrength )
		// to manually specify how large you want the keys to be. Standard
		// security currently places that strength at no less than 1024.
		rsa.generateRSAKeys( message );

		// encrypt( String message ) will encrypt a hexadecimal string
		// using the generated, or specified, RSA keys.
		BigInteger encryptedMessage = rsa.encrypt( message );
		
		System.out.println( "[RSA Generated Values]" );
		System.out.println( "Original Message =\n|" + message + "|" );
		System.out.println( "Cipher Text =\n|" + encryptedMessage + "|" );
		
		// decrypt( BigInteger encryptedMessage ) will decrypt a BigInteger (RSA
		// encrypted number) into its hexadecimal equivalent.
		System.out.println( "Decrypted Text =\n|" + rsa.decrypt( encryptedMessage ) + "|" );

	}

}

API


BigInteger encrypt( String hexStr );
Encrypts a message (hexadecimal string) using the RSA public key.
Returns cipher text (BigInteger)

String decrypt( BigInteger c );
Decrypts a cipher text (BigInteger) using the RSA public key.
Returns plain text message (hexadecimal string)

void generateSessionKey()
Creates a random hexadecimal string which can then be used as a key from a symmetric encryption scheme, such as AES. The default bit strength is 256, unless you invoke the method below at which point calls to this method will use a bit strength of the one specified in the following method.
Creates a randomly generated hexadecimal string. getSessionKey() needs to be invoked to return the generated string

void generateSessionKey( int bitLen );
This method is the same as above however it allows you to specify a bit length which will then overwrite the default, which is 256. As a general rule the higher the bit strength the more security however operations that use it will become less efficient.
Creates a randomly generated hexadecimal string of bitLen length. getSessionKey() needs to be invoked to return the generated string

String getSessionKey();
Returns the session key generated by the generateSessionKey() method (hexadecimal string)

void setRSAKeys( BigInteger publicKey, BigInteger privateKey, BigInteger modulus );
An alternative to the generateRSAKeys() method, this method allows the user to set custom RSA keys for encryption/decryption.
Sets the keys for use by the RSA encrypt/decrypt methods

void generateRSAKeys( int bitStrength );
Invoking this method will generate the needed RSA keys with a bit strength of bitStrength. For security purposes its' recommended your bit strength be n <= 1024. This function is an alternative to setRSAKeys().
Creates RSA keys for use by the class

void generateRSAKeys( String message );
This method does the same action as the previous one, however in this case the keys are created with a bit strength just large enough to accommodate the size of the message to be encrypted.
Creates RSA keys for use by te class

BigInteger getModulus();
Returns the modulus being used by the class (BigInteger). Returns BigInteger( "-1" ) when not set.

BigInteger getPrivateKey();
Returns the private key being used by the class (BigInteger). Returns BigInteger( "-1" ) when not set.

BigInteger getPublicKey();
Returns the public key being used by the class (BigInteger). Returns BigInteger( "-1" ) when not set.


Code

RSA.java - v1.0.1
View Plain   Download Code
/*************************************************
 * RSA Encryption / Decryption class
 * Version: 1.0.1
 * Coded by: Shane Chism <http://shanechism.com>
 * Updates: http://shanechism.com/code/static/10
 * Distributed under the GNU Public License
 *************************************************/

import java.lang.*;
import java.math.*;
import java.security.*;

class RSA {
	
	private String sessionKey;
	
	private int keyBitLen = 256;
	private SecureRandom sRand = new SecureRandom();
	private BigInteger NEGONE = new BigInteger( "-1" );
	
	protected BigInteger publicKey, privateKey, modulus = new BigInteger( "-1" );
	
	public RSA() {
		
		// Generate usable session keys
		this.generateSessionKey();
	
	}
	
	// Encrypts a message (integer) using the RSA public key
	public BigInteger encrypt( String hexStr ){
		
		// Convert the hex input into an integer that can be exponentiated
		BigInteger str = new BigInteger( hexStr, 16 );
		
		// Check to ensure that 1 < M < N (required by the RSA algorithm)
		// Also check to ensure that all needed keys are set
		try {
			
			if( publicKey.compareTo( this.NEGONE ) == 0 || modulus.compareTo( this.NEGONE ) == 0 )
				throw new Exception( "No RSA keys have been set.\n" +
									 "Load keys either by setting them manually with the setRSAKeys() method or\n" +
									 "by invoking generateRSAKeys( BigInteger message ) or generateRSAKeys( int bitStrength )" );
			
			if( str.compareTo( this.modulus ) != -1 )
				throw new Exception( "Message exceeds size of specified modulus.\n" + 
									 "Modulus size must exceed message size. RSA Encryption failed." );
			
		}catch( Exception err ){
			System.err.println( err );
			System.exit( 1 );
		}
		
		BigInteger c = str.modPow( this.publicKey, this.modulus );
		
		return c;
		
	}

	// Decrypts an RSA encrypted message (integer) using the RSA private key
	public String decrypt( BigInteger c ){
		
		try {
			
			if( privateKey.compareTo( this.NEGONE ) == 0 || modulus.compareTo( this.NEGONE ) == 0 )
				throw new Exception( "No RSA keys have been set.\n" +
									 "Load keys either by setting them manually with the setRSAKeys() method or\n" +
									 "by invoking generateRSAKeys( BigInteger message ) or generateRSAKeys( int bitStrength )" );
			
		}catch( Exception e ){
			System.err.println( e );
			System.exit( 1 );
		}
		
		BigInteger m = c.modPow( this.privateKey, this.modulus );
		return( m.toString( 16 ) );
		
	}	

	// Creates a session key for optional use by the user.
	// The session key's intended use is for the key used in a symmetric
	// encryption method such as AES. That will then allow the user to
	// transmit an AES generated hash along with the RSA encrypted key,
	// which will allow the recipient to decode the message.
	public void generateSessionKey() {
		
		BigInteger key = new BigInteger( keyBitLen, sRand );
		this.sessionKey = key.toString( 16 );
		
	}
	
	// Creates a session key for optional use by the user.
	// This method does the same as the above, however it also allows
	// a user to specify a bit length for the session key
	public void generateSessionKey( int bitLen ){
		this.keyBitLen = bitLen;
		this.generateSessionKey();
	}
	
	// Allows user to get the RSA class' generated session key
	public String getSessionKey(){
		return this.sessionKey;
	}
	
	// Allows user to set the RSA keys to custom values
	public void setRSAKeys( BigInteger publicKey, BigInteger privateKey, BigInteger modulus ){
		this.publicKey = publicKey;
		this.privateKey = privateKey;
		this.modulus = modulus;
	}
	
	// Generates usable RSA keys based on bit strength.
	// Results can be accessed from invoking RSA.genPublicKey,
	// RSA.genPrivateKey, and RSA.genModulus
	public void generateRSAKeys( int bitStrength ){
		
		BigInteger p = BigInteger.probablePrime( ( bitStrength / 2 ), this.sRand );
		BigInteger q = BigInteger.probablePrime( ( bitStrength / 2 ), this.sRand );
		
		BigInteger n = p.multiply( q );
		BigInteger phi = ( p.subtract( BigInteger.ONE ) ).multiply( q.subtract( BigInteger.ONE ) );
		
		BigInteger publicKey = new BigInteger( "65537" );
		
		while( publicKey.gcd( phi ).compareTo( BigInteger.ONE ) != 0 ){
			
			publicKey = publicKey.add( BigInteger.ONE );
			
			if( publicKey.compareTo( phi ) == 1 ){
				// Unable to find keys, try again
				this.generateRSAKeys( bitStrength );
			}
			
		}
		
		BigInteger privateKey = publicKey.modInverse( phi );
		
		this.publicKey = publicKey;
		this.privateKey = privateKey;
		this.modulus = n;
		
	}
	
	// Generates usable RSA keys based on message size.
	// Results can be accessed from invoking RSA.genPublicKey,
	// RSA.genPrivateKey, and RSA.genModulus
	public void generateRSAKeys( String message ){
		
		BigInteger temp = new BigInteger( message, 16 );
		this.generateRSAKeys( temp.bitLength() * 2 );
		
	}
	
	// Allows user to get the private key
	protected BigInteger getPrivateKey(){
		return this.privateKey;
	}
	
	// Allows user to get the public key
	protected BigInteger getPublicKey(){
		return this.publicKey;
	}
	
	// Allows user to get the modulus
	protected BigInteger getModulus(){
		return this.modulus;
	}
	
}


 
Java
DECEMBER 18 2010
Download
496 DOWNLOADS