The history of the encryption program known as Pretty Good Privacy (PGP) is long and, at times, annoyingly convoluted from its creation by Philip Zimmermann in 1991, to corporate ownership of the technology, to corporate buyouts and name changes, to legal battles with the feds and various changes in the underlying implementation (some likely due to licensing issues). If you have some time to kill, Wikipedia treats the topic thoroughly.
As for the current state of PGP, the news is good: An Internet standard (defined by RFC 2440) called OpenPGP has emerged. History aside, it is OpenPGP that I'm dealing with here as I offer a simple, command-oriented PGP implementation for the System i.
For contrast, consider the current alternatives. A few full-featured, third-party PGP products are available for the System i, but these products come at a cost. The free and open-source software (FOSS) solutions you are likely to find either don't run on the System i at all or run under PASE. The latter can be a struggle to install and, worse yet, when you fire off a Unix script from a CL program, you usually have to cross your fingers and hope for the best, receiving only unsophisticated return codes (or not even that) in the event of an error. This makes for disconnected, clumsy processes where you would prefer to have rock-solid, tightly integrated solutions.
I combine a free OpenPGP Java API with capabilities of the IBM Toolbox for Java/JTOpen, resulting in a nice marriage with the native i5/OS operating system. With my solution, you don't just have access to encryption/decryption routines; my commands send useful escape messages on error conditions, so you can code defensively in your operational processes.
In a moment, I'll demonstrate a working solution for basic OpenPGP functionality. You can use this solution as is or extend and combine it with other crypto offerings as your environment dictates. (For complete download and installation details, see "Installation Instructions," below.)
PGP Crypto 101
PGP is not a single cryptographic algorithm; rather, it's an approach to encryption that uses a combination of cryptographic algorithms and cryptography techniques. Not every implementation supports all options, which contributes to the complexity of PGP. Also, versions and changes over time have introduced incompatibilities.
Therefore, if you are encrypting for your own internal use, good for you! If not, plan on collaborating with the sender or recipient of the data you are working with and test, test, test.
PGP uses both asymmetric key (public key) and symmetric key cryptography, with symmetric key crypto being used for data encryption and public key crypto being used to encrypt the symmetric keys. Public key crypto is the part of PGP that you deal with as a user of PGP; symmetric key crypto is used behind the scenes.
In public key crypto, you create a public and private pair of keys. These keys are mathematically related, but neither one can be used by itself to derive the other. (That's the basic theory, at least.)
You share your public key freely and widely; on its own, it does not represent a security risk. Another party uses your public key to encrypt data for you and then sends this encrypted data to you. Only your private key can be used to decrypt the data previously encrypted using your public key. It is your private key that you want to protect as if it were the crown jewels.
Similarly, if you want to encrypt data to send off to another party, you must first obtain that party's public key. You use this key to encrypt data, knowing that only the receiving party can decrypt the data by employing its private key.
Regardless of what you are encrypting (e.g., data files, images), the output of PGP encryption is binary data. Often this is fine, but there are times when this is cumbersome, as when you want to pass encrypted data in a standard e-mail message. To simplify this, almost all PGP implementations support ASCII encoding of binary data in a process known as Radix-64 encoding, or ASCII "armor."
Another useful feature found in most PGP implementations is integrity checking through the creation of a hash code via a message digest algorithm. This helps ensure that data did not change or otherwise become corrupted while being communicated from sender to receiver. (My utility includes both ASCII armor and integrity-checking options.)
Their Name Is Legion
The free OpenPGP Java API of my choosing comes from a group that goes by the name Legion of the Bouncy Castle. If that name doesn't inspire confidence, I don't blame you, but the Bouncy Castle people do provide a superb set of crypto APIs, including a Java Cryptography Extension (JCE)/Java Cryptography Architecture (JCA) provider and SMIME/CMS in addition to OpenPGP.
With the support of organizations and more than a hundred individual contributors, a lot of brainpower is going into the Bouncy Castle effort.
Encrypt/Decrypt Example
In this not-quite-real-world example, we'll encrypt data using our own public key and then decrypt the data with our private key. Normally, you would be either encrypting data for someone else using his or her public key or decrypting data sent to you using your private key.
Although you can use the Bouncy Castle APIs to write code that generates keys, it is easier to use a GUI tool to perform key management tasks. Our choice for key management is the Windows Privacy Tray (WinPT) component of the GnuPG for Windows distribution.
GnuPG for Windows is a free software package (see Find Out More on page ProVIP 54). When you start WinPT for the first time, you are prompted to create your own key. This is a simple process of filling in blanks for your name, e-mail address, and a passphrase. (Do not check the box that says "prefer RSA keys.") You want to remember your passphrase. There is no practical way to retrieve it later, and it acts as a password for using your private key to decrypt data.
Figure 1 shows our key as it looks in the WinPT Key Manager. Although you see just one item in the list, the tool actually created two keys one using the DSA algorithm and one using the ElGamal algorithm. The DSA key is used for signing and authentication, and the ElGamal key is used for encryption.
The ElGamal key provides the public key/private key pair used for the asymmetric key cryptography component of PGP. Note that our key carries with it an identifier, or Key ID. Each key in our key file carries a unique identifier.
GnuPG for Windows stores the key data we care about in two files: pubring.gpg contains public keys, and secring.gpg contains our private key. Although it is true that we are using a Windows-based product to manage our key files, we can retain the key files on our System i and access them remotely via a mapped drive or periodically move the key files from a Windows machine to our System i. Using WinPT, you can alter the location of the key files by changing settings under Edit|Preferences|GPG Preferences. For the purposes of this example, I placed the key files in a directory called "/keyfiles" on my System i.
To have something meaningful to encrypt, let's copy a data file to a stream file and translate it to a CSV format. On my System i server, I have a table named CUSTMAST in a library called EXAMPLES. Here, we copy it to a stream file called custmast.csv in the directory /datafiles:
CPYTOIMPF FROMFILE(EXAMPLES/CUSTMAST)
TOSTMF('/datafiles/custmast.csv')
STMFCODPAG(*PCASCII)
RCDDLM(*CRLF)
Figure 2 shows the ENCRYPT command parameters that we use to encrypt our file. We specify the file that we want to encrypt and where we want to put the encrypted output. The utility automatically appends an .asc to the file name if we ask for ASCII armor or a .bpg to the file if it is binary. We are safe, therefore, in specifying that the target directory is the same as the directory containing the unencrypted file.
We specify that we want both ASCII armor and hash integrity. We indicate too the location and name of the file containing our public keys and the Key ID of the key that we want to use (prefaced with "0x" to say that the value is in hexadecimal notation).
Once encrypted, our file is ASCII encoded, so we can look at its contents with the Edit File tool or Windows Notepad. Figure 3 shows a sample of the file's encrypted contents.
To take this file the other direction, we use the DECRYPT command. As you can see in Figure 4, the parameters are similar to the ENCRYPT command. We specify the file that we want to decrypt and where the file should go. Use caution here; the DECRYPT command strips the file of its .asc or .bpg extension, and it will overwrite without warning any existing file with the same name. We indicate the location and name of the file containing our private key and the passphrase associated with this key.
Someone with your private key file and passphrase could compromise the security of encrypted data that you receive, so be smart about how you handle this stuff. You should take appropriate steps to secure your key files, expire keys periodically, and change passphrases both on a scheduled basis and when key staff members leave the organization.
It's normally a bad idea to hard-code a passphrase as plain text into a CL program. You could even put yourself at risk by invoking the DECRYPT command in an unencrypted (non-SSL) telnet session.
Implementation Notes
I used the KeyBasedLargeFileProcessor example provided by Bouncy Castle as the starting point for the Java side of my command processor. My biggest modification to the code involved searching the specified key file for a specific Key ID to use when encrypting. (In the unaltered example, the first key found in the file was used automatically.)
Apart from this, the bulk of my work went into establishing a means for the Java code to tell an invoking CL program of specific errors. See "Message Types," below, for a cross-reference of Java-side exceptions and CL-side escape messages.
The ENCRYPT and DECRYPT commands leverage a single back-end CL program (Figure 5) that, in turn, invokes a Java class called CmdProc. The command parameters are passed to the main() method of the CmdProc class, including a constant indicating whether we are encrypting or decrypting. (The ENCRYPT command passes a 1, and the DECRYPT command passes a 2.) The main() method invokes either the encryptFile() or decryptFile() methods of the CmdProc class based on this constant.
The nature of Java applications running on the System i is such that a separate job is automatically started to host the Java Virtual Machine that runs your Java code. This makes passing information back to an invoking CL program a tricky proposition.
To overcome this, our CL program temporarily creates a data area in QGPL and passes the name of the data area to the CmdProc class. (It's another one of the arguments to the main() method.) The data area name includes the job number of the invoking job for a reasonable degree of uniqueness.
The IBM Toolbox for Java/JTOpen toolkit provides the means for our Java code to place error information in the data area for use by the invoking CL program. Upon completion of the Java utility, the CL program resends any error information it finds in the data area as an escape message.
Loose Ends
As a practical matter, you need to know how to export your public key and how to import the public keys of others. Using GnuPG's WinPT tool, select a key on the list of keys and then choose Export from the Key menu. Figure 6 shows our exported, ASCII-encoded public key. If we wanted to receive an encrypted file from someone, we would e-mail or otherwise send this key data to them.
On the flip side, we should expect to receive such files from those who want us to encrypt data to send to them. We import public keys by selecting Import from the Key menu and pointing the import to an ASCII-encoded file containing the details of a public key. Once imported, the key will be assigned a unique Key ID, and we use this identifier on our ENCRYPT command.
Wrap Up
As you can see, this utility makes basic encryption/decryption with OpenPGP pretty simple. If your needs are complex, you can extend the solution or use one of the fee-based products on the market.
The security of your data is never something to take lightly, so be sure you understand all the concepts involved and are comfortable with the ultimate stability and robustness of the solution you settle on.
Dan Darnell is the author of the book Java and the AS/400, Second Edition (published by 29th Street Press) and an independent consultant in Little Rock, Arkansas.
|
Installation Instructions
|
|
To use the utility, you need to install the article code and two products from the Legion of the Bouncy Castle on your System i. I also recommend installing the latest version of the IBM Toolbox for Java/JTOpen package. Download the Java code for this article from SystemiNetwork.com/code. Deploy this code in the root file system (I deployed my utility code under a parent directory named /java).
From the website, you should download a library (PGPUTILLIB) containing the command and control language elements of the utility. (Detailed instructions for downloading and restoring the library are on the website). Make sure that this library appears in your library list when running the ENCRYPT and DECRYPT commands.
Download the latest Provider and OpenPGP/BCPG JAR files from the Legion of the Bouncy Castle website (see Find Out More, below). At this writing, version 1.37 is the latest release from Bouncy Castle, and I used the versions compatible with JDK 1.4 (Figure A). I placed these JAR files in my /java directory. Download the latest version of the IBM Toolbox for Java/JTOpen toolkit (see Find Out More). I placed the jt400native.jar and jt400.jar files in my /java directory.
If you're not using the 32-bit JVM, optimize the JAR files used by the utility to improve performance. I optimized each JAR to optimization level 30 using the CRTJVAPGM command.
There are a number of ways that you can establish a classpath appropriate to running this utility. In my case, I opted for changing the system-level CLASSPATH environment variable using the WRKENVVAR command. When I was done, the environment variable looked like Figure B.
Remember, I deployed all of my code under a parent directory of my creation named /java. Adjust your classpath entries appropriately if you use a different (or no) parent directory.
D.D.
Author's Addendum (2009-02-20)
Deploying Java applications is often more difficult than writing them. I've heard from several readers who experienced problems because they placed the CmdProc.class file in the /java folder. This file must go in a package-qualified directory under /java, not in /java itself. Place the CmdProc.class file in:
/java/pgp/util/
When debugging deployment problems, it is often helpful to see in detail the Java stack trace when you run the ENCRYPT or DECRYPT commands. To do so, recompile the PgpCmdProc CL program and change the JAVA command call to use an output option of *PAUSE instead of *CONTINUE. You can change the option back when you see that the utility is running without errors related to deployment.
I hear occasionally from readers who are trying to decrypt signed PGP files. The utility as published here does not include this support. I did add this support in a later version, and if you send me a private e-mail (click my byline at the top of this article to obtain my email address), I will send you the latest version and instructions for installing and using it.
|
|
Message Types
|
|
Exceptions that arise out of the Java-based processing program are trapped and turned into escape messages in the CL program that acts as the Command Processing Program for the ENCRYPT and DECRYPT commands. Each type of Java exception is translated into a different escape message type. The detailed text of a message is derived from the message text of the Java exception.
For example, there may be 10 variations on a PGPException, and all will come across as PGP1006 escape messages. But the message text will vary to provide specific information about the error that occurred (Figure A).
If things go totally awry for example, if the Java code can't find the IBM Toolbox for Java/JTOpen package then you will likely see system message JVA0122.
D.D.
|