当前位置: 首页 > 知识库问答 >
问题:

找不到用于加密p12电子邮件地址的(合适的)公钥

严心水
2023-03-14

我试图用bouncy-gpg和我的p12密钥加密文件。但它得到了一个错误没有(合适的)公钥加密到p12电子邮件地址找到老实说,我是一个新手有一个弹力城堡。如有任何建议,将不胜感激。

            KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
            keystore.load(is, p12Password.toCharArray());
            String alias = keystore.aliases().nextElement();

            PrivateKey privateKey = (PrivateKey)keystore.getKey(alias, p12Password.toCharArray());

            Certificate cert = keystore.getCertificate(alias);
            PublicKey publicKey = cert.getPublicKey();

            X509Certificate x509cert = (X509Certificate) cert;
            X509Principal principal = PrincipalUtil.getSubjectX509Principal(x509cert);
            Vector<?> values = principal.getValues(X509Name.EmailAddress);
            String email = (String) values.get(0);

            JcaPGPKeyConverter jcaPGPKeyConverter = new JcaPGPKeyConverter();
            PGPPublicKey pgpPublicKey = jcaPGPKeyConverter.getPGPPublicKey(1, publicKey, new Date());

            PGPPrivateKey pgpPrivateKey = jcaPGPKeyConverter.getPGPPrivateKey(pgpPublicKey, privateKey);
            PGPSecretKey pgpSecretKey = new PGPSecretKey(pgpPrivateKey, pgpPublicKey, null, true, null);

            final InMemoryKeyring keyring = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withPassword(p12Password));
            keyring.addPublicKey(pgpPublicKey.getEncoded());
            keyring.addSecretKey(pgpSecretKey.getEncoded());

            final OutputStream outputStream = BouncyGPG
                            .encryptToStream()
                            .withConfig(keyring)
                            .withStrongAlgorithms()
                            .toRecipient(email)
                            .andDoNotSign()
                            .binaryOutput()
                            .andWriteTo(bufferedOut);

共有1个答案

刘承运
2023-03-14

好吧,这花了一段时间,因为这个项目显然是由一个真正的“K oolaid drinker”完成的--一个类中可能只需10行代码就可以轻松完成的相关操作,需要20个类中的50个方法,这些方法分布在层次结构的多个部分上,并且需要大量不必要的重新调度。要清楚的是,那不是BouncyCastle,它基本上是理智的,虽然不是完美的,而且常常没有很好的评论;Bouncy-GPG层在BouncyCastle的顶部。

PGP密钥可以有几种关联的元数据--通常是userid和signature,很少是属性。参见RFC4880第11.1和11.2节。由真实的PGP程序创建的PGP密钥(如GnuPG)将始终添加此元数据,尽管根据程序的不同,随后可能会删除它。由于PGP最初被设计用于电子邮件,因此通常用户ID包含电子邮件地址,也可以加上其他信息,但技术上不需要这样做,用户ID可以是任何字符串。PGP密钥签名除了实际签名之外,还包含带有其他数据的“子包”。而且PGP密钥通常--现在几乎总是--以一个主密钥和一个或多个链接到该主密钥的子密钥为组,如上面链接的11.1节所示。在这种情况下,userid适用于组中的所有密钥(并且对于组中的所有密钥都是相同的),但是对于每个实际密钥和/或userid,签名是分开的,并且通常在每个实际密钥上至少有一个由“所有者”即由userid标识的实体(总是由主密钥标识)的签名,其中包括定义密钥的过期(如果有的话)和使用标志的子包。正如我在另一个Q中所指出的,BouncyCastle将这组相关密钥称为{Public,Secret}keyring而其他软件将该名称用于可能包含多个此类组的文件,从而加剧了混乱。

大多数PGP程序允许您在需要时选择密钥(用于加密或签名),可以通过用户ID(或其中之一)或“密钥ID”(或指纹或密钥握持,取决于程序)来选择密钥。在前一种情况下,如果使用子密钥,它会根据使用情况(即加密或签名)自动选择适当的子密钥;在后一种情况下,通常只使用主密钥的keyid并让它选择子密钥,但如果合适,可以通过keyid指定特定的(子)密钥。(对于需要使用与上次加密或签名相同的实际密钥的解密和验证,通常通过keyid自动选择正确的(子)密钥,但在某些情况下可能需要或可能手动选择。)特别是,在它调用KeyRingCollection的级别上,BouncyCastle允许您选择一个密钥组,它通过userid或keyid调用KeyRing:请参阅PGPPublicKeyRingCollection和pgpSecretKeyRingCollection的javadoc。

但是Bouncy-GPG没有:它只使用前一个选项,并且通过整个userid或userid的电子邮件部分进行选择,但不通过keyid进行选择。并且jcapgpkeyconverter从JCA转换的密钥没有userid,因此不能通过userid或email选择它们,因此Bouncy-GPG不能用于需要这样选择的操作。

