Шифрование и безопасность_Протоколы связи с шифрованием PGP, OpenPGP и GPG.
Шифрование и безопасность_Протоколы связи с шифрованием PGP, OpenPGP и GPG.

PGP

PGP (Pretty Good Privacy) — это зашифрованный протокол связи, используемый для защиты безопасности и конфиденциальности электронной почты и файлов. Он обеспечивает конфиденциальность, целостность и проверяемость данных за счет использования технологий шифрования, цифровых подписей и сжатия.

Первоначально GP была разработана Ником Эмбрейсом и Эриком Хьюзом в Массачусетском технологическом институте, а затем доработана Филом Циммерманном. Он использует механизм шифрования с открытым ключом и расшифровки с закрытым ключом, чтобы гарантировать, что только получатель сообщения может расшифровать и прочитать содержимое сообщения.

Основные преимущества PGP заключаются в простоте использования и интеграции с большинством популярных почтовых клиентов. Однако с появлением более совершенных технологий и стандартов шифрования (таких как OpenPGP и GPG), PGP был в некоторой степени заменен этими новыми стандартами.

PGP предназначен не только для электронной почты, его также можно использовать для шифрования файлов и данных.

  1. Шифрование и дешифрование: PGP использовать симметричное шифрование, асимметричное шифрование, комбинированный способ достижения шифрования и дешифрование。Отправитель использовать открытый получателя ключ выполняет шифрование сообщения, получатель использует собственный закрытый ключ. ключ Расшифруйте сообщение. Кроме того, ПГП Также поддерживает цифровую информацию для данных. Подпись, чтобы обеспечить целостность данных и подтвердить личность отправителя.
  2. Управление ключами: PGP использовать пару ключей для управления Шифрованием и процесс дешифрования. У каждого пользователя есть открытый ключиодинзакрытый ключ。открытый ключиспользуется дляшифрованиеинформация,закрытый ключиспользуется для Расшифровать сообщение. Доступ к этим парам ключей можно получить через сервер ключей или через обмен. ключами способ получения.
  3. цифровая подпись: PGP Разрешить пользователямиспользоватьсобственныйзакрытый ключ对информацияруководитьцифровая подпись. Получатель может использовать открытый адрес отправителя. ключ Проверьте подпись, чтобы убедиться в целостности сообщения и личности отправителя.
  4. модель доверия: PGP Используйте модель, основанную на доверии, для проверки подлинности ключей. Пользователи могут установить доверие, обмениваясь ключами напрямую, используя цепочку доверия или доверяя серверу.
  5. открытые стандарты: PGP это своего рода открытое Это означает, что каждый может внедрить протокол стандартов, не ограничиваясь конкретным продавцом или поставщиком.

В целом, PGP — это надежный протокол шифрования, используемый для защиты конфиденциальности и целостности коммуникаций, обеспечивая при этом механизм аутентификации. Он широко используется для шифрования электронной почты и файлов, чтобы обеспечить безопасность и конфиденциальность данных пользователей.

OpenPGP и GPG (GNU Privacy Guard) — это открытые стандарты и бесплатные программные реализации PGP (Pretty Good Privacy). Со временем стандарты и реализации PGP постепенно развивались, причем OpenPGP и GPG стали двумя важными разработками.

OpenPGP

OpenPGP — это открытый стандарт, определяющий протокол шифрования и цифровой подписи данных. Этот стандарт обеспечивает совместимость различного криптографического программного обеспечения друг с другом, а это означает, что пользователи, использующие различные реализации OpenPGP, могут безопасно обмениваться зашифрованной информацией. Стандарт OpenPGP определен в RFC 4880 и включает в себя методы генерации, обмена и проверки открытых и закрытых ключей, а также алгоритмы шифрования и подписи.

GPG

GPG — это популярная реализация OpenPGP, которая является частью проекта GNU и выпущена под лицензией GNU General Public License (GPL). GPG — это инструмент командной строки, который работает в различных операционных системах, включая Linux, macOS и Windows. GPG предоставляет возможность создавать и проверять цифровые подписи, шифровать файлы и электронные письма, а также безопасно обмениваться ключами.

Основные компоненты GPG включают в себя:

  • брелок: используется для хранения открытого ключизакрытый ключ。
  • gpg: инструмент командной строки,используется для执行шифрование、Расшифровать、Операции подписи и проверки.
  • gpgconf: инструмент командной строки для настройки GPG.
  • gpg-agent: демон, обеспечивающий управление ключами, шифрованием функций сервера.

Сценарии использования GPG включают:

  • Легко обменивайтесь электронной почтой и файлами.
  • Проверьте целостность и происхождение программного обеспечения.
  • Защищайте личную и деловую конфиденциальность.

