提问者:小点点

弹跳城堡开放gpg2公钥


我试图在这里实现解决方案https://stackoverflow.com/a/33216302/4727842.我的代码看起来像这样

private fun readPublicKey(input: InputStream): PGPPublicKey {
    val publicKey = PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input), BcKeyFingerprintCalculator())
    var key: PGPPublicKey? = null

    publicKey.keyRings.forEach { ring: PGPPublicKeyRing ->
        ring.publicKeys.forEach { k: PGPPublicKey ->
            if (k.isEncryptionKey) {
                key = k
            }
        }
    }

    if (key == null) {
        throw IllegalArgumentException("Can't find encryption key input key ring.")
    } else {
        return key!!
    }
}

private fun encrypt(file: File): String {
    val input = IOUtils.toInputStream("pub.asc", "UTF-8")
    val key = readPublicKey(input)

    Security.addProvider(BouncyCastleProvider())

    val out = ByteArrayOutputStream()
    val compressor = PGPCompressedDataGenerator(PGPCompressedData.ZIP)

    PGPUtil.writeFileToLiteralData(compressor.open(out), PGPLiteralData.BINARY, file)
    compressor.close()

    val builder = BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES)
    val generator = PGPEncryptedDataGenerator(builder.setSecureRandom(SecureRandom()))

    generator.addMethod(BcPublicKeyKeyEncryptionMethodGenerator(key))

    return String(out.toByteArray())
}

使用gpg cli(v2.2.15),生成密钥后,我输出asc文件。

gpg-ab-o./pub. asc

它的内容看起来像这样

-----BEGIN PGP SIGNATURE-----

iQEzBAABCAAdFiEEpjyVE0VY1bLTdOo7wzVyPJ8SXFIFAlzbRfQACgkQwzVyPJ8S
XFKtjwgAp1ad9jFxKtsbzR4XT4HqypTPxpwY8raoIeXNg2PMDAFXGqmcRmP4NEBO
BYqalHAxrzXKVPcmKHtYnm7Jb91VLcYycsF+9RM53mwhg2YJhv49xROx8IsJuhVG
8X52nhPc+qQtzE/79FPDgiZNKSnrHUDvPU3rrZH44WPsGQJ9iGy0eoJPomuU29Cb
wWYxOHq8fRmL5h5Pi9mU1dJRZvHej8ewt0DpredY//7Er7xjCKHrFyzddSn1sGtv
QvoOP+1pLNCV/LKAgCz2N2vSOToLqYTuQlrO/kNApnza0+lO0GW4RMf0OJntbSIa
MHDa+/uc9YnyABkptxD2a9DsbvHwvg==
=QeFf
-----END PGP SIGNATURE-----

然后用线

val input=IOUtils. toInputStream("pub.asc","UTF-8")

我试图运行。它在提取密钥失败后输出消息“找不到加密密钥输入密钥环”。调试后我看到public Key. keyRings大小为0

我不明白这种情况,因为链接指南似乎提倡使用. asc文件进行加密,而我认为这是为了签名。我对PGP了解不多,但我认为这些是不同的步骤,也许签名对我的用例来说不是必要的。

所以,我试着导出公钥

gpg--export-a“用户”

