pgp detached signature in C# and VB.NET


The standard OpenPGP signed format contains the data and the digital signature combined in one file. In contrast OpenPGP detached signatures are stored in a separate file from the data. The signature is produced by our OpenPGP private key. For the verification of detached signatures we need the public key of the sender.

A common file naming convention for files containing detached signatures is to have the same name as the original file with an additional .sig file name extension at the end.

Below we are going to demonstrate how to perform detached signing with DidiSoft OpenPGP Library for .NET

Detached signing a file

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

Detached signing a Stream

3. with a private key supplied as Stream
4. with a private key located in a KeyStore

Detached signing a String

5. Detached signing a string message

Verifying detached signed data

6. verify detached String message
7. verify detached Stream data

Appendix
A. Exception Handling

1. Detached signing a file

In this example we will produce a detached signature for a file and store the signature also in a file.

C# example

using System;
using DidiSoft.Pgp;
 
public class DetachedSignDemo
{
  public static void Demo()
  {
   // create an instance of the library
   PGPLib pgp = new PGPLib();
 
  // should the output be binary (false) or ASCII armored (true)
  bool asciiArmor = true;
 
  pgp.DetachedSignFile(@"c:\INPUT.txt",
			 @"c:\my_private_key.asc",
			 "my key password",
			 @"c:\INPUT.txt.sig",
			 asciiArmor);
  }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Public Class DetachedSignDemo
 Public Shared Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
 
  ' should the output be binary (false) or ASCII armored (true)
  Dim asciiArmor As Boolean = True
 
  pgp.DetachedSignFile("c:\INPUT.txt", _
			"c:\my_private_key.asc", _
			"my key password", _
			"c:\INPUT.txt.sig", _
			asciiArmor)
 End Sub
End Class

Back to Top

2. Detached signing a file with a private key located in a KeyStore

This example is equivalent to the above one, except that the private key used for signing is located in a KeyStore. The private signing key can be referred with it’s User Id or Key Hex Id.

C# example

using System;
using DidiSoft.Pgp;
 
public class DetachedSignDemo
{
 public void Demo()
 {
   // initialize the key store
   KeyStore ks = KeyStore.OpenFile(@"c:\mykey.store", "key store password");
 
   // create an instance of the library  
   PGPLib pgp = new PGPLib();
 
   // should the output be ASCII (true) or binary (false) 
   bool asciiArmor = true;
 
   // The private key can be specified through it's Key Hex Id too
   string privateKeyUserId = "support@didisoft.com";
   string privateKeyPassword = "key password";
 
   pgp.DetachedSignFile(@"C:\Test\INPUT.txt", 
			ks,
			privateKeyUserId, 
			privateKeyPassword,
			@"C:\Test\INPUT.txt.sig", 
			asciiArmor);				
 }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Public Class DetachedSignDemo
 Public Shared Sub Demo()
   ' initialize the key store
   Dim ks As KeyStore = KeyStore.OpenFile("DataFiles\key.store", "key store password")
 
   ' create an instance of the library 
   Dim pgp As New PGPLib()
 
   ' should the output be ASCII (true) or binary (false) 
   Dim asciiArmor As Boolean = True
 
   ' The private key can be specified through it's Key Hex Id too
   Dim privateKeyUserId As String = "support@didisoft.com"
   Dim privateKeyPassword As String = "private key password"
 
