ADK (additional decryption keys) pgp keys with C# and VB.NET


Additional decryption key (ADK) is a feature outside of the OpenPGP Standard. It allows public keys to hold internal information for other public keys noted as additional decryption keys (ADK for short).

The idea in short is : if Alice’s key has Bob’s key as an ADK, then when we encrypt with Alice’s key, the OpenPGP software should automatically also encrypt with Bob’s key, this way the message will be encrypted for multiple recipients and Bob can also decrypt it with his own private key.

ADK support is turned On by default as of version 1.7.11.
It is utilized only when we use the KeyStore key storage.

Table of Contents
1. Register and unregister an ADK key
1.1 registering
1.2 unregistering
2. Listing ADK keys
3. Encrypting
4. What if ADK keys are missing?
5. How to turn ADK support Off?

1. Register and unregister an ADK key

1.1 Registering ADK keys

Assuming that we have a KeyStore containing the main public key of ACM Company. We will produce a key pair for the employee John Doe and we will also register the company public key as an ADK (additional decryption key) for his key. Then his public key will be sent to the other employees of the ACM company, this way having each message encrypted for John, be also encrypted with the main company key.

With this feature if for some reason John leaves the company and deletes his keys or looses his password, the data encrypted for him can still be read and decrypted with the main company private key.

C# example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using DidiSoft.Pgp;
 
public class RegisterADK
{
 public static void Demo()
 {
  // new in-memory key storage
  KeyStore ks = new KeyStore();
 
  // Import the main company public key
  KeyPairInformation mainCompanyKey = ks.ImportPublicKey("acmcompany_pub.asc");
 
  // Create John's key
  string newKeyPassword = "test password";
  ks.GenerateRsaKeyPair(1024, "John Doe <john.doe@acmcompany.com>", newKeyPassword);
 
  // Register the main company key as an ADK for John's key
  ks.AddAdkKey("John Doe", newKeyPassword, mainCompanyKey.UserId);  // Now we can call ks.ExportPublicKey and distribute John's public key to the other employees
 }
}

VB.NET example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Imports System
Imports DidiSoft.Pgp
 
Public Class RegisterADK
 Public Shared Sub Demo()
  ' new in-memory key storage
  Dim ks As New KeyStore()
 
  ' Import the main company public key
  Dim mainCompanyKey As KeyPairInformation = ks.ImportPublicKey("acmcompany_pub.asc")
 
  ' Create John's key
  Dim newKeyPassword As String = "test password"
  ks.GenerateRsaKeyPair(1024, "John Doe <john.doe@acmcompany.com>", newKeyPassword)
 
  ' Register the main company key as an ADK for John's key
  ks.AddAdkKey("John Doe", newKeyPassword, mainCompanyKey.UserId)  ' Now we can call ks.ExportPublicKey and distribute John's public key to the other employees
 End Sub
End Class

Back to Top

1.1 Unregistering ADK keys

In order to modify the ADK list of an OpenPGP key, its private key must also reside in the same KeyStore. In the sample below the first key from the registered ADK keys will be unregistered:

C# example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using DidiSoft.Pgp;
 
public class UnregisterADK
{
 public static void Demo()
 {
  KeyStore ks = new KeyStore();
 
  // Import the key pair of John Doe
  KeyPairInformation key = ks.ImportPublicKey("john_doe_pub.asc");
  // In order to change the ADK list we need also the private key
  ks.ImportPrivateKey("john_doe_priv.asc");
 
  // Remove the first ADK key from John's key
  string keyPassword = "test password";
  if (key.GetAdkKeysCount() > 0)
	ks.DeleteAdkKey(key.KeyId, keyPassword, 0);
  else
	Console.WriteLine("There are no ADK key's in this key");
 }
}

VB.NET example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Imports System
Imports DidiSoft.Pgp
 
Public Class UnregisterADK
 Public Shared Sub Demo()
  Dim ks As New KeyStore()
 
  ' Import the key pair of John Doe
  Dim key As KeyPairInformation = ks.ImportPublicKey("john_doe_pub.asc")
  ' In order to change the ADK list we need also the private key
  ks.ImportPrivateKey("john_doe_priv.asc")
 
  ' Remove the first ADK key from John's key
  Dim keyPassword As String = "test password"
  If key.GetAdkKeysCount() > 0 Then
	ks.DeleteAdkKey(key.KeyId, keyPassword, 0)
  Else
	Console.WriteLine("There are no ADK key's in this key")
  End If
 End Sub
End Class

Back to Top

2. Listing ADK keys

An OpenPGP key with registered ADK keys contains internally only their fingerprints. The ADK keys that are in the same KeyStore, can be observed through the method KeyStore.GetKnownAdkKeys. For the ADK keys that are missing in the KeyStore, we can get only their fingerprints. This example demonstrates this:

C# 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
using System;
using DidiSoft.Pgp;
 
public class ListADKKeys
{
 public static void Demo()
 {
  KeyStore ks = new KeyStore();
 
  // Import John's key
  KeyPairInformation key = ks.ImportPublicKey("john_doe_pub.asc");
 
  // known (in this KeyStore) ADK keys
  KeyPairInformation[] knownAdkKeys = ks.GetKnownAdkKeys(key.KeyIdHex);
  for (int i = 0; i < knownAdkKeys.Length; i++)
  {
	KeyPairInformation adkKey = knownAdkKeys[i];
	Console.WriteLine(String.Format("ADK key {0} User ID is : {1}; Fingerprint: {2}", 
                          i, adkKey.UserId, adkKey.Fingerprint));
  }
 
  // all ADK keys' fingerprints
  for (int i = 0; i < key.GetAdkKeysCount(); i++)
  {
	Console.WriteLine(String.Format("ADK key {0} Fingerprint is: {1}", i, key.GetAdkKeyFingerprint(i)));
  }
 }
}

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
Imports System
Imports DidiSoft.Pgp
 
Public Class ListADKKeys
 Public Shared Sub Demo()
  Dim ks As New KeyStore()
 
  ' Import John's key
  Dim key As KeyPairInformation = ks.ImportPublicKey("john_doe_pub.asc")
 
  ' List known (in this KeyStore) ADK keys
  Dim knownAdkKeys As KeyPairInformation() = ks.GetKnownAdkKeys(key.KeyIdHex)
  For i As Integer = 0 To knownAdkKeys.Length - 1
	Dim adkKey As KeyPairInformation = knownAdkKeys(i)
	Console.WriteLine([String].Format("ADK key {0} User ID is : {1}; Fingerprint: {2}", _
                          i, adkKey.UserId, adkKey.Fingerprint))
  Next
 
  ' all ADK keys' fingerprints
  For i As Integer = 0 To key.GetAdkKeysCount() - 1
	Console.WriteLine([String].Format("ADK key {0} Fingerprint is: {1}", i, key.GetAdkKeyFingerprint(i)))
  Next
 End Sub
End Class

Back to Top

3. Encrypting

When we encrypt using a public key with registered ADK keys, by default the message gets also automatically encrypted with the ADK keys listed in this public key and presented in the same KeyStore. This applies to the operations OpenPGP encrypring and one pass signing and encrypting.

4. What if ADK keys are missing?

The ADK keys that are missing in a KeyStore, are not used in the encryption process and are silently skipped.

Back to Top

5. How to turn ADK support Off?

In order to skip the silent additional encryption with ADK keys, a special setting exists in the PGPLib class, that has to be set to False:

C# example

PGPLib pgp = new PGPLib();
pgp.UseADKs = false;

VB.NET example

Dim pgp As New PGPLib()
pgp.UseADKs = False

Back to Top

Summary

This chapter presented the support for ADK (additional decryption keys) offered by DidiSoft OpenPGP Library for .NET as of version 1.7.11.

ADK provides the ability to silently encrypt for multiple recipients by explicitly providing only one recipient. This can be useful in enterprises where a message must also be accessible by other employees, other than the original recipient.