What's New in IPWorks PGP 2026


Requirements: IPWorks PGP

Introduction

We are pleased to announce the Beta release of IPWorks PGP 2026 (formerly IPWorks OpenPGP). This release adds support for post-quantum cryptography (PQC) algorithms, as well as compatibility with GnuPG's LibrePGP key and message format. This article summarizes the new features below, and includes technical details on the accompanying API changes.

If you are upgrading from a previous version, please see the API Changes section below for details on renamed components and configuration settings that have been removed.

Contents

Post-Quantum Cryptography (PQC) Support

IPWorks PGP now supports the post-quantum composite signature and encryption algorithms defined by RFC 9980. These algorithms combine a post-quantum algorithm (ML-DSA or ML-KEM) with a traditional elliptic-curve algorithm (Ed25519, Ed448, X25519, or X448).

These algorithms are only supported for OpenPGP v6 keys. As such, to make use of PQC, the KeyVersion config must be set to 6 when calling CreateKey, and CompatibilityProfile must be left at its default value, RFC9580 (these algorithms are not supported with CompatibilityProfile=LibrePGP, since LibrePGP does not define a version 6 key).

Public Key Algorithms

The following composite signature algorithms may be specified via the PublicKeyAlgorithm config when creating a primary key:

  • ML-DSA-65+Ed25519
  • ML-DSA-87+Ed448

Subkey Algorithms

The following composite encryption algorithms may be specified via the SubKeyAlgorithm config when creating a subkey (either automatically via CreateKey, or directly via CreateSubKey):

  • ML-KEM-768+X25519
  • ML-KEM-1024+X448

For all four algorithms above, the elliptic curve is already fixed by the algorithm name, so the Curve and SubKeyCurve configs do not need to be set. For example, to create a v6 key using ML-DSA-65+Ed25519 for signing and ML-KEM-768+X25519 for encryption:

keymgr1.Config("KeyVersion=6"); keymgr1.Config("PublicKeyAlgorithm=ML-DSA-65+Ed25519"); keymgr1.Config("SubKeyAlgorithm=ML-KEM-768+X25519");
keymgr1.CreateKey("pqc@example.com", "test");

Once created, the key can be used like any other v6 key for encrypting, decrypting, signing, and verifying using the OpenPGP component.

GnuPG LibrePGP Compatibility

OpenPGP v6, as specified by RFC 9580, has not been adopted by GnuPG. Instead, GnuPG (version 2.5.x and later) uses its own OpenPGP v5 format, known as LibrePGP. IPWorks PGP now supports creating, parsing, encrypting, decrypting, signing, and verifying LibrePGP-formatted keys and messages, for compatibility with GnuPG.

CompatibilityProfile

A new CompatibilityProfile config has been added to both the KeyMgr and OpenPGP components. This config controls which algorithm identifiers and packet formats are used when generating keys or messages. Possible values are:

  • RFC9580 (default): Uses standard OpenPGP conventions, such as native algorithm identifiers for Ed25519/Ed448/X25519/X448, and the RFC 9980 composite PQC algorithms described above.
  • LibrePGP: Uses the conventions GnuPG expects instead, such as legacy EdDSA/ECDH algorithm identifiers with an explicit curve, GnuPG's own ML-KEM encoding (see GnuPG's ML-KEM Algorithm below), and OCB as the only supported AEAD algorithm.

Note that this config only affects the format of keys and messages that are generated. Importing keys and decrypting/verifying messages supports both formats automatically, regardless of this setting.

Creating LibrePGP-Compatible Keys

To create a key that is structurally compatible with GnuPG, the KeyMgr component's KeyVersion config must be set to 5, together with CompatibilityProfile set to LibrePGP. These two configs are not independent: KeyVersion=5 requires CompatibilityProfile=LibrePGP (and vice versa, KeyVersion=6 requires CompatibilityProfile=RFC9580, since LibrePGP does not define a version 6 key). Using an unsupported combination raises an error.

keymgr1.Config("CompatibilityProfile=LibrePGP"); keymgr1.Config("KeyVersion=5");
keymgr1.CreateKey("librepgp@example.com", "test"); keymgr1.SaveKeyring("C:\keyring");

The resulting keyring can be loaded directly by GnuPG 2.5.x, and vice versa: a keyring created by GnuPG 2.5.x can be loaded by KeyMgr.

Encrypting and Signing LibrePGP-Compatible Messages

Similarly, when using the OpenPGP component to encrypt or sign a message using a LibrePGP key (or when the message otherwise needs to be readable by GnuPG), set CompatibilityProfile to LibrePGP:

openpgp1.Config("CompatibilityProfile=LibrePGP"); openpgp1.RecipientKeys.Add(new Key(pubKey, "test")); // a LibrePGP-formatted public key openpgp1.InputMessage = "Hello, World!";
openpgp1.Encrypt();

Unlike KeyMgr, there is no separate key/packet-version config for the OpenPGP component; CompatibilityProfile alone determines which packet version is used for session keys and signatures.

GnuPG's ML-KEM Algorithm

In addition to the RFC 9980 composite algorithms described above, GnuPG defines its own encryption subkey algorithm, referred to simply as ML-KEM. Unlike the RFC 9980 composites, which each pair a fixed ML-KEM parameter set with a fixed curve, GnuPG's ML-KEM allows a variety of curve and parameter set combinations.

This algorithm may be specified via the SubKeyAlgorithm config when creating a LibrePGP v5 key (i.e., KeyVersion=5 and CompatibilityProfile=LibrePGP); it is not supported with any other KeyVersion. The SubKeyCurve config selects the curve (defaulting to Curve25519), and the SubKeyLength config selects the ML-KEM parameter set (768 by default, or 1024).

keymgr1.Config("CompatibilityProfile=LibrePGP"); keymgr1.Config("KeyVersion=5"); keymgr1.Config("PublicKeyAlgorithm=EdDSA"); keymgr1.Config("SubKeyAlgorithm=ML-KEM"); keymgr1.Config("SubKeyCurve=Curve25519"); keymgr1.Config("SubKeyLength=768");
keymgr1.CreateKey("librepgp-mlkem@example.com", "test");

API Changes

  • The IPWorks OpenPGP toolkit has been renamed to IPWorks PGP.
  • The Keyring property of the KeyMgr component has been removed. This property was read-only, and simply echoed the input parameter previously passed to LoadKeyring. The same value is now available via the Keyring field of the Key type, which is now available on all platforms (it was previously unavailable in .NET, Java, Android, and JavaScript). For example:

keymgr1.LoadKeyring("C:\keyring");
// Previously: // Console.WriteLine(keymgr1.Keyring);
// Now: Console.WriteLine(keymgr1.Key.Keyring);

We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@nsoftware.com.