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 |