-
Notifications
You must be signed in to change notification settings - Fork 20
EncryptingFiles
To encrypt a message, create a new Encryptor
object. Add to its ring the public key of each message recipient, and the secret key of each message signer. Then run the encrypt()
method of the Encryptor
-- this will generate a single PGP message encrypted for each key on the ring flagged as forEncryption
, and signed by each secret key flagged as forSigning
(and that has its passphrase supplied). See KeyRings for examples of how to load keys and manipulate their usage flags.
Note that you can reuse Encryptor
objects (including sharing the same Encryptor
among multiple threads) -- just be careful with MultiThreading.
The following examples will all use an Encryptor
configured with Alice's secret key and Bob's public key (so as to encrypt messages for both Alice and Bob, and signed by Alice):
Encryptor encryptor = new Encryptor(
new Key(new File("/path/to/alice-sec.gpg"), "password123"),
new Key(new File("/path/to/bob-pub.gpg"))
);
Note that you need to first supply the passphrase for a secret key before using it to sign or decrypt a message. In the above example, the passphrase password123
was supplied to the Key
constructor for Alice's key (which will be used as the passphrase for all of that key's subkeys).
You can encrypt a file by supplying the existing "plaintext" (unencrypted) version of the file as one java.io.File
object, and the desired location of the "ciphertext" (encrypted) version of the file as a second java.io.File
object. If the second file already exists, it will be overwritten (and you'll get an IOException
if you try to use the same location for both the plaintext and ciphertext files). For example, this encrypts "path/to/plaintext.txt" to "path/to/ciphertext.txt.gpg":
encryptor.encrypt(
new File("path/to/plaintext.txt"),
new File("path/to/ciphertext.txt.gpg")
);
This is equivalent to the following GnuPG command:
gpg --sign --encrypt --local-user alice --recipient alice --recipient bob \
--output path/to/ciphertext.txt.gpg path/to/plaintext.txt
The file extensions aren't important -- you could simply name the plaintext file "path/to/foo" and ciphertext "path/to/bar". Typically an extension of .gpg
(like foo.txt.gpg
) is used to indicate a file encrypted as a PGP message, and an extension of .asc
(like foo.txt.asc
) to indicate a file encrypted as a PGP message and encoded with ASCII Armor (although sometimes these extensions are used interchangeably, or other file-naming conventions are used).
ASCII Armor Base64-encodes a PGP message so that it's safe to copy and paste as text into email messages or other files or applications. Despite its name, it doesn't provide any additional security properties (its "armor" protects PGP messages from inadvertent corruption when embedded in other files, rather than "armoring" against decryption or deliberate modification by third parties). ASCII Armor also conveniently declares what kind of data is encoded within its armor via a header and footer like this (making it easier to figure out what you've been given when someone gives you a .gpg
or .asc
file):
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
jA0EAwMCRPdXu3qZeLBgySHwRvh2vWI8YHXCNDwHDzkMr6ZoR9iZFDM8gaWyIz1T
x/o=
=AqCM
-----END PGP MESSAGE-----
JPGPJ reads armored key files and encrypted messages transparently; but by default it encrypts messages without armoring. To armor encrypted messages, first turn on the Encryptor
object's asciiArmored
flag, and then encrypt the message:
encryptor.setAsciiArmored(true);
encryptor.encrypt(
new File("path/to/plaintext.txt"),
new File("path/to/ciphertext.txt.asc")
);
This is equivalent to the following GnuPG command:
gpg --sign --encrypt --local-user alice --recipient alice --recipient bob \
--armor --output path/to/ciphertext.txt.asc path/to/plaintext.txt
You can encrypt directly from a java.io.InputStream
to a java.io.OutputStream
. The Encryptor
does not call close()
on the InputStream
nor flush()
or close()
on the OutputStream
(so you should, if appropriate).
InputStream input = new URL("http://example.com/plaintext.txt").openStream();
URLConnection post = new URL(
"http://example.com/ciphertext.txt.gpg").openConnection();
post.setDoOutput(true);
InputStream output = post.getOutputStream();
encryptor.encrypt(input, output);
input.close();
output.close();
This is equivalent to the following GnuPG command:
curl http://example.com/plaintext.txt |
gpg --sign --encrypt --local-user alice --recipient alice --recipient bob |
curl --data-binary @- http://example.com/ciphertext.txt.gpg
PGP allows you to supply some optional metadata with a message, such as the original file's name, last-modified date, and line-ending normalization. This metadata often is simply ignored, but may be useful for certain use cases (like where a file is to be encrypted and embedded into as ASCII Armor text inside some other content).
If you supply JPGPJ a file to encrypt, JPGPJ will automatically extract the metadata from the file and include it in the encrypted message. If you supply a stream to encrypt, you can supply this metadata yourself:
HttpURLConnection get = (HttpURLConnection) new URL(
"http://example.com/plaintext.txt").openConnection();
InputStream input = get.getInputStream();
long length = get.getHeaderFieldLong("Content-Length", 0);
long lastModified = get.getHeaderFieldDate("Last-Modified", 0);
URLConnection post = new URL(
"http://example.com/ciphertext.txt.gpg").openConnection();
post.setDoOutput(true);
InputStream output = post.getOutputStream();
encryptor.encrypt(input, output, new FileMetadata(
"plaintext.txt", FileMetadata.Format.BINARY, length, lastModified
));
input.close();
output.close();
When encrypting a message, an Encryptor
will also sign the message content with each key on its ring that has a subkey with the forSigning
flag set to true, and for which the passphrase has been supplied. By default, all secret keys on the Encryptor
object's ring will be flagged as forSigning
.
To avoid signing a message entirely, set the Encryptor
object's signingAlgorithm
property to Unsigned
:
encryptor.setSigningAlgorithm(HashingAlgorithm.Unsigned);
encryptor.encrypt(
new File("path/to/plaintext.txt"),
new File("path/to/ciphertext.txt.gpg")
);
This is equivalent to the following GnuPG command:
gpg --encrypt --recipient alice --recipient bob \
--output path/to/ciphertext.txt.gpg path/to/plaintext.txt
If you do not supply any secret keys and do not explicitly set the Encryptor
object's signingAlgorithm
to Unsigned
, when you try to encrypt a message, a PGPException
will be raised with an exception message of "no suitable signing key found". The same will happen if you supply secret keys, but do not supply a passphrase for any secret key. If you supply the wrong passphrase for a secret key, a PassphraseException
will be raised with a exception message specifying the key with the wrong passphrase.
To sign a message with just a subset of the secret keys on a ring, either A) supply just the public key and not the secret key for any keys with which you don't want to sign (like in this example, load the full secret key for Alice, but just the public key for Bob):
Encryptor encryptor = new Encryptor(
new Key(new File("/path/to/alice-sec.gpg"), "password123"),
new Key(new File("/path/to/bob-pub.gpg"))
);
Or B) supply the passphrase just for the secret keys with which you want to sign (like in this example, load the secret keys for both Alice and Bob, but supply the passphrase only for Alice):
Encryptor encryptor = new Encryptor(
new Key(new File("/path/to/alice-sec.gpg"), "password123"),
new Key(new File("/path/to/bob-sec.gpg"))
);
Or C) extract just the public parts of any secret keys with which you don't want to sign (like in this example, load the secret keys for both Alice and Bob, but use just the public part for Bob):
Encryptor encryptor = new Encryptor(
new Key(new File("/path/to/alice-sec.gpg"), "password123"),
new Key(new File("/path/to/bob-sec.gpg"), "b0bru1z!").toPublicKey()
);
Or D) explicitly turn off the forSigning
flags of any secret keys with which you don't want to sign (like in this example, load the secret keys for both Alice and Bob, but turn off the forSigning
flag for Bob):
Encryptor encryptor = new Encryptor(
new Key(new File("/path/to/alice-sec.gpg"), "password123"),
new Key(new File("/path/to/bob-sec.gpg"), "b0bru1z!")
);
for (Key key: encryptor.getRing().findAll("bob"))
for (Subkey subkey: key.getSubkeys())
subkey.setForSigning(false);
See KeyRings#Setting Usage Flags for further details on subkey usage flags.
By default JPGPJ will compress messages before encrypting them, using the PGP ZLIB
compression option with its default level of 6
. You can configure this via the compressionAlgorithm
and compressionLevel
properties of an Encryptor
, like so:
encryptor.setCompressionAlgorithm(CompressionAlgorithm.BZip2);
encryptor.setCompressionLevel(9);
You can use any of the compression options specified in RFC 4880:
- Uncompressed
- ZIP
- ZLIB
- BZip2
Uncompressed
is ideal for encrypting data that's already been compressed (like an .mp3
or .zip
file). ZIP
and ZLIB
both use the DEFLATE
algorithm (same algorithm as the GNU gzip
utility, and the most commonly-used algorithm for .zip
archives). BZip2
uses the same algorithm as the unix bzip2
utility, which often results in somewhat smaller file sizes than ZIP
/ZLIB
, but at the expense of using somewhat more CPU and memory.
You can encrypt a message with a passphrase in place of, or in addition to, a secret key, by setting the symmetricPassphrase
property of an Encryptor
object. For example, if you were to set up an Encryptor
without any keys, but provide it with a symmetricPassphrase
, it will encrypt the message just with that passphrase:
Encryptor encryptor = new Encryptor();
encryptor.setSymmetricPassphrase("the eagle flies at midnight");
encryptor.encrypt(
new File("path/to/plaintext.txt"),
new File("path/to/ciphertext.txt.gpg")
);
This is equivalent to the following GnuPG command (and entering "the eagle flies at midnight" when prompted for the passphrase):
gpg --symmetric --output path/to/ciphertext.txt.gpg path/to/plaintext.txt
If you were to set up the Encryptor
with Alice's secret key and Bob's public key (like most of the examples on this page), and also supply the Encryptor
with a symmetricPassphrase
, it will encrypt the message with the passphrase as well as Alice's key and Bob's key, and sign it with Alice's key:
Encryptor encryptor = new Encryptor(
new Key(new File("/path/to/alice-sec.gpg"), "password123"),
new Key(new File("/path/to/bob-pub.gpg"))
);
encryptor.setSymmetricPassphrase("the eagle flies at midnight");
encryptor.encrypt(
new File("path/to/plaintext.txt"),
new File("path/to/ciphertext.txt.gpg")
);
This is equivalent to the following GnuPG command (and entering "the eagle flies at midnight" when prompted for the passphrase):
gpg --symmetric --sign --encrypt --local-user alice --recipient alice --recipient bob \
--output path/to/ciphertext.txt.gpg path/to/plaintext.txt
If you wish, you can customize the key-derivation algorithm and work factor for generating a symmetric key from the supplied passphrase via the Encryptor
object's keyDerivationAlgorithm
and keyDerivationWorkFactor
properties (JPGPJ uses the same encryption algorithm for encrypting the session key with the derived key as it does for encrypting the message itself; see below for how to customize that algorithm). The default key-derivation algorithm is SHA512
(the most expensive hash algorithm supported by RFC 4880), and the default work factor is 255
(the highest work factor allowed by RFC 4880). If you're familiar with the corresponding GnuPG options, the JPGPJ defaults would look like this as a GnuPGP command:
gpg --symmetric --s2k-cipher-algo AES128 --s2k-digest-algo SHA512 \
--s2k-mode 3 --s2k-count 65011712 \
--output path/to/ciphertext.txt.gpg path/to/plaintext.txt
By default JPGPJ will encrypt messages using the AES128
encryption algorithm. You can configure this via the encryptionAlgorithm
property of an Encryptor
, like so:
encryptor.setEncryptionAlgorithm(EncryptionAlgorithm.CAST5);
You can use any of the encryption algorithms specified in RFC 4880:
- Unencrypted
- IDEA
- TripleDES
- CAST5
- Blowfish
- AES128
- AES192
- AES256
- Twofish
Plus the Camellia family (RFC 5581):
- Camellia128
- Camellia192
- Camellia256