繁体   English   中英

Bouncycastle PGP 解密和验证

[英]Bouncycastle PGP decrypt and verify

我正在尝试使用 java BouncyCastle 库解密和验证 PGP 消息,但遇到了问题,抱怨 PartialInputStream 过早结束。

我知道加密工作正常,因为我可以在命令行上使用 gpg 解密和验证使用加密功能创建的消息。

这是代码:

public static void signEncryptMessage(InputStream in, OutputStream out, PGPPublicKey publicKey, PGPPrivateKey secretKey, SecureRandom rand) throws Exception {
        out = new ArmoredOutputStream(out);

        PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom(rand));
        encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));

        OutputStream compressedOut = new PGPCompressedDataGenerator(PGPCompressedData.ZIP).open(encryptedDataGenerator.open(out, 4096), new byte[4096]);

        PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(publicKey.getAlgorithm(), HashAlgorithmTags.SHA512));
        signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, secretKey);
        signatureGenerator.generateOnePassVersion(true).encode(compressedOut);

        OutputStream finalOut = new PGPLiteralDataGenerator().open(compressedOut, PGPLiteralData.BINARY, "", new Date(), new byte[4096]);

        byte[] buf = new byte[4096];
        int len;
        while ((len = in.read(buf)) > 0) {
            finalOut.write(buf, 0, len);
            signatureGenerator.update(buf, 0, len);
        }

        finalOut.close();
        in.close();
        signatureGenerator.generate().encode(compressedOut);
        compressedOut.close();
        encryptedDataGenerator.close();
        out.close();
    }

    public static void decryptVerifyMessage(InputStream in, OutputStream out, PGPPrivateKey secretKey, PGPPublicKey publicKey) throws Exception {
        in = new ArmoredInputStream(in);

        PGPObjectFactory pgpF = new PGPObjectFactory(in);
        PGPEncryptedDataList enc = (PGPEncryptedDataList) pgpF.nextObject();

        PGPObjectFactory plainFact = new PGPObjectFactory(((PGPPublicKeyEncryptedData) enc.getEncryptedDataObjects().next()).getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(secretKey)));

        Object message = null;

        PGPOnePassSignatureList onePassSignatureList = null;
        PGPSignatureList signatureList = null;
        PGPCompressedData compressedData = null;

        message = plainFact.nextObject();
        ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();

        while (message != null) {
            System.out.println(message.toString());
            if (message instanceof PGPCompressedData) {
                compressedData = (PGPCompressedData) message;
                plainFact = new PGPObjectFactory(compressedData.getDataStream());
                message = plainFact.nextObject();
                System.out.println(message.toString());
            }

            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();
        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);
                System.out.println("verifier : " + ops.getKeyID());
                if (publicKey != null) {
                    ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey);
                    ops.update(output);
                    PGPSignature signature = signatureList.get(i);
                    if (ops.verify(signature)) {
                        Iterator<?> userIds = publicKey.getUserIDs();
                        while (userIds.hasNext()) {
                            String userId = (String) userIds.next();
                            System.out.println("Signed by " + userId);
                        }
                        System.out.println("Signature verified");
                    } else {
                        throw new SignatureException("Signature verification failed");
                    }
                }
            }

        }

        out.write(output);
        out.flush();
        out.close();
    }

    public static void main(String args[]) {
        Security.insertProviderAt(new BouncyCastleProvider(), 0);
        byte inBytes[] = "The quick brown fox jumps over the lazy dog.".getBytes();

        try {
            SecureRandom rand = new SecureRandom();

            RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
            kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x10001), rand, 1024, 90));

            BcPGPKeyPair sender = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date());
            BcPGPKeyPair recip = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpg.generateKeyPair(), new Date());

            ByteArrayOutputStream sendMessage = new ByteArrayOutputStream();
            ByteArrayOutputStream recvMessage = new ByteArrayOutputStream();
            signEncryptMessage(new ByteArrayInputStream(inBytes), sendMessage, recip.getPublicKey(), sender.getPrivateKey(), rand);

            System.out.println(sendMessage.toString());

            decryptVerifyMessage(new ByteArrayInputStream(sendMessage.toByteArray()), recvMessage, recip.getPrivateKey(), sender.getPublicKey());

            System.out.println(recvMessage.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

几次运行之后message = plainFact.nextObject(); 抛出异常:

-----BEGIN PGP MESSAGE-----
Version: BCPG v1.49

hIwDbgERMnl/xpUBA/98O/by9Ib6/nzXiYWuwT2CYulTqzcY07iuHKB4KQc6m+H1
ZBVAx+HozgxQXQdQcBTcp+YS7Xn3tsReiH28Z9805f65tmASoqrzdf35qiVgFhfA
CbCfIq7cqC4rKut3Y8pNOs1mmhpeVNa+AqTZ1r46uyuloBTllI8OWzWoxjTcZdLP
aQHe2BQnfYk+dFgXZ2LMBMtL9mcsEqRLWIdisJQ4gppyIbQNNE7q5gV1Es63yVoM
3dpfYHxlnIZASuynSZyGorHpYMV6tWNwSRQ9Ziwaw4DwvQGyAHpb1O/tLqrfjLqN
5dj5qNY6nElT1EM94Dd4FOBzI6x6JkfuCH3/Jp8lCA/p8K7jmYu9Xvdld8BgHmRF
ymasPf1JC4xYFa9YQVnn4fK2l//2iVcVayv0On32kxD9XfkPUysYVH38glPaHb48
qWk9i/x0Y3mmCy1RVAGWqimR5DEhZPubJ+Kjk3UsB1m90Pm/6a+/ZfpAEHcxshdX
JeVBr7aQIX3PQIUl+ZPQsgAGEmo0abQVufuKfkfjX0Gh
=ApMf
-----END PGP MESSAGE-----

org.bouncycastle.openpgp.PGPCompressedData@cd36a6d
org.bouncycastle.openpgp.PGPOnePassSignatureList@7e224235
org.bouncycastle.openpgp.PGPLiteralData@7b28e644
java.io.EOFException: premature end of stream in PartialInputStream
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at java.io.InputStream.read(InputStream.java:101)
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:103)
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:177)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at org.bouncycastle.openpgp.PGPEncryptedData$TruncatedStream.read(Unknown Source)
    at java.io.InputStream.read(InputStream.java:170)
    at org.bouncycastle.util.io.TeeInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at org.bouncycastle.openpgp.PGPCompressedData$1.fill(Unknown Source)
    at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:158)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at org.bouncycastle.util.io.Streams.readFully(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.readFully(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.readFully(Unknown Source)
    at org.bouncycastle.bcpg.MPInteger.<init>(Unknown Source)
    at org.bouncycastle.bcpg.SignaturePacket.<init>(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.readPacket(Unknown Source)
    at org.bouncycastle.openpgp.PGPSignature.<init>(Unknown Source)
    at org.bouncycastle.openpgp.PGPObjectFactory.nextObject(Unknown Source)
    at main.decryptVerifyMessage(main.java:113)
    at main.main(main.java:167)

有任何想法吗?

旁注,此解密代码来自如何解密已签名的 pgp 加密文件? ,稍作修改以适应:消息将仅来自该加密方法,并且直接处理密钥而不是密钥流。

干杯

拉莫

我最近尝试做同样的事情,并根据我在Bouncycastle示例中找到的代码以及我在网络上找到的教程将这种方法组合在一起。 出于我的目的,我的代码有一个单独的加密对象,它有一个公钥/私钥对。 在示例代码中,您可以替换

    INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID());

用你的秘密密钥。 我已经使用一个长期过程测试了这个方法,该过程执行了几十次加密和签名/解密和验证操作,并且没有得到您所看到的异常。

public static void decryptAndVerify(InputStream in, OutputStream fOut, InputStream publicKeyIn) throws IOException, SignatureException, PGPException {
    in = PGPUtil.getDecoderStream(in);

    PGPObjectFactory pgpF = new PGPObjectFactory(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<PGPPublicKeyEncryptedData> it = enc.getEncryptedDataObjects();
    PGPPrivateKey sKey = null;
    PGPPublicKeyEncryptedData pbe = null;
    while (sKey == null && it.hasNext()) {
        pbe = it.next();
        PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(INSTANCE._secretKeyPass.toCharArray());
        PGPSecretKey psKey = INSTANCE._secretKeyRingCollection.getSecretKey(pbe.getKeyID());
        if (psKey != null) {
            sKey = psKey.extractPrivateKey(decryptor);
        }
    }
    if (sKey == null) {
        throw new IllegalArgumentException("Unable to find secret key to decrypt the message");
    }

    InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));

    PGPObjectFactory plainFact = new PGPObjectFactory(clear);

    Object message;

    PGPOnePassSignatureList onePassSignatureList = null;
    PGPSignatureList signatureList = null;
    PGPCompressedData compressedData;

    message = plainFact.nextObject();
    ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();

    while (message != null) {
        __l.trace(message.toString());
        if (message instanceof PGPCompressedData) {
            compressedData = (PGPCompressedData) message;
            plainFact = new PGPObjectFactory(compressedData.getDataStream());
            message = plainFact.nextObject();
        }

        if (message instanceof PGPLiteralData) {
            // have to read it and keep it somewhere.
            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);
            __l.trace("verifier : " + ops.getKeyID());
            PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(
                    PGPUtil.getDecoderStream(publicKeyIn));
            publicKey = pgpRing.getPublicKey(ops.getKeyID());
            if (publicKey != null) {
                ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey);
                ops.update(output);
                PGPSignature signature = signatureList.get(i);
                if (ops.verify(signature)) {
                    Iterator<?> userIds = publicKey.getUserIDs();
                    while (userIds.hasNext()) {
                        String userId = (String) userIds.next();
                        __l.trace(String.format("Signed by {%s}", userId));
                    }
                    __l.trace("Signature verified");
                } 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 {
        fOut.write(output);
        fOut.flush();
        fOut.close();
    }
}

让Bouncy Castle一起玩并不容易。 来自Stackoverflow的代码snipets使它可以正常工作 ,但它们大多是神秘的代码片段,没有用户真正理解。

这个问题是: 在一个生产系统中, copy'n'paste片段迅速成为“禁止去”和“不要触摸”的区域。

删除可执行文件可能会产生一些严重的安全隐患,最重要的是处理命令行参数(谈论带有空格的文件名......我怎么知道?不要问......)

我有所有这些(以及更多......)问题,经过一些牦牛剃须后,我写了一个库来处理与Bouncycastle的PGP。

解密的工作方式如下:

final InputStream plaintextStream = BouncyGPG
               .decryptAndVerifyStream()
               .withConfig(keyringConfig)
               .andRequireSignatureFromAllKeys("sender@example.com")
               .fromEncryptedInputStream(cipherTextStream)

该库可以在https://github.com/neuhalje/bouncy-gpg找到:

// in build.gradle add a dependency to bouncy castle and bouncy-gpg
//  ...
dependencies {
    compile 'org.bouncycastle:bcprov-jdk15on:1.56'
    compile 'org.bouncycastle:bcpg-jdk15on:1.56'
    //  ...
    compile 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.+'

你在打电话:

encryptedDataGenerator.open(out, 4096)

你可能意味着什么:

encryptedDataGenerator.open(out, new byte[4096])

第一个版本是打开一个大小(这是错误的),第二个版本给出一个字节缓冲区。

(我知道这是旧的,但是来到这里是因为我在一些示例代码中遇到了同样的问题,所以可能会有其他问题)

使用包含 JCE 的标准现代 Java Core 类(例如 Java 1.8_303+)、BouncyCastle Core 和 Bouncy Castle 提供程序,我开发了一个基于 Spring 的服务,可以处理来自资源中包含的公钥/私钥的 PGP 加密和解密文件。 如果你不使用 Spring,你可以去掉 Spring 特定的代码,只利用公共加密/解密方法以及私有支持方法:

package com.your.organization.impl;

import com.your.organization.exception.EncryptionException; // Your own Exception class
import com.your.organization.service.PgpEncryptionService; // Your own Interface class
import org.apache.commons.io.IOUtils;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
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.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;

@Service("pgpEncryptionService")
public final class PgpEncryptionServiceImpl implements PgpEncryptionService {

    @PostConstruct
    public void initializeSecurityProviders() {

        // Add the Bouncy Castle security Provider to the JVM
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * Encrypts a cleared message {@link String} using the classpath PGPPublicKey using
     * {@link ArmoredOutputStream} to further protect the encrypted message.
     *
     * @param message {@link String}
     * @return Encrypted String with, or without, armoring
     * @throws EncryptionException is thrown if the {@link PGPEncryptedDataGenerator} could not be initialized
     *                             from the provided PGPPublicKey or if the encoded message {@link OutputStream}
     *                             could not be opened
     */
    public String encrypt(String message) throws EncryptionException {

        /*
         * Initialize an OutputStream or ArmoredOutputStream for the encrypted message based on the armor
         * function input
         */
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        OutputStream armoredOutputStream = byteArrayOutputStream;
        armoredOutputStream = new ArmoredOutputStream(armoredOutputStream);

        // Initialize and configure the encryption generator using the provided PGPPublicKey
        PGPEncryptedDataGenerator pgpEncryptedDataGenerator = new PGPEncryptedDataGenerator(
                new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
                        .setSecureRandom(new SecureRandom())
                        .setProvider("BC"));

        pgpEncryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(getPublicKey())
                .setProvider("BC"));

        // Convert message String to byte[] using standard UTF-8
        byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);

        // Open the PGPEncryptedDataGenerator from the ArmoredOutputStream initialized to the message body length
        OutputStream encryptedOutputStream;
        try {
            encryptedOutputStream = pgpEncryptedDataGenerator.open(armoredOutputStream, messageBytes.length);
        } catch (IOException | PGPException e) {
            throw new EncryptionException("Could not open an OutputStream from the PGPEncryptedDataGenerator " +
                    "using the provided message body", e);
        }

        // Write the encrypted message to the encryptedOutputStream
        try {
            encryptedOutputStream.write(messageBytes);
        } catch (IOException e) {
            throw new EncryptionException("Could not write the message body to the encrypted OutputStream", e);
        } finally {

            // Close the encrypted message OutputStream
            try {
                encryptedOutputStream.close();
            } catch (IOException e) {
                // TODO: Log this
            }

            // Close the ArmoredOutputStream
            try {
                armoredOutputStream.close();
            } catch (IOException e) {
                // TODO: Log this
            }
        }

        // Return the encrypted message OutputStream to a String
        return byteArrayOutputStream.toString();
    }

    /**
     * Decrypts an encrypted message {@link String} using the {@link PGPSecretKey} on the classpath and its
     * password {@link String}
     *
     * @param encryptedMessage {@link String}
     * @param password         {@link String}
     * @return String
     * @throws EncryptionException is thrown if an encrypted message InputStream cannot be initialized from the
     *                             encryptedMessage {@link String}, if the PGPEncryptedDataList from that stream
     *                             contains no data, or if the password {@link String} for the
     *                             {@link PGPSecretKey} is incorrect
     */
    public String decrypt(String encryptedMessage, String password) throws EncryptionException {

        // Convert the encrypted String into an InputStream
        InputStream encryptedStream = new ByteArrayInputStream(encryptedMessage.getBytes(StandardCharsets.UTF_8));
        try {
            encryptedStream = PGPUtil.getDecoderStream(encryptedStream);
        } catch (IOException e) {
            throw new EncryptionException("Could not initialize the DecoderStream", e);
        }

        // Retrieve the PGPEncryptedDataList from the encryptedStream
        JcaPGPObjectFactory jcaPGPObjectFactory = new JcaPGPObjectFactory(encryptedStream);
        PGPEncryptedDataList pgpEncryptedDataList;

        /*
         * Evaluate the first object for a leading PGP marker packet and then return the encrypted
         * message body as a PGPEncryptedDataList
         */
        try {
            Object nextDataObject = jcaPGPObjectFactory.nextObject();
            if (nextDataObject instanceof PGPEncryptedDataList) {
                pgpEncryptedDataList = (PGPEncryptedDataList) nextDataObject;
            } else {
                pgpEncryptedDataList = (PGPEncryptedDataList) jcaPGPObjectFactory.nextObject();
            }
        } catch (IOException e) {
            throw new EncryptionException("Could not retrieve the encrupted message body", e);
        }

        // Retrieve the public key encrypted data from the encrypted message body
        PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData =
                (PGPPublicKeyEncryptedData) pgpEncryptedDataList.getEncryptedDataObjects().next();

        // Use the PGPPublicKeyEncryptedData and Secret Key password to decrypt the encoded message
        InputStream decryptedInputStream;
        try {
            decryptedInputStream =
                    pgpPublicKeyEncryptedData.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder()
                            .setProvider("BC")
                            .build(getPrivateKey(getSecretKey(), password)));
        } catch (PGPException e) {
            throw new EncryptionException("Could not decrypt the encoded message from the application " +
                    "Secret Key or the embedded Private Key", e);
        }

        // Convert the InputStream of the decrypted message to a String
        try {
            return IOUtils.toString(decryptedInputStream, StandardCharsets.UTF_8.name());
        } catch (IOException e) {
            throw new EncryptionException("Could not convert the decrypted InputStream to a UTF-8 String", e);
        }
    }

    /**
     * Helper method for retrieving the {@link PGPPublicKey} from the application classpath.
     *
     * @return PGPPublicKey
     * @throws EncryptionException is thrown in the event that the PGP Public Key file does not contain a
     *                             Public Key or if the Public Key cannot be located on the file system
     */
    private PGPPublicKey getPublicKey() throws EncryptionException {

        // Retrieve the application PGP public key file from the classpath
        File publicKeyFile;
        try {
            publicKeyFile = new ClassPathResource("keys/yourpublickey-pub.asc").getFile();
        } catch (IOException e) {
            throw new EncryptionException("Could not retrieve the PGP Public Key from the classpath", e);
        }

        // Read Public Key from the file
        FileInputStream pubKey;
        try {
            pubKey = new FileInputStream(publicKeyFile);
        } catch (FileNotFoundException e) {
            throw new EncryptionException("Could not retrieve the PGP Public Key from the file system", e);
        }

        // Load PGPPublicKey FileInputStream into the PGPPublicKeyRingCollection
        PGPPublicKeyRingCollection pgpPub;
        try {
            pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(pubKey),
                    new JcaKeyFingerprintCalculator());
        } catch (IOException | PGPException e) {
            throw new EncryptionException("Could not initialize the PGPPublicKeyRingCollection", e);
        }


        // Retrieve Public Key and evaluate if for the encryption key
        Iterator<PGPPublicKeyRing> keyRingIter = pgpPub.getKeyRings();
        while (keyRingIter.hasNext()) {
            PGPPublicKeyRing keyRing = keyRingIter.next();

            Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
            while (keyIter.hasNext()) {
                PGPPublicKey key = keyIter.next();

                if (key.isEncryptionKey()) {
                    return key;
                }
            }
        }

        throw new EncryptionException("The application PGPPublicKey is not an allowable encryption key");
    }

    /**
     * Helper method for retrieving the signing key {@link PGPSecretKey} from the classpath.
     *
     * @return Signing key {@link PGPSecretKey}
     * @throws EncryptionException is thrown if the Secret Key is not a signing key or if the Secret Key file
     *                             could not be located on the file system
     */
    private PGPSecretKey getSecretKey() throws EncryptionException {

        // Retrieve the application PGP secret key file from the classpath
        File secretKeyFile;
        try {
            secretKeyFile = new ClassPathResource("keys/yoursecretkey-sec.asc").getFile();
        } catch (IOException e) {
            throw new EncryptionException("Could not retrieve the PGP Secret Key from the classpath", e);
        }

        // Read Secret Key file and load it into a PGPPublicKeyRingCollection for evaluation
        FileInputStream secKey;
        try {
            secKey = new FileInputStream(secretKeyFile);
        } catch (FileNotFoundException e) {
            throw new EncryptionException("Could not retrieve the PGP Secret Key from the file system", e);
        }

        // Load PGPSecretKey FileInputStream into the PGPSecretKeyRingCollection
        PGPSecretKeyRingCollection pgpSec;
        try {
            pgpSec = new PGPSecretKeyRingCollection(
                    PGPUtil.getDecoderStream(secKey), new JcaKeyFingerprintCalculator());
        } catch (IOException | PGPException e) {
            throw new EncryptionException("Could not initialize the PGPSecretKeyRingCollection", e);
        }

        // Retrieve signing Secret Key
        Iterator<PGPSecretKeyRing> secretKeyRingIterator = pgpSec.getKeyRings();
        while (secretKeyRingIterator.hasNext()) {
            PGPSecretKeyRing keyRing = secretKeyRingIterator.next();

            Iterator<PGPSecretKey> keyIter = keyRing.getSecretKeys();
            while (keyIter.hasNext()) {
                PGPSecretKey key = keyIter.next();

                if (key.isSigningKey()) {
                    return key;
                }
            }
        }

        throw new EncryptionException("The application PGPSecretKey is not a signing key");
    }

    /**
     * Retrieves the {@link PGPPrivateKey} from the provided {@link PGPSecretKey} and its password.
     *
     * @param secretKey {@link PGPSecretKey}
     * @param password  {@link String}
     * @return PGPPrivateKey
     * @throws EncryptionException is thrown in the event that the password for the {@link PGPSecretKey}
     *                             is incorrect
     */
    private PGPPrivateKey getPrivateKey(PGPSecretKey secretKey, String password) throws EncryptionException {

        PBESecretKeyDecryptor decryptorFactory = new BcPBESecretKeyDecryptorBuilder(
                new BcPGPDigestCalculatorProvider()).build(password.toCharArray());

        try {
            return secretKey.extractPrivateKey(decryptorFactory);
        } catch (PGPException e) {
            throw new EncryptionException("Could not extract the Private Key from the application Secret Key", e);
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM