无法从.pem文件中读取DSA密钥

时间:2017-10-19 21:38:38

标签: java openssl digital-signature

我使用openssl生成公钥和私钥DSA并运行以下命令:

openssl dsaparam -out dsaparam.pem 1024
openssl gendsa -out dsaprivkey.pem dsaparam.pem
openssl req -new -x509 -key dsaprivkey.pem -out dsacert.pem

使用以下两种方法加载这些键:

public static PrivateKey loadPrivateKey() throws Exception {
    String privateKeyPEM = FileUtils.readFileToString(new File("/Keys/dsaprivkey.pem"), StandardCharsets.UTF_8);

    // strip of header, footer, newlines, whitespaces
    privateKeyPEM = privateKeyPEM
            .replace("-----BEGIN DSA PRIVATE KEY-----", "")
            .replace("-----END DSA PRIVATE KEY-----", "")
            .replaceAll("\\s", "");

    // decode to get the binary DER representation
    byte[] privateKeyDER = Base64.getDecoder().decode(privateKeyPEM);

    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyDER));
    return privateKey;
}

public static PublicKey loadPublicKey() throws Exception {
    String publicKeyPEM = FileUtils.readFileToString(new File("/Keys/dsacert.pem"), StandardCharsets.UTF_8);

    // strip of header, footer, newlines, whitespaces
    publicKeyPEM = publicKeyPEM
            .replace("-----BEGIN CERTIFICATE-----", "")
            .replace("-----END CERTIFICATE-----", "")
            .replaceAll("\\s", "");

    // decode to get the binary DER representation
    byte[] publicKeyDER = Base64.getDecoder().decode(publicKeyPEM);

    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyDER));
    return publicKey;
}

但是,我无法读取公钥或私钥。

当我尝试阅读公钥时,我得到:

java.security.spec.InvalidKeySpecException: Inappropriate key specification: IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)

当我尝试阅读私钥时,我得到:

Exception in thread "main" java.security.spec.InvalidKeySpecException: Inappropriate key specification: IOException : algid parse error, not a sequence

如果某人遇到同样的情况,我将非常感谢您对此问题的任何帮助

1 个答案:

答案 0 :(得分:3)

您没有生成私钥和公钥,而是生成私钥和(X.509)证书。证书包含公钥,但公钥不同。

要使用Java读取X.509证书,请使用CertificateFactory(通常直接来自文件)(see javadoc online)而非KeyFactory(在依赖于密钥的*Spec类上) 。与KeyFactory(s)不同,CertificateFactory可以处理PEM或DER输入,因此您不需要自己执行strip-BEGIN / END和de-base64(除非您愿意)。

对于私钥,您遇到的问题与jww评论的问题类似但不一样。对于公钥文件(您没有),OpenSSL默认使用Java调用X509EncodedKeySpec和OpenSSL内部调用PUBKEY的SubjectPublicKeyInfo格式。但是对于私有密钥文件,OpenSSL使用自己的“遗留”格式标准化的PKCS8格式,但Java的PKCS8EncodedKeySpec仅支持其中的第二种,命令正在使用第一个,并且在代码中它们之间的转换并不是微不足道的。你有三个或四个选择:

  • 使用openssl转换为PKCS8-unncrypted: openssl pkcs8 -topk8 -nocrypt -in dsaprivkey.pem -out dsaprivfixed.pem # or in 1.0.0 up openssl pkey -in dsaprivkey.pem -out dsaprivfixed.pem

    现在,您可以使用发布的代码阅读此内容,但要移除的行是-----BEGIN PRIVATE KEY----------END PRIVATE KEY----- ,而不是 DSA。作为一项小改进,如果您使用getMimeDecoder,则无需自己剥离空白。

  • 生成PKCS8(未加密),以openssl 1.0.0开头: # you can generate the key within req instead of separately: openssl dsaparam -out params size openssl req -new -newkey dsa:params -x509 -nodes -keyout private.pem \ -out cert.pem # -nodes really means "don't encrypt key" for hysterical raisins # or in config file set encrypt_rsa_key=no (yes even for other algos!) # or omit it and set encrypt_key=no (more sensible) # # or you can use (new) genpkey instead of (old) gendsa: openssl dsaparam -out params size openssl genpkey -paramfile params -out private.pem openssl req -new -x509 -key private.pem -out cert.pem

    现在你和上面的情况一样。

  • 使用BouncyCastle中的PEM功能来读取旧版格式。
    Reading elliptic curve private key from file with BouncyCastle
    How to Load RSA Private Key From File

  • 读取旧格式(正如您现在所做)并为其重建PKCS8 ASN.1编码,然后在PKCS8上使用KeyFactory。这是一个很复杂的事情,我不推荐它。我确实有一个适用于RSA(更简单)的工作示例,但我找不到它;如果可能,将在稍后添加。