包含

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBFzaBaIBCACngN7Zu5ZKKJuwlp9/iYLleIbYqTm1mxIVEsCiiksLTwbKIo2M
d7YeFDjJRPoKS94bt0FaRUV7cKwXTvqdVg0OITkTLE446TrMhi6Yz9InxkO1yC2l
RfVIZJgOfFBFTwiqx5HpPMmgHnpyzYESiwkNXR7mVIbIX4/5r+NOjMH/ioBSAd80
FV8Yl7k72B6gpbD/CEV6iR+uWlL99Bv6aYtbubCUEieY0KZyk998TFlatrtHvhDQ
ftVHYS4EsrnvlwtVD8QLbnYA2WsX6xVqpz8KHZ5LzXLys4D64sHZ5BkD3aX8Jp5s
iCpOb6rU4wdlD7gDJb1a1ks613C8Qj5/KHN1ABEBAAG0J0dyYXlkZW4gSG9ybWVz
IDxncmF5ZGVuLmhvcm1lc0BzYXAuY29tPokBVAQTAQgAPhYhBKY8lRNFWNWy03Tq
O8M1cjyfElxSBQJc2gWiAhsDBQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheA
AAoJEMM1cjyfElxS2H0H/0O37sJfcNC2UFeuwoGqPMV4+3dN6sejpWBvQCw8OuGv
lDQmPUpEbBHs3awI83XlpYBbAKaDcJlIHPugM6CKGNWOL8RhL+ziJoGX1/Cldc5M
NHToNwU78/LE9Eog6oiC/VELnLP2qMRGK9+6sSYy7kz4zVPRzGjjD3t2uSxpoclO
LnF7Iqm6W+j2OIHACgBeqjjv4hgH4bJjXuixuPSxRLNp0dQ6PU8fj+xRjJudJWS6
hx3PM8/NZvoDruqEWjoTJW96S7askitImtcSw90kMbTpw/knZhpNeCJMQPF8jLUo
ZSbuC+8EukzuJ1mNxS9S0M1IX4psKEUttBYya+SoX/C5AQ0EXNoFogEIALk9vHyO
sXeqHEXeRsCHDyfOtFJlUFQvtkf3dwyyg4hVQq2vYTVyO+couxpgmCCrCzSNdlwK
Salh7Wejf+U+Erx8RzGJ764uyIlw/1B2qlGFgdWPaRWHtufQiUz6RNtWEhsBuddI
lbWxMOvbA3wfkFAIl+NQ8Aqqd8N9ao7mrXcADF7hRMtM+TllFJjxpNJeCWxwfeDf
EMM6totFf9CyD+Q0Zq6zyVFhgLiMuLPX4LsRMBKHGrg0LyyRQgDEezI1WH25YeAT
El8YJriEV4PcXQGnrsfkKbvsnNkXFb3nRlANuKlnHgBrSLE9Tqm4XuwG+czdGJuU
p0eyoxv4vrCGCgMAEQEAAYkBPAQYAQgAJhYhBKY8lRNFWNWy03TqO8M1cjyfElxS
BQJc2gWiAhsMBQkDwmcAAAoJEMM1cjyfElxSRuwH/3RZ6Zs5K76GaakJh0H5uw3H
mqrQiVSh1PmcGO2qRZuDrGDOiJWnOCnl48t71DgqjyABPAYsYzIhZXltA6lYVCI5
68HmUyfOHyeoZa6t35YM3A6S3jsIHRSQgu98R/1VK5EksQnGTrYwsa3gUQy+7BbN
F88+jRhEKnBYOABQ+M29pkx8zvH9UdrHWMTu2h5tb70volDSQzsdN9KX4EHoAto3
jP3janjIzYohBXM+FFte9HIOndwJ0RsZ5UD8lx8EmKh4DCUw3JxHagHOvdXopAAM
j+bUVTlu72LmvcsiNAKg7UicIuprKyHxDkSeelgEQt7Iz+6w3WL9djvL3hG3cks=
=9i+0
-----END PGP PUBLIC KEY BLOCK-----

并与

val input=IOUtils. toInputStream("public.key","UTF-8")

这没有改变。bouncyCastle在我的公钥文件中没有找到密钥。然后我发现,由于我使用的是gpg2,所以密钥环的处理方式有所不同。我在这里找到了将. pkr转换为.kbx的解决方案https://stackoverflow.com/a/34221494/4727842但在这一点上,这变得非常复杂。我不知道公钥环和公钥之间的区别。我不知道为什么第一个例子使用.asc文件作为假定有效的密钥环。我特别不知道为什么从我的public.key文件创建一个bouncyCastlePGPPublicKey对象如此困难。


共2个答案

匿名用户

如果你只是想做适当的en-/解密使用bouncy-gpg(无耻的插件:我是作者)。

也不要使用3DES,它很慢,不是最现代的算法(尽管它仍然被认为是安全的,AFAIK)。

您可以通过gpg--export-ame@example.com导出公钥。

您可以使用InMemoryKeyring管理密钥(有关详细信息,请参阅此处):

public static KeyringConfig keyringConfigInMemoryForKeys(final String exportedPubKey, final String exportedPrivateKey, final String passphrase) throws IOException, PGPException {

   final InMemoryKeyring keyring = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withPassword(passphrase);

       keyring.addPublicKey(exportedPubKey.getBytes("US-ASCII"));
// you can add many more public keys

       // if you only want to encrypt you do not need a private key and can ignore this line
keyring.addSecretKey(exportedPrivateKey.getBytes("US-ASCII"));
// you can add many more private keys

return keyring;
}


final String original_message = "I love deadlines. I like the whooshing sound they make as they fly by. Douglas Adams";

// Most likely you will use  one of the KeyringConfigs.... methods.
KeyringConfig keyringConfigOfSender = keyringConfigInMemoryForKeys(..); // TODO - here comes your code to get keys

ByteArrayOutputStream result = new ByteArrayOutputStream();

