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.
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).
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
Signing a file
1. with a private key located in a file
2. with a private key located in a KeyStore
Signing a String message
3. with a private key located in a file
4. with a private key located in a KeyStore
Signing a Stream
5. with a private key supplied as a Stream
6. with a private key located in a KeyStore
Signing a file with the older OpnePGP version 3 signature.
7. with a private key located in a file
8. with a private key located in a KeyStore
Appendix
A. Compression and Hash function
B. Exception Handling
1. Signing a file with a private key located in a file
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#
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
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 |
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 |
(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 |
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.
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 |