Java – Asymmetric Cryptography example

Asymmetric Cryptography, also known as Public Key Cryptography, is an encryption system in which two different but uniquely related cryptographic keys are used. The data encrypted using one key can be decrypted with the other. These keys are known as Public and Private Key Pair, and as the name implies the private key must remain private while the public key can be distributed. The most popular Public Key Algorithms are RSA, Diffie-Hellman, ElGamal, DSS.

1. Generate a Public-Private Key Pair

There are several ways to generate a Public-Private Key Pair depending on your platform. In this example, we will create a pair using Java. The Cryptographic Algorithm we will use in this example is RSA.

GenerateKeys.java

package com.mkyong.keypair;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;

public class GenerateKeys {

	private KeyPairGenerator keyGen;
	private KeyPair pair;
	private PrivateKey privateKey;
	private PublicKey publicKey;

	public GenerateKeys(int keylength) throws NoSuchAlgorithmException, NoSuchProviderException {
		this.keyGen = KeyPairGenerator.getInstance("RSA");
		this.keyGen.initialize(keylength);
	}

	public void createKeys() {
		this.pair = this.keyGen.generateKeyPair();
		this.privateKey = pair.getPrivate();
		this.publicKey = pair.getPublic();
	}

	public PrivateKey getPrivateKey() {
		return this.privateKey;
	}

	public PublicKey getPublicKey() {
		return this.publicKey;
	}

	public void writeToFile(String path, byte[] key) throws IOException {
		File f = new File(path);
		f.getParentFile().mkdirs();

		FileOutputStream fos = new FileOutputStream(f);
		fos.write(key);
		fos.flush();
		fos.close();
	}

	public static void main(String[] args) {
		GenerateKeys gk;
		try {
			gk = new GenerateKeys(1024);
			gk.createKeys();
			gk.writeToFile("KeyPair/publicKey", gk.getPublicKey().getEncoded());
			gk.writeToFile("KeyPair/privateKey", gk.getPrivateKey().getEncoded());
		} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
			System.err.println(e.getMessage());
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}

	}

}

Output:

java-asymmetric-cryptography-7a

2. Create a text file to encrypt

java-asymmetric-cryptography-7b

3. Use the Key Pair to encrypt and decrypt data

In this example, we create a class that can load the Public and the Private keys from their files and then uses them to encrypt and decrypt a String and a File. To run this example, you need to have run the code above to generate keys or download the source below.

Note
You need to get Apache Commons Codec and add it to your program.
AsymmetricCryptography.java

package com.mkyong.asymmetric;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;

public class AsymmetricCryptography {
	private Cipher cipher;

	public AsymmetricCryptography() throws NoSuchAlgorithmException, NoSuchPaddingException {
		this.cipher = Cipher.getInstance("RSA");
	}

	// https://docs.oracle.com/javase/8/docs/api/java/security/spec/PKCS8EncodedKeySpec.html
	public PrivateKey getPrivate(String filename) throws Exception {
		byte[] keyBytes = Files.readAllBytes(new File(filename).toPath());
		PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory kf = KeyFactory.getInstance("RSA");
		return kf.generatePrivate(spec);
	}

	// https://docs.oracle.com/javase/8/docs/api/java/security/spec/X509EncodedKeySpec.html
	public PublicKey getPublic(String filename) throws Exception {
		byte[] keyBytes = Files.readAllBytes(new File(filename).toPath());
		X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
		KeyFactory kf = KeyFactory.getInstance("RSA");
		return kf.generatePublic(spec);
	}

	public void encryptFile(byte[] input, File output, PrivateKey key) 
		throws IOException, GeneralSecurityException {
		this.cipher.init(Cipher.ENCRYPT_MODE, key);
		writeToFile(output, this.cipher.doFinal(input));
	}

	public void decryptFile(byte[] input, File output, PublicKey key) 
		throws IOException, GeneralSecurityException {
		this.cipher.init(Cipher.DECRYPT_MODE, key);
		writeToFile(output, this.cipher.doFinal(input));
	}

	private void writeToFile(File output, byte[] toWrite)
			throws IllegalBlockSizeException, BadPaddingException, IOException {
		FileOutputStream fos = new FileOutputStream(output);
		fos.write(toWrite);
		fos.flush();
		fos.close();
	}

	public String encryptText(String msg, PrivateKey key) 
			throws NoSuchAlgorithmException, NoSuchPaddingException,
			UnsupportedEncodingException, IllegalBlockSizeException, 
			BadPaddingException, InvalidKeyException {
		this.cipher.init(Cipher.ENCRYPT_MODE, key);
		return Base64.encodeBase64String(cipher.doFinal(msg.getBytes("UTF-8")));
	}

