Main Tutorials

Java – Digital Signatures example

In Asymmetric Cryptography example we discussed the use of Public Key Pair in Cryptography. Another important use of the Public Key Infrastructure is in Digital Signatures. Digital Signatures are the digital equivalent of handwritten signatures with one important difference; they are not unique but come as a product of the message.

A valid digital signature gives a recipient reason to believe that the message was created by a known sender (authentication), that the sender cannot deny having sent the message (non-repudiation), and that the message was not altered in transit (integrity). (Source: Wikipedia)

1. Generate a Public-Private Key Pair

The code to generate Public-Private Key Pair is identical to the one used in Asymmetric Cryptography example, please refer to Step 1 or download the source code at the end of the article that includes all sources – GenerateKeys.java

java-digital-signatures-1

2. Sign the message

Next we have to write our message and then sign it. The message and the signature can be separate files but in our example we add them to a List of byte[] and write them as Object to the file.

Message.java

package com.mkyong.sender;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

public class Message {
	private List<byte[]> list;
	
	//The constructor of Message class builds the list that will be written to the file. 
	//The list consists of the message and the signature.
	public Message(String data, String keyFile) throws InvalidKeyException, Exception {
		list = new ArrayList<byte[]>();
		list.add(data.getBytes());
		list.add(sign(data, keyFile));
	}
	
	//The method that signs the data using the private key that is stored in keyFile path
	public byte[] sign(String data, String keyFile) throws InvalidKeyException, Exception{
		Signature rsa = Signature.getInstance("SHA1withRSA"); 
		rsa.initSign(getPrivate(keyFile));
		rsa.update(data.getBytes());
		return rsa.sign();
	}
	
	//Method to retrieve the Private Key from a file
	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);
	}
	
	//Method to write the List of byte[] to a file
	private void writeToFile(String filename) throws FileNotFoundException, IOException {
		File f = new File(filename);
		f.getParentFile().mkdirs();
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
	    out.writeObject(list);
		out.close();
		System.out.println("Your file is ready.");
	}
	
	public static void main(String[] args) throws InvalidKeyException, IOException, Exception{
		String data = JOptionPane.showInputDialog("Type your message here");
		
		new Message(data, "MyKeys/privateKey").writeToFile("MyData/SignedData.txt");
	}
}

Output:

java-digital-signatures-2

Your file is ready.
java-digital-signatures-3

3. Verify the Signature

The receiver has the file (he knows it is a List of 2 byte arrays; the message and the signature) and wants to verify that the message comes from the expected source with a pre-shared Public Key.

VerifyMessage.java

package com.mkyong.receiver;

import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.List;

public class VerifyMessage {
	private List<byte[]> list;

	@SuppressWarnings("unchecked")
	//The constructor of VerifyMessage class retrieves the byte arrays from the File 
	//and prints the message only if the signature is verified.
	public VerifyMessage(String filename, String keyFile) throws Exception {
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
	    this.list = (List<byte[]>) in.readObject();
	    in.close();
	    
	    System.out.println(verifySignature(list.get(0), list.get(1), keyFile) ? "VERIFIED MESSAGE" + 
	      "\n----------------\n" + new String(list.get(0)) : "Could not verify the signature.");	    
	}
	
	//Method for signature verification that initializes with the Public Key, 
	//updates the data to be verified and then verifies them using the signature
	private boolean verifySignature(byte[] data, byte[] signature, String keyFile) throws Exception {
		Signature sig = Signature.getInstance("SHA1withRSA");
		sig.initVerify(getPublic(keyFile));
		sig.update(data);
		
		return sig.verify(signature);
	}
	
	//Method to retrieve the Public Key from a file
	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 static void main(String[] args) throws Exception{
		new VerifyMessage("MyData/SignedData.txt", "MyKeys/publicKey");
	}
}

Output:


VERIFIED MESSAGE
----------------
Hello from mkyong.com!!

Download Source Code

Download – digitalsignatures.zip (6 KB)

References

  1. Digital signature
  2. Generating and Verifying Signatures
  3. Java – Asymmetric Cryptography example

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
12 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Fabián Guamán
7 years ago

Very Nice!!! Thx 😀

Kajal Dashrath Pawar
5 years ago

sir , in my project i was implement that code of digital signature but it can not run properly why i don’t know?

Emad
5 years ago

Thanks a lot.
I need the encryption in Hexadecimal, is it possible ?
Thanks in advanced.

Ant
4 years ago
Reply to  Emad

Hexadecimal is an encoding type, so it is not an encryption. But yes, it is possible to convert encryption data to hex encode

Renu
4 years ago

How can provide the KID (key identifier)while signing the message

Mac
4 years ago

Can I cache PrivateKey object so that I dont have to create it everytime. Is that threadsafe?

Arun Sharma
4 years ago

Could you share an example of http post signature in java for GET request. Or a good reference may also help.

Ferran Ramia
4 years ago

Thanks

Alejandro Gandara Mendoza
5 years ago

Great Work… thank you for your time.

kajal dashrath pawar
5 years ago

sir , in my project i was implement that code of digital signature but it can not run properly why i don’t know?

Ashkan
5 years ago

Thank you, very good tutorial.

pritam
6 years ago

Could not verify the signature. always getting same, used same
program