When we receive a signed or clear text signed OpenPGP data it contains data and signature combined in one place. We can both verify that it has a good signature from a trusted senderand extract the original message at the same time, or just verify the signature.
For the verification, we need the public key of the sender. Of course, we can ignore completely the digital signature and extract the data with simple decryption.
Table of contents
Verify a signed or clear text signed file
1. with public key from a file | Async
2. with public key located in a KeyStore | Async
Verify a signed or clear text signed String message
4. with public key from a file | Async
3. with public key located in a KeyStore | Async
Verify a signed or clear text signed Stream
5. with a sender’s public key as Stream | Async
6. with a sender’s public key located in a KeyStore | Async
Appendix
1. Verifying a signed or clear text signed file using sender’s public key located also in a file
There is also an overloaded version of the VerifyFile method that allows just to verify the digital signature without actually extracting the data.
C# example
using System; using DidiSoft.Pgp; public class VerifyDemo { public void Demo() { // create an instance of the library PGPLib pgp = new PGPLib(); // check the signature and extract the data SignatureCheckResult signatureCheck = pgp.VerifyFile(@"C:\Test\INPUT.pgp", @"C:\Test\public_key.asc", @"C:\Test\OUTPUT.txt"); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signare OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signare of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
A VB.NET example is also available here.
Async verifying OpenPGP signed file
Async version of the VerifyFile method is available in the PGPLibAsync class that extends PGPLib. Here in addition to the same set of parameters an optional last parameter of type CancellationToken is available, which can be used to stop the execution of the method call.
This example just like the one above verifies the signature integrity of the OpenPGP signed data and extracts the data itself.
using System.Threading; using DidiSoft.Pgp; class VerifyFileAsync { public async void Demo() { // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); // empty cancellation token for this example CancellationToken token = default(CancellationToken); // verify SignatureCheckResult signatureCheck = await pgp.VerifyFileAsync(@"DataFiles\OUTPUTs.pgp", @"DataFiles\public.key", @"DataFiles\OUTPUT.txt", token); Console.WriteLine(" Signature is " + signatureCheck.ToString()); } } |
2. Verify a signed or clear text signed file using sender’s public key located in a KeyStore
This example is equivalent to the above one, except that the public key of the sender is located in a KeyStore object. The digital signature will be verified among all the public keys in the specified KeyStore.
C# example
using System; using DidiSoft.Pgp; class KeyStoreVerifyFile { public static void Demo() { // create an instance of the library PGPLib pgp = new PGPLib(); // initialize the KeyStore // If the keystore file does not exists, it is created. KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); // verify OpenPGP signed or clear text signed file string outputFileLocation = @"c:\OUTPUT.txt"; SignatureCheckResult signatureCheck = pgp.VerifyFile(@"c:\signed.pgp", ks, outputFileLocation); // Print the results Console.WriteLine("Extracted data in " + outputFileLocation); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signare OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signare of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
Async verifying OpenPGP signed file against public keys from a KeyStore
The advantage of having keys in a KeyStore is that we can verify OpenPGP signed files from multiple recipients, without specifying explicitly the correct public key to verify the data. That is, we store all known public keys in a single KeyStore and this way we can verify the signed data sent from and anyone who’s key is in the KeyStore.
using System; using System.Threading; using System.Threading.Tasks; using DidiSoft.Pgp; class VerifyFileAsyncKS { public async Task Demo() { // obtain an OpenPGP signed or clear text signed file // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); // initialize the KeyStore // If the keystore file does not exists, it is created. KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); // empty cancellation token for this example CancellationToken token = default(CancellationToken); // verify string outputFileLocation = @"DataFiles\OUTPUT.txt"; SignatureCheckResult signatureCheck = await pgp.VerifyFileAsync(@"DataFiles\OUTPUT.pgp", ks, outputFileLocation, token); // Print the results Console.WriteLine("Extracted data in " + outputFileLocation); Console.WriteLine("Signature verification result " + outputFileLocation); } } |
3. Verify a String message using the sender’s public key located in a file
The operation of verifying OpenPGP signed string (which is actually ASCII armored OpenPGP signed message), consists of both extracting the data and verifying the signature attached to it.
The VerifyString method return the SignatureCheckResult and the actual data stored inside the OpenPGP signed message is collected in a out parameter.
Of course an overloaded version of VerifyString exists that only verifies the signature without extracting the data:
C# example
using System; using System.IO; using DidiSoft.Pgp; class VerifyString { public static void Demo() { String signedString = ... // obtain an OpenPGP signed message PGPLib pgp = new PGPLib(); // Extract the message and check the validity of the signature String plainText; SignatureCheckResult signatureCheck = pgp.VerifyString(signedString, @"c\public_key.asc", out plainText); // the same as above but only verifies the signature without extracting the data pgp.VerifyString(signedString, @"c\public_key.asc"); // Print the results Console.WriteLine("Extracted plain text message is " + plainText); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signare OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signare of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
This same code above but in VB.NET can be seen here
Async verifying OpenPGP signed string
Actually we can pass a key file filesystem location or key data in ASCII-armored format in all methods of both PGPLib and PGPLibAsync that expect a key parameter of type string.
This example below illustrates asynchronous verification of OpenPGP signed data available in ASCII-armored format. Because of the nature of OpenPGP signed data, that contains both the data and the signature combined, here the VerifyStringAsync method returns Tuple<SignatureCheckResult, String> so we can get both the signature check and the data:
using System; using System.Threading.Tasks; using DidiSoft.Pgp; class VerifyStringAsyncDemo { public async Task Demo() { // obtain an OpenPGP signed message String signedString = ... // obtain an ASCII armored OpenPGP signed data // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); string publicKey = @"DataFiles\public.key"; // this can also be ASCII armored string with key data Tuple<SignatureCheckResult, String> signatureCheck = await pgp.VerifyStringAsync(signedString, publicKey); SignatureCheckResult signatureCheckResult = signatureCheck.Item1; String plainText = signatureCheck.Item2; // Print the results Console.WriteLine("Signature check result is " + signatureCheckResult); Console.WriteLine("Extracted plain text message is " + plainText); } } |
4. Verify a string message using sender’s public key located in a KeyStore
If we keep our OpenPGP keys in a KeyStore we should use the overloaded VerifyString method that accepts a KeyStore object:
C# example
using System; using DidiSoft.Pgp; class KeyStoreVerifyString { public static void Demo() { // obtain an OpenPGP signed message String signedString = KeyStoreSignString.Demo(); // Extract the message and check the validity of the signature String plainText; PGPLib pgp = new PGPLib(); KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); SignatureCheckResult signatureCheck = pgp.VerifyString(signedString, ks, out plainText); // Print the results Console.WriteLine("Extracted plain text message is " + plainText); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signare OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signare of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
Async verifying of OpenPGP string message with key from a Keystore
The equivalent code, but asynchronous is available below.
using System; using System.Threading.Tasks; using DidiSoft.Pgp; class VerifyStringAsyncKS { public async Task Demo() { String signedString = ... // obtain an OpenPGP signed message // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); // initialize the KeyStore // If the keystore file does not exists, it is created. KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); // Extract the message and check the validity of the signature Tuple<SignatureCheckResult, String> signatureCheckResult = await pgp.VerifyStringAsync(signedString, ks); SignatureCheckResult signatureCheck = signatureCheckResult.Item1; String plainText = signatureCheckResult.Item2; // Print the results Console.WriteLine("Extracted plain text message is " + plainText); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signature OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signature of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
5. Verify a signed or clear text signed Stream with a sender’s public key as Stream
This example shows how to verify data that is in a Stream for reading. The extracted data is stored also in a Stream.
You may notice also a second call of the VerifyStream which illustrates how to only verify without getting the signed data:
using System; using System.IO; using DidiSoft.Pgp; public class VerifyStream { public void Demo() { // create an instance of the library PGPLib pgp = new PGPLib(); // The data and the public key can be any kind of stream Stream dataStream = File.OpenRead(@"c:\signed.pgp"); Stream publicKeyStream = File.OpenRead(@"c:\public_key.asc"); Stream outputStream = new MemoryStream(); // verify signed or clear text signed stream SignatureCheckResult signatureCheck = pgp.VerifyStream(dataStream, publicKeyStream, outputStream); // of course we can verify only the signature without extracting the data SignatureCheckResult signatureCheckIgnoreData = pgp.VerifyStream(dataStream, publicKeyStream, outputStream); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signare OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signare of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } // We must reinitialize the output in order to read from it later (outputStream as MemoryStream).Position = 0; } } |
Equivalent code in VB.NET is available here
Async verification of OpenPGP data from a Stream
If we want to asynchronously verify signed or clear text signed data coming as a Stream, we should use PGPLibAsync.VerifyStreamAsync:
using System; using System.IO; using System.Threading.Tasks; using DidiSoft.Pgp; class VerifyStreamAsync { public async Task Demo() { // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); // The data and the public key can be any kind of stream Stream dataStream = File.OpenRead(@"DataFiles\OUTPUTs.pgp"); Stream publicKeyStream = File.OpenRead(@"DataFiles\public.key"); // for this example the signed data is extracted in a memory Stream // fore illustrative purposes using (Stream outputStream = new MemoryStream()) { // verify signed or clear text signed stream // and extract the embedded data SignatureCheckResult signatureCheck = await pgp.VerifyStreamAsync(dataStream, publicKeyStream, outputStream); } if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signature OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signature of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
6. Verify a Stream when the public key of the sender is in a KeyStore
This example is equivalent to the above one, except that the sender’s public key is located in a KeyStore.
C# example
using System; using System.IO; using DidiSoft.Pgp; class KeyStoreVerifyStream { public static void Demo() { // create an instance of the library PGPLib pgp = new PGPLib(); // initialize the KeyStore that contains the sender's public key KeyStore ks = new KeyStore(@"c:\my_key.store", "changeit"); // The data and the output can be any kind of stream Stream dataStream = File.OpenRead(@"c:\signed.pgp"); Stream outputStream = new MemoryStream(); // verify string outputFileLocation = @"c:\OUTPUT.txt"; SignatureCheckResult signatureCheck = pgp.VerifyStream(dataStream, ks, outputStream); // We must reinitialize the output in order to read from it later (outputStream as MemoryStream).Position = 0; if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signare OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signare of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } |
Async verifying Stream with KeyStore
The same code above rewritten to use public keys stored in a KeyStore is available below:
using System; using System.IO; using System.Threading.Tasks; using DidiSoft.Pgp; class VerifyStreamAsyncKS { public async Task Demo() { // obtain an OpenPGP signed or clear text signed file await new SignFileAsync().Demo(); // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); // initialize the KeyStore that contains the sender's public key KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); // The data and the output can be any kind of stream using (Stream dataStream = File.OpenRead(@"DataFiles\OUTPUTs.pgp")) using (Stream outputStream = new MemoryStream()) { // verify SignatureCheckResult signatureCheck = await pgp.VerifyStreamAsync(dataStream, ks, outputStream); if (signatureCheck == SignatureCheckResult.SignatureVerified) { Console.WriteLine("Signature OK"); } else if (signatureCheck == SignatureCheckResult.SignatureBroken) { Console.WriteLine("Signature of the message is either broken or forged"); } else if (signatureCheck == SignatureCheckResult.PublicKeyNotMatching) { Console.WriteLine("The provided public key doesn't match the signature"); } else if (signatureCheck == SignatureCheckResult.NoSignatureFound) { Console.WriteLine("This message is not digitally signed"); } } } } |
Appendix A. Exception Handling
The exception handling code when verifying signed data shall follow the general exception strategy.
This example illustrates the expected exceptions from the methods with a Verify name prefix.
Exception handling in C#
using System; using DidiSoft.Pgp; using DidiSoft.Pgp.Exceptions; public class VerifyDemo { public void Demo() { // create an instance of the library PGPLib pgp = new PGPLib(); try { SignatureCheckResult signatureCheck = pgp.Verify ... } catch (PGPException e) { if (e is NonPGPDataException) { // The input is not an OpenPGP archive or is corrupted } else if (e is WrongPublicKeyException) { // The supplied public key is not an OpenPGP public key // or is corrupted } else if (e is FileIsEncryptedException) { // The input file is OpenPGP encrypted. // You will have to use one of the Decrypt // or DecryptAndVerify methods } else { // general OpenPGP error Console.WriteLine(e.Message); } } } } |
Exception handling in VB.NET
Imports System Imports DidiSoft.Pgp Imports DidiSoft.Pgp.Exceptions Public Class VerifyDemo Public Sub Demo() ' create an instance of the library Dim pgp As New PGPLib() Try Dim signatureCheck As SignatureCheckResult = pgp.Verify... Catch e As PGPException If TypeOf e Is NonPGPDataException Then ' The input file is not an OpenPGP archive or is corrupted ElseIf TypeOf e Is WrongPublicKeyException Then ' The supplied public key is not an OpenPGP public key ' or is corrupted ElseIf TypeOf e Is FileIsEncryptedException Then ' The input is OpenPGP encrypted. ' You will have to use one of the Decrypt or ' DecryptAndVerify methods instead Else ' general OpenPGP error Console.WriteLine(e.Message) End If End Try End Sub End Class |
Summary
In this chapter, we have shown how to verify an OpenPGP digital signatures and extract the signed content. The examples above apply only to signed and clear text signed data.
Additional methods exist for verification of detached signatures and one pass signed and encrypted data.
You may also be interested in analyzing OpenPGP archive and checking the signing Key ids before performing signature verification.
Methods used in this chapter:
PGPLibAsync.VerifyFileAsyncAsync Verifies an OpenPGP signed or clear text signed file
PGPLib.VerifyFile | Verifies an OpenPGP signed or clear text signed file |
PGPLib.VerifyString | Verifies an OpenPGP signed or clear text signed String message |
PGPLib.VerifyStream | Verifies an OpenPGP signed or clear text signed Stream |
PGPLibAsync.VerifyStringAsync | Async Verifies an OpenPGP signed or clear text signed String message |
PGPLibAsync.VerifyStreamAsync | Async Verifies an OpenPGP signed or clear text signed Stream |