Clear text pgp signing in C# and VB.NET

The OpenPGP clear text signed format is designed for text data. The digital signature is appended after the clear text original message; this way the recipient can still read it without using a special software. The examples below show how to produce clear signed messages with DidiSoft OpenPGP Library for .NET

List of examples

Clear text signing a file

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

Clear text signing a String message

3. with a private key located in a file
4. with a private key located in a KeyStore

Clear text signing a Stream

5. with a private key supplied as a Stream
6. with a private key located in a KeyStore

Clear text signing a file with the old version 3 signature

7. with a private key located in a file

Appendix

A. Verifying and extracting clear text signed data

B. Exception Handling

1. Clear text signing a file with a private key located in a file

C# example

using System.IO;
using DidiSoft.Pgp;
 
class ClearSignFile
{
 public static void Demo()
 {
   // create an instance of the library
   PGPLib pgp = new PGPLib();
 
   // clear text sign
   pgp.ClearSignFile(new FileInfo(@"DataFiles\INPUT.txt"),
		     new FileInfo(@"DataFiles\my_private_key.asc"),
		     "private key password",
		     HashAlgorithm.SHA256,
		     new FileInfo(@"DataFiles\OUTPUT.sig.txt"));
 }
}

VB.NET code

Imports System.IO
Imports DidiSoft.Pgp
 
Class ClearSignFile
 Public Shared Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
 
  ' clear text sign
  pgp.ClearSignFile(New FileInfo("DataFiles\INPUT.txt"), _
		    New FileInfo("DataFiles\private.key"), _
		    "private key password", _
		    HashAlgorithm.SHA256, _
		    New FileInfo("DataFiles\OUTPUT.sig.txt"))
 End Sub
End Class

Back to Top

2. Clear text sign a file with a private key located in a KeyStore

In this example the signing key is located in a KeyStore. The key is specified through it’s User ID, but can be specified also with its Key ID or Key Hex ID.

C# example

using System;
using DidiSoft.Pgp;
 
class KeyStoreClearSignFile
{
 public static void Demo()
 {
  // initialize the key store
  KeyStore ks = new KeyStore(@"DataFiles\key.store", "keystore password");
 
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "my private key password";
 
  // if this key store contains a key with
  // the desired recipient userId, then clear sign,
  // otherwise notify that there is no such key
  if (ks.ContainsKey(signingKeyUserId))
  {
	// create an instance of the library
	PGPLib pgp = new PGPLib();
 
	// clear text sign
	pgp.ClearSignFile(@"DataFiles\INPUT.txt", ks,
			  signingKeyUserId,
			  signingKeyPassword,
			  HashAlgorithm.SHA1,
                          @"DataFiles\OUTPUT.sig.txt");
   }
   else
   {
 	Console.WriteLine("No key with user Id:" +
                          signingKeyUserId +
                          " was found in this key store.");
   }
 }
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Class KeyStoreClearSignFile
 Public Shared Sub Demo()
   ' initialize the key store
   Dim ks As New KeyStore("DataFiles\key.store", "keystore password")
 
   Dim signingKeyUserId As String = "support@didisoft.com"
   Dim signingKeyPassword As String = "my private key password"
 
   ' if this key store contains a key with
   ' the desired recipient userId, then clear sign,
   ' otherwise notify that there is no such key
   If ks.ContainsKey(signingKeyUserId) Then
      ' create an instance of the library
      Dim pgp As New PGPLib()
 
      ' clear text sign
      pgp.ClearSignFile("DataFiles\INPUT.txt", ks, _
                       signingKeyUserId, _
                       signingKeyPassword, _
                       HashAlgorithm.SHA1, _
                       "DataFiles\OUTPUT.sig.txt")
   Else
      Console.WriteLine("No key with user Id:" +
                        signingKeyUserId +
                        " was found in this key store.")
   End If
 End Sub
End Class

Back to Top

3. Clear signing a String message with a private key located in a file

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class ClearSignString
{
 public static String Demo()
 {
   String plainString = "Hello World";
 
   PGPLib pgp = new PGPLib();
   String clearSignedString =
     pgp.ClearSignString(plainString,
			 new FileInfo(@"DataFiles\my_private_key.asc"),
			 "private key password",
			 HashAlgorithm.SHA1);
   return clearSignedString;
 }
}

VB.NET code

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class ClearSignString
 Public Shared Function Demo() As String
   Dim plainString As String = "Hello World"
 