Принцип работы

PGP (Pretty Good Privacy) включает в себя такие ключевые этапы, как шифрование, цифровые подписи и управление ключами.

  1. Генерация ключей: Созданная пользователем пара в открытом виде ключизакрытый ключ。открытый ключиспользуется дляшифрованиеинформация,закрытый ключиспользуется для Расшифровать сообщениеигенерироватьцифровая подпись。
  2. шифрование: Отправитель использовать открытый получателя ключ к шифрованию новостей. Таким образом, только если у вас есть соответствующий закрытый Получатель ключа может Расшифровать сообщение。
  3. цифровая подпись: отправительиспользоватьсобственныйзакрытый ключ Подпишите сообщение. Получательиспользовать открытый отправителя ключ Проверяет подпись, чтобы гарантировать целостность сообщения и личность отправителя.
  4. Управление ключами: Пользователи могут управлять и делиться ими через сервер ключей или путем обмена ключами напрямую. ключ。

Рабочий процесс

  1. обмен ключами: Отправителю и получателю необходимо обмениваться открытыми ключ. Это можно сделать через сервер ключей, прямой обмен или другой канал безопасности.
  2. шифрованиеинформация:
    • Отправитель выбирает сообщение для отправки и открытый адрес получателя. ключ выполнить шифрование сообщения.
    • Отправитель может выбрать использование алгоритма симметричного шифрования для шифрования содержимого сообщения.,Затем используйте открытый ключ получателя для шифрования симметричного ключа.,Это повышает эффективность.
    • Отправитель отправляет сообщение после шифрования получателю.
  3. Расшифровать сообщение:
    • Получательиспользоватьсобственныйзакрытый ключ Расшифроватьловитьполучатьизинформация。
    • еслиинформация有цифровая подпись,Получательиспользовать открытый отправителя ключ Проверьте подпись.
  4. цифровая подписьпроверять:
    • Получательиспользовать открытый отправителя ключпроверятьцифровая Подпись, обеспечивающая целостность сообщения и личность отправителя.
  5. доверительное управление:
    • Пользователи могут устанавливать доверительные отношения, чтобы обеспечить доверие других пользователей. ключ к его подлинности.
    • Доверительные отношения могут быть установлены путем прямого обмена ключами, цепочками доверия или серверами доверия.

В целом, ПГПиз Принцип работыс участиемшифрование、цифровая подпись Управление ключами, конфиденциальность сообщения гарантируется этими шагами.、Полнота и проверяемость.

использовать

По сути, PGP имеет три основных использования:

  • Отправляйте и получайте шифрованные электронные письма.
  • Подтвердите личность человека, отправившего вам сообщение.
  • шифрованиедокумент。

Описание случая

Предположим, Алиса и Боб — два пользователя, общающиеся с использованием шифрования PGP. Им нужна безопасная связь по электронной почте, чтобы защитить конфиденциальность и целостность их сообщений.

процесс

  1. Генерация ключей:
    • Alice и Bob Сгенерировать пару открытых соответственно ключизакрытый ключ。
  2. обмен ключами:
    • Alice Будет ли она открытой ключ Отправить Боб, пока Bob также его открытый ключ Отправить Алиса. Это можно сделать по электронной почте Службы безопасности или по другому каналу безопасности.
  3. шифрованиеинформация:
    • Алиса решает, Боб отправляет электронное письмо с шифрованием.
    • Alice использовать Bob изоткрытый ключ Изменить содержимое письмашифрование。
    • Alice Вы также можете выбрать использовать алгоритм симметричного шифрования для шифрования содержимого электронной почты, а затем использовать Bob изоткрытый Ключ поставляется с симметричными ключами шифрования для повышения эффективности.
  4. Расшифровать сообщение:
    • Bob получать Alice После отправки сообщения шифрование используйте собственное закрытие. ключ Расшифровать Содержимое электронной почты。
    • если В электронном письме естьцифровая подпись,Bob использовать Alice изоткрытый ключ Проверка подписей для обеспечения целостности электронной почты Alice личность.
  5. цифровая подписьпроверять:
    • если Alice Добавил цифровую информацию к вашему сообщению подпись,Bob использовать Alice изоткрытый ключ Проверьте подпись, чтобы обеспечить целостность сообщения. Alice личность.
  6. доверительное управление:
    • Alice и Bob Возможен прямой обмен открытый ключ или используйте доверенный сервер для установления доверительных отношений и обеспечения открытости другой стороны. Подлинность ключа.

