OpenPGP signing in .NET

The OpenPGP sign operation converts the input data into the OpenPGP packet format and appends a digital signature produced with the private key of the sender. The opposite command for extracting signed content is verify or simply decrypt if we do not wish to check the validity of the signature.

Note that OpenPGP signed data is not encrypted. If the data has to be also encrypted check the one pass sign and encrypt section.

The examples below demonstrate signing with DidiSoft OpenPGP Library for .NET

Appendix

A. Compression and Hash function
B. Exception Handling


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

OpenPGP signing combines the data to be signed and the signature in a single output file, much similar to PDF signatures. If you need only signature then you should use detached signatures.

People often get confused that the data is protected but it’s not, if you need signed and protected data then use sign and encrypt.
C# example

using System;
using DidiSoft.Pgp;
 
public class SignDemo
{
 public void Demo()
 {
   // create an instance of the library
   PGPLib pgp = new PGPLib();
   // should the output be ASCII or binary
   bool asciiArmor = true;
 
   pgp.SignFile(@"C:\INPUT.txt",
                @"C:\private_key.asc",
                "private key passphrase",
                @"C:\OUTPUT.pgp",
                asciiArmor);
 }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Public Class SignDemo
 Public Sub Demo()
    ' create an instance of the library
    Dim pgp As New PGPLib()
 
    ' should the output be ASCII or binary
    Dim asciiArmor As Boolean = True
 
    pgp.SignFile("C:\INPUT.txt", _
                  "C:\private_key.asc", _
                  "private key passphrase", _
                  "C:\OUTPUT.pgp", _
                  asciiArmor)
 End Sub
End Class

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

This example is equivalent to the above one, except that the signing key resides in a KeyStore file. We specify which key to be used for signing by its User Id.

C# sample

using System;
using DidiSoft.Pgp;
 
class KeyStoreSignFile
{
 public static void Demo()
 {
  // initialize the key store
  KeyStore store = new KeyStore(@"c:\key.store",
				"changeit");
 
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "changeit";
 
  // if this key store contains a key with this User Id,
  // then sign,
  // otherwise notify that there is no such key
  if (store.ContainsKey(signingKeyUserId))
  {
	// create an instance of the library
	PGPLib pgp = new PGPLib();
 
	// should the output be ASCII or binary
	bool asciiArmor = true;
 
	pgp.SignFile(@"c:\INPUT.txt", store,
		     signingKeyUserId,
		     signingKeyPassword,
		     @"c:\INPUT.sig.txt",
		     asciiArmor);
 
  }
  else
  {
	Console.WriteLine("The key was not found!");
  }
 }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Class KeyStoreSignFile
 Public Shared Sub Demo()
  ' initialize the key store
  Dim store As New KeyStore("c:\key.store", "changeit")
 
  Dim signingKeyUserId As String = "support@didisoft.com"
  Dim signingKeyPassword As String = "changeit"
 
  ' if this key store contains a key with this User Id,
  ' then sign,
  ' otherwise notify that there is no such key
  If store.ContainsKey(signingKeyUserId) Then
    ' create an instance of the library
    Dim pgp As New PGPLib()
 
    ' should the output be ASCII or binary
    Dim asciiArmor As Boolean = True
 