   ' create an instance of the library
   Dim pgp As New PGPLib()
 
   ' clear text sign
   Dim clearSignedString As String = _
      pgp.ClearSignString(plainString, _
			  New FileInfo("DataFiles\my_private_key.asc"), _
			  "my private key password", _
			  HashAlgorithm.SHA1)
	Return clearSignedString
 End Function
End Class

Back to Top

4. Clear text signing a String message with a private key located in a KeyStore

C# example

using System;
using DidiSoft.Pgp;
 
class KeyStoreClearSignString
{
 public static String Demo()
 {
  // initialize the key store
  KeyStore ks = new KeyStore(@"DataFiles\key.store", "keystore password");
 
  string signingKeyUserId = "support@didisoft.com";
  string signingKeyPassword = "private key password";
 
  // if this key store contains a key with the desired recipient userId - clear 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";
 
	// clear text sign
	string clearSignedString =
            pgp.ClearSignString( plainText, ks,
				 signingKeyUserId,
				 signingKeyPassword,
				 HashAlgorithm.SHA1);
 
	   return clearSignedString;
  }
  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 KeyStoreClearSignString
 Public Shared Function Demo() As String
  Dim signingKeyUserId As String = "support@didisoft.com"
  Dim signingKeyPassword As String = "private key password"
 
  ' initialize the key store
  Dim ks As New KeyStore("DataFiles\key.store", "keystore password")
 
  ' if this key store contains a key with the desired recipient userId - clear 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 clearSignedString As String = _
       pgp.ClearSignString(plainText, ks, _
				signingKeyUserId, _
				signingKeyPassword, _
				HashAlgorithm.SHA1)
 
