Video Screencast Help

PGP Command Line and Java Application?

Created: 05 Apr 2011 | 7 comments

We are using PGP Command line for file encryption and the creation of Self-Decrypting archive files for email attachments.

However we want to also deploy some file level encryption to a batch process.  The process is:

1) A file arrives on an SFTP Server.

2) The file is encrypted using PGP and a public key.

3) The encrypted file is sent to an Application server.

4) A Java process detects the file, decrypts it and processes the content.

The issue I have is what is the best way to achieve the decryption?  Obviously this will require a private key and a passphrase but with the command line software these would be provided on the command line and that can theoretically be snooped by root administrators and will appear in the shell history.

I have seen some examples that use Runtime.getRuntime().exec to run the command required and these examples used --passphrase-fd 0 to somehow magically give the command the passphrase required.   The command line user guide seems a little vague on how that operates?

An alternative solution I have considered uses the Sun JCE libraries to create a suitable cipher object with a key and a file can then be read as a CipherInputStream and processed on the fly without having to actually decrypt the file.   Is there any way to achieve this with the command line tool or would I have to use the PGP SDK API for that?

If I did use the SDK for this requirement can the SDK also be used for the SDA creation?

The licensing terms seem a little confusing for the SDK so is it already included in the command line software or not?  if so is there actually a separate license or cost to using this?

Regards,

Chris.

Comments 7 CommentsJump to latest comment

dfinkelstein's picture

PGP Command Line can take the passphrase in one of three ways:

1.  As a option during invocation ("--passphrase").

2.  Via an environment variable ("PGP_PASSPHRASE").

3.  From a file descriptor ("--passphrase-fd" or "--passphrase-fd8").

As an example of how to do #3, if you have your passphrase in a file called "pw.txt" (and mind that it doesn't have a trailing CRLF, unless your passphrase does), then you can run something like

pgp --decrypt input.pgp --passphrase-fd 0 < pw.txt

This redirects the contents of pw.txt to the standard input of PGP Command Line (standard input is file descriptor 0).

If you don't mind interacting with the server once when it starts up, you can also cache the passphrase using the "--cache-passphrase" command.  E.g., you would run

pgp --cache-passphrase mykey --passphrase "key passphrase" --passphrase-cache --passphrase-cache-timeout 0

This will keep the passphrase cached without any timeout; you'd only have to enter it again at the next reboot.  You'll need to run the command as the same user who executes the script since the cache is per user.

Of course if you don't trust root-level administrators on that box, they could possibly sniff the passphrase with a key logger.  If you are that concerned, you could set up PGP Universal as a KMS server, and your PGP Command Line process would call into KMS to do the decryption.  You'd still need to authenticate with a credential (e.g. username/passphrase) but then the only thing that is at risk is the authentication credential and not the key material (and you could shut off access to the key if you got concerned).

The PGP SDK does not currently include SDA creation functionality.  The PGP SDK is used by all PGP products but if you want to use the SDK for your own purpose you need a separate license.  I'm not quite sure I understand your use case of processing your file without decrypting it; in any event I don't see that it gets you any better security.

--------

David Finkelstein

Symantec R&D

FuzzyJack's picture

Thanks for the response.   I have had a bit of a play with the --passphrase-fd command, specifically with the standard input (--passphrase-fd 0).

Basically I have used the Runtime.exec operation available in Java to provide the passphrase to the pgp command as standard input.  By setting the output of the PGP command to be to standard out "--output -" I can then also capture the decrypted data line by line using a BufferedReader on the output stream.

Some example code below:

                        // Execute the decryption command
                        // This uses standard input to supply the passphrase and the resulting decrypted data is
                        // output to the standard output rather than a file.
                        Process p = Runtime.getRuntime().exec("pgp --decrypt TestFile.txt.pgp --output - --passphrase-fd 0");

                        // Write the passphrase out to the std input of the exec command
                        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
                        try
                        {
                                out.write("TestPassphrase");
                                out.close();
                        }
                        catch(IOException io)
                        {
                                System.out.println("Exception at write! " + io.getMessage ());
                        }

                        // Read the result from the standard output
                        BufferedReader in = new BufferedReader(
                                                        new InputStreamReader(p.getInputStream()));
                        String line = null;
                        while ((line = in.readLine()) != null) {
                                        System.out.println(line);
                        }

                        // Wait for the process to finish
                        p.waitFor();

                        System.out.println("Exit Code from command: " + p.exitValue() );

                        // Ensure that the child process is terminated properly
                        p.destroy();

 

This seems to work fine anyway.   I'm just trying to see if there is anything that would appear on the process stack or tracing on the server that can see the content of these streams but it's looking so far that the runtime.exec process may be secure enough to do this.

Because the java process created isn't actually a shell or console command none of this appears in the ps output or in the shell history which is good.  It's just a question of could an admnistrator (or intruder) to the server trace the JVM and see the data or not.

At the moment this means that I can then store the passphrase wherever I need for the application to access it AND read the decrypted data straight into my app.

I just need to worry about what I do to manage the periodic change of keys (decrypt a file encrypted with and older key after the private key has been replaced) or whether I need to rename the file somehow to show which key was used to generate it.

