前言
根据上一节生成的pgp公钥、密钥给文件加解密,传送门 Java生成PGP的公钥和密钥
一、使用步骤
1.加解密工具类
代码如下(示例):
private static final String PROVIDER_BC = "BC";
public static void encryptToStream(byte[] data, OutputStream out, String fileName, InputStream publicKey) throws IOException, PGPException {
byte[] compressedData = compressData(data, fileName);
PGPPublicKey pgpPublicKey = readPublicKey(publicKey);
PGPEncryptedDataGenerator pgpEncryptedDataGenerator = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5)
.setWithIntegrityPacket(true)
.setSecureRandom(new SecureRandom())
.setProvider(PROVIDER_BC));
pgpEncryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(pgpPublicKey).setProvider(PROVIDER_BC));
OutputStream encryptOutputStream = pgpEncryptedDataGenerator.open(out, compressedData.length);
encryptOutputStream.write(compressedData);
encryptOutputStream.close();
}
public static void decryptDataToStream(InputStream encryptedData, InputStream secretKeyInputStream, OutputStream out, String passphrase) throws IOException {
try (InputStream pgpEncryptedData = PGPUtil.getDecoderStream(encryptedData)) {
JcaPGPObjectFactory jcaPGPObjectFactory = new JcaPGPObjectFactory(pgpEncryptedData);
Object object = jcaPGPObjectFactory.nextObject();
PGPEncryptedDataList pgpEncryptedDataList;
if (object instanceof PGPEncryptedDataList) {
pgpEncryptedDataList = (PGPEncryptedDataList) object;
} else {
pgpEncryptedDataList = (PGPEncryptedDataList) jcaPGPObjectFactory.nextObject();
}
Iterator iterator = pgpEncryptedDataList.getEncryptedDataObjects();
PGPPrivateKey pgpPrivateKey = null;
PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData = null;
PGPSecretKeyRingCollection pgpSecretKeyRingCollection = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(secretKeyInputStream), new JcaKeyFingerprintCalculator());
while (pgpPrivateKey == null && iterator.hasNext()) {
pgpPublicKeyEncryptedData = (PGPPublicKeyEncryptedData) iterator.next();
pgpPrivateKey = findSecretKey(pgpSecretKeyRingCollection, pgpPublicKeyEncryptedData.getKeyID(), passphrase.toCharArray());
}
if (pgpPrivateKey == null) {
throw new IllegalArgumentException("secret key for message not found.");
}
InputStream pgpPrivateKeyInputStream = pgpPublicKeyEncryptedData.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider(PROVIDER_BC).build(pgpPrivateKey));
JcaPGPObjectFactory pgpPrivateKey_jcaPGPObjectFactory = new JcaPGPObjectFactory(pgpPrivateKeyInputStream);
Object message = pgpPrivateKey_jcaPGPObjectFactory.nextObject();
if (message instanceof PGPCompressedData) {
PGPCompressedData pgpCompressedData = (PGPCompressedData) message;
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(pgpCompressedData.getDataStream());
message = pgpFact.nextObject();
}
if (message instanceof PGPLiteralData) {
PGPLiteralData pgpLiteralData = (PGPLiteralData) message;
InputStream unc = pgpLiteralData.getInputStream();
Streams.pipeAll(unc, out);
} else if (message instanceof PGPOnePassSignatureList) {
throw new PGPException("encrypted message contains a signed message - not literal data.");
} else {
throw new PGPException("message is not a simple encrypted file - type unknown.");
}
if (pgpPublicKeyEncryptedData.isIntegrityProtected()) {
if (!pgpPublicKeyEncryptedData.verify()) {
log.error("message failed integrity check");
} else {
log.info("message integrity check passed");
}
} else {
log.error("no message integrity check");
}
} catch (PGPException e) {
log.error(e.getMessage(), e);
if (e.getUnderlyingException() != null) {
log.error(e.getUnderlyingException().getMessage(), e.getUnderlyingException());
}
}
}
public static byte[] compressData(byte[] data, String fileName) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PGPCompressedDataGenerator pgpCompressedDataGenerator = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP);
OutputStream compressStream = pgpCompressedDataGenerator.open(byteArrayOutputStream);
PGPLiteralDataGenerator pgpLiteralDataGenerator = new PGPLiteralDataGenerator();
OutputStream pgpOutputStream = pgpLiteralDataGenerator.open(compressStream,
PGPLiteralData.BINARY,
fileName,
data.length,
new Date()
);
pgpOutputStream.write(data);
pgpOutputStream.close();
compressStream.close();
return byteArrayOutputStream.toByteArray();
}
public static PGPPublicKey readPublicKey(InputStream keyInputStream) throws IOException, PGPException {
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(keyInputStream), new JcaKeyFingerprintCalculator());
Iterator keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext()) {
PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();
Iterator keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey key = (PGPPublicKey) keyIter.next();
if (key.isEncryptionKey()) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
public static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSecretKeyRingCollection, long keyID, char[] pass) throws PGPException {
PGPSecretKey pgpSecretKey = pgpSecretKeyRingCollection.getSecretKey(keyID);
if (pgpSecretKey == null) return null;
PBESecretKeyDecryptor pbeSecretKeyDecryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass);
return pgpSecretKey.extractPrivateKey(pbeSecretKeyDecryptor);
}
2.测试
代码如下(示例):
private static void encrypt() throws Exception {
String dataPath = "template.csv";
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(dataPath);
InputStream pubKey = new ClassPathResource("pgp/PUBLIC_KEY_2048.asc").getInputStream();
byte[] encData = toByteArray(inputStream);
FileOutputStream fileOutputStream = new FileOutputStream("template-encrypt.csv");
encryptToStream(encData, fileOutputStream, "template-encrypt.csv", pubKey);
}
private static void decrypt() throws Exception{
InputStream encryptedData = Thread.currentThread().getContextClassLoader().getResourceAsStream("template-encrypt.csv");
InputStream secretKey = new ClassPathResource("pgp/PRIVATE_KEY_2048.asc").getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream("template-decrypt.csv");
decryptDataToStream(encryptedData, secretKey, fileOutputStream, "");
}
public static void main(String[] args) throws Exception {
encrypt();
decrypt();
}
总结
通过公钥给文件加密,私钥给文件解密,RSA非对称加密算法。
|