The OpenPGP clear text signed format is designed for text data and contains the data intact plus the signature.
In this format the digital signature is appended after the clear text original message; this way the recipient can still read it without using special software. The examples below show how to produce clear signed messages with DidiSoft OpenPGP Library for .NET
This format differs from the usual OpenPGP signature format but the data can be extracted and the signature verified with the same set of PGP signature verifying methods.
List of examples
Clear text signing a file
1. with a private key located in a file | Async
2. with a private key located in a KeyStore | Async
Clear text signing a String message
3. with a private key located in a file | Async
4. with a private key located in a KeyStore | Async
Clear text signing a Stream
5. with a private key supplied as a Stream | Async
6. with a private key located in a KeyStore | Async
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
1. Clear text signing a file with a private key located in a file
When producing clear text signed OpenPGP messages, we can provide a file location and with our private key, produce signature over it.
The hash algorithm used form the digital signature is specified explicitly.
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 |
1-A. Async clear text signing a file
The asynchronous of the ClearSignFile method is ClearSignFileAsync and is available in the sub class PGPLibAsync. This sample code below produces the same clear text signed PGP file but in asynchronous fashion:
using System; using System.Threading; using System.Threading.Tasks; using DidiSoft.Pgp; class CleartextSignFileAsync { public async Task Demo() { // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); string privateKeyPassword = "changeit"; // optional parameter CancellationToken token = default(CancellationToken); // clear text sign await pgp.ClearSignFileAsync(@"DataFiles\INPUT.txt", @"DataFiles\private.key", privateKeyPassword, HashAlgorithm.SHA256, @"DataFiles\OUTPUT.sig.txt", token); } } |
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 its 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 |
2-A. Async clear signing a File message with a key from a KeyStore
We can also clearsign a textual file with private key from a KeyStore.
In this example we have omitted the CancellationToken parameter for simplicity, but it can always be supplied as the last parameter of all Async methods.
using System; using System; using System.Threading.Tasks; using DidiSoft.Pgp; class ClearsignFileAsyncKS { public async Task Demo() { // initialize the key store KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); string signingKeyUserId = "contact@didisoft.com"; string signingKeyPassword = "changeit"; // 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 PGPLibAsync pgp = new PGPLibAsync(); // clear text sign await pgp.ClearSignFileAsync(@"DataFiles\INPUT.txt", ks, signingKeyUserId, signingKeyPassword, HashAlgorithm.SHA1, @"DataFiles\INPUT.sig.txt"); } else { Console.WriteLine("No key with user Id:" + signingKeyUserId + " was found in this key store."); } } |
3. Clear signing a String message with a private key located in a file
The ClearSignString method of the PGPLib class returns the clearsigned PGP message as String.
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 |
3-A. Async Clear signing a String message
The method for asynchronous clear signing is ClearSignStringAsync and is located in the PGPLibAsync class:
using System; using System.Threading; using System.Threading.Tasks; using DidiSoft.Pgp; class ClearsignStringAsync { public async Task Demo() { String plainString = "Hello World"; // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); // optional parameter CancellationToken token = default(CancellationToken); // clear text sign String clearSignedString = await pgp.ClearSignStringAsync(plainString, @"DataFiles\private.key", "changeit", HashAlgorithm.SHA256, token); return clearSignedString; } } |
4. Clear text signing a String message with a private key located in a KeyStore
This sample is equivalent to the above one, but using keys from a KeyStore file.
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 |
4-A. Async Clear text signing a String with a key from a KeyStore
We can also use a private key from a KeyStore to OpenPGP clear text sign a String message as you can see from this example code:
using System; using System.Threading; using System.Threading.Tasks; using DidiSoft.Pgp; class ClearsignStringAsyncKS { public async Task Demo() { // initialize the key store KeyStore ks = new KeyStore(@"DataFiles\key.store", "changeit"); string signingKeyUserId = "support@didisoft.com"; string signingKeyPassword = "changeit"; // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); string plainText = "Hello World"; // optional parameter CancellationToken token = default(CancellationToken); // clear text sign string clearSignedString = await pgp.ClearSignStringAsync(plainText, ks, signingKeyUserId, signingKeyPassword, HashAlgorithm.SHA256); return clearSignedString; } } |
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 |
5-A. Async Clear text signing a Stream
We can also asynchronously clear text sign data from a Stream with the ClearSignStreamAsync method available in the PGPLibAsync class, as you can see in the example below:
using System; using System.IO; using System.Threading; using System.Threading.Tasks; using DidiSoft.Pgp; public class ClearsignStreamAsyncDemo { public async Task Demo() { // create an instance of the library PGPLibAsync pgp = new PGPLibAsync(); Stream outputStream = new MemoryStream(); // optional parameter CancellationToken token = default(CancellationToken); // although here we use File Streams // we can use any kinf of Streams as well using (Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt")) using (Stream keyStream = File.OpenRead(@"DataFiles\my_private_key.asc")) { // clear text sign await pgp.ClearSignStreamAsync(dataStream, keyStream, "private key password", HashAlgorithm.SHA256, outputStream, token); } // .. The outputStream Position is at the end of the Stream } } |
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 its 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 |
6-A. Async Clear text signing a Stream with key from a KeyStore
You can see an Async version of the ClearSignStream method from the PGPLibAsync class in the following example:
using System; using System.IO; using System.Threading; using System.Threading.Tasks; using DidiSoft.Pgp; class ClearsignStreamAsyncKS { public async Task 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 PGPLibAsync pgp = new PGPLibAsync(); // optional parameter CancellationToken token = default(CancellationToken); using (Stream outputStream = new MemoryStream()) using (Stream dataStream = File.OpenRead(@"DataFiles\INPUT.txt")) { // clear text sign await pgp.ClearSignStreamAsync(dataStream, ks, signingKeyHexId, signingKeyPassword, HashAlgorithm.SHA256, outputStream, token); } } } |
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 a 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 |
Appendix A. Verifying and extracting clear text signed data
Verification and extraction of clear-signed data are done through the verification methods.
A key difference is that when we supply a wrong public key nonmatching 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 its catch clause in order to identify what exactly went wrong.
Below is an example that illustrates the subclasses 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 |
Summary
This chapter presented OpenPGP cleartext signing in C# and VB.NET. The class PGPLib that provides those methods is located in the namespace DidiSoft.Pgp. The methods that perform cleartext signing are:
PGPLib.ClearSignFileProduces PGP clear text signed message from a Text file
PGPLibAsync.ClearSignFileAsync | Asynchronously produces PGP clear text signed message from a Text file |
PGPLibAsync.ClearSignStringAsync | Asynchronously produces PGP clear text signed message from a String |
PGPLibAsync.ClearSignStreamAsync | Asynchronously produces PGP clear text signed message from Stream containing character data |
PGPLib.ClearSignString | Produces PGP clear text signed message from a String |
PGPLib.ClearSignStream | Produces PGP clear text signed message from Stream containing character data |
PGPLib.ClearSignFileV3 | Produces PGP clear text signed message in the old format |