我使用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
如果某人遇到同样的情况,我将非常感谢您对此问题的任何帮助
答案 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(更简单)的工作示例,但我找不到它;如果可能,将在稍后添加。