OpenPGP KeyStore events in C# and VB.NET

The KeyStore class some events that we can use. In this chapter we are going to summarize them with some simple examples. In other chapters where they can be more relevant you will find specific show cases.

Table of contents

Event OnSave

The OnSave event is triggered at moments when the KeyStore data is changed and is going to be written to disk, but before actually storing it. This event is available also for in-memory KeyStores, event though they don’t perform disk write operations.

In the example below, we will show how to create a custom backup strategy:

C# example

using System;
using DidiSoft.Pgp;
 
public class OnSaveExample
{
 public static void Main(String[] args)
 {
	KeyStore ks = new KeyStore();
	ks.OnSave += MySaveHandler;
 }
 
 /// Custom event handler that saves copies of the KeyStore
 /// with file names : [KeyStore_FileName].X.bak
 /// where X is a counter
 private void MySaveHandler(KeyStore ks, EventArgs e) 
 { 
   ks.SaveToFileProtected(ks.FileName + "." + backupCounter + ".bak", ks.Password); 
   backupCounter++; 
  }
 
  private int backupCounter = 0; 
}

VB.NET example

Imports System
Imports DidiSoft.Pgp
 
Class OnSave
 Public Sub Demo()
	Dim ks As New KeyStore()
	AddHandler ks.OnSave, AddressOf MySaveHandler
 End Sub
 
 ''' Custom event handler that saves copies of the KeyStore
 ''' with file names : [KeyStore_FileName].X.bak
 ''' where X is a counter
 Private Sub MySaveHandler(ByVal ks As KeyStore, ByVal e As EventArgs)  
  ks.SaveToFileProtected(Convert.ToString(ks.FileName) & "." & backupCounter & ".bak", ks.Password)  
  backupCounter += 1 
 End Sub 
 
 Private backupCounter As Integer = 0 
End Class

Event OnKeyNotFound

(available as of version 1.7.9.6)
As the name of the OnKeyNotFound event suggests, it is fired when a key being searched in the KeyStore cannot be found. This applies to the cases when a KeyStore object is used as parameter in the methods of the PGPLib class and for the KeyStore class own methods, except the ContainsKey family of methods.

This method can be used for example to dynamically synchronize the KeyStore by searching a missing key from a remote key server or perform other recovery actions.

In the example below, we try to verify an OpenPGP digital signature, but we supply an empty KeyStore instance as a parameter to the PGPLib class. The event will be triggered with information for the missing public key that can be used to verify the signature:

C# example

using System;
using DidiSoft.Pgp;
 
class OnKeyNotFound
{
 public void Demo()
 {
	KeyStore ks = new KeyStore();
	ks.OnKeyNotFound += MyKeyNotFoundHandler;
 
	PGPLib pgp = new PGPLib();
	pgp.VerifyFileWithoutExtracting(@"c:\Test\data.pgp", ks);
 }
 
 /// Custom handler when a key searched in a KeyStore is not found
 private void MyKeyNotFoundHandler(KeyStore ks, KeyStore.KeyNotFoundEventArgs args) 
 { 
   Console.WriteLine("Missing key is " + (args.IsPublic ? "Public" : "Private")); 
   if (!String.IsNullOrEmpty(args.KeyHexId)) 
   { 
     Console.WriteLine("Missing key Hex ID is " + (args.KeyHexId)); 
   } else { 
     Console.WriteLine("Missing key User ID is " + (args.UserId)); 
   } 
 } 
}

VB.NET exmaple

Imports System
Imports DidiSoft.Pgp
 
Class OnKeyNotFound
 Public Shared Sub Main(ByVal args As String())
	Dim ks As New KeyStore()
	AddHandler ks.OnKeyNotFound, AddressOf MyKeyNotFoundHandler
 
        Dim pgp As New PGPLib()
	pgp.VerifyFileWithoutExtracting("c:\Test\data.pgp", ks)
 End Sub
 
 ''' Custom handler when a key searched in a KeyStore is not found
 Private Sub MyKeyNotFoundHandler(ByVal ks As KeyStore, ByVal args As KeyStore.KeyNotFoundEventArgs) 
  Dim keyType As String 
  If args.IsPublic Then 
    keyType = "Public" 
  Else 
    keyType = "Private" 
  End If     
  Console.WriteLine("Missing key is " & keyType) 
 
  If Not [String].IsNullOrEmpty(args.KeyHexId) Then   
    Console.WriteLine("Missing key Hex ID is " & Convert.ToString((args.KeyHexId))) 
  Else 
    Console.WriteLine("Missing key User ID is " & Convert.ToString((args.UserId))) 
  End If 
 End Sub 
End Class

Event OnKeyInserted, OnKeyUpdated, OnKeyRemoved

The KeyStore.OnKeyInserted event is fired when a new key is created or an existing key is imported in the KeyStore.

The KeyStore.OnKeyUpdated event is fired when a key is modified inside the KeyStore. (Examples for key update are changing key expiration time, trust, etc.)

The KeyStore.OnKeyRemoved event is executed when a key is deleted from the KeyStore.

Note: deleting only the public key or only the private key when the other part of the key pair is still in the KeyStore will fire KeyStore.OnKeyUpdated!

All the above events have the same signature:

public event System.EventHandler<DidiSoft.Pgp.Storage.KeyEventArgs>

A simple method handler that can be applied for all of them is:

private void OnKeyEvent(object sender, DidiSoft.Pgp.Storage.KeyEventArgs args)
{
  KeyPairInformation key = args.Key;
  Console.WriteLine(key.KeyIdHex);
}
...
// registering the event handler
KeyStore ks = new KeyStore();
ks.OnKeyInserted += OnKeyEvent;

Log message event

The logging events are triggered internally by the library revealing information about the internal operations. This event is similar to the logging event exposed by the PGPLib class.

The example below shows how to attach an event handler that can get this information and afterward display or save it for inspection in case of any faults:

C# example

using System;
using System.IO;
using DidiSoft.Pgp;
 
public class LogMessagesDemo
{
 public void Demo() 
 {
	KeyStore ks = new KeyStore();
	ks.LogMessageEvent += Log_Event;
	// all subsequent operations will be logged
 }
 
 /// This is our event handler where we receive the log messages
 private void Log_Event(object sender, DidiSoft.Pgp.Logging.LogEventArgs e)
 {
	using (StreamWriter log = File.AppendText(@"DataFiles\log.txt")) 
	{
		log.WriteLine(e.EventTime);
		log.WriteLine(e.Message);
 	}
 }
}

VB.NET example

Imports System
Imports System.IO
Imports DidiSoft.Pgp
 
Public Class LogMessagesDemo
 Public Sub Demo()
	Dim ks As New KeyStore()
	AddHandler ks.LogMessageEvent, AddressOf Log_Event
	' all subsequent operations will produce verbose log messages
 End Sub
 
 ''' This is our event handler where we receive the log messages
 Private Sub Log_Event(ByVal sender As Object, ByVal e As DidiSoft.Pgp.Logging.LogEventArgs)
	Using log As StreamWriter = File.AppendText("DataFiles\log.txt")
		log.WriteLine(e.EventTime)
		log.WriteLine(e.Message)
	End Using
 End Sub
End Class

Summary

This chapter illustrated the events fired by the KeyStore class.