Generate Public\Private Key: http://www.javamex.com/tutorials/cryptography/rsa_encryption.shtml
Encrypt files: http://www-users.york.ac.uk/~mal503/lore/pkencryption.htm
With the increase awareness to security the demand for securing data is rising. Fortunately Java provides pretty good tools that can help developers encrypt and decrypt data.
One of the most popular encryption is called RSA encryption. Named after its inventors, Ron Rivest, Adi Shamir and Leonard Adleman, RSA encryption transforms the number “char” into the number “cipher” with the formula
cipher = char^e (mod n)
The numbers e and n are the two numbers you create and publish. They are your “public key.” The number char can be simply the digital value of a block of ASCII characters. The formula says: multiply the number char by itself e times, then divide the result by the number n and save only the remainder. The remainder that we have called cipher is the encrypted representation of char.
Using the two numbers you have published, anyone can scramble a message and send it to you. You are the only one who can unscramble it; not even the sender of the message can decrypt the ciphertext.
Standard Java 2 distribution includes security provider support for generation of RSA digital signatures, but does NOT contain a provider implementation for generating RSA encrypted data. An extra provider must be added to obtain this capability from standard Java 2, such as the Bouncy Castle Provider.
Since I couldn’t find any good examples that use Java with RSA, we’ll build a nice RSAEncryptUtil class that you can use as a reference for using RSA encryption (you can download the full source code here).
The first thing we need to do is to define the algorithm that we want to use.
protected static final String ALGORITHM = "RSA";
Then as stated before we’ll need to add Bouncy Castle as our RSA provider. In order to do that we’ll write an Init method for our class
/**
* Init java security to add BouncyCastle as an RSA provider
*/
public static void init()
{
Security.addProvider(new BouncyCastleProvider());
}
To generate what is called private and public keys, Java provides us with a simple to use KeyPairGenerator class. The java.security.KeyPairGenerator generates the two keys that are returned in a java.security.KeyPair object.
/**
* Generate key which contains a pair of privae and public key using 1024 bytes
* @return key pair
* @throws NoSuchAlgorithmException
*/
public static KeyPair generateKey() throws NoSuchAlgorithmException
{
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(1024);
KeyPair key = keyGen.generateKeyPair();
return key;
}
Now that we have the two keys we can encrypt and decrypt information. In order to do that we are going to use javax.crypto.Cipher. This class provides the functionality of a cryptographic cipher for encryption and decryption. It forms the core of the Java Cryptographic Extension (JCE) framework.
In order to create a Cipher object, the application calls the Cipher’s getInstance method, and passes the name of the requested transformation to it. Optionally, the name of a provider may be specified.
A transformation is a string that describes the operation (or set of operations) to be performed on the given input, to produce some output. A transformation always includes the name of a cryptographic algorithm, and may be followed by a feedback mode and padding scheme. A transformation is of the form:”algorithm/mode/padding” or “algorithm”
In our example we’ll encrypt a message using our public key.
/**
* Encrypt a text using public key.
* @param text The original unencrypted text
* @param key The public key
* @return Encrypted text
* @throws java.lang.Exception
*/
public static byte[] encrypt(byte[] text, PublicKey key) throws Exception
{
byte[] cipherText = null;
// get an RSA cipher object and print the provider
Cipher cipher = Cipher.getInstance(”RSA/ECB/PKCS1Padding”);
System.out.println(”nProvider is: ” + cipher.getProvider().getInfo());
// encrypt the plaintext using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text);
return cipherText;
}
The opposite method is to decrypt a message that was encrypted using a public key. Remember the only one who can decrypt an encrypted message is the one with the private key.
/**
* Decrypt text using private key
* @param text The encrypted text
* @param key The private key
* @return The unencrypted text
* @throws java.lang.Exception
*/
public static byte[] decrypt(byte[] text, PrivateKey key) throws Exception
{
byte[] dectyptedText = null;
// decrypt the text using the private key
Cipher cipher = Cipher.getInstance(”RSA/ECB/PKCS1Padding”);
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text);
return dectyptedText;
}
So far we’ve created public and private keys, encrypted and decrypted messaged. But in order for this utility to be useful we need to be able to send and receive keys and messages. In many implementations you’ll need to do those actions without using bytes, but using strings. The first notion is just convert the byte array to a string object. But this will not work. In order to do that you’ll need to convert the bytes array to a Base64 string representation. Luckily for us this is a very easy task. The following methods will convert bytes to Base64 string and back.
/**
* Encode bytes array to BASE64 string
* @param bytes
* @return Encoded string
*/
private static String encodeBASE64(byte[] bytes)
{
BASE64Encoder b64 = new BASE64Encoder();
return b64.encode(bytes);
}
/**
* Decode BASE64 encoded string to bytes array
* @param text The string
* @return Bytes array
* @throws IOException
*/
private static byte[] decodeBASE64(String text) throws IOException
{
BASE64Decoder b64 = new BASE64Decoder();
return b64.decodeBuffer(text);
}
Now that we have the strings we can do anything we want with them: Save the key in a database, send the public key thru email, web page or any other method, send and receive encrypted messages and anything else you can think of.
One more useful task you would like to do is to be able to handle files. The problem with files (and large strings) is that RSA encryption data size limitations are slightly less than the key modulus size, depending on the actual padding scheme used (e.g. with 1024 bit (128 byte) RSA key, the size limit is 117 bytes for PKCS#1 v 1.5 padding. Hence in order to handle files we need to read and write the files in small blocks. In our example well use blocks of 100 bytes.
/**
* Encrypt and Decrypt files using 1024 RSA encryption
*
* @param srcFileName Source file name
* @param destFileName Destination file name
* @param key The key. For encryption this is the Private Key and for decryption this is the public key
* @param cipherMode Cipher Mode
* @throws Exception
*/
public static void encryptDecryptFile(String srcFileName, String destFileName, Key key, int cipherMode) throws Exception
{
OutputStream outputWriter = null;
InputStream inputReader = null;
try
{
Cipher cipher = Cipher.getInstance(”RSA/ECB/PKCS1Padding”);
String textLine = null;
byte[] buf = cipherMode == Cipher.ENCRYPT_MODE? new byte[100] : new byte[128];
int bufl;
// init the Cipher object for Encryption…
cipher.init(cipherMode, key);
// start FileIO
outputWriter = new FileOutputStream(destFileName);
inputReader = new FileInputStream(srcFileName);
while ( (bufl = inputReader.read(buf)) != -1)
{
byte[] encText = null;
if (cipherMode == Cipher.ENCRYPT_MODE)
{
encText = encrypt(copyBytes(buf,bufl),(PublicKey)key);
}
else
{
encText = decrypt(copyBytes(buf,bufl),(PrivateKey)key);
}
outputWriter.write(encText);
}
outputWriter.flush();
}
finally
{
try
{
if (outputWriter != null)
{
outputWriter.close();
}
if (inputReader != null)
{
inputReader.close();
}
}
catch (Exception e)
{
// do nothing…
}
}
}
public static byte[] copyBytes(byte[] arr, int length)
{
byte[] newArr = null;
if (arr.length == length)
{
newArr = arr;
}
else
{
newArr = new byte[length];
for (int i = 0; i < length; i++)
{
newArr[i] = (byte) arr[i];
}
}
return newArr;
}
I hope this article will help you make your first steps in to the encryption world. You can download RSAEncryptUtil.zip (2.51 kb), which includes some other convenient methods for you to work with.