号称是世界上使用最广泛的邮件加密标准.
这篇例子介绍如何使用这个标准进行文件的加密解密 (https://www.bouncycastle.org/latest_releases.html, 需要下载: bcprov-jdk15on-151.jar, bcpg-jdk15on-151.jar).
package org.bouncycastle.openpgp.examples;
import java.io.bufferedinputstream;
import java.io.bufferedoutputstream;
import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.io.outputstream;
import java.security.nosuchproviderexception;
import java.security.securerandom;
import java.security.security;
import java.util.iterator;
import org.bouncycastle.bcpg.armoredoutputstream;
import org.bouncycastle.bcpg.compressionalgorithmtags;
import org.bouncycastle.jce.provider.bouncycastleprovider;
import org.bouncycastle.openpgp.pgpcompresseddata;
import org.bouncycastle.openpgp.pgpencrypteddata;
import org.bouncycastle.openpgp.pgpencrypteddatagenerator;
import org.bouncycastle.openpgp.pgpencrypteddatalist;
import org.bouncycastle.openpgp.pgpexception;
import org.bouncycastle.openpgp.pgpliteraldata;
import org.bouncycastle.openpgp.pgponepasssignaturelist;
import org.bouncycastle.openpgp.pgpprivatekey;
import org.bouncycastle.openpgp.pgppublickey;
import org.bouncycastle.openpgp.pgppublickeyencrypteddata;
import org.bouncycastle.openpgp.pgpsecretkeyringcollection;
import org.bouncycastle.openpgp.pgpsignaturelist;
import org.bouncycastle.openpgp.pgputil;
import org.bouncycastle.openpgp.jcajce.jcapgpobjectfactory;
import org.bouncycastle.openpgp.operator.jcajce.jcakeyfingerprintcalculator;
import org.bouncycastle.openpgp.operator.jcajce.jcepgpdataencryptorbuilder;
import org.bouncycastle.openpgp.operator.jcajce.jcepublickeydatadecryptorfactorybuilder;
import org.bouncycastle.openpgp.operator.jcajce.jcepublickeykeyencryptionmethodgenerator;
import org.bouncycastle.util.io.streams;
/**
* a simple utility class that encrypts/decrypts public key based
* encryption files.
*
* to encrypt a file: keybasedfileprocessor -e [-a|-ai] filename publickeyfile.
* if -a is specified the output file will be "ascii-armored".
* if -i is specified the output file will be have integrity checking added.
*
* to decrypt: keybasedfileprocessor -d filename secretkeyfile passphrase.
*
* note 1: this example will silently overwrite files, nor does it pay any attention to
* the specification of "_console" in the filename. it also expects that a single pass phrase
* will have been used.
*
* note 2: if an empty file name has been specified in the literal data object contained in the
* encrypted packet a file with the name filename.out will be generated in the current working directory.
*/
public class keybasedfileprocessor
{
private static void decryptfile(
string inputfilename,
string keyfilename,
char[] passwd,
string defaultfilename)
throws ioexception, nosuchproviderexception
{
inputstream in = new bufferedinputstream(new fileinputstream(inputfilename));
inputstream keyin = new bufferedinputstream(new fileinputstream(keyfilename));
decryptfile(in, keyin, passwd, defaultfilename);
keyin.close();
in.close();
}
/**
* decrypt the passed in message stream
*/
private static void decryptfile(
inputstream in,
inputstream keyin,
char[] passwd,
string defaultfilename)
throws ioexception, nosuchproviderexception
{
in = pgputil.getdecoderstream(in);
try
{
jcapgpobjectfactory pgpf = new jcapgpobjectfactory(in);
pgpencrypteddatalist enc;
object o = pgpf.nextobject();
//
// the first object might be a pgp marker packet.
//
if (o instanceof pgpencrypteddatalist)
{
enc = (pgpencrypteddatalist)o;
}
else
{
enc = (pgpencrypteddatalist)pgpf.nextobject();
}
//
// find the secret key
//
iterator it = enc.getencrypteddataobjects();
pgpprivatekey skey = null;
pgppublickeyencrypteddata pbe = null;
pgpsecretkeyringcollection pgpsec = new pgpsecretkeyringcollection(
pgputil.getdecoderstream(keyin), new jcakeyfingerprintcalculator());
while (skey == null && it.hasnext())
{
pbe = (pgppublickeyencrypteddata)it.next();
skey = pgpexampleutil.findsecretkey(pgpsec, pbe.getkeyid(), passwd);
}
if (skey == null)
{
throw new illegalargumentexception("secret key for message not found.");
}
inputstream clear = pbe.getdatastream(new jcepublickeydatadecryptorfactorybuilder().setprovider("bc").build(skey));
jcapgpobjectfactory plainfact = new jcapgpobjectfactory(clear);
object message = plainfact.nextobject();
while ( true ) {
if (message instanceof pgpcompresseddata)
{
pgpcompresseddata cdata = (pgpcompresseddata)message;
jcapgpobjectfactory pgpfact = new jcapgpobjectfactory(cdata.getdatastream());
message = pgpfact.nextobject();
}
if (message instanceof pgpliteraldata)
{
pgpliteraldata ld = (pgpliteraldata)message;
string outfilename = ld.getfilename();
if (outfilename.length() == 0)
{
outfilename = defaultfilename;
}
inputstream unc = ld.getinputstream();
outputstream fout = new bufferedoutputstream(new fileoutputstream(outfilename));
streams.pipeall(unc, fout);
fout.close();
break;
}
else if (message instanceof pgponepasssignaturelist)
{
system.out.println("encrypted message contains a signed message - not literal data.");
}
else if (message instanceof pgpsignaturelist)
{
system.out.println("encrypted message contains a signed message - not literal data.");
}
else
{
throw new pgpexception("message is not a simple encrypted file - type unknown.");
}
message = plainfact.nextobject();
}
if (pbe.isintegrityprotected())
{
if (!pbe.verify())
{
system.err.println("message failed integrity check");
}
else
{
system.err.println("message integrity check passed");
}
}
else
{
system.err.println("no message integrity check");
}
}
catch (pgpexception e)
{
system.err.println(e);
if (e.getunderlyingexception() != null)
{
e.getunderlyingexception().printstacktrace();
}
}
}
private static void encryptfile(
string outputfilename,
string inputfilename,
string enckeyfilename,
boolean armor,
boolean withintegritycheck)
throws ioexception, nosuchproviderexception, pgpexception
{
outputstream out = new bufferedoutputstream(new fileoutputstream(outputfilename));
pgppublickey enckey = pgpexampleutil.readpublickey(enckeyfilename);
encryptfile(out, inputfilename, enckey, armor, withintegritycheck);
out.close();
}
private static void encryptfile(
outputstream out,
string filename,
pgppublickey enckey,
boolean armor,
boolean withintegritycheck)
throws ioexception, nosuchproviderexception
{
if (armor)
{
out = new armoredoutputstream(out);
}
try
{
byte[] bytes = pgpexampleutil.compressfile(filename, compressionalgorithmtags.zip);
pgpencrypteddatagenerator encgen = new pgpencrypteddatagenerator(
new jcepgpdataencryptorbuilder(pgpencrypteddata.cast5).setwithintegritypacket(withintegritycheck).setsecurerandom(new securerandom()).setprovider("bc"));
encgen.addmethod(new jcepublickeykeyencryptionmethodgenerator(enckey).setprovider("bc"));
outputstream cout = encgen.open(out, bytes.length);
cout.write(bytes);
cout.close();
if (armor)
{
out.close();
}
}
catch (pgpexception e)
{
system.err.println(e);
if (e.getunderlyingexception() != null)
{
e.getunderlyingexception().printstacktrace();
}
}
}
public static void main(
string[] args)
throws exception
{
security.addprovider(new bouncycastleprovider());
if (args.length == 0)
{
system.err.println("usage: keybasedfileprocessor -e|-d [-a|ai] file [secretkeyfile passphrase|pubkeyfile]");
return;
}
if (args[0].equals("-e"))
{
if (args[1].equals("-a") || args[1].equals("-ai") || args[1].equals("-ia"))
{
encryptfile(args[2] ".asc", args[2], args[3], true, (args[1].indexof('i') > 0));
}
else if (args[1].equals("-i"))
{
encryptfile(args[2] ".bpg", args[2], args[3], false, true);
}
else
{
encryptfile(args[1] ".bpg", args[1], args[2], false, false);
}
}
else if (args[0].equals("-d"))
{
decryptfile(args[1], args[2], args[3].tochararray(), new file(args[1]).getname() ".out");
}
else
{
system.err.println("usage: keybasedfileprocessor -d|-e [-a|ai] file [secretkeyfile passphrase|pubkeyfile]");
}
}
}