首页 > 解决方案 > 无法使用 Curve25519 生成 DSA/ECDH 密钥以用作使用 Bouncy Castle 的 OpenPGP 密钥

问题描述

我正在尝试使用 Bouncy Castle 的 Java API 使用 DSA 和 ECDH 密钥对组合生成 OpenPGP 密钥环。为了不依赖 NIST 曲线,我选择了 Curve25519 作为我想要使用的函数。但是,在密钥环导出后,我得到一个IllegalArgumentException

java.lang.IllegalArgumentException: illegal object in getInstance: org.bouncycastle.asn1.DLSequence
   at: org.bouncycastle.asn1.ASN1ObjectIdentifier.getInstance(Unknown Source)
   at: org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPGPPublicKey(Unknown Source)
   at: org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPGPPublicKey(Unknown Source)
   at: org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair.getPublicKey(Unknown Source)
   at: org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair.(Unknown Source)

我用来生成两个密钥对的代码如下:

String identity, passphrase;        // User input
OutputStream secretOut, publicOut;  // File streams

try {
    KeyPairGenerator dsaKeygen  = KeyPairGenerator.getInstance ("DSA", "BC");
    KeyPairGenerator ecdhKeygen = KeyPairGenerator.getInstance ("ECDH", "BC");

    dsaKeygen.initialize (2048);
    KeyPair dsaKeypair = dsaKeygen.generateKeyPair ();

    X9ECParameters ecParams = CustomNamedCurves.getByName ("Curve25519");
    ECParameterSpec ecSpecs = new ECParameterSpec (
        ecParams.getCurve (),
        ecParams.getG (),
        ecParams.getN (),
        ecParams.getH (),
        ecParams.getSeed ()
    );

    ecdhKeygen.initialize (ecSpecs, new SecureRandom ());
    KeyPair ecdhKeypair = ecdhKeygen.generateKeyPair ();

    PGPKeyPair dsaPgpKeypair  = new JcaPGPKeyPair (PGPPublicKey.DSA, dsaKeypair, new Date ());
    PGPKeyPair ecdhPgpKeypair = new JcaPGPKeyPair (PGPPublicKey.ECDH, ecdhKeypair, new Date ()); // Fails

    PGPSignatureSubpacketGenerator flagsGen = new PGPSignatureSubpacketGenerator ();
    flagsGen.setKeyFlags (
        true,
        KeyFlags.CERTIFY_OTHER | 
            KeyFlags.SIGN_DATA | 
            KeyFlags.ENCRYPT_COMMS |
            KeyFlags.ENCRYPT_STORAGE
    );

    PGPDigestCalculator sha1Calculator = new JcaPGPDigestCalculatorProviderBuilder ()
        .build ()
        .get (HashAlgorithmTags.SHA1);

    PGPKeyRingGenerator keyRingGenerator = new PGPKeyRingGenerator (
        PGPSignature.POSITIVE_CERTIFICATION,
        dsaPgpKeypair,
        identity,
        sha1Calculator,
        flagsGenerator.generate (),
        null,
        new JcaPGPContentSignerBuilder (dsaPgpKeypair.getPublicKey ().getAlgorithm (), AlgorithmTags.SHA1),
        new JcePBESecretKeyEncryptorBuilder (PGPEncryptedDate.AES_256, sha1Calculator)
            .setProvider ("BC")
            .build (passphrase.toCharArray ())
    );

    keyRingGenerator.addSubKey (ecdhPgpKeypair);

    keyRingGenerator.generateSecretKeyRing ().encode (secretOut);
    secretOut.close ();

    keyRingGenerator.generatePublicKeyRing ().encode (publicOut);
    publicOut.close ();
} catch (Exception e) {
    // obligatory exception handling
}

供参考:生成 Curve25519 密钥的代码我改编自这个 GitHub 问题,以及生成和导出整个密钥环的代码我改编自这个 Bouncy Castle 示例

但是,上面的代码使用ECNamedCurveTable来自prime256v1.

为什么 JCA 密钥对和 OpenPGP 密钥对之间的转换对于使用 Curve25519 创建的密钥失败,而不是使用来自 的规范创建的密钥ECNamedCurveTable?我是否遗漏了某些东西,或者 Bouncy Castle 不支持 OpenPGP 键的自定义曲线?

标签: javabouncycastleopenpgpecdh

解决方案


推荐阅读