    pgp.SignFile("c:\INPUT.txt", store, _
		     signingKeyUserId, _
		     signingKeyPassword, _
		     "c:\INPUT.sig.txt", _
		     asciiArmor)
  Else
	Console.WriteLine("The key was not found!")
  End If
 End Sub
End Class

3. Signing a String message with a private key located in a file

If we wish to sign a string message directly we should use one of the SignString methods:

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class SignString
{
  public static String Demo()
  {
    // message to be signed
    String plainString = "Hello World";
 
    // create an instance of the library
    PGPLib pgp = new PGPLib();
 
    // sign
    String signedString =
	pgp.SignString(plainString,
		       new FileInfo(@"c:\private_key.asc"),
		       "private key password");
 
    return signedString;
  }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class SignString
  Public Shared Function Demo() As String
    ' message to be signed
    Dim plainString As String = "Hello World"
 
    ' create an instance of the library
    Dim pgp As New PGPLib()
 
    ' sign
    Dim signedString As String = _
	pgp.SignString(plainString, _
			New FileInfo("DataFiles\private_key.asc"), _
			"private key password")
    Return signedString
  End Function
End Class

4. Signing a String message with a private key located in a KeyStore

If we keep our keys in a KeyStore object we should use the overloaded version of the SignString method that accepts KeyStore in order to sign a String message:

C# example

using System;
using DidiSoft.Pgp;
 
class KeyStoreSignString
{
  public static String Demo()
  {
    string signingKeyUserId = "support@didisoft.com";
    string signingKeyPassword = "changeit";
 
    // initialize the key store
    KeyStore ks = new KeyStore(@"DataFiles\key.store",
			  "keystore password");
 
   // if this key store contains the desired key - sign,
   // otherwise notify that there is no such key
   if (ks.ContainsKey(signingKeyUserId))
   {
	PGPLib pgp = new PGPLib();
 
	string plainText = "Hello World";
 
	string signedString =
		pgp.SignString(plainText, ks,
				signingKeyUserId,
				signingKeyPassword);
	return signedString;
    }
    else
    {
	Console.WriteLine("No key with user Id:" +
			signingKeyUserId +
			" was found in this key store.");
	return null;
    }
  }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Class KeyStoreSignString
  Public Sub Demo()
    Dim signingKeyUserId As String = "support@didisoft.com"
    Dim signingKeyPassword As String = "changeit"
 
    ' initialize the key store
    Dim ks As New KeyStore("DataFiles\key.store", "changeit")
 
    ' if this key store contains a key with this recipient userId
    ' then sign, otherwise notify that there is no such key
    If ks.ContainsKey(signingKeyUserId) Then
     Dim pgp As New PGPLib()
 
     Dim plainText As String = "Hello World"
 
     Dim signedString As String = pgp.SignString(plainText, _
						ks, _
						signingKeyUserId, _
						signingKeyPassword)
    Else
     Console.WriteLine("No key with user Id:" + _
			signingKeyUserId + _
			" was found in this key store.")
    End If
  End Sub
End Class

5. Signing a stream with a private key supplied as Stream

We can also sign a stream directly by passing the data and the private key as streams.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
public class SignStreamDemo
{
 public void Demo()
 {
  // create an instance of the library
  PGPLib pgp = new PGPLib();
  // should the output be ASCII or binary
  bool asciiArmor = true;
 
  // Just for the example the signed output is a 
  // MemoryStream object, It's Position property
  // will point at it's end after the method ends            
  Stream signedOutputStream = new MemoryStream();
 
  using (Stream dataStream = File.OpenRead(@"C:\INPUT.txt"))
  using (Stream keyStream = File.OpenRead(@"C:\private_key.asc")) 
  {
   // This is an arbitrary file name string that is 
   // associated with the signed data in the OpenPGP archive
   string internalFileNameLabel = "INPUT.txt";
   pgp.SignStream(dataStream,
		 internalFileNameLabel,
		 keyStream,
		 "private key passphrase",
		 signedOutputStream,
		 asciiArmor);
  }
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Public Class SignStreamDemo
 Public Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
  ' should the output be ASCII or binary
  Dim asciiArmor As Boolean = True
 
  ' Just for the example the signed output is a 
  ' MemoryStream object, It's Position property
  ' will point at it's end after the method ends		
  Dim signedOutputStream As Stream = New MemoryStream()
  Using dataStream As Stream = File.OpenRead("C:\INPUT.txt")
   Using keyStream As Stream = File.OpenRead("C:\private_key.asc")
    ' This is an arbitrary file name string that is 
    ' associated with the signed data in the OpenPGP archive
    Dim internalFileNameLabel As String = "INPUT.txt"
    pgp.SignStream(dataStream, _
                   internalFileNameLabel, _
                   keyStream, _
                   "private key passphrase", _
                   signedOutputStream, _
                   asciiArmor)
   End Using
  End Using
 End Sub
End Class

6. Signing a Stream with a private key located in a KeyStore

In this example, the private key is stored in a KeyStore object and we want to sign data available as a Stream for reading.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
public class SignStreamDemo
{
 public void Demo()
 {
  // create an instance of the library
  PGPLib pgp = new PGPLib();
  // should the output be ASCII or binary
  bool asciiArmor = true;
 
  // initialize the key store
  KeyStore ks = new KeyStore(@"c:\key.store", "keystore password");
 
  // Just for the example the signed output is a 
  // MemoryStream object, It's Position property
  // will point at it's end after the method ends            
  Stream signedOutputStream = new MemoryStream();
 
  using (Stream dataStream = File.OpenRead(@"C:\INPUT.txt"))
  {
     string privateKeyID = "A32BF480";
 
     // This is an arbitrary file name string that is 
     // associated with the signed data in the OpenPGP archive
     string internalFileNameLabel = "INPUT.txt";
     pgp.SignStream(dataStream,
                    internalFileNameLabel,
                    ks,
                    privateKeyID,
                    "private key passphrase",
                     signedOutputStream,
                     asciiArmor);
  }
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Public Class SignStreamDemo
 Public Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
  ' should the output be ASCII or binary
  Dim asciiArmor As Boolean = True
 
  ' initialize the key store
  Dim ks As New KeyStore("c:\key.store", "keystore password")
 
  ' Just for the example the signed output is a 
  ' MemoryStream object, It's Position property
  ' will point at it's end after the method ends		
  Dim signedOutputStream As Stream = New MemoryStream()
  Using dataStream As Stream = File.OpenRead("C:\INPUT.txt")
   Dim privateKeyID As String = "A32BF480"
 
   ' This is an arbitrary file name string that is 
   ' associated with the signed data in the OpenPGP archive
   Dim internalFileNameLabel As String = "INPUT.txt"
   pgp.SignStream(dataStream, _
                  internalFileNameLabel, _
                  ks, _
                  privateKeyID, _
                  "private key passphrase", _
                  signedOutputStream, _
		  asciiArmor)
  End Using
 End Sub
End Class

7. Signing a file with the older version 3 OpenPGP signature format

Note: Use this format only if you know that the recipient require it.

Some old OpenPGP implementations do not recognize the current signature format and may require the old version 3 signature format. In order to create compatible signed data, we can invoke the Sign methods that end with V3.

The example below illustrates signing a file with the old OpenPGP digital signature format.

C# example

using System;
using DidiSoft.Pgp;
 
public class SignDemoV3
{
 public void Demo()
 {
   // create an instance of the library
   PGPLib pgp = new PGPLib();
   // should the output be ASCII or binary
   bool asciiArmor = true;
 
   pgp.SignFileV3(@"C:\INPUT.txt",
                @"C:\private_key.asc",
                "private key passphrase",
                @"C:\OUTPUT.pgp",
                asciiArmor);
 }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Public Class SignDemoV3
 Public Sub Demo()
    ' create an instance of the library
    Dim pgp As New PGPLib()
 
    ' should the output be ASCII or binary
    Dim asciiArmor As Boolean = True
 
    pgp.SignFileV3("C:\INPUT.txt", _
                  "C:\private_key.asc", _
                  "private key passphrase", _
                  "C:\OUTPUT.pgp", _
                  asciiArmor)
 End Sub
End Class

Back to Top

8. Signing a file with a private key located in a KeyStore

This example is equivalent to the above one, except that the signing key resides in a KeyStore file. We can specify which key to be used for signing by its User Id, Key Hex ID as String or Key ID of type System.Int64.

C#

using System;
using DidiSoft.Pgp;
 
class KeyStoreSignFileV3
{
 public static void Demo()
 {
  // initialize the key store
  KeyStore store = new KeyStore(@"c:\key.store",
				"changeit");
 
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "changeit";
 
  // if this key store contains a key with this User Id,
  // then sign,
  // otherwise notify that there is no such key
  if (store.ContainsKey(signingKeyUserId))
  {
	// create an instance of the library
	PGPLib pgp = new PGPLib();
 
	// should the output be ASCII or binary
	bool asciiArmor = true;
 
	pgp.SignFileV3(@"c:\INPUT.txt", store,
		     signingKeyUserId,
		     signingKeyPassword,
		     @"c:\INPUT.sig.txt",
		     asciiArmor);
 
  }
  else
  {
	Console.WriteLine("The key was not found!");
  }
 }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Class KeyStoreSignFileV3
 Public Shared Sub Demo()
  ' initialize the key store
  Dim store As New KeyStore("c:\key.store", "changeit")
 
  Dim signingKeyUserId As String = "support@didisoft.com"
  Dim signingKeyPassword As String = "changeit"
 
  ' if this key store contains a key with this User Id,
  'then sign,
  ' otherwise notify that there is no such key
  If store.ContainsKey(signingKeyUserId) Then
    ' create an instance of the library
    Dim pgp As New PGPLib()
 
    ' should the output be ASCII or binary
    Dim asciiArmor As Boolean = True
 
    pgp.SignFileV3("c:\INPUT.txt", store, _
		     signingKeyUserId, _
		     signingKeyPassword, _
		     "c:\INPUT.sig.txt", _
		     asciiArmor)
  Else
	Console.WriteLine("The key was not found!")
  End If
 End Sub
End Class


1-A Async signing a file with a key from a file

Async OpenPGP cryptography methods are methods are available in the PGPLibAsync class that extends PGPLib.

This demo function would take in a file to sign, a key file, output file and a parameter for the output type. The function would then sign the file with the key from the key file, and output the result as either binary or ASII armored, depending on the output type parameter.

As the invoked method is asynchronous, there is an optional last parameter of type CancellationToken, that can be used to cancel the execution of the operation.

C# example

using System;
using System.Threading;
using DidiSoft.Pgp;
 
class SignFileAsync
{
  public async void Demo()
  {
   // create an instance of the library
   PGPLibAsync pgp = new PGPLibAsync();
 
   // should output be binary (false) or ASCII armored (true)
   bool asciiArmor = true;
 
   // optional parameter
   CancellationToken token = default(CancellationToken);
 
   await pgp.SignFileAsync(@"DataFiles\INPUT.txt",
			 @"DataFiles\private.key",
			 "changeit",
			 @"DataFiles\OUTPUTs.pgp",
			 asciiArmor,
			 token);
 
  }
}

2-A Async signing a file with a key from a KeyStore

This example is equivalent to the above one, except that the signing key resides in a KeyStore file. The signing key can be specified by part or the whole User Id string, or by its hexadecimal key Id.

C#

using System;
using DidiSoft.Pgp;
 
class KeyStoreSignFile
{
 public static void Demo()
 {
  // initialize the key store
  KeyStore store = new KeyStore(@"c:\key.store",
				"changeit");
 
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "changeit";
 
  // if this key store contains a key with this User Id,
  // then sign,
  // otherwise notify that there is no such key
  if (store.ContainsKey(signingKeyUserId))
  {
	// create an instance of the library
	PGPLib pgp = new PGPLib();
 
	// should the output be ASCII or binary
	bool asciiArmor = true;
 
	pgp.SignFile(@"c:\INPUT.txt", store,
		     signingKeyUserId,
		     signingKeyPassword,
		     @"c:\INPUT.sig.txt",
		     asciiArmor);
 
  }
  else
  {
	Console.WriteLine("The key was not found!");
  }
 }
}

3-A Async OpenPGP signing a String message with a private key from a file

If we wish to sign a string message and get the result as ASCII String then we can use one of the SignStringAsync methods:

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class SignString
{
 public async Task Demo()
 {
  String plainString = "Hello World";
 
  // create an instance of the library
  PGPLibAsync pgp = new PGPLibAsync();
 
  String signedString = await pgp.SignStringAsync(plainString,
						 @"DataFiles\private.key",
						 "changeit");
  return signedString;
 }
}

4-A. Async Signing a String message with a private from a KeyStore

If we keep our keys in a KeyStore object we should use the overloaded version of the SignStringAsync method that accepts KeyStore:

C# example

using System;
using DidiSoft.Pgp;
 
class KeyStoreSignString
{
 public async Task Demo()
 {
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "changeit";
 
  // initialize the key store
  KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit");
 
  // if this key store contains the desired key - sign,
  // otherwise notify that there is no such key
  if (ks.ContainsKey(signingKeyUserId))
 {
	// create an instance of the library
	PGPLib pgp = new PGPLib();
 
	string plainText = "Hello World";
 
	string signedString = pgp.SignString(plainText, ks,
					 signingKeyUserId,
					 signingKeyPassword);
 
	return signedString; 
  }
  else
  {
	Console.WriteLine("No key with user Id:" + signingKeyUserId + " was found in this key store.");
	return null;
  }
 }
}

5-A. Async Signing a stream with a private key as Stream

We can also sign a stream directly by passing the data and the private key as streams.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
public class SignStreamAsyncDemo
{
 public async void Demo()
 {
  // create an instance of the library
  PGPLibAsync pgp = new PGPLibAsync();
 
  // should output be binary (false) or ASCII armored (true)
  bool asciiArmor = true;
 
  // The output must be a stream that supports writing
  Stream outputSignedStream = new MemoryStream();
 
  // Optional parameter
  // dummy cancellation tokjen for the example
  CancellationToken token = default(CancellationToken);
 
  // The data stream and the private key stream can be any kind of stream 
  // that supports reading
  using (Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt"))
  using (Stream privateKeyStream = File.OpenRead(@"DataFiles\private.key"))
  {
	string privateKeyPassword = "changeit";
 
	// File name label to be associated with the data in the OpenPGP archive
	// You can also use the constant PGPLib.CONSOLE 
	// or just make up an arbitrary string here
	string internalFileNameLabel = "INPUT.txt";
 
	await pgp.SignStreamAsync(dataStream,
			 internalFileNameLabel,
			 privateKeyStream,
			 privateKeyPassword,
			 outputSignedStream,
			 asciiArmor,
			 token);
  }
 }
}

6-A. Signing a Stream with a private key located in a KeyStore

In this example, the private key is taken form KeyStore object. The output Stream is just a local variable, but in a real world scenario you will usually obtain a Stream ready from writing from some kind of persistent storage.

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
public class SignStreamAsyncDemo
{
 public async void Demo()
 {
  KeyStore store = KeyStore.OpenFile(@"DataFiles\key.store", "changeit");
 
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "changeit";
 
  // create an instance of the library
  PGPLibAsync pgp = new PGPLibAsync();
 
  // should the output signed file be ASCII or binary
  bool asciiArmor = true;
 
  // File name label to be associated with the data in the OpenPGP archive
  // You can also use the constant PGPLib.CONSOLE 
  // or just make up an arbitrary string here
  string internalFileNameLabel = "INPUT.txt";
 
  // The output must be a stream that supports writing
  Stream outputSignedStream = new MemoryStream();
 
  // The data stream can be any kind of stream that supports reading
  using (Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt"))
  {
	await pgp.SignStreamAsync(dataStream,
			        internalFileNameLabel,
				store,
				signingKeyUserId,
				signingKeyPassword,
				outputSignedStream,
				asciiArmor);
  }
 
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Public Class SignStreamDemo
 Public Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
  ' should the output be ASCII or binary
  Dim asciiArmor As Boolean = True
 
  ' initialize the key store
  Dim ks As New KeyStore("c:\key.store", "keystore password")
 
  ' Just for the example the signed output is a 
  ' MemoryStream object, It's Position property
  ' will point at it's end after the method ends		
  Dim signedOutputStream As Stream = New MemoryStream()
  Using dataStream As Stream = File.OpenRead("C:\INPUT.txt")
   Dim privateKeyID As String = "A32BF480"
 
   ' This is an arbitrary file name string that is 
   ' associated with the signed data in the OpenPGP archive
   Dim internalFileNameLabel As String = "INPUT.txt"
   pgp.SignStream(dataStream, _
                  internalFileNameLabel, _
                  ks, _
                  privateKeyID, _
                  "private key passphrase", _
                  signedOutputStream, _
		  asciiArmor)
  End Using
 End Sub
End Class

(Appendix A) Compression and Signature Hash

The default compression of the signed file is ZIP. It can be changed through the Compression property of the PGPLib class.

The default signature hash function is SHA-1. It can be changed through the Hash property of the PGPLib class.
Back to Top

(Appendix B) Exception Handling

The main two checked exceptions thrown by all Sign methods are System.IO.IOException in case of an I/O error and DidiSoft.Pgp.PGPException in case of an OpenPGP related error.

In order to identify more thoroughly what went wrong, we can check is the thrown PGPException of a specific subclass.

Below is an example that illustrates how to perform that check and the possible exception subclasses expected from the Sign methods.

C# example

PGPLib pgp = new PGPLib();
try
{
  pgp.Sign...
}
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
  }
}

VB.NET example

Dim pgp As New PGPLib()
Try
  pgp.Sign...
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

Back to Top

Summary

As you have learned from this chapter, OpenPGP signing does not protect the data from being read. It just appends a digital signature to verify the sender.

You may also consider reading about clear text signatures, detached signatures and one pass signed and encrypted data.

Older OpenPGP implementations (like PGP 6.5.x) used a different digital signature format called version 3 signatures. In order to produce signed content compatible with older implementations, we should use the Sign methods that end with V3 (for example SignFileV3).

Methods used in this chapter:

PGPLib.SignFile Produces an OpenPGP archive containing the unencrypted data and an additional signature
PGPLib.SignString Produces an ASCII armored OpenPGP signed message
PGPLib.SignStream OpenPGP signs data supplied as Stream
PGPLib.SignFileV3 Produces an OpenPGP signed archive but with the older version 3 signature format
PGPLibAsync.SignFileAsync Produces an OpenPGP archive containing the unencrypted data and an additional signature
PGPLibAsync.SignStringAsync Produces an ASCII armored OpenPGP signed message
PGPLibAsync.SignStreamAsync OpenPGP signs data supplied as Stream