pgp signing in Java

A digital signature is a number cryptographically computed from the byte contents of the signed document. In OpenPGP the signature message digest is produced with a signing key, usually this is our private key.

OpenPGP signed files contain the original message compressed by default (see Compression) and the digital signature attached appended. The default signature message digest functions can be changed through the Hash option.

Below you will find examples that demonstrate how to OpenPGP sign file and stream data:

Sign a file

1. with a private key located in a file
2. with a private key located in a KeyStore

Sign a stream

3. with a private key located in a file
4. with a private key located in a KeyStore

Appendix A
Exception handling

1. Sign a file with private key located in a file

import com.didisoft.pgp.PGPLib;
 
public class SignFile {
 public static void main(String[] args) throws Exception{
	// initialize the library
	PGPLib pgp = new PGPLib();
 
	// specify should the output be ASCII or binary
	boolean asciiArmor = false;
	// sign
	pgp.signFile("INPUT.txt",
		     "private.key",
		     "changeit",
		     "signed.pgp",
		     asciiArmor);
 }
}

2. Sign file with private key located in a KeyStore

import com.didisoft.pgp.KeyStore;
import com.didisoft.pgp.PGPLib;
 
public class KeyStoreSignFile {
 public static void main(String[] args) throws Exception{
	// create an instance of the KeyStore
	KeyStore keyStore = new KeyStore("pgp.keystore", "changeit");
 
	// initialize the library
	PGPLib pgp = new PGPLib();
 
	// The signing key is usually our private key
	String signUserId = "demo@didisoft.com";
	String signKeyPassword = "changeit";		
 
	// specify should the output be ASCII or binary
	boolean asciiArmor = false;
	// sign
	pgp.signFile("INPUT.txt",
		     keyStore,
		     signUserId,
		     signKeyPassword,
		     "signed.pgp",
		     asciiArmor);
 }
}

3. Sign input stream with private key located in file

In the example below the file streams are used only to demonstrate how to encrypt with stream. The streams can be of any other type that implements InputStream.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import com.didisoft.pgp.PGPLib;
 
public class SignStream {
 public static void main(String[] args) throws Exception {
   // create instance of the library
   PGPLib pgp = new PGPLib();
 
   // if true the output file will be in ascii armored format,
   // otherwise will be in binary format
   boolean asciiArmor = false;
 
   InputStream dataStream = new FileInputStream("INPUT.txt");
   InputStream privateKeyStream = new FileInputStream("private.key");
   String privateKeyPassword = "changeit";
   OutputStream signedStream = new FileOutputStream("signed.pgp");
 
   // This parameter is needed because OpenPGP requires
   // the encrypted content to have a file name label
   String internalFileName = "INPUT.txt";
 
   pgp.signStream(dataStream,
		internalFileName,
		privateKeyStream,
		privateKeyPassword,
		signedStream,
		asciiArmor);
 }
}

4. Sign input stream with private key located in a KeyStore

You may notice that the second parameter of the signStream method for KeyStore has a file name parameter. This is often misunderstood, the idea is that this is just a label associated with the encrypted content in the output stream. The OpenPGP format in addition to the encrypted content stores a file name label and time stamp.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import com.didisoft.pgp.KeyStore;
import com.didisoft.pgp.PGPLib;
 
public class KeyStoreSignStream {
 public static void main(String[] args) throws Exception{
  // create an instance of the KeyStore
  KeyStore keyStore = new KeyStore("pgp.keystore", "changeit");
 
  // initialize the library
  PGPLib pgp = new PGPLib();
 
  // The signing key is usually our private key
  String signUserId = "demo@didisoft.com";
  String signKeyPassword = "changeit";		
 
  InputStream dataStream = new FileInputStream("INPUT.txt");
  // this parameter is just a label that is associated with
  // the encrypted content in the OpenPGP archive
  String signedContentLabel = "INPUT.txt";
 
  // create the output stream
  OutputStream signedStream = new FileOutputStream("signed.pgp"); 
 
  // specify should the output be ASCII or binary
  boolean asciiArmor = false;
 
  pgp.signStream(dataStream,
		signedContentLabel,
		keyStore,
		signUserId,
		signKeyPassword,
		signedStream,
		asciiArmor);
 }
}


Exception handling

In addition to the java.io.IOException that is thrown if an I/O error occurs reading or writing the data, com.didisoft.pgp.PGPException must also be caught in case of OpenPGP related error.

A more thorough exception handling is to catch a few sub classes of PGPException before catching PGPException itself. This way we can identify more specifically what has gone wrong.

Here is a short example that illustrates how to organize the catch clauses.

import java.io.IOException;
import com.didisoft.pgp.*;
import com.didisoft.pgp.exceptions.*;
 
public class ExceptionHandlingDemo {
 public static void main(String[] a) {
   PGPLib pgp = new PGPLib();
   try {
    pgp.decrypt...
   } catch (IOException e) {
    // I/O error reading input or writing output
 
   } catch (KeyIsExpiredException e) {
    // the passed private key file is expired
   } catch (KeyIsRevokedException e) {
    // the passed private key file is revoked
   } catch (NoPrivateKeyFoundException e) {
    // the passed private key source does not contain a private key
   } catch (WrongPasswordException e) {
    // the password for the provided private key is wrong
   } catch (PGPException e) {
    // general error during signing, not among the above ones 
   } 
 }
}

Summary

In this chapter we have discussed OpenPGP signing with DidiSoft OpenPGP Library for Java.