Main Tutorials

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 Author

author image
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 [email protected] or through her LinkedIn.

Comments

Subscribe
Notify of
24 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Joana Chavez La Valle
6 years ago

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.

Marilena
2 years ago

Public and Private Key are just naming conventions. The math behind it is such that it doesn’t matter. Go generate a pair and switch their names around. You will get the same functionality out of it.

Daniel
1 year ago
Reply to  Marilena

Joana is correct, the code is wrong for encryption. The whole point of asymmetric encryption is that you DON’T need the private key of the receiver. ONLY the receiver may have the private key so only they can decrypt the message.

You can switch them around, but then you aren’t encrypting the message since anyone can decrypt it, since the public key is public. As others have said, this is for signature verification (verifying that the message was written by a trusted author).

Anonymous
1 year ago
Reply to  Daniel

You can not decrypt with the same key you encrypted.

Boyan
6 years ago

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!

JayWal
5 years ago
Reply to  Boyan

I know this is old thread. But still want to hear thoughts. To verify the authenticity of the sender and checking whether the message is tampered there is signature verification feature (i.e. generate signature using private key, verify it with public key). I am trying to understand what is the need for allowing “encrypt using private and decrypt using public” when a) encryption is not relevant for verification and b) separate verification feature is available.

Ajit Paswan
5 years ago
Reply to  Boyan

You nailed it 🙂

Julio Cesar Torres
4 years ago

People that say the encryption was not correct with the keys the way Marilena put aren’t getting one thing: we can use private for enc / public for dec, or the other way round.

If we use it the way it’s written, we establish a message that allows us authenticate that we possess the private key – in other words, it’s kinda a part of a digital signature implementation.

If we use it the other way, public enc / private dec, we create a securely encrypted message that only the private key owner will be able to decrypt.

Marilena, thanks for the post, that implemented these functionalities in such a simple and uncomplicated way. Maybe, the only change I would do in it would be substitute the keys parameters in the enc and dec function for their super class Key: this way, on runtime, we can decide if we use the encryption for authentication or for privacy.

Congrats for the great job!

Dimitris Kounas
5 years ago

Hi, thank you for these examples!
If someone wants to use the Base64 package now included in Java instead of the org.apache.commons.codec.binary.Base64, they need to make the following changes:

import java.util.Base64; // ——Add this import——

public String encryptText(String msg, PrivateKey key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
UnsupportedEncodingException, IllegalBlockSizeException,
BadPaddingException, InvalidKeyException {
this.cipher.init(Cipher.ENCRYPT_MODE, key);
Base64.Encoder encoder = Base64.getEncoder(); // ———Add this line——–
// return Base64.encodeBase64String(cipher.doFinal(msg.getBytes(“UTF-8”))); ——–Remove this line——-
return encoder.encodeToString(cipher.doFinal(msg.getBytes(“UTF-8”))); // ———Add this line——–

}

public String decryptText(String msg, PublicKey key)
throws InvalidKeyException, UnsupportedEncodingException,
IllegalBlockSizeException, BadPaddingException {
this.cipher.init(Cipher.DECRYPT_MODE, key);
Base64.Decoder decoder = Base64.getDecoder(); // ———Add this line——–
// return new String(cipher.doFinal(Base64.decodeBase64(msg)), “UTF-8”); ——–Remove this line——-
return new String(cipher.doFinal(decoder.decode(msg)), “UTF-8”); // ———Add this line——–
}

Someone
4 years ago

Thanks a lot

raj
4 years ago

Thanks a lot

Daniel
6 years ago

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

tripletail
3 years ago

Thanks for your hard work, Marilena! I transformed it into Scala! Cheers!

https://tinyurl.com/y6zbkg9k


Vidal
5 years ago

Hello.
I can’t decrypt file with this method. Encryption work fine but when I want to decrypt I have padding exception on dofinal.
Share my code :
public void decryptFile(byte[] input, File output, PrivateKey key)

throws IOException, GeneralSecurityException , IllegalBlockSizeException, BadPaddingException{

this.cipher.init(Cipher.DECRYPT_MODE, key);

System.out.println(“input lenght -> ” + input.length);

int bytesLonger = 128;

byte[] tmpInput = new byte[bytesLonger];

int j = 0;

for (int i = 0; i != input.length; i++)

{

tmpInput[j] = input[i];

System.out.println(input[i]);

if (i % bytesLonger == 0)

{

writeToFile(output, this.cipher.doFinal(tmpInput));

tmpInput = new byte[bytesLonger];

j = 0;

}

}

}

private void writeToFile(File output, byte[] toWrite)

throws IllegalBlockSizeException, BadPaddingException, IOException {

FileOutputStream fos = new FileOutputStream(output, true);

fos.write(toWrite);

fos.flush();

fos.close();

}

Thank you

CryptoSM
5 years ago

Hi Marilena, use of private/public key aside this is a great help to me as are your other examples. I’ve looked around for similar examples and yours are some of the best in my humble opinion.

Gyanendra Singh Chandrawat
3 years ago

Hi, I’m student and new to java and need encryption in an academic project. I downloaded this project and tried but its showing error “The import org.apache cannot be resolved” at “import org.apache.commons.codec.binary.Base64;” in class “AsymmetricCryptography”. I’ve tried to download the jar apache-commons-codec-1.3.jar and added it in project libraries but still not working.
please help me with this.

Prashant Jeet Singh
5 years ago

Can you suggest how can I generate public and private key like………..
-----BEGIN PGP PUBLIC KEY BLOCK-----
mI0EXEMqFwEEANS1o8wI2kW1bIohbEyygDBkuP0hLo4EE98S2ZfMpM2Fs4m8sHkD =arHQ
-----END PGP PUBLIC KEY BLOCK-----

Guru
4 years ago

This looks more of a keytool generated public / private key pair. just do man keytool you shall get it.

Stephen
6 years ago

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

Mtaok
6 years ago

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.

vassilis spiliopoulos
7 years ago

Thanks Marilena for the great example!

Nagaraj N
7 years ago

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
6 years ago
Reply to  Nagaraj N

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

Jeroen de Haas
6 years ago

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.