RSA [Rivest Shamir Adleman] is a strong encryption and decryption algorithm which uses public key cryptography. RSA algorithm is an Asymmetric Cryptography algorithm, unlike Symmetric algorithm which uses the same key for both Encryption and Decryption we will be using two different keys. One key can be given to anyone [Public Key] and the other key should be kept private [Private Key].
In this article, we will be discussing about RSA Encryption and Decryption in Java with OAEPWITHSHA-512ANDMGF1PADDING padding and 4096 Bit Key.
What is RSA Encryption ?
RSA Encryption algorithm was published in the 70’s by Ron Rivest, Adi Shamir, and Leonard Adleman. It is the most widely-used public key cryptography algorithm in the world and based on the difficulty of factoring large integers.
It can be used to encrypt a message without the need to exchange a secret key separately. RSA supports key length of 1024, 2048, 3072, 4096 7680 and 15360 bits.
Java RSA Encryption and Decryption Example
Let’s say if John and Smith want to exchange a message and by using using RSA Encryption then,
- Before sending the message, John must know the Public Key of Smith. Using the public key, John encrypts the message and sends the encrypted message to Smith.
- Smith can use his Private key to decrypt the message with ease.
package com.javainterviewpoint; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Base64; import javax.crypto.Cipher; public class RSA_Encryption { static String plainText = "Plain text which need to be encrypted by Java RSA Encryption in ECB Mode"; public static void main(String[] args) throws Exception { // Get an instance of the RSA key generator KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(4096); // Generate the KeyPair KeyPair keyPair = keyPairGenerator.generateKeyPair(); // Get the public and private key PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); System.out.println("Original Text : "+plainText); // Encryption byte[] cipherTextArray = encrypt(plainText, publicKey); String encryptedText = Base64.getEncoder().encodeToString(cipherTextArray); System.out.println("Encrypted Text : "+encryptedText); // Decryption String decryptedText = decrypt(cipherTextArray, privateKey); System.out.println("DeCrypted Text : "+decryptedText); } public static byte[] encrypt (String plainText,PublicKey publicKey ) throws Exception { //Get Cipher Instance RSA With ECB Mode and OAEPWITHSHA-512ANDMGF1PADDING Padding Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-512ANDMGF1PADDING"); //Initialize Cipher for ENCRYPT_MODE cipher.init(Cipher.ENCRYPT_MODE, publicKey); //Perform Encryption byte[] cipherText = cipher.doFinal(plainText.getBytes()) ; return cipherText; } public static String decrypt (byte[] cipherTextArray, PrivateKey privateKey) throws Exception { //Get Cipher Instance RSA With ECB Mode and OAEPWITHSHA-512ANDMGF1PADDING Padding Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-512ANDMGF1PADDING"); //Initialize Cipher for DECRYPT_MODE cipher.init(Cipher.DECRYPT_MODE, privateKey); //Perform Decryption byte[] decryptedTextArray = cipher.doFinal(cipherTextArray); return new String(decryptedTextArray); } }
- KeyPairGenerator Class is used to generate asymmetric encryption keys [public and private keys] , we will get the KeyPairGenerator instance by calling the getInstance() method passing the name of the algorithm as a parameter, in our case it is RSA
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- We need to initialize the KeyPairGenerator instance is created above by calling its initialize() method, we need to pass the size of the keys to generate. We have passed 4096, as we are creating 4096 bit key.
keyPairGenerator.initialize(4096);
- Once the KeyPairGenerator is initialized, we can generate the PublicKey and PrivateKey by calling the generateKeyPair() method on top of the KeyPairGenerator instance.
- getPublic() method returns the PublicKey and getPrivate() method returns the PrivateKey
KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate();
- Cipher is the class which handles the actual encryption and decryption. The instance of the Cipher class is created by calling the getInstance() method to which the Cipher name is passed as a parameter, Cipher name comprises 3 parts
- The first part is the name of the algorithm, in our case it RSA
- The second part is the mode in which the algorithm should be used – ECB. “ECB” is a symmetric cipher mode and RSA is an asymmetric cipher, So “ECB” has no effect
- The third part is the padding scheme which is going to be used – OAEPWITHSHA-512ANDMGF1PADDING
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-512ANDMGF1PADDING");
- We need to initialize the Cipher in order to perform the encryption or decryption, bypassing the mode and key.
- Cipher Mode can Cipher.ENCRYPT_MODE for Encryption or Cipher.DECRYPT_MODE for Decryption
- PublicKey for Encryption or PrivateKey for Decryption
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
or
cipher.init(Cipher.DECRYPT_MODE, privateKey);
- Once after the Mode and Key is set to the Cipher
- In order to Encrypt, we need to pass the PlainText as a parameter to the doFinal() method of the Cipher Instance
byte[] cipherText = cipher.doFinal(plainText.getBytes()) ; String encryptedText = Base64.getEncoder().encodeToString(cipherTextArray);
-
- In order to Decrypt, we need to pass the cipherText as a parameter to the doFinal() method of the Cipher instance
byte[] decryptedTextArray = cipher.doFinal(cipherTextArray);
Output:
Original Text : Plain text which need to be encrypted by Java RSA Encryption in ECB Mode Encrypted Text : uce+oEhtismUZwJ0GjWb+C8u+RqXm7WGyJAinTzgY19H9wKHvVhk0PzQ0LH3xByudag1cYuFOej882yYnW73jPMo9aZhiCEaccy702jaTeeLhw9jB56coH71OxMxJI1xWlX/vVmqkmT8TCJEDOZZgdxtq8nyW36SDR1negt6YkBLN05A9dm8FIXVxdDgSpioWL+mkZ7QdTgtqCUZEb4d2TWb77Tu55okhKqIOwvQ3YSCe0mKpfYQ5uOaMCcVL6mqwJmI0uRB0Ja6uxlIE1WpZKzv2Hn1MQ7psc1tsVUF3B0NLK38Qb/A5m2CRB/9L5dhQTzBAC5pU5CnCgHhiE9Ms/3wp6a60FQfph26ibIKKhG37DsUJAX6p0jIhulYkuWJXT0Z87UhM11dSDIMIjcFV00R7NvmRycGu3DiDsxK06c7Yt9Ep6n8PyBoI6lMN7kKdtWD5HwGdU6OIeNluaLoAAxDUtUX1gQN//3o+aol29G6xJf42VsbG/g/7tgGDlWVoEuTR97vhdKWoq8w3XZKIsiDU+kHIjE3Z22MxLOW0w7nmGbX6bU6GZUUZBBkhcW2bjReKieGCB3acMDBGl5getpyaKK4Vt+HMiUwhTfRbarDA8itggjxlw4nmXrAAShXT4MgO9kxRSmUqfOAkKx9gNIApycNEtWukDmJuYtKXU4= DeCrypted Text : Plain text which need to be encrypted by Java RSA Encryption in ECB Mode
Saving RSA algorithm public and private key
In real time we cannot keep the Keys as such we need to the write the Public Key and Private Key to a file, in order to save the keys we need to get the modulus and exponent of both the keys and write it to the key file.
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); RSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(privateKey, RSAPrivateKeySpec.class); saveKeyToFile("public.key", publicKeySpec.getModulus(), publicKeySpec.getPublicExponent()); saveKeyToFile("private.key", privateKeySpec.getModulus(), privateKeySpec.getPrivateExponent());
- Get the instance of the KeyFactory class by calling the getInstance() method and pass “RSA” as a parameter
- Once we get the KeyFactor instance, then we can get the individual Spec class [RSAPublicKeySpec, RSAPrivateKeySpec] by passing the respective key and KeySpec class.
public static void saveKeyToFile(String fileName, BigInteger modulus, BigInteger exponent) throws IOException { ObjectOutputStream ObjOutputStream = new ObjectOutputStream( new BufferedOutputStream (new FileOutputStream(fileName))); try { ObjOutputStream.writeObject(modulus); ObjOutputStream.writeObject(exponent); } catch (Exception e) { e.printStackTrace(); } finally { ObjOutputStream.close(); } }
- Finally we can save the modulus and exponent which can be obtained from the respective KeySpec class using serialization. Create the ObjectOutputStream object and write the modulus and exponent using the writeObject() method.
Reading RSA key from file
- Create ObjectInputStream object to read the key file
InputStream inputStream = new FileInputStream (keyFileName); ObjectInputStream objectInputStream = new ObjectInputStream (new BufferedInputStream(inputStream));
- Get the modulus and exponent using the readObject() method
BigInteger modulus = (BigInteger) objectInputStream.readObject(); BigInteger exponent = (BigInteger) objectInputStream.readObject();
- Get the instance of the KeyFactory class by calling the getInstance() method and pass “RSA” as a parameter
KeyFactory keyFactory = KeyFactory.getInstance("RSA")
- If the Key file starts with “public” then call generatePublic() method passing modulus and exponent else call the generatePrivate() method to get the public and private key respectively.
if (keyFileName.startsWith("public")) key = keyFactory.generatePublic(new RSAPublicKeySpec(modulus, exponent)); else key = keyFactory.generatePrivate(new RSAPrivateKeySpec(modulus, exponent));
Finally, Put all together
package com.javainterviewpoint; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.util.Base64; import javax.crypto.Cipher; public class RSA_Read_Write_Key { static String plainText = "Plain text which need to be encrypted by Java RSA Encryption in ECB Mode"; public static void main(String[] args) throws Exception { // Get an instance of the RSA key generator KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(4096); // Generate the KeyPair KeyPair keyPair = keyPairGenerator.generateKeyPair(); // Get the public and private key PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // Get the RSAPublicKeySpec and RSAPrivateKeySpec KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKeySpec publicKeySpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); RSAPrivateKeySpec privateKeySpec = keyFactory.getKeySpec(privateKey, RSAPrivateKeySpec.class); // Saving the Key to the file saveKeyToFile("public.key", publicKeySpec.getModulus(), publicKeySpec.getPublicExponent()); saveKeyToFile("private.key", privateKeySpec.getModulus(), privateKeySpec.getPrivateExponent()); System.out.println("Original Text : " + plainText); // Encryption byte[] cipherTextArray = encrypt(plainText, "D:\\sts-3.8.3.RELEASE\\Workspace\\Encryption\\public.key"); String encryptedText = Base64.getEncoder().encodeToString(cipherTextArray); System.out.println("Encrypted Text : " + encryptedText); // Decryption String decryptedText = decrypt(cipherTextArray, "D:\\sts-3.8.3.RELEASE\\Workspace\\Encryption\\private.key"); System.out.println("DeCrypted Text : " + decryptedText); } public static void saveKeyToFile(String fileName, BigInteger modulus, BigInteger exponent) throws IOException { ObjectOutputStream ObjOutputStream = new ObjectOutputStream( new BufferedOutputStream(new FileOutputStream(fileName))); try { ObjOutputStream.writeObject(modulus); ObjOutputStream.writeObject(exponent); } catch (Exception e) { e.printStackTrace(); } finally { ObjOutputStream.close(); } } public static Key readKeyFromFile(String keyFileName) throws IOException { Key key = null; InputStream inputStream = new FileInputStream(keyFileName); ObjectInputStream objectInputStream = new ObjectInputStream(new BufferedInputStream(inputStream)); try { BigInteger modulus = (BigInteger) objectInputStream.readObject(); BigInteger exponent = (BigInteger) objectInputStream.readObject(); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); if (keyFileName.startsWith("public")) key = keyFactory.generatePublic(new RSAPublicKeySpec(modulus, exponent)); else key = keyFactory.generatePrivate(new RSAPrivateKeySpec(modulus, exponent)); } catch (Exception e) { e.printStackTrace(); } finally { objectInputStream.close(); } return key; } public static byte[] encrypt(String plainText, String fileName) throws Exception { Key publicKey = readKeyFromFile("public.key"); // Get Cipher Instance Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-512ANDMGF1PADDING"); // Initialize Cipher for ENCRYPT_MODE cipher.init(Cipher.ENCRYPT_MODE, publicKey); // Perform Encryption byte[] cipherText = cipher.doFinal(plainText.getBytes()); return cipherText; } public static String decrypt(byte[] cipherTextArray, String fileName) throws Exception { Key privateKey = readKeyFromFile("private.key"); // Get Cipher Instance Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-512ANDMGF1PADDING"); // Initialize Cipher for DECRYPT_MODE cipher.init(Cipher.DECRYPT_MODE, privateKey); // Perform Decryption byte[] decryptedTextArray = cipher.doFinal(cipherTextArray); return new String(decryptedTextArray); } }
Output:
Original Text : Plain text which need to be encrypted by Java RSA Encryption in ECB Mode Encrypted Text : RQal6CxZAtuOU3kusg3s19FQhLrczjHq4i8wkRBh8nG0+j7mGP3LPq65mBfC8jrqTNSmdhmGyx42OzrIXaOCIfU3vw4irfmi7OpxIA7ymLIcy5L3wh/KEAfzTJhecM0r5513h/oviAYhwATkvpgsnWeOPTgCvMaoOgzULYJekEXsvmOr0mZv5ECrZa1Zj+5GQzK6Vz5MpeOHy/giPpnlQK9TIYI1KbD/2dFHYDqoeKFQ6KlaIt1VMyAzIm2FZ2GSKcqq2HRbCri+iS5xpGht8fDpLthPizvVlls5T/67341GyaKR8s+jumOQvsqB011R/TvzUY7OXquxHICqMW+UBMPoO0c92jisxyWiyHoT376KKZxuY2//Z3MRFmw/LKNaacD3OIqGjU5bnZbhMMF5QL8jLclJ7JQbxadqwCnOcaW7t2XPdYOtND1xGB4vg/eEfuCq1PytoGTTsKjnZfjozX3Mka7MIcVxKiYO0A/LksnI/sQMoZx1yNE3b6qs+v2rW0gsRLLE/DYcKczPxi1QPMqRphvKr3j93IvfNCt/V+cUdwOLM0O0Yrm5Hmsk8ggdBPlCzv7NxrglOhUDtKa6RPxQgzxAX54LkrjB8/h+I24CYNaKiFuCx5CJxeagaujEa/9uGMf6vkRWUW7CW3Gdpo5abedJmGsTNFHd6KYhZqo= DeCrypted Text : Plain text which need to be encrypted by Java RSA Encryption in ECB Mode
Dhiren says
Good example I was facing some issues which is now fixed just because of this example.
Thanks 🙂