OpenPGP KeyStore for C# and VB.NET


The KeyStore class encapsulates a storage that contains public and private OpenPGP keys. Referencing the keys in the key store is done either by their Key ID, Key Hex ID or by their User ID.

The DidiSoft.Pgp.KeyStore object is an implementation of the PKCS 12 standard

Common operations

1. Create and Open

2. Save
3. Auto save and backup
4. List keys
5. Referencing a key

6. Check for a key
7. Reusing an existing .pkr and .skr files from PGP®, GnuPG, EBS®
8. Importing and Exporting
9. Change password

1. Create and open a KeyStore

1.1 KeyStore in a File

The KeyStore data is usually stored in a file. The KeyStore constructor shown below is used when we want to create or open an existing KeyStore file:

// C#
KeyStore ks = new KeyStore(@"c:\my.keystore", "my password");
' VB.NET
Dim ks As New KeyStore("c:\my.keystore", "my password")

As of version 1.7.2 an equivalent static construction method has been added:

// C#
KeyStore ks = KeyStore.OpenFile(@"c:\my.keystore", "my password");
' VB.NET
Dim ks As KeyStore = KeyStore.OpenFile("c:\my.keystore", "my password")

The key store location can be a also a valid shared network path with read\write access, e.g. \\SharedServer\\SharedFolder\\my.keystore

1.2 In-memory KeyStore

As of version 1.7.2 we can also have an in-memory KeyStore, that disappears if not serialized explicitly on program exit.

// C#
KeyStore ks = KeyStore.OpenInMemory();
' VB.NET
Dim ks As KeyStore = KeyStore.OpenInMemory()

The property IsInMemory can be used to check is this instance backed by a file or located in-memory.

2. Saving a KeyStore

The Save() method of the KeyStore class writes back the KeyStore object to its file on the disk. This operation has no effect over an in-memory KeyStore.

3. Auto save and backup

By default the AutoSave property is on, and after each operation the modified state of the KeyStore is saved to the disk automatically. The BackupOnSave property is true by default too and on each save a backup file is stored with the previous state before the save operation (only one backup though).

4. List the contained keys

A list of all keys (unsorted) is obtained with the KeyStore.GetKeys() method. Each key is represented as an instance of DidiSoft.Pgp.KeyPairInformation. If you wish the list to be sorted you can do so with by ordering based on properties of the KeyPairInformation class like:

KeyPairInformation[] keysByCreationTime = ks.GetKeys().OrderBy(item => item.CreationTime).ToArray();

The example below lists and prints the keys in a way similar to GnuPG/gpg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Text;
using DidiSoft.Pgp;
 
public class KeyStoreListKeys
{
 public static void Demo()
 {
   // initialize the key store
   KeyStore ks = KeyStore.OpenFile(@"c:\my_key.store", "keystore password");
 
   KeyPairInformation[] keys = ks.GetKeys(); 
   StringBuilder sb = new StringBuilder();
   sb.Append("Type".PadRight(10));
   sb.Append("Key Id".PadRight(30));
   sb.Append("Created".PadRight(20));
   sb.Append("User Id");
   Console.WriteLine(sb.ToString());
 
   foreach (KeyPairInformation key in keys) {
	sb.Remove(0, sb.Length);
 
	String keyType = null;
	if (key.HasPrivateKey) {
		keyType = "pub/sec";	
	} else {
		keyType = "pub";	
	}
	sb.Append(keyType.PadRight(10));
 
	sb.Append(Convert.ToString(key.KeyId).PadRight(30));
	sb.Append(key.CreationTime.ToShortDateString().PadRight(20));
 
	foreach (String id in key.UserIds) {
		sb.Append(id);
	}
 
	Console.WriteLine(sb.ToString());
   }
 }
}

VB.NET example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Imports System
Imports System.Text
Imports DidiSoft.Pgp
 
Public Class KeyStoreListKeys
 Public Shared Sub Demo()
   ' initialize the key store
   Dim ks As KeyStore = KeyStore.OpenFile("c:\my_key.store", "keystore password")
 
   Dim keys As KeyPairInformation() = ks.GetKeys() 
   For Each key As KeyPairInformation In keys
 
	Dim sb As New StringBuilder()
	sb.Append("Type".PadRight(10))
	sb.Append("Key Id".PadRight(30))
	sb.Append("Created".PadRight(20))
	sb.Append("User Id")
	Console.WriteLine(sb.ToString())
 
	sb.Remove(0, sb.Length)
	Dim keyType As String = Nothing
	If key.HasPrivateKey Then
		keyType = "pub/sec"
	Else
		keyType = "pub"
	End If
	sb.Append(keyType.PadRight(10))
 
	sb.Append(Convert.ToString(key.KeyId).PadRight(30))
	sb.Append(key.CreationTime.ToShortDateString().PadRight(20))
 
	For Each id As String In key.UserIds
		sb.Append(id)
	Next
 
	Console.WriteLine(sb.ToString())
   Next
 End Sub
End Class

5. Referencing a key

Here you can see how to reference a key located in a KeyStore instance through its Key ID, part of or the whole User ID and by the short or long hexadecimal representation of the Key ID.

5.1 Referencing a key by User ID

A full User ID of an OpenPGP key is usually in the format “Name of the user <email>”. In older versions of the library a key had to be referenced by the full User ID.

