提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
PGP加解密
PGP全称 Pretty Good Privacy, 由Phil Zimmermann在1991年开发,开源后由各个组织开发过不同版本的PGP实现,后由IETF成立OPenPGP工作组并统一制定了一套标准,也是本文中使用的版本。
PGP:由Phil Zimmermann开发,最终被赛门铁克收购,被收购后是一个商业软件,需要付费。
OpenPGP:由开源组织规范的PGP协议,定义了加密消息、签名、私钥和用于交换公钥的证书统一标准。
GPG(GnuPG):符合OpenPGP标准的开源加密软件,PGP的开源实现。
使用maven引入库
<!--空气城堡的加解密库类-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<!--工具集,非必须-->
<dependency>
<groupId>name.neuhalfen.projects.crypto.bouncycastle.openpgp</groupId>
<artifactId>bouncy-gpg</artifactId>
<version>2.2.0</version>
</dependency>
<!--断言工具,非必须-->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.16.1</version>
</dependency>
private static BouncyCastleProvider provider;
private static SecureRandom secureRandom;
static {
provider = new BouncyCastleProvider();
secureRandom = new SecureRandom();
Security.addProvider(provider);
}
/**
* <pre>
* to generate PGP key pairs.
* usage: generatePGPKeyPair(2048, true, "tom", "my pass", "/www/pub", "/www/pri");
* return key pairs, str[0]=publicKey, str[1]=privateKey.
* if armor, return armored key string, if unarmored, return key path.
* </pre>
*
* @param keyWidth key width, 1024/2048/3072/4096, recommend 2048
* @param armor designate if key format with armored or not
* @param identity key holder's identity, recommend write as email
* @param passPhrase password to open private key
* @return return key pairs, str[0]=publicKey, str[1]=privateKey.
* @throws Exception
*/
public static String[] generatePGPKeyPair(int keyWidth, boolean armor, String identity, String passPhrase,
String pubKeyFile, String priKeyFile) throws Exception {
KeyPairGenerator var1 = KeyPairGenerator.getInstance(MyPGPUtil.RSA, MyPGPUtil.PROVIDER_BC);
var1.initialize(keyWidth);
KeyPair var2 = var1.generateKeyPair();
OutputStream var3;
OutputStream var4;
try (ByteArrayOutputStream pubKeyOut = new ByteArrayOutputStream();
ByteArrayOutputStream priKeyOut = new ByteArrayOutputStream();
) {
if (armor) {
// key format with armored
var3 = new ArmoredOutputStream(priKeyOut);
var4 = new ArmoredOutputStream(pubKeyOut);
} else {
// key format without armored
var3 = new FileOutputStream(priKeyFile);
var4 = new FileOutputStream(pubKeyFile);
}
// the pass phrase for open private key
char[] var11 = passPhrase.toCharArray();
PGPDigestCalculator var6 = (new JcaPGPDigestCalculatorProviderBuilder()).build().get(2);
JcaPGPKeyPair var7 = new JcaPGPKeyPair(1, var2, new Date());
PGPSecretKey var8 = new PGPSecretKey(16, var7, identity, var6, (PGPSignatureSubpacketVector) null,
(PGPSignatureSubpacketVector) null, new JcaPGPContentSignerBuilder(var7.getPublicKey().getAlgorithm(), 8),
(new JcePBESecretKeyEncryptorBuilder(3, var6)).setProvider(MyPGPUtil.PROVIDER_BC).build(var11));
var8.encode(var3);
(var3).close();
PGPPublicKey var9 = var8.getPublicKey();
var9.encode(var4);
(var4).close();
// build return result
String[] keyPair = new String[2];
if (armor) {
keyPair[0] = pubKeyOut.toString();
keyPair[1] = priKeyOut.toString();
} else {
keyPair[0] = pubKeyFile;
keyPair[1] = priKeyFile;
}
return keyPair;
}
}
使用接收者的公钥加密,使用发送者的私钥签名
import java.io.*;
import java.security.*;
import java.util.Date;
import java.util.Iterator;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.jcajce.*;
import org.bouncycastle.util.io.Streams;
private static BouncyCastleProvider provider;
private static SecureRandom secureRandom;
static {
provider = new BouncyCastleProvider();
secureRandom = new SecureRandom();
Security.addProvider(provider);
}
/**
* encrypt with receiver's public key and sign with sender's secretKey
*
* @param encryptedData data to be encrypt and sign
* @param publicKeyPath receiver's public key path
* @param secretKeyPath sender's secretKey path
* @param password password to open secret key
* @param armor define whether to armor the output data
* @param withIntegrityCheck define whether to generate integrity check
* @return
* @throws Exception
*/
public static byte[] encryptAndSign(byte[] encryptedData, String publicKeyPath, String secretKeyPath,
String password, boolean armor, boolean withIntegrityCheck) throws Exception {
FileInputStream pubKey = new FileInputStream(publicKeyPath);
FileInputStream secretKeyIn = new FileInputStream(secretKeyPath);
PGPSecretKey secretKey = MyPGPUtil.readSecretKey(secretKeyIn);
PGPPublicKey publicKey = MyPGPUtil.readPublicKey(pubKey);
// output as byte data
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();) {
OutputStream out = new ByteArrayOutputStream();
if (armor) {
out = new ArmoredOutputStream(byteArrayOutputStream);
}
JcePGPDataEncryptorBuilder jcePGPDataEncryptorBuilder = (new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES))
.setWithIntegrityPacket(withIntegrityCheck)
.setSecureRandom(secureRandom)
.setProvider(provider);
PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(jcePGPDataEncryptorBuilder);
if (!publicKey.isEncryptionKey()) {
throw new IllegalArgumentException("passed in key not an encryption key!");
} else {
encryptedDataGenerator.addMethod((new JcePublicKeyKeyEncryptionMethodGenerator(publicKey))
.setProvider(new BouncyCastleProvider())
.setSecureRandom(secureRandom));
}
OutputStream encryptedOut = encryptedDataGenerator.open(out, new byte[MyPGPUtil.BUFFER_SIZE]);
PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
OutputStream compressedOut = compressedDataGenerator.open(encryptedOut, new byte[MyPGPUtil.BUFFER_SIZE]);
// extract private key from secret key
PGPPrivateKey privateKey = secretKey.extractPrivateKey(
(new JcePBESecretKeyDecryptorBuilder((new JcaPGPDigestCalculatorProviderBuilder())
.setProvider(provider)
.build()))
.setProvider(provider)
.build(password.toCharArray()));
// signer builder
JcaPGPContentSignerBuilder jcaPGPContentSignerBuilder = (new JcaPGPContentSignerBuilder(
secretKey.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1))
.setProvider(provider)
.setDigestProvider(provider);
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(jcaPGPContentSignerBuilder);
// private key to sign
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);
boolean firstTime = true;
Iterator it = secretKey.getPublicKey().getUserIDs();
while (it.hasNext() && firstTime) {
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, (String) it.next());
signatureGenerator.setHashedSubpackets(spGen.generate());
firstTime = false;
}
signatureGenerator.generateOnePassVersion(false).encode(compressedOut);
PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();
OutputStream literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY, "any str", new Date(),
new byte[MyPGPUtil.BUFFER_SIZE]);
ByteArrayInputStream in = new ByteArrayInputStream(encryptedData);
byte[] buf = new byte[MyPGPUtil.BUFFER_SIZE];
int len;
while ((len = in.read(buf)) > 0) {
literalOut.write(buf, 0, len);
signatureGenerator.update(buf, 0, len);
}
in.close();
literalDataGenerator.close();
signatureGenerator.generate().encode(compressedOut);
compressedDataGenerator.close();
encryptedDataGenerator.close();
if (armor) {
out.close();
}
byte[] bytes = byteArrayOutputStream.toByteArray();
return bytes;
}
}
接收者使用自己的私钥解密,使用发送者的公钥验签。
/**
* check sign and decryption
*
* @param encData data to be decrypt
* @param publicKeyPath public key to check sign(sender's key)
* @param pass pass to open secret key, pass was generated when creating the key pair.
* @param secretKeyPath Secret Key Path, ex: private_key_sender.asc
* @throws IOException
* @throws SignatureException
* @throws PGPException
*/
public static byte[] decryptAndVerify(byte[] encData, String publicKeyPath, String secretKeyPath,
String pass) throws Exception {
JcaKeyFingerprintCalculator jcaKeyFingerprintCalculator = new JcaKeyFingerprintCalculator();
InputStream in = PGPUtil.getDecoderStream(new ByteArrayInputStream(encData));
PGPObjectFactory pgpF = new PGPObjectFactory(in, jcaKeyFingerprintCalculator);
PGPEncryptedDataList enc;
// get obj from encryption data
Object o = pgpF.nextObject();
if (o instanceof PGPEncryptedDataList) {
enc = (PGPEncryptedDataList) o;
} else {
enc = (PGPEncryptedDataList) pgpF.nextObject();
}
Iterator it = enc.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData pbe = null;
FileInputStream secretKeyIn = new FileInputStream(secretKeyPath);
while (sKey == null && it.hasNext()) {
pbe = (PGPPublicKeyEncryptedData) it.next();
PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(
new BcPGPDigestCalculatorProvider()).build(pass.toCharArray());
PGPSecretKey secretKey = MyPGPUtil.readSecretKey(secretKeyIn);
if (secretKey != null) {
// sKey has nothing to do with it.hasNext, why put it in same block ?
sKey = secretKey.extractPrivateKey(decryptor);
}
}
if (sKey == null) {
throw new IllegalArgumentException("Unable to find secret key to decrypt the message");
}
// log.debug("keyId:{}", sKey.getKeyID());
InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
PGPObjectFactory plainFact = new PGPObjectFactory(clear, jcaKeyFingerprintCalculator);
Object message;
PGPOnePassSignatureList onePassSignatureList = null;
PGPSignatureList signatureList = null;
PGPCompressedData compressedData;
message = plainFact.nextObject();
ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();
while (message != null) {
if (message instanceof PGPCompressedData) {
compressedData = (PGPCompressedData) message;
plainFact = new PGPObjectFactory(compressedData.getDataStream(), jcaKeyFingerprintCalculator);
message = plainFact.nextObject();
}
if (message instanceof PGPLiteralData) {
Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput);
} else if (message instanceof PGPOnePassSignatureList) {
onePassSignatureList = (PGPOnePassSignatureList) message;
} else if (message instanceof PGPSignatureList) {
signatureList = (PGPSignatureList) message;
} else {
throw new PGPException("message unknown message type.");
}
message = plainFact.nextObject();
}
actualOutput.close();
PGPPublicKey publicKey = null;
byte[] output = actualOutput.toByteArray();
if (onePassSignatureList == null || signatureList == null) {
throw new PGPException("Poor PGP. Signatures not found.");
} else {
for (int i = 0; i < onePassSignatureList.size(); i++) {
PGPOnePassSignature ops = onePassSignatureList.get(0);
FileInputStream pubKeyIn = new FileInputStream(publicKeyPath);
PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(pubKeyIn), jcaKeyFingerprintCalculator);
publicKey = pgpRing.getPublicKey(ops.getKeyID());
if (publicKey != null) {
ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey);
// load data to check sign
ops.update(output);
PGPSignature signature = signatureList.get(i);
if (ops.verify(signature)) {
Iterator<?> userIds = publicKey.getUserIDs();
while (userIds.hasNext()) {
String userId = (String) userIds.next();
// get userId and check
log.debug("decryptAndVerify get userId from pubKey:{}", userId);
}
} else {
throw new SignatureException("Signature verification failed");
}
}
}
}
if (pbe.isIntegrityProtected() && !pbe.verify()) {
throw new PGPException("Data is integrity protected but integrity is lost.");
} else if (publicKey == null) {
throw new SignatureException("Signature not found");
} else {
ByteArrayOutputStream fOut = new ByteArrayOutputStream();
// flush output to file
fOut.write(output);
fOut.flush();
IOUtils.close(fOut);
return fOut.toByteArray();
}
}
import java.io.*;
import java.security.NoSuchProviderException;
import java.util.Iterator;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
/**
* Create by wiwi on 2020/9/22 17:53 <p>
* Description: <p>
* PGP Util, also see to org.bouncycastle.openpgp.examples.PGPExampleUtil
*
* @see org.bouncycastle.openpgp.examples.PGPExampleUtil
* @since
*/
class MyPGPUtil {
static final int BUFFER_SIZE = 1 << 16;
static final String PROVIDER_BC = "BC";
static final String RSA = "RSA";
private MyPGPUtil() {
}
static byte[] compressFile(String var0, int var1) throws IOException {
ByteArrayOutputStream var2 = new ByteArrayOutputStream();
PGPCompressedDataGenerator var3 = new PGPCompressedDataGenerator(var1);
PGPUtil.writeFileToLiteralData(var3.open(var2), 'b', new File(var0));
var3.close();
return var2.toByteArray();
}
static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection var0, long var1, char[] var3) throws PGPException, NoSuchProviderException {
PGPSecretKey var4 = var0.getSecretKey(var1);
return var4 == null ? null : var4.extractPrivateKey((new JcePBESecretKeyDecryptorBuilder()).setProvider("BC").build(var3));
}
static PGPPublicKey readPublicKey(String var0) throws IOException, PGPException {
BufferedInputStream var1 = new BufferedInputStream(new FileInputStream(var0));
PGPPublicKey var2 = readPublicKey((InputStream) var1);
var1.close();
return var2;
}
static PGPPublicKey readPublicKey(InputStream var0) throws IOException, PGPException {
PGPPublicKeyRingCollection var1 = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(var0), new JcaKeyFingerprintCalculator());
Iterator var2 = var1.getKeyRings();
while (var2.hasNext()) {
PGPPublicKeyRing var3 = (PGPPublicKeyRing) var2.next();
Iterator var4 = var3.getPublicKeys();
while (var4.hasNext()) {
PGPPublicKey var5 = (PGPPublicKey) var4.next();
if (var5.isEncryptionKey()) {
return var5;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
static PGPSecretKey readSecretKey(String var0) throws IOException, PGPException {
BufferedInputStream var1 = new BufferedInputStream(new FileInputStream(var0));
PGPSecretKey var2 = readSecretKey((InputStream) var1);
var1.close();
return var2;
}
static PGPSecretKey readSecretKey(InputStream var0) throws IOException, PGPException {
PGPSecretKeyRingCollection var1 = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(var0), new JcaKeyFingerprintCalculator());
Iterator var2 = var1.getKeyRings();
while (var2.hasNext()) {
PGPSecretKeyRing var3 = (PGPSecretKeyRing) var2.next();
Iterator var4 = var3.getSecretKeys();
while (var4.hasNext()) {
PGPSecretKey var5 = (PGPSecretKey) var4.next();
if (var5.isSigningKey()) {
return var5;
}
}
}
throw new IllegalArgumentException("Can't find signing key in key ring.");
}
}
/**
* Create by wiwi on 2020/9/22 18:22 <p>
* Description: <p>
*
* @since
*/
public class PGPTest {
public static void main(String[] args) throws Exception {
// pgp2();
// generatePGP_armor(); // 生成 armor 格式的密钥对
// generatePGP_unarmored(); // 生成非 armor 格式的密钥对
}
private static void generatePGP_unarmored() throws Exception {
String[] keyPair = PGP.generateUnarmoredPGPKeyPair(2048, "wiwi2019@163.com", "test passphrase", "/test/key1", "/test/key2");
System.out.println(keyPair[0]);
System.out.println(keyPair[1]);
}
private static void generatePGP_armor() throws Exception {
String[] keyPair = PGP.generateArmoredPGPKeyPair(2048, "wiwi2019@163.com", "java passphrase");
System.out.println(keyPair[0]);
System.out.println(keyPair[1]);
}
private static void pgp2() throws Exception {
String data = "-----hello PGP-----";
// 将上述生成的秘钥粘贴进文件并保存
String receiverPubKey = "/test/MY_PGP_PUB_KEY.asc";
String senderPriKey = "/test/THIRD_PGP_PRI_KEY.asc";
String senderPriKeyPass = "java passphrase";
byte[] encData = data.getBytes();
byte[] encryptAndSign = PGP.encryptAndSign(encData, receiverPubKey, senderPriKey, senderPriKeyPass);
System.out.println(new String(encryptAndSign));
System.out.println("--------------a separator-----------------");
String receiverPriKey = "/test/MY_PGP_PRI_KEY.asc";
String receiverPass = "test passphrase";
String senderPubKey = "/test/THIRD_PGP_PUB_KEY.asc";
byte[] verify = PGP.decryptAndVerify(encryptAndSign, senderPubKey, receiverPriKey, receiverPass);
System.out.println(new String(verify));
}
}
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.66
mQENBF9rCWMBCADdPtQ0ElM9w2I7WZUPOupfdDTi8hJ1Mwi3R0YUQoIyT+9+dock
r+jS97FhB29SI7oQgh/bHGxxq0Pt7koMk6zFmOaeGqSuFHhO5DncZGDiuM+zx4n7
X9nFAVHlhlo+KcJl6ZDCrFkpNyp1eVaMjfhwTRaUNcKKRxb2+O0GwBmdjlHkjUH7
VBmwmTWSRk9KhKj77pFFpegJklQiqaepmR4/iWPwJiwgIjOk6yazlLgM1B5vvxNg
nDfDPsqzHkuSn4NxNEP3a/P9TzL2yKlUr4Bmt/XvjjPmnq5I954v5EZ60F43CZ6A
8FDK7Zj1C+pGHsU3w4DePw57X7xVfWmdYVbbABEBAAG0F21wdXJzZUBzdGF0ZWZv
cnR1bWUuY29tiQEcBBABCAAGBQJfawljAAoJEPZ2+ejYz07SLZEIAJCP7gnSqmjA
cnyz837h5FFAE5kbEys4RGgFm0VBbU5aoGcVBTEUyNEYhdNep61OjC0QHfGd6ePJ
3xkHOV/pqurCFSlOXywPh1otBK5cUa7CSPsYnve/rxieG82o17sFbwysfJUglRl4
e0AmUIBJ3xOf6p0dkxmaAO5Qdr+p0g4xNuj6Z8clCh/g8HUhSNDoPtNjP4GwT/CR
JpKscEMEL/xAZ6iygmIv0kOvhmPMgslUYRelA6R8gipHCroIc++jd4c/ZtEa5bhF
TADgOz7N8L7nIG1ktOdRg9ZTtGkwv+xCewCKdJqBEQIErjOQ7zbwIQgV+bWbLzJi
5F/cNiImOG0=
=SPVs
-----END PGP PUBLIC KEY BLOCK-----
----------------------下面是私钥---------------------
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: BCPG v1.66
lQO+BF9rCWMBCADdPtQ0ElM9w2I7WZUPOupfdDTi8hJ1Mwi3R0YUQoIyT+9+dock
r+jS97FhB29SI7oQgh/bHGxxq0Pt7koMk6zFmOaeGqSuFHhO5DncZGDiuM+zx4n7
X9nFAVHlhlo+KcJl6ZDCrFkpNyp1eVaMjfhwTRaUNcKKRxb2+O0GwBmdjlHkjUH7
VBmwmTWSRk9KhKj77pFFpegJklQiqaepmR4/iWPwJiwgIjOk6yazlLgM1B5vvxNg
nDfDPsqzHkuSn4NxNEP3a/P9TzL2yKlUr4Bmt/XvjjPmnq5I954v5EZ60F43CZ6A
8FDK7Zj1C+pGHsU3w4DePw57X7xVfWmdYVbbABEBAAH+AwMCCyTZz/1NLxxgoPxH
7mNbLvdSANetZlZc+klJq0xVVYN2NYj5ia3ZgKwJoAaaZbwADzH7xuvWPyYgqtix
qyKnom3FQBt+Yv2gV4/j6Q2Y6jSXOqKG9VxnMqjjlxlxPShcTP2EJUx5+q8GFRuy
/E/VSjcaNgnrVNCGKoVYFDM0bDLlPbZdijc+27kn1nQrsPiUKJEEbXokPBIWhB5V
zMgdsK9Pce1fvUmkTFPIKHTV+B+cYgG5t5BkyiJxdR1cobukg/7M7jgfBR6haRXp
wqBvodpizWde6yOkU+h9su+sejuqtYxoOygdJa4okkkUf+JYBw1FIg8CzJH1rWhW
RmUCcocLYz+gO98kFBNbMlXuPSjuIFu3671FlTJKKvKhAPwKtHmIPs2NX4kU9LuD
Q7AT9aIN2adHeS86G7liuyUWLKH/3biFK+Qfhid08b4c3Ovdg9VL5huIKazv+IHH
t8tI9LT3/qTXNJFMNrgERLW1W0J6e2XmQPPXXlskOM0SuDf8OgLp+402Hr3ZisS9
Kwr2FC7Ols/6G17w6zrk+m1ntinZlI1muG58y8BvYFglenTq3NwgiJiLFlSJpxS3
G+/pG5V2sptIDUdExdBnEi8q8aLGGMi6lmtI7cBiRoQA1U8Cn2j3LIFvkVFGXvok
JjHh8WxiekcRItQ1tcqwyUJ6+Ql5qGslOKK9xFDA7eO4VoO2X85nj/keXbaJd8Nm
1A/R/scO8yEbdhGGu+McdYL7fSNZbMT68ajCDzVunW7J668QUxTAg9yJtUVqHjWL
4OzeeRfVNaLUaCboTPtmT7+UFdCoSrzASLa4CjyH94q2IcdDt0INS0UEqYwuHIgv
QA71In88CqaRfleSND8kqzcmVr3dIIM0bwg4J5sTepQSqqpeOXVIkeeenqScmYJF
4bQXbXB1cnNlQHN0YXRlZm9ydHVtZS5jb22JARwEEAEIAAYFAl9rCWMACgkQ9nb5
6NjPTtItkQgAkI/uCdKqaMByfLPzfuHkUUATmRsTKzhEaAWbRUFtTlqgZxUFMRTI
0RiF016nrU6MLRAd8Z3p48nfGQc5X+mq6sIVKU5fLA+HWi0ErlxRrsJI+xie97+v
GJ4bzajXuwVvDKx8lSCVGXh7QCZQgEnfE5/qnR2TGZoA7lB2v6nSDjE26PpnxyUK
H+DwdSFI0Og+02M/gbBP8JEmkqxwQwQv/EBnqLKCYi/SQ6+GY8yCyVRhF6UDpHyC
KkcKughz76N3hz9m0RrluEVMAOA7Ps3wvucgbWS051GD1lO0aTC/7EJ7AIp0moER
AgSuM5DvNvAhCBX5tZsvMmLkX9w2IiY4bQ==
=rmYP
-----END PGP PRIVATE KEY BLOCK-----
-----BEGIN PGP MESSAGE-----
Version: BCPG v1.66
hQEMAzYf+y1QT6gLAQf9F2Cs6SjREWxeirf7Fu6jN1p9CmKt1n1gLFnTCi/+Xcu/
87keLBiGCaGY9SfVjPC3c+zwc2AE96w6pBgkm3sXrqAQo0yJ5+IzGnj1Y+o1JJ97
XpGKSxJVsOphFNSAa+V6NyX64C9IVU1FvRk69tSJEKDbN0VbNWw3dpOCu3JV2pGf
KjFh9GKS5pYufNePP+5z3sx4f5f3FSbvbnR/Q2QjLy4QLH8sMQH+0I4CYW0kJFcH
kqjvEjm99lDeLUKYBmdOqxPtFcYZXtvJUevaBiPI++vIHzcc/uIo67yoBnRDiRhA
fP3JHHy3y3EQIph/IZcp1bveIV7STL26fWK/aKMfutLAwAElPKKIHYLYQUJaXHi2
hdH2c87l/Odez8sUSPvDNrx+KNNgcw6Rqas4I5v9yPiY7KjtxoT6p3ZokuvP7U4o
nhG3wZW28wM5kFNdvCF3OJJfkDsu501nuCicgehcjq9kx+l4fVPwV6IxOyYmQInZ
xDgTFHEab382cLzBoEbBtrV+shceAezxy+MDwkd2o57VycxzX+Kpxnzt1MD4eMDy
SycuYQudYOeihO6d4F+bHh7T4Vqag6t6aT0TzQgs3ipunhaJqIANh5iEsTBU/41T
nVpKs0c86BEPzc3X4plK69Z/JPGVd4egXa0jiGRk6226ww6MZomJAv2j/CGOO7Qd
OoetQ8hMUsbIJEc4G2LPyIxhc2mxgXdX4Dof7qpaORz/et0M6NR+OWcs2hm7YJVu
JXKXNS+e9bi4RTghF/bA8NcN58mRmizSi6mvs573vlJJjh0nJpESZh8RJCCSf6Hi
1oUlhSms4Iea5hX5LZ3fbREEwWysK4HRg8drsHJ9Kwn21Q==
=hXUY
-----END PGP MESSAGE-----
若需要对文件做加解密,只需要把
ByteArrayInputStream 改为 FileInputStream, ByteArrayOutputStream 改为 FileOutputStream 即可.