有两种方法来处理这个问题。这些密钥对象可以直接与BouncyCastle一起使用,其代码与示例KeyBasedFileProcessor中的代码类似,只是使用转换后的密钥,而不是像示例那样从“KeyRingCollection”(通常是一个密钥环文件)中选择的密钥。

另一种方法是不使用简单的PGP{Public,Secret}key对象(它只对应于实际密钥)来创建带有元html" target="_blank">数据的keyring。这使我进入了一些未评论的领域,这花了一段时间,并留下了一些不确定的东西,但我认为类似这样的东西将会起作用:

    String userid = "<email@host>"; // Bouncy-GPG defaults to email, but can be changed for other userids
    PGPSignatureSubpacketGenerator hsub = new PGPSignatureSubpacketGenerator();
    hsub.setKeyFlags(false, 0xF); // should be enough for masterkey-only, I hope
    // don't bother with expiration, features, or (multiple) preferences, for now at least
    // the generator below automatically adds hashed 2=signtime and unhashed 16=issuerkeyid
    PGPKeyRingGenerator gen = new PGPKeyRingGenerator(
            PGPSignature.DEFAULT_CERTIFICATION, new PGPKeyPair(pub2,prv2), userid,
            new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1), 
            hsub.generate(), /*unhash*/null, 
            new JcaPGPContentSignerBuilder(pub2.getAlgorithm(), HashAlgorithmTags.SHA1), 
            new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.NULL).build(new char[0]) );
    // I'm not sure ContentSigner will work right for all key-algos with SHA1, may need to tweak;
    // if so I don't _think_ DigestCalculator has to match ContentSigner, but I could be wrong
    // use gen.generatePublicKeyRing() directly or its .getEncoded() see below
    // and gen.generateSecretKeyRing() directly or its .getEncoded() see below

注意,Bouncy-GPGInMemoryKeyRing.Add{Public,Secret}key方法实际上将其(编码的)参数解析为KeyRing(在BC的意思中),而不仅仅是一个简单的密钥(在技术上是这种组的最小情况),或者您可以使用BC的Generate{Public,Secret}KeyRing中的(结构化)对象直接调用Add{Public,Secret}KeyRing

补充道:我本想说,但忘了,这个设计有味道。公钥加密的全部要点在于,我们通常使用属于另一个人或实体(或其他几个实体)的公钥进行加密,并且我们永远不应该拥有这类其他人的(公钥)密钥的私钥,只有我们自己的(多个)密钥。对于PGP格式和信任模型以及PKCS12和X.509等其他格式都是如此。对于PGP设计并经常使用的电子邮件,有一个部分例外,我们可能希望加密给另一个人或多个人,也希望加密给我们自己(并保存它),以便我们可以在以后检查发送了什么,以防发生错误通信或分歧。但你没有那样做;您只对一个拥有私钥的密钥进行加密,这不会提供任何安全好处,也没有任何意义。

咻。

 类似资料:
  • 我有一个托管在Git存储中的项目(现在更名为比特桶服务器)。它是用詹金斯构建的。现在我在本地安装Git时打错了。比如@ab.com而不是@abc.com 每次构建后,詹金斯都会发送电子邮件通知,它会从Git提交中获取我不正确的电子邮件地址,并尝试发送它。 即使我在本地Git中更改了电子邮件地址,我仍然看到詹金斯将电子邮件发送到旧的错误地址。 我该怎么解决这个问题?

  • 问题内容: 我需要验证用户的电子邮件地址。不幸的是,很难使验证器符合标准 这是一个试图符合标准的正则表达式的示例 是否有任何PHP库(最好是开源的)可以验证电子邮件地址? 问题答案: 您是否看过PHP的filter_函数?它们并不完美,但是根据我的经验,它们做得相当不错。 用法示例(返回布尔值):

  • 问题内容: 我想在我的网站上使用自动填充/自动格式化的“收件人”字段,该字段的工作方式类似于GMail中的字段。 有谁知道jQuery这样的事情? 纯JavaScript?还是其他选择? 问题答案: 有很多的jquery位可以做到这一点,您可以在Google上搜索“ jquery autocomplete”,然后看看最喜欢哪个。 这是比较有名的一个:http : //docs.jquery.com

  • 我想使用Google表单填充Google电子表格。其中一个字段是电子邮件地址,我需要对照我们组织的电子邮件列表来验证这一点--换句话说,强制人们使用有效的和现有的电子邮件地址。 我们的组织使用谷歌应用程序。该表单将由在我们组织中的用户创建,并且只有来自我们组织/域的电子邮件地址才被认为是有效的。

  • 我使用的是。 当我尝试并继续到链接的下一页时,我得到以下错误 文件“scrape.py”,第43行,在查找(driver)文件“scrape.py”中,第26行,在查找links.extend中([link.get_attribute('href')for link in driver.find_elements_by_xpath('//h2[@class=“heading”]/a')])文件“/