   pgp.DetachedSignFile("C:\Test\INPUT.txt", _
                        ks, _
                        privateKeyUserId, _
                        privateKeyPassword, _
                        "C:\Test\INPUT.txt.sig", _
                        asciiArmor)
 End Sub
End Class

Back to Top

3. Produce a detached signature from a Stream

In this example we will produce a detached signature for data provided as Stream. The detached signature is also stored in a Stream.

C# example

using System;
using DidiSoft.Pgp;
 
public class DetachedSignStreamDemo
{
  public static void Demo()
  {
      // initialize the library
      PGPLib pgp = new PGPLib();
 
      // should the output be binary or ASCII armored 
      bool asciiArmor = true;
 
      Stream dataFileStream = File.Open(@"C:\INPUT.txt"); 
      Stream privateKeyStream = File.Open(@"C:\private_key.asc");
 
      using (Stream outputSigned = File.Create(@"C:\INPUT.txt.sig")
      {
        pgp.DetachedSignStream(dataFileStream, 
                              privateKeyStream, 
                              "private key password",
                              outputSigned, 
                              asciiArmor);				
      }
  }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Public Class DetachedSignStreamDemo
 Public Shared Sub Demo()
    ' initialize the library 
    Dim pgp As New PGPLib()
 
    ' should the output be binary or ASCII armored 
    Dim asciiArmor As Boolean = True
 
    Dim dataFileStream As Stream = File.Open("C:\INPUT.txt")
    Dim privateKeyStream As Stream = File.Open("C:\private_key.asc")
 
    Using outputSigned As Stream = File.Create("C:\INPUT.txt.sig")
     pgp.DetachedSignStream(dataFileStream, _
                            privateKeyStream, _
                            "private key password", _
                            outputSigned, _
                            asciiArmor)
    End Using
 End Sub
End Class

Back to Top

4. Produce a detached signature from a Stream with key located in a KeyStore

This example is equivalent to the above one except that the private signing key is located in a KeyStore.

C# example

using System;
using DidiSoft.Pgp;
 
public class DetachedSignStreamDemo
{
  public static void Demo()
  {
      // create an instance of the library
      PGPLib pgp = new PGPLib();
 
      // should output be binary (false) or ASCII armored (true)
      bool asciiArmor = true;
 
      // initialize the KeyStore
      KeyStore ks = new KeyStore(@"c:\mykey.store", "key store password");
 
      // The private key can be specified through it's Key Hex Id too
      string privateKeyUserId = "support@didisoft.com";
 
      Stream dataFileStream = File.Open(@"C:\INPUT.txt"); 
 
      using (Stream outputSigned = File.Create(@"C:\INPUT.txt.sig"))
      {
        pgp.DetachedSignStream(dataFileStream, 
                              ks, 
                              privateKeyUserId,
                              "private key password",
                              outputSigned, 
                              asciiArmor);				
      }
  }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Public Class DetachedSignStreamDemo
 Public Shared Sub Demo()
    ' initialize the library 
    Dim pgp As New PGPLib()
 
    ' should the output be binary or ASCII armored 
    Dim asciiArmor As Boolean = True
 
    ' initialize the key store
    Dim ks As New KeyStore("DataFiles\key.store", "key store password")
 
    ' The private key can be specified through it's Key Hex Id too
    Dim privateKeyUserId As String = "support@didisoft.com"
 
    Dim dataFileStream As Stream = File.Open("C:\INPUT.txt")
 
    Using outputSigned As Stream = File.Create("C:\INPUT.txt.sig")
      pgp.DetachedSignStream(dataFileStream, _
                             ks, _
                             privateKeyUserId, _
                             "private key password", _
                             outputSigned, _
                             asciiArmor)
    End Using
 End Sub
End Class

Back to Top

5. Detached signing a string message

Below is shown how to detached sign a string message and get the signature as a string too.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class DetachedSignStringDemo
{
  public void Demo()
  {
   String plainString = "Hello World";
 
   // initialize the library
   PGPLib pgp = new PGPLib();
 
   Stream privateKeyStream = File.OpenRead(@"c:\my_private_key.asc");
 
   String signatureString = pgp.DetachedSignString(plainString,
						privateKeyStream,
						"my key password");
   Console.WriteLine(signatureString);
  }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class DetachedVerifyString
 Public Sub Demo()
  Dim plainString As String = "Hello World"
 
  ' initialize the library
  Dim pgp As New PGPLib()
 
  Dim privateKeyStream As Stream = File.OpenRead("c:\my_private_key.asc")
 
  Dim signatureString As String = _
       pgp.DetachedSignString(plainString, _
                              privateKeyStream, _
                              "my key password")
 
  Console.WriteLine(signatureString)
 End Sub
End Class

Back to Top

6. Verify a detached signed String

Below is shown how to verify a detached String signature. For the verification we also need the String message for which it was created.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class DetachedVerifyStringDemo
{
  public void Demo()
  {
    String plainString = "Hello World";
 
    // initialize the library 
    PGPLib pgp = new PGPLib();
 
    Stream privateKeyStream = File.OpenRead(@"c:\private_key.asc");
 
    String signedString = pgp.DetachedSignString(plainString,
						privateKeyStream,
						"key password");
    Console.WriteLine(signedString);
 
    Stream publicKeyStream = File.OpenRead(@"c:\public_key.asc");
 
    bool correct = pgp.DetachedVerifyString(plainString, 
                                            signedString, 
                                            publicKeyStream);
    if (correct)
    {
	Console.WriteLine("Signature is correct");
    }
    else
    {
	Console.WriteLine("Signature is wrong.");
     }
  }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class DetachedVerifyString
 Public Sub Demo()
   Dim plainString As String = "Hello World"
 
  ' initialize the library 
  Dim pgp As New PGPLib()
 
  Dim privateKeyStream As Stream = File.OpenRead("c:\private_key.asc")
 
  Dim signedString As String = pgp.DetachedSignString(plainString, _
                                                      privateKeyStream, _
                                                      "key password")
  Console.WriteLine(signedString)
 
  Dim publicKeyStream As Stream = File.OpenRead("c:\private_key.asc")
 
  Dim correct As Boolean = pgp.DetachedVerifyString(plainString, _
                                                    signedString, _
                                                    publicKeyStream)
  If correct Then
	Console.WriteLine("Signature is correct")
  Else
	Console.WriteLine("Signature is wrong.")
  End If
 End Sub
End Class

Back to Top

7. Verify a detached signed Stream data

This example demonstrates how to verify a detached Stream data. The data, the detached signature and the public key that will be used for the verification are obtained as Streams from files, but of course they can be any kind of Stream sub class.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class DetachedVerifyDemo
{
 public static void Demo()
 {
  // create an instance of the library
  PGPLib pgp = new PGPLib();
 
  bool signatureIsValid = false;
  using (Stream dataStream = File.OpenRead(@"c:\INPUT.txt"))
  {
    using (Stream signatureStream = File.OpenRead(@"c:\INPUT.txt.sig"))
    {
 	using (Stream publicKeyStream = File.OpenRead(@"c:\public_key.asc"))
	{
 	 signatureIsValid = pgp.DetachedVerifyStream(dataStream,
						     signatureStream,
						     publicKeyStream);
	}
    }
  }
 
  if (signatureIsValid)
  {
	Console.WriteLine("Signature is valid.");
  }
  else
  {
	Console.WriteLine("Signature is invalid!");
  }
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class DetachedVerifyDemo
 Public Shared Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
 
  Dim signatureIsValid As Boolean = False
  Using dataStream As Stream = File.OpenRead("DataFiles\INPUT.txt")
    Using signatureStream As Stream = File.OpenRead("DataFiles\INPUT.txt.sig")
	Using publicKeyStream As Stream = File.OpenRead("DataFiles\public.key")
		signatureIsValid = _
			pgp.DetachedVerifyStream(dataStream, _
						signatureStream, _
						publicKeyStream)
	End Using
    End Using
  End Using
 
  If signatureIsValid Then
	Console.WriteLine("Signature is valid.")
  Else
	Console.WriteLine("Signature is invalid!")
  End If
 End Sub
End Class

Back to Top

Appendix A. Exception Handling

All DetachedSign and DetachedVerify methods throw System.IO.IOException in case of an I/O error and DidiSoft.Pgp.PGPException in case of an OpenPGP related error.
We can investigate further an OpenPGP exception cause by trying to check is the exception of a given sub class defined in the DidiSoft.Pgp.Exceptions namespace.

Below is an example that illustrates what are the expected exception sub classes from the DetachedSign and DetachedVerify methods.

C# example

PGPLib pgp = new PGPLib();
try
{
  pgp.DetachedSign...
}
catch (System.IO.IOException e)
{
  // in case of an input file not found or other I/O related error
}
catch (DidiSoft.Pgp.PGPException e)
{
  if (e is DidiSoft.Pgp.Exceptions.WrongPrivateKeyException)
  {
   // The supplied private key source is not a private key at all 
   // or does not contain a signing key
   // For example we have supplied an arbitrary file for the private 
   // key parameter, or in the case with a KeyStore parameter 
   // there is no private key with the specified Key ID or User ID
  }
  else if (e is DidiSoft.Pgp.Exceptions.WrongPasswordException)
  {
   // The supplied private key password is misspelled
  }
  else
  {
   // General OpenPGP error non among the above
  }
}
 
try
{
  pgp.DetachedVerify...
}
catch (System.IO.IOException e)
{
  // in case of an input file not found or other I/O related error
}
catch (DidiSoft.Pgp.PGPException e)
{
  if (e is DidiSoft.Pgp.Exceptions.NonPGPDataException)
  {
   // The supplied detached signed data is corrupted or is not an OpenPGP data at all
  }
  else
  {
   // General OpenPGP error non among the above
  }
}

VB.NET example

Dim pgp As New PGPLib()
Try
  pgp.DetachedSign...
Catch e As System.IO.IOException
  ' in case of an input file not found or other I/O related error
Catch e As DidiSoft.Pgp.PGPException
  If TypeOf e Is DidiSoft.Pgp.Exceptions.WrongPrivateKeyException Then
   ' The supplied private key source is not a private key at all 
   ' or does not contain a signing key
   ' For example we have supplied an arbitrary file for the private 
   ' key parameter, or in the case with a KeyStore parameter 
   ' there is no private key with the specified Key ID or User ID	
  ElseIf TypeOf e Is DidiSoft.Pgp.Exceptions.WrongPasswordException Then
   ' The supplied private key password is misspelled	
  Else
   ' General OpenPGP error non among the above	
  End If
End Try
 
Try
  pgp.DetachedVerify...
Catch e As System.IO.IOException
  ' in case of an input file not found or other I/O related error
Catch e As DidiSoft.Pgp.PGPException
  If TypeOf e Is DidiSoft.Pgp.Exceptions.NonPGPDataException Then
   ' The supplied detached signed data is corrupted or is not an OpenPGP data at all
  Else
   ' General OpenPGP error non among the above	
  End If
End Try

Back to Top

Summary

In this chapter we have discussed OpenPGP detached signatures and how to produce them using DidiSoft OpenPGP Library for .NET.

List of methods used:

PGPLib.DetachedSignFile Creates an OpenPGP detached signature for a file
PGPLib.DetachedSignStream Creates an OpenPGP detached signature for the contents of a Stream
PGPLib.DetachedSignFile Creates an OpenPGP detached signature for a String message
PGPLib.DetachedVerifyString Verifies an OpenPGP detached signature available as String
PGPLib.DetachedVerifyStream Verifies an OpenPGP detached signature available as Stream