OpenPGP 号称是世界上使用最广泛的邮件加密标准. OpenPGP is the most widely used email encryption standard in the world. ( http://www.openpgp.org/ )
这篇例子介绍如何使用这个标准进行文件的加密解密 (https://www.bouncycastle.org/latest_releases.html, 需要下载: bcprov-jdk15on-151.jar, bcpg-jdk15on-151.jar).
主要是使用bouncycastle提供的OpenPGP的库来完成这个功能,参照了其提供的示例程序,进行了部分改动 ( Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包。它支持大量的密码术算法,并提供 JCE 1.2.1 的实现。因为 Bouncy Castle 被设计成轻量级的,所以从 J2SE 1.4 到 J2ME(包括 MIDP)平台,它都可以运行。它是在 MIDP 上运行的唯一完整的密码术包。)
- 添加循环遍历来查找第一个可用的message
- 需要注意的是在main函数中的,如果不添加这一句的话 Security.addProvider(new BouncyCastleProvider()); 程序运行中会报错:No such Provider "BC"
- 错误Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters , 这是因为java缺省的库支持的key长度比较短,需要到oracle的网站上去下载一个支持更长key的库覆盖原有的库文件
/lib/securty/ 目录下的两个jar文件
local_policy.jar and US_export_policy.jar
搜索这个文件: Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
下载页面(以JDK6为例):http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
package com.test.test;
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]"); }
}
} -