Encryption and Decryption of Strings in Java

In this tutorial, you will learn about encryption and decryption of strings in Java.

Encryption

Encryption is the process of converting a plain text into a ciphertext. A ciphertext is not readable until it is converted to plain text using a secret key.

Decryption

Decryption is the process of converting a ciphertext into a plain text using a secret key so as to make it readable.

Types of Encryption

There are two types of encryption:

  1. Asymmetric Encryption - Asymmetric encryption uses two keys - public key and private key. A public key is used to encrypt a plain text. A public key can be made freely available to anyone who might want to encrypt and send a text. The encrypted text can only be read using a private key. A private key must be kept secret or exchanged over the internet to people who you want to be able to read your encrypted texts. Some of the asymmetric key encryption algorithm are DSA, RSA, PKCS, ELGamal, ECC, Diffie-Hellman, etc.
  2. Symmetric Encryption - Symmetric encryption uses a single key for both encryption and decryption. Some of the symmetric key encryption algorithm are AES (Advanced Encryption Standard), DES (Data Encryption Standard), etc.

Asymmetric encryption is considered to be more secure than symmetric encryption because asymmetric encryption technique is relatively new compared to symmetric encryption and asymmetric encryption also uses two keys for encryption and decryption.

Java provides the Cipher class with cryptographic functions for encryption and decryption. You can simply import the Cipher class from the package javax.crypto.Cipher.

To create a Cipher object, we need to call the Cipher's getInstance() method and pass the name of the transformation to it.

A transformation is a string in the form algorithm/mode/scheme or algorithm. It includes the name of the cryptographic algorithm and may be followed by a feedback mode and padding scheme.

The following is an example of creating a Cipher object with a valid transformation:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

Asymmetric Encryption Example

The code below shows how to generate and save public private key pair files to a specific location, load the keys from files to encrypt and decrypt a string using asymmetric encryption technique:

Note: You should create the public and private key pair once and use the same keys everytime for encryption and decryption. A text that is encrypted using a specific public private key pair cannot be decrypted using a private key of another public private key pair.


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class AsymmetricEncryptionManager {

    public static void main(String[] args) {
        /* path to project root folder for saving public and private keys */
        String path = System.getProperty("user.dir");

        // Generates New public and private keys
        KeyPair keyPair = generateKeys();

        /* save public and private keys to files at the given location */
        saveKeysToFiles(path, keyPair.getPublic(), keyPair.getPrivate());

        // Algorithm to convert keys
        String algorithm = "RSA";

        // Read keys from files
        PublicKey publicKey = loadPublicKey(path, algorithm);
        PrivateKey privateKey = loadPrivateKey(path, algorithm);

        // Test
        String plainText = "This is a  secret message";
        /* Encrypting plain text to ciphertext */
        String encryptedText = encrypt(publicKey, plainText);
        System.out.println("Encrypted text = " + encryptedText);

        /* Decrypting encrypted text back to plain text */
        String decryptedText = decrypt(privateKey, encryptedText);
        System.out.println("Decrypted text = " + decryptedText);
    }

    public static String encrypt(PublicKey publicKey, String plainText) {
        if (plainText == null || plainText.isEmpty()) {
            System.out.println("No data to encrypt!");
            return plainText;
        }
        Cipher cipher = null;
        String encryptedString = "";
        try {
            // Creating a Cipher object
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

            // Initializing a Cipher object with public key
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            // Encrypting the plain text string
            byte[] encryptedText = cipher.doFinal(plainText.getBytes());

            // Encoding the encrypted text to Base64
            encryptedString = Base64.getEncoder().encodeToString(encryptedText);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
                | IllegalBlockSizeException | BadPaddingException ex) {
            System.out.println("Exception caught while encrypting : " + ex);
        }

        return encryptedString;
    }

    public static String decrypt(PrivateKey privateKey, String cipherText) {
        if (cipherText == null || cipherText.isEmpty()) {
            System.out.println("No data to decrypt!");
            return cipherText;
        }
        String decryptedString = "";
        Cipher cipher = null;
        try {
            // Creating a Cipher object
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

            // Initializing a Cipher object with private key
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            // Decoding from Base64
            byte[] encryptedText = Base64.getDecoder().decode(cipherText.getBytes());

            // Decrypting to plain text
            decryptedString = new String(cipher.doFinal(encryptedText));

        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException
                | IllegalBlockSizeException | BadPaddingException ex) {
            System.out.println("Exception caught while decrypting : " + ex);
        }
        return decryptedString;
    }


    public static KeyPair generateKeys() {
        KeyPair keyPair = null;
        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");

            SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");

            // Initializing KeyPairGenerator
            keyGen.initialize(2048, random);

            // Generate keys
            keyPair = keyGen.generateKeyPair();

        } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
            e.printStackTrace();
        }
        return keyPair;
    }

    public static void saveKeysToFiles(String path, PublicKey publicKey, PrivateKey privateKey) {

        FileOutputStream fos = null;

        try {
            File file = new File(path + "/public.key");
            if (file.createNewFile()) {
                fos = new FileOutputStream(file);
                X509EncodedKeySpec x509EncodedKeySpec =
                        new X509EncodedKeySpec(publicKey.getEncoded());
                fos.write(x509EncodedKeySpec.getEncoded());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        // Private Key
        try {
            File file = new File(path + "/private.key");
            if (file.createNewFile()) {
                fos = new FileOutputStream(file);
                PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
                        new PKCS8EncodedKeySpec(privateKey.getEncoded());
                fos.write(pkcs8EncodedKeySpec.getEncoded());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static PublicKey loadPublicKey(String path, String algorithm) {

        FileInputStream fis = null;
        PublicKey publicKey = null;
        try {
            File file = new File(path + "/public.key");
            fis = new FileInputStream(file);
            byte[] encodedPublicKey = new byte[(int) file.length()];
            fis.read(encodedPublicKey);

            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedPublicKey);
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return publicKey;
    }

    public static PrivateKey loadPrivateKey(String path, String algorithm) {

        FileInputStream fis = null;
        PrivateKey privateKey = null;

        try {
            File file = new File(path + "/private.key");
            fis = new FileInputStream(file);
            byte[] encodedPrivateKey = new byte[(int) file.length()];
            fis.read(encodedPrivateKey);

            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            privateKey = keyFactory.generatePrivate(privateKeySpec);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return privateKey;
    }

}
Output:
Encrypted text = P+wlSykyT9DfNLtr39mvo9xlMkvhQ5I6BUtngrTbls34pYZfJ9pux9Lrf9bB9RryYWEvww1v6MzScXuMXbEsTRVaYxRGFnF6uLPJ/+ypZDmOTwRJ1abJuyG/h5Vc0K3pnMtZG8De6uVckXeIPmDRsZP5NexIo5Folf4N/Rin6eqXxuk6Vu7UlesJewuAROTYfKBCh/bYTpH41D4hLKi86dkWgwYfKzGOZ4ZBZLh0UNF3a0FIk9F4t8ooxd+Xf7ooTJqGppby9Kn0MiaL/iWzz1UdLudHH5CNUr6k5PVCYc9DZUglUCBnEefE/4ojv9VDai9PuT1uvSsdDLCnNg0Mwg==
Decrypted text = This is a secret message

Symmetric Encryption Example

Here is a Java example code with methods - encrypt() method to encrypt a string and decrypt() method to decrypt the encrypted string:


import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class CryptoManager {
    //Key for encryption and decryption
    public static final byte[] KEY =
            {118, 106, 107, 122, 76, 99, 69, 83, 101, 103, 82, 101, 116, 75, 101, 127};

    public static void main(String args[]) {
        String salt = "HELLO";
        String encryptedString = encrypt(salt, "HelloWorld12345");
        System.out.println("Encripted string is " + encryptedString);

        String decryptedString = decrypt(salt, encryptedString);
        System.out.println("Decrypted string is " + decryptedString);

    }

    public static String encrypt(String salt, String plainText) {
        if (plainText == null || plainText.isEmpty()) {
            System.out.println("No data to encrypt!");
            return plainText;
        }
        Cipher cipher = null;
        String encryptedString = "";
        try {
            // Creating a Cipher object
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

            // Creating a secret key from KEY byte array
            final SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES");

            // Initializing a Cipher object
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            // Encrypting the plain text string
            byte[] encryptedText = cipher.doFinal(salt.concat(plainText).getBytes());

            // Encoding the encrypted text to Base64
            encryptedString = Base64.getEncoder().encodeToString(encryptedText);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
                | IllegalBlockSizeException | BadPaddingException ex) {
            System.out.println("Exception caught while encrypting : " + ex);
        }
        return encryptedString;
    }


    public static String decrypt(String salt, String cipherText) {
        if (cipherText == null || cipherText.isEmpty()) {
            System.out.println("No data to decrypt!");
            return cipherText;
        }
        String decryptedString = "";
        Cipher cipher = null;
        try {
            // Creating a Cipher object
            cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");

            // Creating a secret key from KEY byte array
            final SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES");

            // Initializing a Cipher object
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

            // Decoding from Base64
            byte[] encryptedText = Base64.getDecoder().decode(cipherText.getBytes());

            // Decrypting to plain text
            decryptedString = new String(cipher.doFinal(encryptedText));

        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException
                | IllegalBlockSizeException | BadPaddingException ex) {
            System.out.println("Exception caught while decrypting : " + ex);
        }
        return decryptedString.replace(salt, "");
    }

}
Output:
Encripted string is VKttEiG2vqYr4t7R7plUhmY0bLmHwvH21zKVz7n4BrM=
Decrypted string is HelloWorld12345