try (
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(result);

    final OutputStream outputStream = BouncyGPG
        .encryptToStream()
        .withConfig(keyringConfigOfSender)
        .withStrongAlgorithms()
        .toRecipients("recipient@example.com", "sender@example.com") // TODO - also your job to set the recipients 
        .andSignWith("sender@example.com") // TODO - same here
        .binaryOutput()
        .andWriteTo(bufferedOutputStream);
    // Maybe read a file or a webservice?
    final ByteArrayInputStream is = new ByteArrayInputStream(original_message.getBytes())
) {
  Streams.pipeAll(is, outputStream);
// It is very important that outputStream is closed before the result stream is read.
// The reason is that GPG writes the signature at the end of the stream.
// This is triggered by closing the stream.
// In this example outputStream is closed via the try-with-resources mechanism of Java
}

result.close();
byte[] chipertext = result.toByteArray();

匿名用户

你可以使用PGPS不锈钢(另一个无耻的插件-作者也在这里: P):

        // Prepare keys
        // Required by the sender
        PGPSecretKeyRing keyAlice = PGPainless.readKeyRing().secretKeyRing(ALICE_KEY);
        PGPPublicKeyRing certificateBob = PGPainless.readKeyRing().publicKeyRing(BOB_CERT);
        SecretKeyRingProtector protectorAlice = SecretKeyRingProtector.unprotectedKeys();

        // Required by the recipient
        PGPSecretKeyRing keyBob = PGPainless.readKeyRing().secretKeyRing(BOB_KEY);
        PGPPublicKeyRing certificateAlice = PGPainless.readKeyRing().publicKeyRing(ALICE_CERT);
        SecretKeyRingProtector protectorBob = SecretKeyRingProtector.unprotectedKeys();

        // plaintext message to encrypt
        String message = "Hello, World!\n";
        ByteArrayOutputStream ciphertext = new ByteArrayOutputStream();
        // Encrypt and sign
        EncryptionStream encryptor = PGPainless.encryptAndOrSign()
                .onOutputStream(ciphertext)
                .withOptions(ProducerOptions.signAndEncrypt(
                        // we want to encrypt communication (affects key selection based on key flags)
                        EncryptionOptions.encryptCommunications()
                                .addRecipient(certificateBob)
                                .addRecipient(certificateAlice),
                        new SigningOptions()
                                .addInlineSignature(protectorAlice, keyAlice, DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)
                        ).setAsciiArmor(true)
                );

        // Pipe data trough and CLOSE the stream (important)
        Streams.pipeAll(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)), encryptor);
        encryptor.close();

        // Encrypted message
        String encryptedMessage = ciphertext.toString();

        // Decrypt and verify signatures
        DecryptionStream decryptor = PGPainless.decryptAndOrVerify()
                .onInputStream(new ByteArrayInputStream(encryptedMessage.getBytes(StandardCharsets.UTF_8)))
                .withOptions(new ConsumerOptions()
                        .addDecryptionKey(keyBob, protectorBob)
                        .addVerificationCert(certificateAlice)
                );

        ByteArrayOutputStream plaintext = new ByteArrayOutputStream();

        Streams.pipeAll(decryptor, plaintext);
        decryptor.close();

        // Check the metadata to see how the message was encrypted/signed
        OpenPgpMetadata metadata = decryptor.getResult();
        assertTrue(metadata.isEncrypted());
        assertTrue(metadata.containsVerifiedSignatureFrom(certificateAlice));
        assertEquals(message, plaintext.toString());

如果你想让它更简单,PGPA无痛提供了一个SOP(无状态OpenPGP协议)API通过pgPe无痛SOP:

SOP sop = new SOPImpl();
        
// Generate an OpenPGP key - Alternatively just read existing (unencrypted) key from disk
byte[] key = sop.generateKey()
        .userId("Alice <alice@example.org>")
        .generate()
        .getBytes();

// Extract the certificate (public key) - alternatively just read certificate from disk
byte[] cert = sop.extractCert()
        .key(key)
        .getBytes();

// Encrypt a message
byte[] message = ...
byte[] encrypted = sop.encrypt()
        .withCert(cert)
        .signWith(key)
        .plaintext(message)
        .getBytes();

// Decrypt a message
ByteArrayAndResult<DecryptionResult> messageAndVerifications = sop.decrypt()
        .verifyWith(cert)
        .withKey(key)
        .ciphertext(encrypted)
        .toByteArrayAndResult();
byte[] decrypted = messageAndVerifications.getBytes();
// Signature Verifications
DecryptionResult messageInfo = messageAndVerifications.getResult();
List<Verification> signatureVerifications = messageInfo.getVerifications();