java - 使用 bouncy caSTLe 生成 dsa/elgamal key 对,在 GPG 中导入时不会出错

标签 java bouncycastle gnupg dsa elgamal

我创建了一个小程序来使用 Bouncy CaSTLe 1.47 API 生成 DSA/El Gamal PGP key 环。 key 生成非常顺利,没有错误。我使用装甲输出将私钥和公钥导出到一个文件中,当我尝试使用 GPG(确切地说是 KGpg)导入生成的私钥时,出现以下错误:

[GNUPG:] NODATA 1
[GNUPG:] IMPORT_OK 17 1277C25B455C71D91EE42C8FF9A6087305C00DA6
[GNUPG:] IMPORTED F9A6087305C00DA6 test@gmail.com
[GNUPG:] IMPORT_OK 1 1277C25B455C71D91EE42C8FF9A6087305C00DA6
[GNUPG:] IMPORT_RES 1 0 1 0 0 0 0 0 0 1 1 0 0 0

单击“确定”后,它告诉我只处理了 1 个 key 。看起来它只使用了 DSA key ,因为在屏幕上它显示为 1024/0。

** 编辑 ** 我刚刚尝试在 Windows 上的 PGP 10.1.0 中打开 key ,它也给了我一个错误“ key 环包含一个坏的(损坏的)PGP 数据包。”

我正在使用的代码如下所示,第一个是 Utility 类,第二个是调用它来创建 Key 的程序。

package george.crypto.pgp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.Date;

import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ElGamalParameterSpec;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPKeyRingGenerator;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;

public final class PGPTools {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private PGPTools() {

    }

    public static final void exportSecretKey(PGPKeyRingGenerator pgpKeyRingGen, File keyFile, boolean asciiArmor) throws IOException {
        PGPSecretKeyRing pgpSecKeyRing = pgpKeyRingGen.generateSecretKeyRing();

        if(asciiArmor) {
            pgpSecKeyRing.encode(new ArmoredOutputStream(new FileOutputStream(keyFile)));
        }
        else {
            pgpSecKeyRing.encode(new FileOutputStream(keyFile));
        }
    }

    public static final void exportPublicKey(PGPKeyRingGenerator pgpKeyRingGen, File keyFile, boolean asciiArmor) throws IOException {
        PGPPublicKeyRing pgpPubKeyRing = pgpKeyRingGen.generatePublicKeyRing();

        if(asciiArmor) {
            pgpPubKeyRing.encode(new ArmoredOutputStream(new FileOutputStream(keyFile)));
        }
        else {
            pgpPubKeyRing.encode(new FileOutputStream(keyFile));
        }
    }