	public String decryptText(String msg, PublicKey key)
			throws InvalidKeyException, UnsupportedEncodingException, 
			IllegalBlockSizeException, BadPaddingException {
		this.cipher.init(Cipher.DECRYPT_MODE, key);
		return new String(cipher.doFinal(Base64.decodeBase64(msg)), "UTF-8");
	}

	public byte[] getFileInBytes(File f) throws IOException {
		FileInputStream fis = new FileInputStream(f);
		byte[] fbytes = new byte[(int) f.length()];
		fis.read(fbytes);
		fis.close();
		return fbytes;
	}

	public static void main(String[] args) throws Exception {
		AsymmetricCryptography ac = new AsymmetricCryptography();
		PrivateKey privateKey = ac.getPrivate("KeyPair/privateKey");
		PublicKey publicKey = ac.getPublic("KeyPair/publicKey");

		String msg = "Cryptography is fun!";
		String encrypted_msg = ac.encryptText(msg, privateKey);
		String decrypted_msg = ac.decryptText(encrypted_msg, publicKey);
		System.out.println("Original Message: " + msg + 
			"\nEncrypted Message: " + encrypted_msg
			+ "\nDecrypted Message: " + decrypted_msg);

		if (new File("KeyPair/text.txt").exists()) {
			ac.encryptFile(ac.getFileInBytes(new File("KeyPair/text.txt")), 
				new File("KeyPair/text_encrypted.txt"),privateKey);
			ac.decryptFile(ac.getFileInBytes(new File("KeyPair/text_encrypted.txt")),
				new File("KeyPair/text_decrypted.txt"), publicKey);
		} else {
			System.out.println("Create a file text.txt under folder KeyPair");
		}
	}
}

Output:


Original Message: Cryptography is fun!

Encrypted Message: NZY+9v4AWoADVBQiFmS8ake6dG8M9v4WDf4TSPKgGPoKeJtHxEWVFGFL57qR2mbuknn8WYjfjcN+BA/
  RDsDQ9Q5SxQFLi8GE7A/6fdURjO+Vz3qYFaefpXccp7SnObKXnFfUNp00m5BtMSdTLEYfngF9UDBVYVFz0EZwuyP50xY=

Decrypted Message: Cryptography is fun!

Encrypted text:

java-asymmetric-cryptography-7c

Decrypted text:

java-asymmetric-cryptography-7d

Download Source Code

References

  1. Asymmetric Encryption Algorithms
  2. Comparative Study of Asymmetric Key Cryptographic Algorithms
  3. KeyPairGenerator Algorithms

About the Author

author image
Marilena
Marilena Panagiotidou is a senior at University of the Aegean, in the department of Information and Communication Systems Engineering. She is passionate about programming in a wide range of languages. You can contact her at an3liram@gmail.com or through her LinkedIn.

Comments

Leave a Reply

avatar
newest oldest most voted
Joana Chavez La Valle
Guest
Joana Chavez La Valle

There is an error in this code, the decryption should be done with the private key and not with the public key and viceversa with the encryption: it should use the public key to encrypt instead of the private key.

Boyan
Guest
Boyan

Using the private key for encrypting and the public for decrypting — that’s the process of signing a message/verifying that a message is coming from a particular source.
Using the public key for encrypting and the private for decrypting — that’s secure communication.
Cheers!

Ajit Paswan
Guest
Ajit Paswan

You nailed it :)

Mtaok
Guest
Mtaok

Thanks for the example.But as Joana and Jeroen said, the encryption should be done using the public key and the decryption with the private key.

Daniel
Guest
Daniel

Thank you for share! The sample was help me a lot ! (and better after fixing the public/enc private/dec).

**If you have a data to encrypt major than 117 bytes ( ( KeySize 1024/8) – 11) java throws javax.crypto.IllegalBlockSizeException – possible solution: https://stackoverflow.com/questions/10007147/getting-a-illegalblocksizeexception-data-must-not-be-longer-than-256-bytes-when

Jeroen de Haas
Guest
Jeroen de Haas

Thanks for the example, though you encrypt with the public key , and decrypt with a private key. I think you doing it the other wrong way around.

Stephen
Guest
Stephen

hi
I’m developing a java dynamic web app using spring
I wanted to use the encryption in the project
I added keypair folder to my webcontent folder but when I run the project it gives the no such file exception
can someone help me please

vassilis spiliopoulos
Guest
vassilis spiliopoulos

Thanks Marilena for the great example!

Nagaraj N
Guest
Nagaraj N

Hi,

I am developing an android app which has login and registration features. I am thinking of using encryption and decryption technique.

My assumption is generating private key and public key in client side and encrypting password using private key and sending the encrypted password to server.

But how can I send public key to the server to decrypt the password.

Or If I am wrong please tell me how to do it.
If there is any other easy way please suggest me.

Ezekiel Newren
Guest
Ezekiel Newren

Don’t create your own encryption scheme. Use https if you want to keep the password confidential.