Getting Started with OpenPGP

Requirements: IPWorks OpenPGP

Introduction

IPWorks OpenPGP is a comprehensive suite of components that implements the OpenPGP standard for encryption and decryption, as well as key generation and management.

This guide will focus specifically on the IPWorks OpenPGP components, which can be used to perform a combination of signing and encrypting messages as well as decrypting and verifying. If you're interested in using OpenPGP encryption in your solution, you're in the right place.

Before continuing, it is recommended to download IPWorks OpenPGP in order to follow along with this tutorial.

Contents

  1. Key Management
  2. Signing
  3. Verifying
  4. Encrypting
  5. Decrypting
  6. Sign and Encrypt
  7. Decrypt and Verify
  8. Streaming
  9. Code Examples

Generating or Importing OpenPGP Keys

The KeyMgr component can be used to perform a variety of key-related actions. You can create, delete, import, export, and manage keys. Both individual keys and keyrings can be created and used.

Keyring Management

Keyrings vs Keys

A single PGP key contains a public portion and a private portion. Single keys often come in an ASCII-armored (.asc) format. Multiple keys can be stored in a keyring. This makes it easier to store not only your own key, but the keys of any of your contacts. Keyrings as a concept originate from GPG and our tools follow their standards.

Keyring Format

GPG has two formats to store multiple keys. Versions 2.0 and older use keyrings. Public keys are stored in pubring.gpg. Secret keys are stored in secring.gpg. Versions 2.1 and newer use a keybox. Public keys are stored in a .kbx file. Private keys are stored in private-keys-v1.d. By default KeyMgr will use the older style. To use the newer, .kbx format set the KeyringFormat configuration setting to 2.

keymgr1.Config("KeyringFormat=2");

Loading & Saving Keyrings

After creating a new key or set of keys, or modifying an existing keyring, call SaveKeyring. This writes any keys held in memory to disk in the current KeyringFormat.

keymgr1.SaveKeyring("C:\\keyring");

To list keys from an existing keyring or otherwise modify it, load it into memory from disk from using the LoadKeyring method.

keymgr1.LoadKeyring("C:\\keyring");

Listing Keys

The keys (public/private key pairs) in the selected keyring can be listed using the ListKeys method. The results of this method are provided through the KeyList event.

keymgr1.ListKeys(); // KeyList event handler void keymgr1_OnKeyList(object sender, KeymgrKeyListEventArgs e) { lstKeys.Items.Add(e.UserId + " [" + e.KeyId + "]"); }

Setting the Key.UserId property to a valid UserId will effectively load that key, setting all of the other Key properties to the corresponding values for that key. This can be used to view detailed information or perform operations on a specific key.

Generating Keys

The CreateKey method can be used to create a new OpenPGP key pair by passing in the UserId and Passphrase for the new key.

keymgr1.CreateKey("newKeyUserId", "passphrase");

Note that the UserId format is as follows:

FirstName LastName (Comment) <Email>

Not all values are required when selecting or generating a key, but at least FirstName or Email are required.

Importing Keys

The ImportKey method can be used to import a key (with the specified UserId) from a key file into the current keyring. If the UserId parameter is set to "*" or "", all keys in the specified key file will be imported.

keymgr1.ImportKey("C:\\temp\\keyfile.key", "")

Exporting Keys

In order to export a specific key, it will first need to be selected within the keyring. As mentioned above, this can be done by setting the Key.UserId property. After this is done, the ExportPublicKey and ExportSecretKey methods can be used to export the public and secret key values to a specified file, respectively.

keymgr1.LoadKeyring("C:\\keyring"); keymgr1.Key.UserId = "UserId"; keymgr1.ExportPublicKey("C:\\temp\\publicKey.asc", true); keymgr1.ExportSecretKey("C:\\temp\\secretKey.asc", true);

Signing

The OpenPGP component's Sign method can be used to sign a given message using the secret key specified in the Keys collection.

openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.InputFile = "C:\\temp\\inputData.txt"; openpgp1.OutputFile = "C:\\temp\\outputData.pgp"; openpgp1.Sign();

Verifying

The VerifySignature method can be used to do just that: verify the signature of a message. The message will be verified using the keys specified in SignerKeys. Before verification begins the component will fire the SignatureInfo event with information about the signature including the key used to sign the message. Within this event you may use the information available to load the correct key into SignerKeys.

openpgp1.SignerKeys.Add(new Key("C:\\keyring", "SignerUserId")); openpgp1.InputFile = "C:\\temp\\signedData.pgp"; openpgp1.OutputFile = "C:\\temp\\outputData.txt"; openpgp1.VerifySignature();

By default, if the signature is not valid the component will throw an exception. The VerificationStatus event can also be checked to determine the result of the operation.

Encrypting

Encryption is performed using the recipient's public key. The OpenPGP component can be used to encrypt data by first specifying the recipient's key via RecipientKeys and calling the Encrypt method.

openpgp1.RecipientKeys.Add(new Key("C:\\keyring", "RecipientUserId")); openpgp1.InputFile = "C:\\temp\\inputData.txt"; openpgp1.OutputFile = "C:\\temp\\outputData.pgp"; openpgp1.Encrypt();

When encrypting, you can specify which encryption and compression algorithms to use via the EncryptingAlgorithm and CompressionMethod properties, respectively. You also have the option to encode the output message using ASCII armor by setting the ASCIIArmor property to true.

