网站建设的难处,微信链接怎么wordpress,中国国际园林博览会,深圳12个区地图文章目录 PGPOpenPGPGPG工作原理工作流程用途案例说明过程 代码实现pom依赖PgpEncryptionUtilPgpDecryptionUtilCommonUtilsPgpEncryptionTest 小结 PGP
PGP (Pretty Good Privacy) 是一种加密通信协议#xff0c;用于保护电子邮件和文件的安全性和隐私。它通过使用加密、数字… 文章目录 PGPOpenPGPGPG工作原理工作流程用途案例说明过程 代码实现pom依赖PgpEncryptionUtilPgpDecryptionUtilCommonUtilsPgpEncryptionTest 小结 PGP
PGP (Pretty Good Privacy) 是一种加密通信协议用于保护电子邮件和文件的安全性和隐私。它通过使用加密、数字签名和压缩技术来确保数据的保密性、完整性和可验证性。
GP最初由麻省理工学院的Nick embrace和Eric Hughes开发后来由Phil Zimmermann进一步发展。它使用公钥加密和私钥解密的机制以确保只有信息的接收者才能解密和阅读邮件内容。
PGP的主要优点是它易于使用并能在大多数流行的电子邮件客户端中集成。然而随着更高级的加密技术和标准如OpenPGP和GPG的出现PGP已经在一定程度上被这些新标准取代。
PGP不仅仅用于电子邮件它也可以用于加密文件和数据。 加密和解密: PGP 使用对称加密和非对称加密相结合的方式来实现加密和解密。发送方使用接收方的公钥对消息进行加密接收方使用自己的私钥对消息进行解密。此外PGP 还支持对数据进行数字签名以确保数据的完整性和验证发送方的身份。 密钥管理: PGP 使用密钥对来管理加密和解密过程。每个用户都有一个公钥和一个私钥。公钥用于加密消息私钥用于解密消息。这些密钥对可以通过密钥服务器或密钥交换方式获取。 数字签名: PGP 允许用户使用自己的私钥对消息进行数字签名。接收方可以使用发送方的公钥验证签名以确保消息的完整性和发送方的身份。 信任模型: PGP 使用基于信任的模型来验证密钥的真实性。用户可以通过直接交换密钥、使用信任链或通过信任服务器来建立信任。 开放标准: PGP 是一种开放标准意味着任何人都可以实现和使用该协议而不受限于特定的厂商或供应商。
总的来说PGP 是一种强大的加密协议用于保护通信内容的机密性和完整性同时提供身份验证机制。它广泛用于电子邮件和文件加密以确保用户的数据安全和隐私。 OpenPGP和GPGGNU Privacy Guard是PGPPretty Good Privacy的开放标准和自由软件实现。 随着时间的推移PGP的标准和实现逐渐演进OpenPGP和GPG就是其中的两个重要发展。 OpenPGP
OpenPGP是一个开放标准它定义了一种用于加密和数字签名数据的协议。这个标准允许不同的加密软件相互兼容这意味着使用不同OpenPGP实现的用户可以安全地交换加密信息。OpenPGP标准是由RFC 4880定义的它包括了公钥和私钥的生成、交换和验证方法以及加密和签名的算法。
GPG
GPG是OpenPGP的一个流行实现它是GNU项目的一部分由GNU通用公共许可证GPL发布。GPG是一个命令行工具可以在多种操作系统中运行包括Linux、macOS和Windows。GPG提供了创建和验证数字签名、加密文件和电子邮件以及安全地交换密钥等功能。
GPG的核心组件包括
keyring用于存储公钥和私钥。gpg命令行工具用于执行加密、解密、签名和验证等操作。gpgconf用于配置GPG的命令行工具。gpg-agent一个守护进程用于提供密钥管理、加密和服务器功能。
GPG的使用场景包括
安全地交换电子邮件和文件。验证软件的完整性和来源。保护个人隐私和商业机密。 工作原理
PGPPretty Good Privacy涉及加密、数字签名和密钥管理等关键步骤 密钥生成: 用户生成一对公钥和私钥。公钥用于加密消息私钥用于解密消息和生成数字签名。 加密: 发送方使用接收方的公钥来加密消息。这样只有拥有相应私钥的接收方才能解密消息。 数字签名: 发送方使用自己的私钥对消息进行签名。接收方使用发送方的公钥验证签名确保消息的完整性和发送方的身份。 密钥管理: 用户可以通过密钥服务器或直接交换密钥的方式来管理和共享公钥。 工作流程 密钥交换: 发送方和接收方需要交换公钥。这可以通过密钥服务器、直接交换或其他安全渠道完成。 加密消息: 发送方选择要发送的消息并使用接收方的公钥对消息进行加密。发送方可以选择使用对称加密算法来加密消息内容然后再使用接收方的公钥来加密对称密钥这样可以提高效率。发送方发送加密后的消息给接收方。 解密消息: 接收方使用自己的私钥解密接收到的消息。如果消息有数字签名接收方使用发送方的公钥验证签名。 数字签名验证: 接收方使用发送方的公钥验证数字签名确保消息的完整性和发送方的身份。 信任管理: 用户可以建立信任关系以确保使用其他用户的公钥时其真实性。信任关系可以通过直接交换密钥、信任链或信任服务器来建立。
总的来说PGP的工作原理涉及加密、数字签名和密钥管理通过这些步骤保证了消息的机密性、完整性和可验证性。 用途 PGP 本质上有三个主要用途
发送和接收加密电子邮件。验证向你发送消息的人的身份。加密文件。
案例说明
假设Alice和Bob是两个使用PGP加密通信的用户。他们希望通过电子邮件进行安全通信以保护其消息的机密性和完整性。
过程 密钥生成: Alice 和 Bob 分别生成一对公钥和私钥。 密钥交换: Alice 将她的公钥发送给 Bob而 Bob 也将他的公钥发送给 Alice。这可以通过安全的电子邮件或其他安全通道完成。 加密消息: Alice 决定向 Bob 发送一封加密的电子邮件。Alice 使用 Bob 的公钥将邮件内容进行加密。Alice 还可以选择使用对称加密算法来加密邮件内容然后再使用 Bob 的公钥来加密对称密钥以提高效率。 解密消息: Bob 收到 Alice 发送的加密邮件后使用自己的私钥解密邮件内容。如果邮件有数字签名Bob 使用 Alice 的公钥验证签名确保邮件的完整性和 Alice 的身份。 数字签名验证: 如果 Alice 在邮件中添加了数字签名Bob 使用 Alice 的公钥验证签名以确保邮件的完整性和 Alice 的身份。 信任管理: Alice 和 Bob 可能通过直接交换公钥或使用信任服务器来建立信任关系以确保对方公钥的真实性。
在这个案例中Alice 和 Bob 使用PGP协议加密和解密他们之间的通信同时还可以使用数字签名来确保消息的完整性和验证发送方的身份。通过这种方式他们可以安全地交换信息而不用担心被未经授权的第三方窃取或篡改。 代码实现
在Java中完全实现PGP协议需要使用第三方库因为PGP是一个复杂的加密协议。常用的库之一是Bouncy Castle. pom依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.artisan/groupIdartifactIdpgp-encryption/artifactIdversion1.0-SNAPSHOT/versionbuildpluginsplugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-compiler-plugin/artifactIdconfigurationsource8/sourcetarget8/target/configuration/plugin/plugins/builddependencies!-- https://mvnrepository.com/artifact/junit/junit --dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.13.2/versionscopetest/scope/dependency!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --dependencygroupIdorg.bouncycastle/groupIdartifactIdbcpg-jdk15on/artifactIdversion1.70/versionscopecompile/scope/dependency!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --dependencygroupIdorg.bouncycastle/groupIdartifactIdbcpkix-jdk15on/artifactIdversion1.70/versionscopecompile/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.24/versionscopeprovided/scope/dependency!-- https://mvnrepository.com/artifact/commons-io/commons-io --dependencygroupIdcommons-io/groupIdartifactIdcommons-io/artifactIdversion2.11.0/version/dependency/dependencies/projectPgpEncryptionUtil
package com.artisan.pgpUtils;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Objects;/*** author artisan*/
Getter
Builder
AllArgsConstructor
public class PgpEncryptionUtil {/*** 将Bouncy Castle添加到JVM中*/static {// 将Bouncy Castle添加到JVM中if (Objects.isNull(Security.getProvider(BouncyCastleProvider.PROVIDER_NAME))) {Security.addProvider(new BouncyCastleProvider());}}/*** 压缩算法默认为ZIP*/Builder.Defaultprivate int compressionAlgorithm CompressionAlgorithmTags.ZIP;/*** 对称密钥算法默认为AES-128*/Builder.Defaultprivate int symmetricKeyAlgorithm SymmetricKeyAlgorithmTags.AES_128;/*** 是否启用ASCII Armor默认为true*/Builder.Defaultprivate boolean armor true;/*** 是否启用完整性检查默认为true*/Builder.Defaultprivate boolean withIntegrityCheck true;/*** 缓冲区大小默认为65536字节*/Builder.Defaultprivate int bufferSize 1 16;/*** 加密方法将明文数据使用公钥进行加密** param encryptOut* param clearIn* param length* param publicKeyIn* throws IOException* throws PGPException*/public void encrypt(OutputStream encryptOut, InputStream clearIn, long length, InputStream publicKeyIn)throws IOException, PGPException {// 创建压缩数据生成器PGPCompressedDataGenerator compressedDataGenerator new PGPCompressedDataGenerator(compressionAlgorithm);// 创建PGP加密数据生成器PGPEncryptedDataGenerator pgpEncryptedDataGenerator new PGPEncryptedDataGenerator(// 配置加密数据生成器new JcePGPDataEncryptorBuilder(symmetricKeyAlgorithm).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider(BouncyCastleProvider.PROVIDER_NAME));// 添加公钥pgpEncryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(CommonUtils.getPublicKey(publicKeyIn)));// 如果启用ASCII Armor则创建ArmoredOutputStreamif (armor) {encryptOut new ArmoredOutputStream(encryptOut);}// 打开加密输出流OutputStream cipherOutStream pgpEncryptedDataGenerator.open(encryptOut, new byte[bufferSize]);// 将压缩数据生成器打开并将明文数据以字面形式复制到加密输出流中CommonUtils.copyAsLiteralData(compressedDataGenerator.open(cipherOutStream), clearIn, length, bufferSize);// 依次关闭所有输出流compressedDataGenerator.close();cipherOutStream.close();encryptOut.close();}/*** 加密方法返回加密后的字节数组** param clearData* param pubicKeyIn* return* throws PGPException* throws IOException*/public byte[] encrypt(byte[] clearData, InputStream pubicKeyIn) throws PGPException, IOException {ByteArrayInputStream inputStream new ByteArrayInputStream(clearData);ByteArrayOutputStream outputStream new ByteArrayOutputStream();encrypt(outputStream, inputStream, clearData.length, pubicKeyIn);return outputStream.toByteArray();}// 加密方法返回加密后的输入流public InputStream encrypt(InputStream clearIn, long length, InputStream publicKeyIn)throws IOException, PGPException {File tempFile File.createTempFile(pgp-, -encrypted);encrypt(Files.newOutputStream(tempFile.toPath()), clearIn, length, publicKeyIn);return Files.newInputStream(tempFile.toPath());}/*** 加密方法将明文数据使用公钥字符串进行加密** param clearData* param publicKeyStr* return* throws PGPException* throws IOException*/public byte[] encrypt(byte[] clearData, String publicKeyStr) throws PGPException, IOException {return encrypt(clearData, IOUtils.toInputStream(publicKeyStr, Charset.defaultCharset()));}/*** 加密方法返回加密后的输入流** param clearIn* param length* param publicKeyStr* return* throws IOException* throws PGPException*/public InputStream encrypt(InputStream clearIn, long length, String publicKeyStr) throws IOException, PGPException {return encrypt(clearIn, length, IOUtils.toInputStream(publicKeyStr, Charset.defaultCharset()));}
}
PgpDecryptionUtil package com.artisan.pgpUtils;import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.security.Security;
import java.util.Iterator;
import java.util.Objects;/*** author artisan*/
public class PgpDecryptionUtil {static {// 将Bouncy Castle添加到JVM中if (Objects.isNull(Security.getProvider(BouncyCastleProvider.PROVIDER_NAME))) {Security.addProvider(new BouncyCastleProvider());}}/*** 私钥密码*/private final char[] passCode;/*** 密钥环集合*/private final PGPSecretKeyRingCollection pgpSecretKeyRingCollection;/*** param privateKeyIn* param passCode* throws IOException* throws PGPException*/public PgpDecryptionUtil(InputStream privateKeyIn, String passCode) throws IOException, PGPException {this.passCode passCode.toCharArray(); // 将密码转换为字符数组// 从输入流中读取PGP密钥环集合this.pgpSecretKeyRingCollection new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateKeyIn), new JcaKeyFingerprintCalculator());}/*** param privateKeyStr* param passCode* throws IOException* throws PGPException*/public PgpDecryptionUtil(String privateKeyStr, String passCode) throws IOException, PGPException {// 将私钥字符串转换为输入流this(IOUtils.toInputStream(privateKeyStr, Charset.defaultCharset()), passCode);}/*** 查找指定ID的私钥** param keyID* return* throws PGPException*/private PGPPrivateKey findSecretKey(long keyID) throws PGPException {// 从密钥环中获取指定ID的私钥PGPSecretKey pgpSecretKey pgpSecretKeyRingCollection.getSecretKey(keyID);// 使用密码解密私钥return pgpSecretKey null ? null : pgpSecretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(passCode));}/*** 解密方法将加密输入流解密为明文输出流** param encryptedIn* param clearOut* throws PGPException* throws IOException*/public void decrypt(InputStream encryptedIn, OutputStream clearOut)throws PGPException, IOException {// 去除ASCII Armor并返回底层的二进制加密流encryptedIn PGPUtil.getDecoderStream(encryptedIn);JcaPGPObjectFactory pgpObjectFactory new JcaPGPObjectFactory(encryptedIn);Object obj pgpObjectFactory.nextObject();// 第一个对象可能是标记数据包PGPEncryptedDataList pgpEncryptedDataList (obj instanceof PGPEncryptedDataList)? (PGPEncryptedDataList) obj : (PGPEncryptedDataList) pgpObjectFactory.nextObject();PGPPrivateKey pgpPrivateKey null;PGPPublicKeyEncryptedData publicKeyEncryptedData null;IteratorPGPEncryptedData encryptedDataItr pgpEncryptedDataList.getEncryptedDataObjects();while (pgpPrivateKey null encryptedDataItr.hasNext()) {publicKeyEncryptedData (PGPPublicKeyEncryptedData) encryptedDataItr.next();pgpPrivateKey findSecretKey(publicKeyEncryptedData.getKeyID()); // 查找私钥}if (Objects.isNull(publicKeyEncryptedData)) {throw new PGPException(无法生成PGPPublicKeyEncryptedData对象);}if (pgpPrivateKey null) {throw new PGPException(无法提取私钥);}CommonUtils.decrypt(clearOut, pgpPrivateKey, publicKeyEncryptedData); // 调用通用解密方法}/*** 解密方法将加密字节数组解密为明文字节数组** param encryptedBytes* return* throws PGPException* throws IOException*/public byte[] decrypt(byte[] encryptedBytes) throws PGPException, IOException {ByteArrayInputStream encryptedIn new ByteArrayInputStream(encryptedBytes);ByteArrayOutputStream clearOut new ByteArrayOutputStream();// 调用解密方法decrypt(encryptedIn, clearOut);// 将解密后的明文字节数组返回return clearOut.toByteArray();}
}
CommonUtils
package com.artisan.pgpUtils;import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Date;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Optional;/*** author artisan*/
public class CommonUtils {/*** 使用提供的私钥解密公钥加密数据并将其写入输出流** param clearOut 要写入数据的输出流* param pgpPrivateKey 私钥实例* param publicKeyEncryptedData 公钥加密数据实例* throws IOException IO相关错误* throws PGPException PGP相关错误*/static void decrypt(OutputStream clearOut, PGPPrivateKey pgpPrivateKey, PGPPublicKeyEncryptedData publicKeyEncryptedData) throws IOException, PGPException {PublicKeyDataDecryptorFactory decryptorFactory new JcePublicKeyDataDecryptorFactoryBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(pgpPrivateKey);InputStream decryptedCompressedIn publicKeyEncryptedData.getDataStream(decryptorFactory);JcaPGPObjectFactory decCompObjFac new JcaPGPObjectFactory(decryptedCompressedIn);PGPCompressedData pgpCompressedData (PGPCompressedData) decCompObjFac.nextObject();InputStream compressedDataStream new BufferedInputStream(pgpCompressedData.getDataStream());JcaPGPObjectFactory pgpCompObjFac new JcaPGPObjectFactory(compressedDataStream);Object message pgpCompObjFac.nextObject();if (message instanceof PGPLiteralData) {PGPLiteralData pgpLiteralData (PGPLiteralData) message;InputStream decDataStream pgpLiteralData.getInputStream();IOUtils.copy(decDataStream, clearOut);clearOut.close();} else if (message instanceof PGPOnePassSignatureList) {throw new PGPException(加密消息包含签名消息而不是文字数据);} else {throw new PGPException(消息不是简单加密文件 - 类型未知);}// 执行完整性检查if (publicKeyEncryptedData.isIntegrityProtected()) {if (!publicKeyEncryptedData.verify()) {throw new PGPException(消息未通过完整性检查);}}}/*** 将输入流中的数据复制到pgp文字数据并写入提供的输出流** param outputStream 输出流要写入其中的数据* param in 要读取数据的输入流* param length 要读取的数据长度* param bufferSize 缓冲区大小因为使用缓冲区加速复制* throws IOException IO相关错误*/static void copyAsLiteralData(OutputStream outputStream, InputStream in, long length, int bufferSize) throws IOException {PGPLiteralDataGenerator lData new PGPLiteralDataGenerator();OutputStream pOut lData.open(outputStream, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE,Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), new byte[bufferSize]);byte[] buff new byte[bufferSize];try {int len;long totalBytesWritten 0L;while (totalBytesWritten length (len in.read(buff)) 0) {pOut.write(buff, 0, len);totalBytesWritten len;}pOut.close();} finally {// 清除缓冲区Arrays.fill(buff, (byte) 0);// 关闭输入流in.close();}}/*** 从密钥输入流获取公钥** param keyInputStream 密钥输入流* return PGPPublicKey实例* throws IOException IO相关错误* throws PGPException PGP相关错误*/static PGPPublicKey getPublicKey(InputStream keyInputStream) throws IOException, PGPException {PGPPublicKeyRingCollection pgpPublicKeyRings new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyInputStream), new JcaKeyFingerprintCalculator());IteratorPGPPublicKeyRing keyRingIterator pgpPublicKeyRings.getKeyRings();while (keyRingIterator.hasNext()) {PGPPublicKeyRing pgpPublicKeyRing keyRingIterator.next();OptionalPGPPublicKey pgpPublicKey extractPGPKeyFromRing(pgpPublicKeyRing);if (pgpPublicKey.isPresent()) {return pgpPublicKey.get();}}throw new PGPException(无效的公钥);}private static OptionalPGPPublicKey extractPGPKeyFromRing(PGPPublicKeyRing pgpPublicKeyRing) {for (PGPPublicKey publicKey : pgpPublicKeyRing) {if (publicKey.isEncryptionKey()) {return Optional.of(publicKey);}}return Optional.empty();}} PgpEncryptionTest
package com.artisan.pgpUtils;import org.apache.commons.io.IOUtils;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.openpgp.PGPException;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.Optional;import static org.junit.Assert.assertEquals;public class PgpEncryptionTest {public static final TemporaryFolder tempFolder new TemporaryFolder();private PgpEncryptionUtil pgpEncryptionUtil null;private PgpDecryptionUtil pgpDecryptionUtil null;/*** 加载资源文件的辅助方法* param resourcePath* return*/private static URL loadResource(String resourcePath) {return Optional.ofNullable(PgpEncryptionTest.class.getResource(resourcePath)).orElseThrow(() - new IllegalArgumentException(Resource not found));}private static final String passkey dummy;private final URL privateKey loadResource(/private.pgp);private final URL publicKey loadResource(/public.pgp);private final URL testFile loadResource(/Sample_CSV_5300kb.csv);private static final String testString This text needs to be PGP encrypted;/*** 在测试类运行之前创建临时文件夹* throws IOException*/BeforeClasspublic static void construct() throws IOException {tempFolder.delete();tempFolder.create();}/*** 在测试类运行之后清理临时文件夹*/AfterClasspublic static void destroy() {tempFolder.delete();}/*** 初始化方法在每个测试方法运行之前执行*/Beforepublic void init() {// 初始化加密工具类pgpEncryptionUtil PgpEncryptionUtil.builder().armor(true).compressionAlgorithm(CompressionAlgorithmTags.ZIP).symmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_128).withIntegrityCheck(true).build();try {// 初始化解密工具类pgpDecryptionUtil new PgpDecryptionUtil(privateKey.openStream(), passkey);} catch (IOException | PGPException e) {throw new RuntimeException(e);}}/*** 测试字节数组加密* throws IOException* throws PGPException*/Testpublic void testByteEncryption() throws IOException, PGPException {// 加密测试字节数组byte[] encryptedBytes pgpEncryptionUtil.encrypt(testString.getBytes(Charset.defaultCharset()),publicKey.openStream());// 解密生成的加密字节数组byte[] decryptedBytes pgpDecryptionUtil.decrypt(encryptedBytes);// 将解密后的字节数组转换为字符串并与原始测试字符串进行比较assertEquals(testString, new String(decryptedBytes, Charset.defaultCharset()));}/*** 测试文件加密* throws IOException* throws URISyntaxException* throws PGPException*/Testpublic void testFileEncryption() throws IOException, URISyntaxException, PGPException {// 生成一个从测试文件生成的PGP加密临时文件File encryptedFile tempFolder.newFile();File originalFile new File(testFile.toURI());try (OutputStream fos Files.newOutputStream(encryptedFile.toPath())) {pgpEncryptionUtil.encrypt(fos, Files.newInputStream(originalFile.toPath()), originalFile.length(),publicKey.openStream());}// 解密生成的PGP加密临时文件并写入另一个临时文件File decryptedFile tempFolder.newFile();pgpDecryptionUtil.decrypt(Files.newInputStream(encryptedFile.toPath()), Files.newOutputStream(decryptedFile.toPath()));// 比较原始文件内容与解密后的文件内容assertEquals(IOUtils.toString(Files.newInputStream(originalFile.toPath()), Charset.defaultCharset()),IOUtils.toString(Files.newInputStream(decryptedFile.toPath()), Charset.defaultCharset()));}/*** 测试输入流加密* throws IOException* throws URISyntaxException* throws PGPException*/Testpublic void testInputStreamEncryption() throws IOException, URISyntaxException, PGPException {// 生成一个从测试文件生成的PGP加密输入流File originalFile new File(testFile.toURI());InputStream encryptedIn pgpEncryptionUtil.encrypt(Files.newInputStream(originalFile.toPath()), originalFile.length(), publicKey.openStream());// 解密生成的输入流并写入临时文件File decryptedFile tempFolder.newFile();pgpDecryptionUtil.decrypt(encryptedIn, Files.newOutputStream(decryptedFile.toPath()));// 比较原始文件内容与解密后的文件内容assertEquals(IOUtils.toString(Files.newInputStream(originalFile.toPath()), Charset.defaultCharset()),IOUtils.toString(Files.newInputStream(decryptedFile.toPath()), Charset.defaultCharset()));}/*** 使用新配置测试字节数组加密* throws IOException* throws PGPException*/Testpublic void testByteEncryptionWithNewConf() throws IOException, PGPException {pgpEncryptionUtil PgpEncryptionUtil.builder().armor(false).compressionAlgorithm(CompressionAlgorithmTags.BZIP2).symmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.BLOWFISH).withIntegrityCheck(false).build();// 加密测试字节数组byte[] encryptedBytes pgpEncryptionUtil.encrypt(testString.getBytes(Charset.defaultCharset()),publicKey.openStream());// 解密生成的加密字节数组byte[] decryptedBytes pgpDecryptionUtil.decrypt(encryptedBytes);// 将解密后的字节数组转换为字符串并与原始测试字符串进行比较assertEquals(testString, new String(decryptedBytes, Charset.defaultCharset()));}
} 小结
当我们在互联网上发送电子邮件或文件时我们希望它们的内容能够保密并且我们希望确认发送方的身份和数据的完整性。这就是PGPPretty Good Privacy的作用。
想象一下你有一把钥匙。这把钥匙有两个部分一个是公钥一个是私钥。 公钥就像你家门口的邮箱钥匙一样你可以把它给任何人。任何人都可以用你的公钥锁住一份文件但只有你才能用你的私钥打开它。 私钥就像你的家里的钥匙一样只有你有它。你用它来打开那些别人用你的公钥锁住的文件。
当你想给某人发送私密信息时你会使用他们的公钥来加密消息。然后只有他们可以使用自己的私钥来解密消息。这样即使在传输过程中即使有人截获了消息他们也无法阅读它因为他们没有私钥。
此外PGP还可以用于数字签名。就像在一封信上签名一样数字签名证明了发送方的身份和消息的完整性。发送方使用自己的私钥对消息进行签名然后接收方使用发送方的公钥来验证签名确保消息没有被篡改并且是来自于发送方的。
总而言之PGP是一种用于保护电子邮件和文件安全的加密技术它通过使用公钥和私钥来加密和解密消息并通过数字签名来验证消息的来源和完整性。