What does happen to encrypted data in PGP when you regenerate/replace/change your key (which is a requirement every 6 months)?

Back to the PGP manual for that I guess.

 

 

 

Chris Swallow
Technical Architect
Atos Origin IT Services (UK) Ltd
www.atosorigin.com

Andreas Zengel's picture

You might also want to have a look at the PGP Key Management Server which allows you to have all private and public keys stored in a central place. To decrypt data the private key does not have to be stored on the system that is doing the decryption anymore.

An example with the PGP Key Management Server can be found here:

https://www-secure.symantec.com/connect/forums/sec...

more information about PGP Key Management server here:

http://www.symantec.com/business/key-management-se...

dfinkelstein's picture

If your requirement is simply to rotate the encryption key used, you could generate a new encryption subkey on your existing key.  All new data will be encrypted to the new encryption subkey, but the old encryption subkey will still be present, so you will be able to decrypt any old data.

--------

David Finkelstein

Symantec R&D

FuzzyJack's picture

However generating a new subkey uses the same passphrase (as it is part of the master key) so this does rotate the keys but not the passphrases used so it's less useful.

It looks like I can generate multiple keys for the same username with different validity dates.  If I then encrypt a file for that user name it will encrypt the file with ALL keys that match that username.  Interestingly even though the creation date is a point in the future any encryption still uses that key?

However once one of the keys expires or is revoked any attempt to encrypt a file for that user results in either a "key revoked" or "key expired" error.  The way around that is to remove the public key from the encrypting server.  Now providing we generate a new key before the old one expires and then remove the key before it does actually expire this should be workable.

The encrypting server will at most have two valid keys for a short period but normally only one.  The target server can have two key pairs as it will need to be able to decrypt files encrypted with the old key for a period of time but then the old key pair should also be removed when no longer needed.

It's just a shame this will be a manual process but for the sake of once or twice a year this shouldn't be a big problem.

Chris Swallow
Technical Architect
Atos Origin IT Services (UK) Ltd
www.atosorigin.com

dfinkelstein's picture

PGP Command Line supports having different passphrases on your subkeys.

You can run

"pgp --change-passphrase KeyID --subkey SubkeyID --passphrase "old passphrase"  --new-passphrase "new passphrase"

--------

David Finkelstein

Symantec R&D

FuzzyJack's picture

Yes fair point.  Thanks.

Was a little confused by a test of this though.

I generated a new subkey with a creation date of tomorrow.  Therefore this key shouldn't be active yet however it is used when I then encrypt and the old subkey usage has changed to Unused?

Key Details: user1
     Key ID: 0xC7BA82BB (0xD158224FC7BA82BB)
       Type: RSA (v4) key pair
       Size: 2048
   Validity: Complete
      Trust: Implicit (Axiomatic)
    Created: 2011-04-12
    Expires: 2012-04-11

     Status: Active
     Cipher: AES-256
       Hash: SHA-256
       Hash: SHA-512
   Compress: Zip (Absent)
      Photo: No
  Revocable: Yes
      Token: No
  Keyserver: Absent
    Default: Yes
    Wrapper: No
 Prop Flags: Sign user IDs
 Prop Flags: Sign messages
 Prop Flags: PGP NetShare
 Prop Flags: PGP WDE
 Prop Flags: PGP ZIP
 Prop Flags: PGP Messaging
 Ksrv Flags: Absent
 Feat Flags: Modification detection
  Notations: 01 0x80000000 preferred-email-encoding@pgp.com=pgpmime
      Usage: Sign user IDs
      Usage: Sign messages

  Subkey ID: 0xF399AFAC (0xD6CB2DECF399AFAC)
       Type: RSA (v4) subkey pair
       Size: 2048
    Created: 2011-04-12
    Expires: 2012-04-11

     Status: Active
  Revocable: Yes
      Token: No
      X.509: No
 Prop Flags: Encrypt communications
 Prop Flags: Encrypt storage
 Prop Flags: PGP NetShare
 Prop Flags: PGP WDE
 Prop Flags: PGP ZIP
 Prop Flags: PGP Messaging
  Notations: None
      Usage: Unused

  Subkey ID: 0x21ED2493 (0xF61C8FCE21ED2493)
       Type: RSA (v4) subkey pair
       Size: 2048
    Created: 2011-04-13
    Expires: 2011-04-14
     Status: Active
  Revocable: Yes
      Token: No
      X.509: No
 Prop Flags: Encrypt communications
 Prop Flags: Encrypt storage
 Prop Flags: PGP NetShare
 Prop Flags: PGP WDE
 Prop Flags: PGP ZIP
 Prop Flags: PGP Messaging
  Notations: None
      Usage: Encrypt communications
      Usage: Encrypt storage
      Usage: PGP NetShare
      Usage: PGP WDE
      Usage: PGP ZIP
      Usage: PGP Messaging

        ADK: None

    Revoker: None

1 key found

 

So the new key has rendered the old subkey (which had a longer expiration date as well) redundant even though the new subkey isn't strictly valid yet?

I saw this when creating a seperate key as well where the encryption would use both keys I created for the encryption for a user despite one of them having a creation date in the future.   Is this expected?

Chris Swallow
Technical Architect
Atos Origin IT Services (UK) Ltd
www.atosorigin.com