	Return clearSignedString
  Else
	Console.WriteLine("No key with user Id:" + _
                          signingKeyUserId + _
                          " was found in this key store.")
	Return Nothing
  End If
 End Function
End Class

5. Clear text signing a Stream with a private key supplied as a Stream

In this example we will create a clear text signed output of data available as a Stream for reading.

C# code

using System;
using System.IO;
using DidiSoft.Pgp;
 
public class ClearSignStream
{
 public static void Demo()
 {
   // create an instance of the library
   PGPLib pgp = new PGPLib();
 
   Stream outputStream = new MemoryStream();
 
   using (Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt"))
   using (Stream keyStream = File.OpenRead(@"DataFiles\my_private_key.asc"))
   {
     // clear text sign
     pgp.ClearSignStream(dataStream,
		     keyStream,
		     "private key password",
		     HashAlgorithm.SHA256,
		     outputStream);
   }
   // .. The outputStream Position is at the end of the Stream
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class ClearSignStream
 Public Shared Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
 
  Dim outputStream As Stream = New MemoryStream()
 
  Using Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt")
   Using Stream keyStream = File.OpenRead(@"DataFiles\my_private_key.asc")
    ' clear text sign
    pgp.ClearSignStream(dataStream, _
		    keyStream, _
		    "private key password", _
		    HashAlgorithm.SHA256, _
		    outputStream)
   End Using
  End Using
  ' .. The outputStream Position is at the end of the Stream
 End Sub
End Class

Back to Top

6. Clear text signing a Stream with a private key located in a KeyStore

In this example the signing key is located in a KeyStore. The key is specified through it’s Key Hex ID, but can be specified also with its Key ID (of type System.Int64) or User ID

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
class KeyStoreClearSignStream
{
 public static void Demo()
 {
  // initialize the key store
  KeyStore ks = new KeyStore(@"DataFiles\key.store", "keystore password");
 
  string signingKeyHexId = "395A421B";
  string signingKeyPassword = "my private key password";
 
 
  // create an instance of the library
  PGPLib pgp = new PGPLib();
 
  Stream outputStream = new MemoryStream();
 
  using (Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt"))
  {
    // clear text sign
    pgp.ClearSignStream(dataStream, ks,
			signingKeyHexId,
			signingKeyPassword,
			HashAlgorithm.SHA1,
                        outputStream);
  }
  // .. The outputStream Position is at the end of the Stream
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Class KeyStoreClearSignStream
 Public Shared Sub Demo()
   ' initialize the key store
   Dim ks As New KeyStore("DataFiles\key.store", "keystore password")
 
   Dim signingKeyHexId As String = "395A421B"
   Dim signingKeyPassword As String = "my private key password"
 
   ' create an instance of the library
   Dim pgp As New PGPLib()
 
   Dim outputStream As Stream = New MemoryStream()
 
   Using Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt")
      ' clear text sign
      pgp.ClearSignStream(dataStream, ks, _
                       signingKeyHexId, _
                       signingKeyPassword, _
                       HashAlgorithm.SHA1, _
                       outputStream)
   End Using
   ' .. The outputStream Position is at the end of the Stream
 End Sub
End Class

Back to Top

7. Clear text signing a file with the old version 3 signatures

Older OpenPGP implementations used a different signature format and if we wish to create clear text signed message that can be verified by them, we should use the methods that end with V3. Newer implementations can process both the old and the new signature format.

C# example

using System.IO;
using DidiSoft.Pgp;
 
class ClearSignFile
{
 public static void Demo()
 {
   // create an instance of the library
   PGPLib pgp = new PGPLib();
 
   // clear text sign
   pgp.ClearSignFileV3(new FileInfo(@"DataFiles\INPUT.txt"),
			new FileInfo(@"DataFiles\my_private_key.asc"),
			"private key password",
			HashAlgorithm.SHA256,
			new FileInfo(@"DataFiles\OUTPUT.sig.txt"));
 }
}

VB.NET example

Imports System.IO
Imports DidiSoft.Pgp
 
Class ClearSignFile
 Public Shared Sub Demo()
  ' create an instance of the library
  Dim pgp As New PGPLib()
 
  ' clear text sign
  pgp.ClearSignFileV3(new FileInfo("DataFiles\INPUT.txt"), _
		    new FileInfo("DataFiles\my_private_key.asc"), _
		    "private key password", _
		    HashAlgorithm.SHA256, _
		    new FileInfo("DataFiles\OUTPUT.sig.txt"))
 End Sub
End Class

Back to Top

Appendix A. Verifying and extracting clear text signed data

Verification and extraction of clear signed data is done through the verification methods.

A key difference is that when we supply a wrong public key non matching the signature, or a KeyStore with no matching public key in it a DidiSoft.Pgp.Exceptions.WrongPublicKeyException will be thrown:

C# example

PGPLib pgp = new PGPLib();
string signed = pgp.ClearSignString("Hello world", "my_private_key.asc", "my password", HashAlgorithm.SHA1);
string extracted = string.Empty;
bool verified = false;
try
{
    verified = pgp.VerifyString(signed, "wrong_pub_key.asc", out extracted);
}
catch (DidiSoft.Pgp.Exceptions.WrongPublicKeyException) 
{
    Console.WriteLine("The specified public key doesn't match the signature, you should use another key");
    // simply extract the clear text data
    extracted = pgp.DecryptString(signed, null, string.Empty);
}

VB.NET example

Dim pgp As New PGPLib()
Dim signed As String = pgp.ClearSignString("Hello world", "my_private_key.asc", "my password", HashAlgorithm.SHA1)
Dim extracted As String = String.Empty
Dim verified As Boolean = False
Try
    verified = pgp.VerifyString(signed, "wrong_pub_key.asc", extracted)
Catch (DidiSoft.Pgp.Exceptions.WrongPublicKeyException) 
    Console.WriteLine("The specified public key doesn't match the signature, you should use another key");
    // simply extract the clear text data
    extracted = pgp.DecryptString(signed, null, string.Empty);
End Try

Appendix B. Exception Handling

All ClearSign methods throw System.IO.IOException and DidiSoft.Pgp.PGPException. We can try to cast the DidiSoft.Pgp.PGPException variable in it’s catch clause in order to identify what exactly went wrong.

Below is an example that illustrates the sub classes that we can try to cast the exception of type DidiSoft.Pgp.PGPException to:

C# example

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

This chapter presented OpenPGP clear text signing in C# and VB.NET. The class PGPLib that provides those methods is located in the namespace DidiSoft.Pgp. The methods that perform clear text signing are:

PGPLib.ClearSignFile
PGPLib.ClearSignString
PGPLib.ClearSignStream
PGPLib.ClearSignFileV3