    /**
     * 
     * @param dsaKeyPair - the generated DSA key pair
     * @param elGamalKeyPair - the generated El Gamal key pair
     * @param identity - the given identity of the key pair ring
     * @param passphrase - the secret pass phrase to protect the key pair
     * @return a PGP Key Ring Generate with the El Gamal key pair added as sub key
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public static final PGPKeyRingGenerator createPGPKeyRingGenerator(KeyPair dsaKeyPair, KeyPair elGamalKeyPair, String identity, char[] passphrase) throws Exception
    {
        PGPKeyPair dsaPgpKeyPair = new PGPKeyPair(PGPPublicKey.DSA, dsaKeyPair, new Date());
        PGPKeyPair elGamalPgpKeyPair = new PGPKeyPair(PGPPublicKey.ELGAMAL_ENCRYPT, elGamalKeyPair, new Date());
        PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1);
        PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, dsaPgpKeyPair, identity, sha1Calc, null, null, new JcaPGPContentSignerBuilder(dsaPgpKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("BC").build(passphrase));
        keyRingGen.addSubKey(elGamalPgpKeyPair);
        return keyRingGen;
    }

    /**
     * 
     * @param keySize 512 - 1024 (multiple of 64)
     * @return the DSA generated key pair
     * @throws NoSuchProviderException 
     * @throws NoSuchAlgorithmException 
     */
    public static final KeyPair generateDsaKeyPair(int keySize) throws NoSuchAlgorithmException, NoSuchProviderException
    {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA", "BC");
        keyPairGenerator.initialize(keySize);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    /**
     * 
     * @param keySize - 1024, 2048, 4096
     * @return the El Gamal generated key pair
     * @throws Exception 
     */
    public static final KeyPair generateElGamalKeyPair(int keySize) throws Exception
    {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ELGAMAL", "BC");
        keyPairGenerator.initialize(keySize);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    /**
     * 
     * @param paramSpecs - the pre-defined parameter specs
     * @return the El Gamal generated key pair
     * @throws Exception
     */
    public static final KeyPair generateElGamalKeyPair(ElGamalParameterSpec paramSpecs) throws Exception
    {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ELGAMAL", "BC");
        keyPairGenerator.initialize(paramSpecs);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }
}

package george.crypto.pgp;

import java.io.File;
import java.math.BigInteger;
import java.security.KeyPair;

import org.bouncycastle.jce.spec.ElGamalParameterSpec;
import org.bouncycastle.openpgp.PGPKeyRingGenerator;

public class PGPCryptoBC {

    public PGPCryptoBC() {
        try {
            String keysDir = System.getProperty("user.dir")+File.separator+"src/george/crypto/pgp/keys";

            //Generating a safe prime is a very long process so it's better to use
            //a pre-generated safe prime, I took this from http://www.cryptopp.com/fom-serve/cache/71.html
            BigInteger primeModulous = new BigInteger("36F0255DDE973DCB3B399D747F23E32ED6FDB1F77598338BFDF44159C4EC64DDAEB5F78671CBFB22106AE64C32C5BCE4CFD4F5920DA0EBC8B01ECA9292AE3DBA1B7A4A899DA181390BB3BD1659C81294F400A3490BF9481211C79404A576605A5160DBEE83B4E019B6D799AE131BA4C23DFF83475E9C40FA6725B7C9E3AA2C6596E9C05702DB30A07C9AA2DC235C5269E39D0CA9DF7AAD44612AD6F88F69699298F3CAB1B54367FB0E8B93F735E7DE83CD6FA1B9D1C931C41C6188D3E7F179FC64D87C5D13F85D704A3AA20F90B3AD3621D434096AA7E8E7C66AB683156A951AEA2DD9E76705FAEFEA8D71A5755355970000000000000001", 16);
            BigInteger baseGenerator = new BigInteger("2", 16);
            ElGamalParameterSpec paramSpecs = new ElGamalParameterSpec(primeModulous, baseGenerator);

            KeyPair dsaKeyPair = PGPTools.generateDsaKeyPair(1024);
            KeyPair elGamalKeyPair = PGPTools.generateElGamalKeyPair(paramSpecs);
            PGPKeyRingGenerator pgpKeyRingGen = PGPTools.createPGPKeyRingGenerator(dsaKeyPair, elGamalKeyPair, "test@gmail.com", "TestPass12345!".toCharArray());

            PGPTools.exportSecretKey(pgpKeyRingGen, new File(keysDir+File.separator+"secret.asc"), true);
            PGPTools.exportPublicKey(pgpKeyRingGen, new File(keysDir+File.separator+"public.asc"), true);
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String ... args) {
        new PGPCryptoBC();
    }
}

生成的输出是 2 个文件“secret.asc”和“public.asc”如果我尝试在 GPG 中导入“secret.asc”我会收到错误消息并且 El Gamal 子 key 不会被导入。

有谁知道这有什么问题吗?

最佳答案

我设法解决了我自己的问题。我需要在最后明确关闭输出流。不这样做会导致数据损坏。

其次,作为额外的奖励,如果我使用 rfc3526 中列出的 Safe Prime(素数模数),它允许我生成不同位大小长度的 El Gamal key 。

关于java - 使用 bouncy caSTLe 生成 dsa/elgamal key 对,在 GPG 中导入时不会出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13733260/

相关文章:

java.lang.ClassNotFoundException : org. bouncycaSTLe.jcajce.provider.asymmetric.rsa.CipherSpi$NoPadding 错误

java - OnPostExecute 未获取字符串

java - 为什么final变量没有内部类就返回?

java - Android 1.6 中 bundle 了哪个版本的 Apache HTTP 客户端?

java - 通过使用 BouncyCaSTLe 进行 CSR 签名生成的证书被认为是不受信任的

java - bouncy caSTLe pgp - PartialInputStream 中的流过早结束

repository - 如何在Windows中的Jcenter的Bintray中生成gpg签名 key

c# - 假设 always-trust 在 GPG cmd 中是 yes/true

gnupg - 如何编辑我的私有(private)/ secret gnupg key

javascript - 在包中运行 Javascript 和 Servlet 代码