Java中ECDSA的PEM编码
我需要关于如何正确构造Java Private.pem的帮助。我有一个用java创建的ECDSA pem文件和一个用python创建的文件。我有正确的python实现,但java实现不正确Java中ECDSA的PEM编码,java,cryptography,bouncycastle,pem,ecdsa,Java,Cryptography,Bouncycastle,Pem,Ecdsa,我需要关于如何正确构造Java Private.pem的帮助。我有一个用java创建的ECDSA pem文件和一个用python创建的文件。我有正确的python实现,但java实现不正确 KeyPair pair = GenerateKeys(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic(); // Convert to Bytes then Hex for new account params
KeyPair pair = GenerateKeys();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();
// Convert to Bytes then Hex for new account params
byte[] bytePriv = priv.getEncoded();
byte[] bytePub = pub.getEncoded();
// save keys
SaveKeyToFile(bytePriv, "private", "private");
// Calls this function
public static void SaveKeyToFile(byte[] Key, String filename, String keyType) throws IOException, NoSuchAlgorithmException, NoSuchAlgorithmException, InvalidKeySpecException {
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
PemObjectGenerator pemObject = new PemObject("EC " + keyType.toUpperCase() + " KEY", Key);
pemWriter.flush();
pemWriter.close();
String privateKeyString = stringWriter.toString();
FileUtils.writeStringToFile(new File(filename + ".pem"), privateKeyString);
}
对于Java和Python的带有OpenSSL的ASN1解析(由于其长度,不包括hexdump):
至于输出PEM:
Java:
-----BEGIN EC PRIVATE KEY-----
MIGNAgEAMBAGByqGSM49AgEGBSuBBAAKBHYwdAIBAQQgiEc2TOzXj4mrUisuv+0p
xZ/z+Z/VyIvWug17zjNOPIKgBwYFK4EEAAqhRANCAATWi28vsiZdfqbqodDZc1uz
UFwNcu90l2ezayH0L4ZYB+MfReMCBFG/P6kn12GLj3DipqmvRucgmOlFVmggm+nH
-----END EC PRIVATE KEY-----
Python:
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEINTaEQvUvtOQlanp0lWv0KBcSs8IltKYH26OkoNxLQc5oAcGBSuBBAAK
oUQDQgAEcp3sseSpAXzIzWCwswYnsVnIZ0EEtkXl/CJWChQHilWLwWsxGq11/g/6
38UfZbsjE5TSf6zT8VXvTZE++u9c+A==
-----END EC PRIVATE KEY-----
非常感谢您的帮助 (很抱歉耽搁了。)
好的,您确实需要特定于算法的表单,但是JCE
PrivateKey.getEncoded()
返回PKCS8(处理所有算法)编码,这与Q基本相同,只是您需要ECC而不是RSA,而且(更重要的是)您正在使用Java和BouncyCastle
因此,您的选择是:
- 用PEM或直接用二进制(DER)编写PKCS8编码,并使用
或1.1.0openssl ec
将其转换为特定于算法的PEM形式,即SEC1(rfc5915基本上是SEC1的再版)openssl pkey-traditional
- 编写PKCS8编码(PEM或DER)并使用
提取算法特定部分,或确定算法特定部分的偏移量并直接提取。256位ECC密钥对DER编码大多为单八位组长度,但识别(命名)曲线的OID可能因不同曲线的大小不同而不同;如您的示例所示,secp256k1的值为24+2,因此您可以只为当前逻辑指定openssl asn1parse-strparse
对于大于256位的ECC密钥对,DER编码可能需要改变,边界附近可能取决于密钥对中的公共值是未压缩的还是压缩的形式,您没有实际的控制方法(JCE不提供编码中的选项)。这种情况下,至少需要手动处理一些DER,在这种情况下,我将转到下一个选项Arrays.copyOfRange(Key,26,Key.length)
- 您已经在使用的BC公开了操作PKCS8结构的能力,您可以使用它来提取特定于算法的SEC1编码,如下所示:
好的,您确实需要特定于算法的表单,但是JCE
PrivateKey.getEncoded()
返回PKCS8(处理所有算法)编码,这与Q基本相同,只是您需要ECC而不是RSA,而且(更重要的是)您正在使用Java和BouncyCastle
因此,您的选择是:
- 用PEM或直接用二进制(DER)编写PKCS8编码,并使用
或1.1.0openssl ec
将其转换为特定于算法的PEM形式,即SEC1(rfc5915基本上是SEC1的再版)openssl pkey-traditional
- 编写PKCS8编码(PEM或DER)并使用
提取算法特定部分,或确定算法特定部分的偏移量并直接提取。256位ECC密钥对DER编码大多为单八位组长度,但识别(命名)曲线的OID可能因不同曲线的大小不同而不同;如您的示例所示,secp256k1的值为24+2,因此您可以只为当前逻辑指定openssl asn1parse-strparse
对于大于256位的ECC密钥对,DER编码可能需要改变,边界附近可能取决于密钥对中的公共值是未压缩的还是压缩的形式,您没有实际的控制方法(JCE不提供编码中的选项)。这种情况下,至少需要手动处理一些DER,在这种情况下,我将转到下一个选项Arrays.copyOfRange(Key,26,Key.length)
- 您已经在使用的BC公开了操作PKCS8结构的能力,您可以使用它来提取特定于算法的SEC1编码,如下所示:
JCE
PrivateKey.getEncoded()
返回未加密的PKCS8编码;正确的PEM类型是BEGIN/END PRIVATE KEY
(没有像EC
这样的特定算法),然后OpenSSL和与OpenSSL兼容的东西将读取它。如果您需要OpenSSL的“传统”算法特定形式,则更难,但大部分是重复的;我现在得走了,如果需要的话,我可以稍后再补上。PS:EC密钥/keyparis可用于ECDSA,但不限于此。证书的使用会受到密钥使用的限制。谢谢您提供的信息。java pem输出必须符合以下规范:。信息技术
Java:
-----BEGIN EC PRIVATE KEY-----
MIGNAgEAMBAGByqGSM49AgEGBSuBBAAKBHYwdAIBAQQgiEc2TOzXj4mrUisuv+0p
xZ/z+Z/VyIvWug17zjNOPIKgBwYFK4EEAAqhRANCAATWi28vsiZdfqbqodDZc1uz
UFwNcu90l2ezayH0L4ZYB+MfReMCBFG/P6kn12GLj3DipqmvRucgmOlFVmggm+nH
-----END EC PRIVATE KEY-----
Python:
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEINTaEQvUvtOQlanp0lWv0KBcSs8IltKYH26OkoNxLQc5oAcGBSuBBAAK
oUQDQgAEcp3sseSpAXzIzWCwswYnsVnIZ0EEtkXl/CJWChQHilWLwWsxGq11/g/6
38UfZbsjE5TSf6zT8VXvTZE++u9c+A==
-----END EC PRIVATE KEY-----
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; // as defined by PKCS8
...
PrivateKey k = /* whatever */;
PemWriter w = new PemWriter (/* underlying writer */);
PrivateKeyInfo i = PrivateKeyInfo.getInstance(ASN1Sequence.getInstance(k.getEncoded()));
if( ! i.getPrivateKeyAlgorithm().getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey) ){
throw new Exception ("not EC key");
}
ASN1Object o = (ASN1Object) i.parsePrivateKey();
w.writeObject (new PemObject ("EC PRIVATE KEY", o.getEncoded("DER")));
// DER may already be the default but safer to (re)specify it
w.close();