В этом случае Алиса и Боб используют протокол PGP для шифрования и дешифрования связи между ними, а также могут использоваться цифровые подписи для обеспечения целостности сообщения и проверки личности отправителя. Таким образом, они могут безопасно обмениваться информацией, не опасаясь, что она будет украдена или подделана неавторизованными третьими лицами.

Реализация кода

Полная реализация протокола PGP в Java требует использования сторонних библиотек, поскольку PGP — это сложный протокол шифрования. Одной из часто используемых библиотек является Bouncy Castle.

зависимость от помпа

Язык кода:javascript
копировать
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.artisan</groupId>
    <artifactId>pgp-encryption</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpg-jdk15on</artifactId>
            <version>1.70</version>
            <scope>compile</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.70</version>
            <scope>compile</scope>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>

    </dependencies>


</project>

PgpEncryptionUtil

Язык кода:javascript
копировать
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 {

    /**
     * Уилл Надувной Замок добавлен в JVM
     */
    static {
        // Уилл Надувной Замок добавлен в JVM
        if (Objects.isNull(Security.getProvider(BouncyCastleProvider.PROVIDER_NAME))) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    /**
     * Алгоритм сжатия, по умолчанию ZIP.
     */
    @Builder.Default
    private int compressionAlgorithm = CompressionAlgorithmTags.ZIP;

    /**
     * Алгоритм симметричного ключа, по умолчанию AES-128.
     */
    @Builder.Default
    private int symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;

    /**
     * Включить ли ASCII Броня, по умолчанию верно
     */
    @Builder.Default
    private boolean armor = true;


    /**
     * Включить ли проверку целостности, по умолчанию — true.
     */
    @Builder.Default
    private boolean withIntegrityCheck = true;

    /**
     * Размер буфера, по умолчанию — 65536 байт.
     */
    @Builder.Default
    private 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 Броня, создайте ArmoredOutputStream.
        if (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());
    }

    /**
     * шифрованиеметод,чистый текстданныеиспользоватьоткрытый ключString шифрование
     *
     * @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

Язык кода:javascript
копировать
 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 {
        // Уилл Надувной Замок добавлен в 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);
    }

    /**
     * Найти закрытый по указанному идентификатору ключ
     *
     * @param keyID
     * @return
     * @throws PGPException
     */
    private PGPPrivateKey findSecretKey(long keyID) throws PGPException {
        // Получите закрытие с указанным идентификатором из брелока. ключ
        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();
        // Первым объектом может быть пакет с тегом data.
        PGPEncryptedDataList pgpEncryptedDataList = (obj instanceof PGPEncryptedDataList)
                ? (PGPEncryptedDataList) obj : (PGPEncryptedDataList) pgpObjectFactory.nextObject();

        PGPPrivateKey pgpPrivateKey = null;
        PGPPublicKeyEncryptedData publicKeyEncryptedData = null;

        Iterator<PGPEncryptedData> 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

Язык кода:javascript
копировать
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  Ошибки, связанные с вводом-выводом
     * @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 Ошибки, связанные с вводом-выводом
     */
    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  Ошибки, связанные с вводом-выводом
     * @throws PGPException Ошибки, связанные с PGP
     */
    static PGPPublicKey getPublicKey(InputStream keyInputStream) throws IOException, PGPException {
        PGPPublicKeyRingCollection pgpPublicKeyRings = new PGPPublicKeyRingCollection(
                PGPUtil.getDecoderStream(keyInputStream), new JcaKeyFingerprintCalculator());
        Iterator<PGPPublicKeyRing> keyRingIterator = pgpPublicKeyRings.getKeyRings();
        while (keyRingIterator.hasNext()) {
            PGPPublicKeyRing pgpPublicKeyRing = keyRingIterator.next();
            Optional<PGPPublicKey> pgpPublicKey = extractPGPKeyFromRing(pgpPublicKeyRing);
            if (pgpPublicKey.isPresent()) {
                return pgpPublicKey.get();
            }
        }
        throw new PGPException("Недопустимый открытый ключ");
    }

    private static Optional<PGPPublicKey> extractPGPKeyFromRing(PGPPublicKeyRing pgpPublicKeyRing) {
        for (PGPPublicKey publicKey : pgpPublicKeyRing) {
            if (publicKey.isEncryptionKey()) {
                return Optional.of(publicKey);
            }
        }
        return Optional.empty();
    }

}

PgpEncryptionTest

Язык кода:javascript
копировать
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
     */
    @BeforeClass
    public static void construct() throws IOException {
        tempFolder.delete();
        tempFolder.create();
    }

    /**
     * Очистить временную папку после запуска тестового класса
     */
    @AfterClass
    public static void destroy() {
        tempFolder.delete();
    }

    /**
     *  Метод инициализации, выполняемый перед запуском каждого метода тестирования.
     */
    @Before
    public void init() {
        // Класс инструмента инициализации шифрования
        pgpEncryptionUtil = PgpEncryptionUtil.builder()
                .armor(true)
                .compressionAlgorithm(CompressionAlgorithmTags.ZIP)
                .symmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_128)
                .withIntegrityCheck(true)
                .build();

        try {
            // Инициализировать класс инструмента дешифрования
            pgpDecryptionUtil = new PgpDecryptionUtil(privateKey.openStream(),ключ доступа);
        } catch (IOException | PGPException e) {
            выдать новые исключения RuntimeException;
        }
    }

    /**
     * тест байт-множествошифрование
     * @выбрасывает исключение IOException
     * @throws PGPException
     */
    @Тест
    public void testByteEncryption() выдает IOException,PGPException {
        // шифрованиетестбайтмножество        byte[] encryptedBytes = pgpEncryptionUtil.encrypt(testString.getBytes(Charset.defaultCharset()),
                publicKey.openStream());
        // Расшифруйте сгенерированное шифрование в большом количестве байтов.
        byte[] decryptedBytes = pgpDecryptionUtil.decrypt(encryptedBytes);
        // Преобразуйте множество расшифрованных байтов в строку и сравните с исходной тестовой строкой.
        assertEquals(testString, new String(decryptedBytes,Charset.defaultCharset()));
    }

    /**
     *документшифрование
     * @выбрасывает исключение IOException
     * @throws URISyntaxException
     * @throws PGPException
     */
    @Тест
    public void testFileEncryption() выдает 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()));
    }

    /**
     *Входной поток шифрование
     * @выбрасывает исключение IOException
     * @throws URISyntaxException
     * @throws PGPException
     */
    @Тест
    public void testInputStreamEncryption() выдает 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
     */
    @Test
    public void testByteEncryptionWithNewConf() throws IOException,PGPException {
        pgpEncryptionUtil = PgpEncryptionUtil.builder()
                .armor(ложь)
                .compressionAlgorithm(CompressionAlgorithmTags.BZIP2)
                .symmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.BLOWFISH)
                .withIntegrityCheck(ложь)
                .строить();
        // тест на шифрование множество
        byte[] EncryptionBytes = pgpEncryptionUtil.encrypt(testString.getBytes(Charset.defaultCharset()),
                publicKey.openStream());
        // Расшифруйте сгенерированное шифрование в большом количестве байтов.
        byte[] decryptedBytes = pgpDecryptionUtil.decrypt(encryptedBytes);
        // Преобразуйте множество расшифрованных байтов в строку и сравните с исходной тестовой строкой.
        assertEquals(testString, new String(decryptedBytes, Charset.defaultCharset()));
    }
}