Decrypting

Decryption using the component is as simple as setting the secret key via Keys and calling the Decrypt method. Before decryption begins, the component's RecipientInfo event will fire with information about the encrypted message, including the key used to encrypt the message. Within this event, you may use this information to load the correct key into Keys.

openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.InputFile = "C:\\temp\\inputData.pgp"; openpgp1.OutputFile = "C:\\temp\\outputData.txt"; openpgp1.Decrypt();

Sign and Encrypt

Signing and encrypting can be combined into one step using the SignAndEncrypt method. When called, the component will sign and subsequently encrypt the specified data. When using this, it will be necessary to specify both the recipient's key and your secret key.

openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.RecipientKeys.Add(new Key("C:\\keyring", "RecipientUserId")); openpgp1.InputFile = "C:\\temp\\inputData.txt"; openpgp1.OutputFile = "C:\\temp\\outputData.pgp"; openpgp1.SignAndEncrypt();

Decrypt and Verify

The DecryptAndVerify method can be used to decrypt and verify a message in one step. To do this, set the signer keys via SignerKeys as well as your secret key via Keys.

openpgp1.SignerKeys.Add(new Key("C:\\keyring", "SignerUserId")); openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.InputFile = "C:\\temp\\inputData.pgp"; openpgp1.OutputFile = "C:\\temp\\outputData.txt"; openpgp1.DecryptAndVerifySignature();

Streaming

Java and .NET

Streaming to and from files is supported in the Java and .NET editions of the toolkit via the SetInputStream and SetOutputStream methods. Simply specify the corresponding streams to use for input and/or output prior to calling the method to complete the operation using these streams.

pgp.SetInputStream(inputStream); pgp.SetOutputStream(outputStream); pgp.Encrypt();

Note that by default streams specified via these methods will be closed after processing, however, there are configuration settings to instruct the component to keep these streams open. When the CloseInputStreamAfterProcess or CloseOutputStreamAfterProcess configs are set to false, the respective streams will be kept open after processing. For example:

pgp.Config("CloseInputStreamAfterProcess=false"); pgp.Config("CloseOutputStreamAfterProcess=false");

Other Languages (C++, Delphi, ActiveX, etc.)

The component can be configured to output the encrypted/decrypted data to the progress event. This can be enabled via the WriteToProgressEvent configuration setting. When used, the component will repeatedly fire the Progress event to provide output data. Inside the event check OutputMessage when the Operation parameter of the event is 2 (Write). The IsEOF parameter should be checked inside the event to determine when all output data has been provided. This allows output data to be chunked and obtained piece by piece. For example:

pgp.RecipientKeys.Add(new Key("C:\\keyring", "RecipientUserId")); pgp.Keys.Add(new Key("C:\\keyring", "UserId") { Passphrase = "test" }); pgp.InputFile = inputFile; FileStream fs = new FileStream(encryptedFile, FileMode.OpenOrCreate); pgp.OnProgress += new Openpgp.OnProgressHandler(delegate(object sender, OpenpgpProgressEventArgs e) { if (e.Operation == 2) { fs.Write(pgp.OutputMessageB, 0, pgp.OutputMessageB.Length); if (e.IsEOF) { fs.Flush(); fs.Close(); } } }); pgp.Config("WriteToProgressEvent=true"); pgp.SignAndEncrypt();

Code Examples

Encrypting Strings

Aside from the streaming section, all of the above examples exhibit the use of OpenPGP on files using the InputFile and OutputFile properties. The InputMessage and OutputMessage properties can also be used to read and write directly using strings. When doing so, it is useful to set the ASCIIArmor property to true to ASCII armor encode the output message.

// Signing openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.InputMessage = "This is a test message."; openpgp1.ASCIIArmor = true; openpgp1.Sign(); signedData = openpgp1.OutputMessage; // Verifying openpgp1.SignerKeys.Add(new Key("C:\\keyring", "SignerUserId")); openpgp1.InputMessage = signedData; openpgp1.VerifySignature(); data = openpgp1.OutputMessage; // Encrypting openpgp1.RecipientKeys.Add(new Key("C:\\keyring", "RecipientUserId")); openpgp1.InputMessage = "This is a test message."; openpgp1.ASCIIArmor = true; openpgp1.Encrypt(); encryptedData = openpgp1.OutputMessage; // Decrypting openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.InputMessage = encryptedData; openpgp1.Decrypt(); data = openpgp1.OutputMessage; // Sign and Encrypt openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.RecipientKeys.Add(new Key("C:\\keyring", "RecipientUserId")); openpgp1.InputMessage = "This is a test message."; openpgp1.ASCIIArmor = true; openpgp1.SignAndEncrypt(); encryptedData = openpgp1.OutputMessage; // Decrypt and Verify openpgp1.SignerKeys.Add(new Key("C:\\keyring", "SignerUserId")); openpgp1.Keys.Add(new Key("C:\\keyring", "UserId")); openpgp1.Keys[0].Passphrase = "passphrase"; openpgp1.InputMessage = encryptedData; openpgp1.DecryptAndVerifySignature(); data = openpgp1.OutputMessage;

The InputMessageB and OutputMessageB properties can be used to read and write binary data from memory.

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