Detached pgp signature in Java

In this chapter we are going to discuss OpenPGP detached signing and verification of detached signatures with DidiSoft OpenPGP Library for Java.

Detached signatures in contrast to the classic OpenPGP signature format contain only the digital signature and are kept separately from the data. They are usually used when we want to check that a file was not modified or tampered.

List of examples

1. Detached signing of a File
2. Detached signing of a Stream

3. Verification of detached signature Stream
4. Verification of detached signed String
5. Verification of detached signed File with key in a KeyStore

1. Detached signing a file

In order to create an OpenPGP detached signature for a file we need an OpenPGP private key.

The naming convention for file name for the detached signature file is usually the name of the data file including the extension with an additional file name extension .sig. For example in the same code below the data file is INPUT.txt and the detached signature file is INPUT.txt.sig.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import com.didisoft.pgp.PGPLib;
 
public class DetachedSignFile {
 public static void main(String[] args) throws Exception{
  // initialize the library 
  PGPLib pgp = new PGPLib();
 
  // specify should the output be ASCII (true) or binary (false)
  boolean asciiArmor = false;
  pgp.detachedSignFile("examples/DataFiles/INPUT.txt", 
			"examples/DataFiles/private.key", 
			"changeit", 
			"examples/DataFiles/INPUT.txt.sig", 
			asciiArmor);
 }
}

2. Detached sign a Stream

In this sample we will show how to produce the detached OpenPGP signature into an output Stream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.*;
import com.didisoft.pgp.PGPLib;
 
public class DetachedSignStream {
 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("examples/DataFiles/INPUT.txt");
  InputStream privateKeyStream = new FileInputStream("examples/DataFiles/private.key");
  String privateKeyPassword = "changeit";
  OutputStream signedStream = new FileOutputStream("examples/DataFiles/INPUT.txt.sig");
 
  pgp.detachedSignStream(dataStream, 
	 			privateKeyStream, 
				privateKeyPassword, 
				signedStream, 
				asciiArmor);
 
  dataStream.close();
  privateKeyStream.close();
  signedStream.close();
 }
}

3. Verify a detached signature Stream

In the example below you can see how a detached signature available as an Input Stream can be verified. The public key of the sender is used for the verification process.

import java.io.*;
import com.didisoft.pgp.PGPLib;
 
public class DetachedVerifyStream {
 public static void main(String[] args) throws Exception {
  PGPLib pgp = new PGPLib();
 
  InputStream dataStream = new FileInputStream("examples/DataFiles/INPUT.txt");
  InputStream senderPublicKeyStream = new FileInputStream("examples/DataFiles/sender_public_key.asc");
  InputStream detachedSignatureStream = new FileInputStream("examples/DataFiles/INPUT.txt.sig");
 
  SignatureCheckResult signatureCheck = pgp.detachedVerify(dataStream, 
											   detachedSignatureStream,
											   senderPublicKeyStream);
  if (signatureCheck == SignatureCheckResult.SignatureVerified) {
		System.out.println("The signature is valid.");
  } else if (signatureCheck == SignatureCheckResult.SignatureBroken) {
		System.out.println("Message corrupted or signature forged");
  } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) {
		System.out.println("Signature not matching provided public key /it is from another sender/");
  } else {
		  System.out.println("No signature found in message");
  }
 
  dataStream.close();
  senderPublicKeyStream.close();
  detachedSignatureStream.close();
 }
}

4. Verify a detached signature as String

The library also accepts detached signatures supplied as file locations or plain String text. The same method will be used and the library will determine automatically if the data is a file path location or a String message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.*;
import com.didisoft.pgp.PGPLib;
 
public class DetachedVerify {
 public static void main(String[] args) throws Exception {
  PGPLib pgp = new PGPLib();
 
  String message = "Hello world"; // this could also be a file path location
  String senderPublicKey = "examples/DataFiles/sender_public_key.asc";
  String detachedSignature = "examples/DataFiles/INPUT.txt.sig"; // this could also be a signature in ASCII armored format
 
  SignatureCheckResult signatureCheck = pgp.detachedVerify(message, 
                                               detachedSignature,
                                               senderPublicKey);
  if (signatureCheck == SignatureCheckResult.SignatureVerified) {
        System.out.println("The signature is valid.");
  } else if (signatureCheck == SignatureCheckResult.SignatureBroken) {
        System.out.println("Message corrupted or signature forged");
  } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) {
        System.out.println("Signature not matching provided public key /it is from another sender/");
  } else {
    	  System.out.println("No signature found in message");
  }
 
  dataStream.close();
  senderPublicKeyStream.close();
  detachedSignatureStream.close();
 }
}

5. Verify a detached signature File with a key located in a KeyStore

When we supply a KeyStore object instead of a public key in order to verify a signature, the library will try all available public keys in the KeyStore.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.*;
import com.didisoft.pgp.PGPLib;
 
public class DetachedVerify {
 public static void main(String[] args) throws Exception {
  PGPLib pgp = new PGPLib();
 
  String message = "Hello world"; // this could also be a file path location
  KeyStore keyStore = new KeyStore("examples/DataFiles/mykeys.keysore", "key store password");
  String detachedSignature = "examples/DataFiles/INPUT.txt.sig"; // this could also be a signature in ASCII armored format
 
  SignatureCheckResult signatureCheck = pgp.detachedVerify(message, 
                                               detachedSignature,
                                               senderPublicKey);
  if (signatureCheck == SignatureCheckResult.SignatureVerified) {
        System.out.println("The signature is valid.");
  } else if (signatureCheck == SignatureCheckResult.SignatureBroken) {
        System.out.println("Message corrupted or signature forged");
  } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) {
        System.out.println("No matching public key found in the KeyStore");
  } else {
    	  System.out.println("No signature found in message");
  }
 
  dataStream.close();
  senderPublicKeyStream.close();
  detachedSignatureStream.close();
 }
}

Summary

In this chapter we have discussed how to create OpenPGP detached signatures and how to verify them.

The OpenPGP standard provides also signed message format, clear text signing and signed and encrypted format.

List of methods used:

PGPLib.detachedSignFile produces a detached OpenPGP signature into a file
PGPLib.detachedSignStream produces a detached OpenPGP signature into a Stream
PGPLib.detachedVerify verifies a detached OpenPGP signature provided as Stream, String or file path location