краткое содержание

Когда мы отправляем электронные письма или файлы через Интернет, мы хотим, чтобы их содержимое оставалось конфиденциальным, и мы хотим подтвердить личность отправителя и целостность данных. Именно это и делает PGP (Pretty Good Privacy).

Представьте, что у вас есть ключ. Этот ключ состоит из двух частей: одна — открытый ключ, а другая — закрытый ключ.

  • открытый ключ:就像你家门口из邮箱钥匙一样,ты можешь отдать это кому угодно。任何人都可以用你изоткрытый ключ Заблокируйте документ, но использовать его с закрытым экраном сможете только вы. ключ Открой его.
  • закрытый ключ:就像你из家里из钥匙一样,только у тебя это есть。你用它Приходить打开那些别人用你изоткрытый ключ заблокированных файлов.

Если вы хотите отправить кому-то личное сообщение, вы используете его открытое сообщение. ключ к шифрованию новостей. Только тогда они смогут использовать свой собственный закрытый двор. ключ Приходить Расшифровать сообщение. Таким образом, даже если кто-то перехватит сообщение во время передачи, он не сможет его прочитать, поскольку у него нет закрытого доступа. ключ。

Кроме того, PGP также можно использовать для цифровых подписей. Как и подпись в письме, цифровая подпись подтверждает личность отправителя и целостность сообщения. Отправитель использует свой закрытый ключ для подписи сообщения, а получатель использует открытый ключ отправителя для проверки подписи, чтобы гарантировать, что сообщение не было подделано и отправлено отправителем.

Подводя итог, можно сказать, что PGP — это технология шифрования, используемая для защиты электронной почты и файлов с помощью открытых и закрытых ключей для шифрования и дешифрования сообщений, а также с помощью цифровых подписей для проверки происхождения и целостности сообщения.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose