我想用SHA-384生成384位椭圆曲线签名,以生成密钥。我通过查看这个SO从OpenSSL命令行生成EC密钥对来运行以下步骤
openssl ecparam -name secp384r1 -genkey -noout -out d:/private.ec.key
openssl ec -in d:/private.pem -pubout -out d:/public.pem
openssl pkcs8 -topk8 -nocrypt -in d:/private.ec.key -out d:/private.pem
当我被要求输入密码时,我按下了回车键(因为我不想拥有受密码保护的密钥)。
然后,我为JRE 14下载了bcprov-jdk15on-168.jar Bouncy Castle lib,并将其添加到我的类路径中。并做了一个小的测试应用程序,将这些键的内容直接复制到java源代码中去做简单的事情。
制作了一个简单的剥离方法来删除密钥的"文本"部分并解码其base64内容:
private static byte[] bytesFromKeyStrings(String string) {
string = string.replaceAll("-----BEGIN PRIVATE KEY-----", "");
string = string.replaceAll("-----BEGIN EC PRIVATE KEY-----", "");
string = string.replaceAll("-----END EC PRIVATE KEY-----", "");
string = string.replaceAll("-----END PRIVATE KEY-----", "");
string = string.replaceAll("r", "");
string = string.replaceAll("n", "");
var bytes = Base64.getDecoder().decode(string);
return bytes;
}
然后,我从这些字节中生成一个PrivateKey:
private static PrivateKey keyFromBytes(byte[] pkcs8key) throws NoSuchAlgorithmException, InvalidKeySpecException {
Security.addProvider(BOUNCY_CASTLE_PROVIDER);
var spec = ECNamedCurveTable.getParameterSpec("secp384r1");;
var ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(1, pkcs8key), spec);
var factory = KeyFactory.getInstance("ECDSA", BOUNCY_CASTLE_PROVIDER);
return factory.generatePrivate(ecPrivateKeySpec);
}
但是,当我要使用PrivateKey对消息进行签名时(在本例中为零数组),我会得到一个异常:
var key = keyFromBytes(bytesFromKeyStrings(privatePem));
var ecdsaSign = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
ecdsaSign.initSign(key, new SecureRandom());
ecdsaSign.update(content);
var signature = ecdsaSign.sign();
线路上引起:
ecdsaSign.initSign(密钥,new SecureRondom());
java.lang.IllegalArgumentException: Scalar is not in the interval [1, n - 1]
at org.bouncycastle.provider/org.bouncycastle.crypto.params.ECDomainParameters.validatePrivateScalar(ECDomainParameters.java:146)
at org.bouncycastle.provider/org.bouncycastle.crypto.params.ECPrivateKeyParameters.<init>(ECPrivateKeyParameters.java:16)
at org.bouncycastle.provider/org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil.generatePrivateKeyParameter(ECUtil.java:245)
at org.bouncycastle.provider/org.bouncycastle.jcajce.provider.asymmetric.ec.SignatureSpi.engineInitSign(Unknown Source)
at java.base/java.security.SignatureSpi.engineInitSign(SignatureSpi.java:131)
at java.base/java.security.Signature$Delegate.engineInitSign(Signature.java:1364)
at java.base/java.security.Signature.initSign(Signature.java:658)
at ecdsa/ecdsa.Main.main(Main.java:75)
如果我正确理解ECDSA,我们需要将私钥乘以某个随机值,所以我提供它secureRandom。奇怪的是,我之前的尝试是,当我没有尝试读取密钥并使用KeyPairGenerator.getInstance("EC")(没有bouncycastle库)动态生成密钥时,这些生成的密钥可以毫无例外地用于对消息进行签名,我单独验证了生成的签名是否正确。
我是不是生成的密钥不好,或者有其他方法可以提供乘数常数,这样它就不会试图直接用私钥签名并给我一个例外?
还是我错过了一些愚蠢的东西?
下面是我的测试应用程序的完整列表,它可以重现异常:
package ecdsa;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
public class Main {
private final static String privatePem = "-----BEGIN PRIVATE KEY-----rn"
+ "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdxrn"
+ "bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjsrn"
+ "zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmrn"
+ "MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=rn"
+ "-----END PRIVATE KEY-----rn";
private final static String privateEc = "-----BEGIN EC PRIVATE KEY-----rn"
+ "MIGkAgEBBDBBdsy5smSA2+DvnIdxbqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfrn"
+ "BpYPgCWlybGgBwYFK4EEACKhZANiAAQ0iyw2wPjszhale0mPkiCCTzcNzTW1g7zqrn"
+ "UoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmMWGYZUSSq4noniTDt8INj/Elrn"
+ "ndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=rn"
+ "-----END EC PRIVATE KEY-----rn";
private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
private static byte[] bytesFromKeyStrings(String string) {
string = string.replaceAll("-----BEGIN PRIVATE KEY-----", "");
string = string.replaceAll("-----BEGIN EC PRIVATE KEY-----", "");
string = string.replaceAll("-----END EC PRIVATE KEY-----", "");
string = string.replaceAll("-----END PRIVATE KEY-----", "");
string = string.replaceAll("r", "");
string = string.replaceAll("n", "");
var bytes = Base64.getDecoder().decode(string);
return bytes;
}
private static PrivateKey keyFromBytes(byte[] pkcs8key) throws NoSuchAlgorithmException, InvalidKeySpecException {
Security.addProvider(BOUNCY_CASTLE_PROVIDER);
var spec = ECNamedCurveTable.getParameterSpec("secp384r1");;
var ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(1, pkcs8key), spec);
var factory = KeyFactory.getInstance("ECDSA", BOUNCY_CASTLE_PROVIDER);
return factory.generatePrivate(ecPrivateKeySpec);
}
public static void main(String[] args) {
var content = new byte[100];
try {
var key = keyFromBytes(bytesFromKeyStrings(privatePem));
var ecdsaSign = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
ecdsaSign.initSign(key, new SecureRandom());
ecdsaSign.update(content);
var signature = ecdsaSign.sign();
} catch (Exception e) {
e.printStackTrace();
}
}
}
编辑:更新了示例(以前我使用加密私钥)
为什么它不起作用
OpenSSL支持的所有密钥格式不仅仅是原始密钥,还包括一些元数据;特别是所有EC密钥都是有意义的并且仅关于密钥文件中包括的特定曲线可用。openssl pkcs8 -topk8 [-nocrypt]
产生的两种格式是PKCS8中定义的未加密和加密格式,更方便地使用RFC5208,例如在维基百科中可以很容易地找到。这些格式在PEM类型"BEGIN/END PRIVATE KEY"one_answers"BEGIN/END ENCRYPTED PRIVATE KEY'中的使用在RFC7468第10节和第11节中进行了形式化,尽管几十年前OpenSSL已经将它们作为实际标准。
Michael Fehr的第一个答案向您显示了加密表单的细分,但即使是未加密的表单也仍然包含元数据,该元数据使用secp384r1(也称为p-384曲线)将其识别为EC算法:
$ cat 65740255.clr
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdx
bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjs
zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMm
MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=
-----END PRIVATE KEY-----
$ openssl asn1parse <65740255.clr -i
0:d=0 hl=3 l= 182 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :00
6:d=1 hl=2 l= 16 cons: SEQUENCE
8:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
17:d=2 hl=2 l= 5 prim: OBJECT :secp384r1
24:d=1 hl=3 l= 158 prim: OCTET STRING [HEX DUMP]:30819B02010104304176CCB9B26480DBE0EF9C87716EAABA1B0C0769D11DB47A9C28EF4DF21074FCD2AF14E0A61C149F06960F8025A5C9B1A16403620004348B2C36C0F8ECCE16A57B498F9220824F370DCD35B583BCEA5283775CDB996DA2B514785554CB32C14692E8C494248EABD50714CE2326316198654492AB89E89E24C3B7C20D8FF1259DD2A16E1DE8482AB78F5A0A2BD7185E2DEE1AE0C55E4B
对于熟悉ASN.1的人来说,PKCS8中最后一个未加密的字段(即依赖于算法的编码)本身就是ASN.1结构。RFC5915指定了基于"SEC1"文档的X9类型EC私钥的ASN.1结构(但不是像Bernstein等人的EdDSA这样的较新EC算法)。分析发现,它实际上包含实际私钥(即通常用Java S表示的数字)和公钥(一个通常用Q表示的点,但在Java W中,用X9未压缩格式表示)(这在技术上是多余的,因为它可以从私钥和曲线方程中重新计算):
$ openssl asn1parse <65740255.clr -i -strparse 27 -dump
0:d=0 hl=3 l= 155 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :01
6:d=1 hl=2 l= 48 prim: OCTET STRING
0000 - 41 76 cc b9 b2 64 80 db-e0 ef 9c 87 71 6e aa ba Av...d......qn..
0010 - 1b 0c 07 69 d1 1d b4 7a-9c 28 ef 4d f2 10 74 fc ...i...z.(.M..t.
0020 - d2 af 14 e0 a6 1c 14 9f-06 96 0f 80 25 a5 c9 b1 ............%...
56:d=1 hl=2 l= 100 cons: cont [ 1 ]
58:d=2 hl=2 l= 98 prim: BIT STRING
0000 - 00 04 34 8b 2c 36 c0 f8-ec ce 16 a5 7b 49 8f 92 ..4.,6......{I..
0010 - 20 82 4f 37 0d cd 35 b5-83 bc ea 52 83 77 5c db .O7..5....R.w.
0020 - 99 6d a2 b5 14 78 55 54-cb 32 c1 46 92 e8 c4 94 .m...xUT.2.F....
0030 - 24 8e ab d5 07 14 ce 23-26 31 61 98 65 44 92 ab $......#&1a.eD..
0040 - 89 e8 9e 24 c3 b7 c2 0d-8f f1 25 9d d2 a1 6e 1d ...$......%...n.
0050 - e8 48 2a b7 8f 5a 0a 2b-d7 18 5e 2d ee 1a e0 c5 .H*..Z.+..^-....
0060 - 5e 4b ^K
另一个选项
如果除了bcprov
之外还使用BouncyCastlebcpkix
jar,它还提供了直接读取(和写入)所有OpenSSL PEM格式的例程,包括PKCS8和OpenSSL的"传统"或"遗留"算法特定格式BEGIN/END EC PRIVATE KEY
,后者只是PEM包装中的SEC1。请参阅例如:
在JAVA中读取格式为PKCS1的RSA私钥
从RSA.pem文件中获取私钥
使用BouncyCastle从文件中读取椭圆曲线私钥
How to Load RSA private key from file
(尽管其中一些适用于RSA,但问题与EC相同)。
String pk8e = "-----BEGIN ENCRYPTED PRIVATE KEY-----rn"
+ "MIIBHDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIG5SFWXEmy8QCAggArn"
+ "MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBu6HN0VZ92vDYuKa5aLoD8BIHArn"
+ "UK8AbLTo5C2ZkhVfnXSfNefUup2Il1xwF0FXrA2WkJ/d+fokLijgkTyal43t8iMJrn"
+ "ne3gOjYP8Q558x+4k4TAMWug0nDh9RPINMqABnhPkf5wyCCYI2RN2b3C4SZCBMQwrn"
+ "r+cwVgwiShhPHcuUM9BmFlt9eCr3kuFnfMxlvvpR482kIT+Q6+hZsyUL/oJjOVC9rn"
+ "R2S7AwiKH4BPj5TBjMKF4ZI5cS0DMXn1q3h21AUdMPUchX6itcDTfWvEIfTwpUr0rn"
+ "-----END ENCRYPTED PRIVATE KEY-----rn";
String pk8u = "-----BEGIN PRIVATE KEY-----rn"
+ "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdxrn"
+ "bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjsrn"
+ "zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmrn"
+ "MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=rn"
+ "-----END PRIVATE KEY-----rn";
String trad = "-----BEGIN EC PRIVATE KEY-----rn"
+ "MIGkAgEBBDBBdsy5smSA2+DvnIdxbqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfrn"
+ "BpYPgCWlybGgBwYFK4EEACKhZANiAAQ0iyw2wPjszhale0mPkiCCTzcNzTW1g7zqrn"
+ "UoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmMWGYZUSSq4noniTDt8INj/Elrn"
+ "ndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=rn"
+ "-----END EC PRIVATE KEY-----rn";
@SuppressWarnings("resource") // should use try-resources or similar
Object o1 = new PEMParser (new StringReader (pk8e)).readObject();
PrivateKey k1 = new JcaPEMKeyConverter().getPrivateKey(
((org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo)o1).decryptPrivateKeyInfo(
new JceOpenSSLPKCS8DecryptorProviderBuilder().build(/*password*/"".toCharArray()) ));
System.out.println ( ((java.security.interfaces.ECPrivateKey)k1).getS() .toString(16));
@SuppressWarnings("resource") // should use try-resources or similar
Object o2 = new PEMParser (new StringReader (pk8u)).readObject();
PrivateKey k2 = new JcaPEMKeyConverter().getPrivateKey((PrivateKeyInfo)o2);
System.out.println ( ((java.security.interfaces.ECPrivateKey)k2).getS() .toString(16));
@SuppressWarnings("resource") // should use try-resources or similar
Object o3 = new PEMParser (new StringReader (trad)).readObject();
PrivateKey k3 = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair)o3).getPrivate();
System.out.println ( ((java.security.interfaces.ECPrivateKey)k3).getS() .toString(16));
->
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fcd2af14e0a61c149f06960f8025a5c9b1
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fcd2af14e0a61c149f06960f8025a5c9b1
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fcd2af14e0a61c149f06960f8025a5c9b1
这个(十六进制)数字是"原始"私钥,这是您可以为发布的方法在ECPrivateKeySpec
中放入的值(作为正BigInteger
)。(我不得不使一些名称包合格,因为在我的开发环境中,我有冲突的导入;你可能不需要它。)
我在第二个答案中回答,因为我的第一个答案不再适合这个问题,因为您编辑了您的问题,并将私钥pem更改为未加密数据。
由于您的密钥是私钥的编码形式,它具有PKCS#8结构,因此任何读者都可以识别密钥的类型和底层曲线,因此您不需要使用ECPrivateKeySpec构建它。使用此代码有一种更简单的方法:
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8key);
return keyFactory.generatePrivate(privateKeySpec);
公钥也是如此,只需使用X509EncodedKeySpec(请参阅完整的代码示例)。
我附加了bytesFromKeyStrings函数,将公钥的密钥数据转换为字节数组。
以下是读取私钥pem、对消息进行签名、读取公钥pem(源自私钥)并用";真";如预期结果。
输出:
signatureVerified: true
安全警告:以下代码没有异常处理,仅用于教育目的:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class MainSo {
private final static String privatePem = "-----BEGIN PRIVATE KEY-----rn"
+ "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBBdsy5smSA2+DvnIdxrn"
+ "bqq6GwwHadEdtHqcKO9N8hB0/NKvFOCmHBSfBpYPgCWlybGhZANiAAQ0iyw2wPjsrn"
+ "zhale0mPkiCCTzcNzTW1g7zqUoN3XNuZbaK1FHhVVMsywUaS6MSUJI6r1QcUziMmrn"
+ "MWGYZUSSq4noniTDt8INj/ElndKhbh3oSCq3j1oKK9cYXi3uGuDFXks=rn"
+ "-----END PRIVATE KEY-----rn";
/*
Key Details:
Type: EC
Size (bits): 384
Curve Name: secp384r1
Curve OID: 1.3.132.0.34
Public key (x):
348b2c36c0f8ecce16a57b498f9220824f370dcd35b583bcea5283775cdb996d
a2b514785554cb32c14692e8c494248e
Public key (y):
abd50714ce2326316198654492ab89e89e24c3b7c20d8ff1259dd2a16e1de848
2ab78f5a0a2bd7185e2dee1ae0c55e4b
Private key (d):
4176ccb9b26480dbe0ef9c87716eaaba1b0c0769d11db47a9c28ef4df21074fc
d2af14e0a61c149f06960f8025a5c9b1
Public Key in PEM Format:
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENIssNsD47M4WpXtJj5Iggk83Dc01tYO8
6lKDd1zbmW2itRR4VVTLMsFGkujElCSOq9UHFM4jJjFhmGVEkquJ6J4kw7fCDY/x
JZ3SoW4d6Egqt49aCivXGF4t7hrgxV5L
-----END PUBLIC KEY-----
*/
private final static String publicPem = "-----BEGIN PUBLIC KEY-----n" +
"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENIssNsD47M4WpXtJj5Iggk83Dc01tYO8n" +
"6lKDd1zbmW2itRR4VVTLMsFGkujElCSOq9UHFM4jJjFhmGVEkquJ6J4kw7fCDY/xn" +
"JZ3SoW4d6Egqt49aCivXGF4t7hrgxV5Ln" +
"-----END PUBLIC KEY-----";
private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
private static byte[] bytesFromKeyStrings(String string) {
string = string.replaceAll("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
string = string.replaceAll("-----BEGIN PRIVATE KEY-----", "");
string = string.replaceAll("-----BEGIN PUBLIC KEY-----", "");
string = string.replaceAll("-----BEGIN EC PRIVATE KEY-----", "");
string = string.replaceAll("-----END EC PRIVATE KEY-----", "");
string = string.replaceAll("-----END ENCRYPTED PRIVATE KEY-----", "");
string = string.replaceAll("-----END PRIVATE KEY-----", "");
string = string.replaceAll("-----END PUBLIC KEY-----", "");
string = string.replaceAll("r", "");
string = string.replaceAll("n", "");
return Base64.getDecoder().decode(string);
}
private static PrivateKey privateKeyFromBytes(byte[] pkcs8key) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
Security.addProvider(BOUNCY_CASTLE_PROVIDER);
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8key);
return keyFactory.generatePrivate(privateKeySpec);
}
private static PublicKey publicKeyFromBytes(byte[] x509key) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
Security.addProvider(BOUNCY_CASTLE_PROVIDER);
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(x509key);
return keyFactory.generatePublic(publicKeySpec);
}
public static void main(String[] args) {
System.out.println("https://stackoverflow.com/questions/65740255/scalar-is-not-in-the-interval-1-n-1-exception-when-signing-ecdsa-with-sha/65742506?noredirect=1#comment116237430_65742506");
var content = new byte[100];
try {
// signature with private key
var privateKey = privateKeyFromBytes(bytesFromKeyStrings(privatePem));
var ecdsaSign = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
ecdsaSign.initSign(privateKey, new SecureRandom());
ecdsaSign.update(content);
var signature = ecdsaSign.sign();
// verification with the public key
var publicKey = publicKeyFromBytes(bytesFromKeyStrings(publicPem));
var ecdsaVerify = Signature.getInstance("SHA384withECDSA", BOUNCY_CASTLE_PROVIDER);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(content);
boolean signatureVerified = ecdsaVerify.verify(signature);
System.out.println("signatureVerified: " + signatureVerified);
} catch (Exception e) {
e.printStackTrace();
}
}
}
根据https://lapo.it/asn1js/PEM编码中的私钥仍然是加密一个-用"-----开始加密私钥-----":
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.113549.1.5.13 pkcs5PBES2 (PKCS #5 v2.0)
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.113549.1.5.12 pkcs5PBKDF2 (PKCS #5 v2.0)
SEQUENCE (3 elem)
OCTET STRING (8 byte) 1B9485597126CBC4
INTEGER 2048
SEQUENCE (2 elem)
OBJECT IDENTIFIER 1.2.840.113549.2.9 hmacWithSHA256 (RSADSI digestAlgorithm)
NULL
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC (NIST Algorithm)
OCTET STRING (16 byte) 6EE87374559F76BC362E29AE5A2E80FC
OCTET STRING (192 byte) 50AF006CB4E8E42D9992155F9D749F35E7D4BA9D88975C70174157AC0D96909FDDF9F…
要获得一个有效且未加密的文件,请使用此OpenSSL命令将加密文件转换为未加密文件:
openssl pkcs8 -topk8 -nocrypt -in ecprivateencrypted.pem -out ecprivateunencrypted.pem
我试图自己转换文件,但我的OpenSSL拒绝了,因为密码短语长度(只需点击回车键)太短。