Java中ECDSA的PEM编码

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

我需要关于如何正确构造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
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编码,并使用
    openssl ec
    或1.1.0
    openssl pkey-traditional
    将其转换为特定于算法的PEM形式,即SEC1(rfc5915基本上是SEC1的再版)

  • 编写PKCS8编码(PEM或DER)并使用
    openssl asn1parse-strparse
    提取算法特定部分,或确定算法特定部分的偏移量并直接提取。256位ECC密钥对DER编码大多为单八位组长度,但识别(命名)曲线的OID可能因不同曲线的大小不同而不同;如您的示例所示,secp256k1的值为24+2,因此您可以只为当前逻辑指定
    Arrays.copyOfRange(Key,26,Key.length)

    对于大于256位的ECC密钥对,DER编码可能需要改变,边界附近可能取决于密钥对中的公共值是未压缩的还是压缩的形式,您没有实际的控制方法(JCE不提供编码中的选项)。这种情况下,至少需要手动处理一些DER,在这种情况下,我将转到下一个选项

  • 您已经在使用的BC公开了操作PKCS8结构的能力,您可以使用它来提取特定于算法的SEC1编码,如下所示:

导入org.bouncycastle.asn1.asn1对象; 导入org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 导入org.bouncycastle.asn1.pkcs.PrivateKeyInfo;//如PKCS8所定义 ... 私钥k=/*无论什么*/; PemWriter w=新PemWriter(/*底层writer*/); PrivateKeyInfo i=PrivateKeyInfo.getInstance(ASN1Sequence.getInstance(k.getEncoded()); 如果(!i.getPrivateKeyAlgorithm().getAlgorithm().equals)(X9ObjectIdentifiers.id\u ecPublicKey)){ 抛出新异常(“非EC密钥”); } ASN1Object o=(ASN1Object)i.parsePrivateKey(); w、 writeObject(新的PemObject(“EC私钥”,o.getEncoded(“DER”)); //DER可能已经是默认值,但更安全的做法是(重新)指定它 w、 close(); (很抱歉耽搁了。)


好的,您确实需要特定于算法的表单,但是JCE
PrivateKey.getEncoded()
返回PKCS8(处理所有算法)编码,这与Q基本相同,只是您需要ECC而不是RSA,而且(更重要的是)您正在使用Java和BouncyCastle

因此,您的选择是:

  • 用PEM或直接用二进制(DER)编写PKCS8编码,并使用
    openssl ec
    或1.1.0
    openssl pkey-traditional
    将其转换为特定于算法的PEM形式,即SEC1(rfc5915基本上是SEC1的再版)

  • 编写PKCS8编码(PEM或DER)并使用
    openssl asn1parse-strparse
    提取算法特定部分,或确定算法特定部分的偏移量并直接提取。256位ECC密钥对DER编码大多为单八位组长度,但识别(命名)曲线的OID可能因不同曲线的大小不同而不同;如您的示例所示,secp256k1的值为24+2,因此您可以只为当前逻辑指定
    Arrays.copyOfRange(Key,26,Key.length)

    对于大于256位的ECC密钥对,DER编码可能需要改变,边界附近可能取决于密钥对中的公共值是未压缩的还是压缩的形式,您没有实际的控制方法(JCE不提供编码中的选项)。这种情况下,至少需要手动处理一些DER,在这种情况下,我将转到下一个选项

  • 您已经在使用的BC公开了操作PKCS8结构的能力,您可以使用它来提取特定于算法的SEC1编码,如下所示:

导入org.bouncycastle.asn1.asn1对象; 导入org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 导入org.bouncycastle.asn1.pkcs.PrivateKeyInfo;//如PKCS8所定义 ... 私钥k=/*无论什么*/; PemWriter w=新PemWriter(/*底层writer*/); PrivateKeyInfo i=PrivateKeyInfo.getInstance(ASN1Sequence.getInstance(k.getEncoded()); 如果(!i.getPrivateKeyAlgorithm().getAlgorithm().equals)(X9ObjectIdentifiers.id\u ecPublicKey)){ 抛出新异常(“非EC密钥”); } ASN1Object o=(ASN1Object)i.parsePrivateKey(); w、 writeObject(新的PemObject(“EC私钥”,o.getEncoded(“DER”)); //DER可能已经是默认值,但更安全的做法是(重新)指定它 w、 close();
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();