As User ID can be specified by only a part of it, for example “John Doe <john@doe.com>” can be referenced only with “john@doe.com”. Strict User ID referencing can be turned on by setting the property KeyStore.PartialMatchUserIds to false. The case sensitivity of the User ID referencing is controlled with the property KeyStore.CaseSensitiveMatchUserIds.

A key can also have multiple User ID’s associated with it and we can use any of them.

In this example we show how to export a key to a file by specifying it by its User ID.

C# example

   KeyStore ks = KeyStore.OpenFile(@"c:\my_key.store", "keystore password");
 
   String partnerUserId = "partner@company.com";
   bool asciiArmor = true;
   ks.ExportPublicKey(@"c:\public_key.asc", partnerUserId, asciiArmor);

VB.NET example

   Dim ks As KeyStore = KeyStore.OpenFile("c:\my_key.store", "keystore password")
 
   Dim partnerUserId As String = "partner@company.com"
   Dim asciiArmor As Boolean = True
   ks.ExportPublicKey("c:\public_key.asc", partnerUserId, asciiArmor)

5.2 Referencing a key by hexadecimal Key ID

The hexadecimal representation of a Key ID is a string 16 characters long (2 characters for each byte). In order to ease users, command line PGP and GnuPG used a short hex Key ID of 8 characters representing the lower 4 bytes of the real Key ID (which is a System.Int64 value). You can use both short and long hexadecimal Key ID’s with the OpenPGP Library for .NET.

This example demonstrates how to reference an OpenPGP public key by its hexadecimal Key ID.

C# example

1
2
3
4
5
6
7
   KeyStore ks = KeyStore.OpenFile(@"c:\my_key.store", "keystore password");
 
   String partnerKeyId = "197B3E74";  // we can use any the short and the long form
   String partnerLongKeyId = "A01234B7197B3E74";
 
   bool asciiArmor = true;
   ks.ExportPublicKey(@"c:\public_key.asc", partnerKeyId, asciiArmor);

VB.NET example

1
2
3
4
5
6
   Dim ks As KeyStore = KeyStore.OpenFile("c:\my_key.store", "keystore password")
   ' we can use both the short and the long form
   Dim partnerKeyId As String = "197B3E74" 
   Dim partnerLongKeyId As String = "A01234B7197B3E74"
   Dim asciiArmor As Boolean = True
   ks.ExportPublicKey("c:\public_key.asc", partnerKeyId, asciiArmor)

5.3 Referencing a key by Key ID

The real OpenPGP Key ID is a 64 bit integer value. The Key Hex ID is constructed by the lower 32 bits of the real Key ID. The library accepts the real Key ID as a number of type Long (System.Int64).

Below we demonstrate how to obtain the real Key ID that corresponds to a given User ID.

C# example

   KeyStore ks = KeyStore.OpenFile(@"c:\my_key.store", "keystore password");
 
   String partnerUserId = "partner@company.com";
   long keyId = ks.GetKeyIdForUserId(partnerUserId);

VB.NET example

   Dim ks As KeyStore = KeyStore.OpenFile("c:\my_key.store", "keystore password")
 
   Dim partnerUserId As String = "partner@company.com"
   Dim keyId As Long = ks.GetKeyIdForUserId(partnerUserId)

6. Check for a key

Here you can see how to check is a given key contained in a KeyStore instance. Check can be made by part of the key User ID, the hexadecimal Key ID or the raw Key ID:

C# example

   KeyStore ks = KeyStore.OpenFile(@"c:\my_key.store", "keystore password");
 
   String partnerUserId = "partner@company.com";
   bool containsKey = ks.ContainsKey(partnerUserId);

VB.NET example

   Dim ks As KeyStore = KeyStore.OpenFile("c:\my_key.store", "keystore password")
 
   Dim partnerUserId As String = "partner@company.com"
   Dim containsKey As Boolean = ks.ContainsKey(partnerUserId)

7. Reusing an existing .pkr and .skr files from PGP®, GnuPG, EBS®

We can easily reuse keys from an existing PGP(r) installation. In the example below we will create an in-memory located KeyStore instance and load the keys used by PGP(r). The same code can be used with the GnuPG key ring files too.

C# example

   KeyStore ks = KeyStore.OpenInMemory();
 
   ks.ImportKeyRing(@"C:\Users\JohnDoe\Documents\PGP\pubring.pkr");
   ks.ImportKeyRing(@"C:\Users\JohnDoe\Documents\PGP\secring.skr");

VB.NET example

   Dim ks As KeyStore = KeyStore.OpenInMemory()
 
   ks.ImportKeyRing("C:\Users\JohnDoe\Documents\PGP\pubring.pkr")
   ks.ImportKeyRing("C:\Users\JohnDoe\Documents\PGP\secring.skr")

8. Importing and Exporting keys

Please refer to the complete chapters that explains Importing and Exporting keys.

9. Change password

In order to change the password of a KeyStore we have to open it and afterwards change its Password property.
(available as of version 1.7.8.8)

// C#
KeyStore ks = KeyStore.OpenFile(@"c:\my.keystore", "my password");
ks.Password = "new password";
ks.Save();
' VB.NET
Dim ks As KeyStore = KeyStore.OpenFile("c:\my.keystore", "my password")
ks.Password = "new password"
ks.Save()

Summary

This chapter discussed basic operations with the KeyStore object.

Topics not discussed here which can be of further interest are importing keysexporting keys, generating keys, deleting keys.