文档首页/ 数据加密服务 DEW/ 常见问题/ 密钥管理/ 如何将原始SM2私钥转换成PKCS8格式的私钥对象?
更新时间:2025-05-13 GMT+08:00
分享

如何将原始SM2私钥转换成PKCS8格式的私钥对象?

背景

SM2私钥是一个256bits的大整数,但是在密钥对导入场景,要求私钥对象是ASN.1编码之后,再对数据进行二进制编码,得到DER格式。仅通过OPENSSL命令无法获得。

本示例介绍如何将一个原始的SM2私钥转换成PKCS8格式的私钥。

环境准备

  • 搭建JAVA环境,并引入bouncy castle 1.78及其以后的版本。
  • 环境安装OpenSSL 1.1.1m及以后的版本。

将私钥转换为PKCS8对象

sm2p256v1的私钥示例, 原始私钥16进制表示如下:

```5AF8F37036DFF6C303B65DF52674B6B8269BCDF1D70DC6305D93F975DCA2469A```

  • 示例的私钥仅作演示使用,请勿用到实际生产环境。
  • 本示例不包含修补GmSSL启用包装密钥算法。

通过如下代码,将私钥转换成PKCS8对象:

```java
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;

public class RawSm2PrivateKeyToPKCS8Object {

    private static final String CURVE_NAME = "sm2p256v1";

    private static final X9ECParameters X9_EC_PARAMETERS = GMNamedCurves.getByName(CURVE_NAME);

    private static final ECParameterSpec EC_PARAMETER_SPEC = new ECNamedCurveParameterSpec(CURVE_NAME,
        X9_EC_PARAMETERS.getCurve(),
        X9_EC_PARAMETERS.getG(), X9_EC_PARAMETERS.getN());

    public static void main(String[] args)
        throws InvalidParameterSpecException, NoSuchAlgorithmException, InvalidKeySpecException {
        Security.addProvider(new BouncyCastleProvider());

        KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());

        // 替换成待导入的私钥,如下内容仅为示例,实际使用时请替换
        String hexPrivateKey = "5AF8F37036DFF6C303B65DF52674B6B8269BCDF1D70DC6305D93F975DCA2469A";

        BigInteger d = new BigInteger(hexPrivateKey, 16);
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, EC_PARAMETER_SPEC);
        BCECPrivateKey ec = new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);

        ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(CURVE_NAME);
        ECPoint q = ecSpec.getG().multiply(((ECPrivateKey) ec).getD());
        ECPublicKeySpec pubSpec = new ECPublicKeySpec(q, ecSpec);
        PublicKey publicKey = keyFactory.generatePublic(pubSpec);

        BCECPrivateKey ec2 = new BCECPrivateKey("EC", ec.engineGetKeyParameters(), (BCECPublicKey) publicKey,
            ecPrivateKeySpec.getParams(), BouncyCastleProvider.CONFIGURATION);

        System.out.println(Base64.getEncoder().encodeToString(ec2.getEncoded()));
    }

}
```

执行上述代码,获得如下输出:

```ignorelang
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgWvjzcDbf9sMDtl31JnS2uCabzfHXDcYwXZP5ddyiRpqgCgYIKoEcz1UBgi2hRANCAATOxASdjgJXIhnJOF/bTZwE0mnK6BEGoJIOmFHQzpMbrlu+hoRIXOGX/pEtsZqJsKZLD99/iDjB5bM9y/f9GaEC
```

使用ASN.1解码工具查看:

```
 <SEQUENCE>
  <INTEGER/>
  <SEQUENCE>
   <OBJECT_IDENTIFIER Comment="ANSI X9.62 public key type" Description="ecPublicKey">1.2.840.10045.2.1</OBJECT_IDENTIFIER>
   <OBJECT_IDENTIFIER Comment="China GM Standards Committee" Description="sm2ECC">1.2.156.10197.1.301</OBJECT_IDENTIFIER>
  </SEQUENCE>
  <OCTET_STRING>
   <SEQUENCE>
    <INTEGER>1</INTEGER>
    <OCTET_STRING>0x5AF8F37036DFF6C303B65DF52674B6B8269BCDF1D70DC6305D93F975DCA2469A</OCTET_STRING>
    <NODE Sign="a0">
     <OBJECT_IDENTIFIER Comment="China GM Standards Committee" Description="sm2ECC">1.2.156.10197.1.301</OBJECT_IDENTIFIER>
    </NODE>
    <NODE Sign="a1">
     <BIT_STRING Bits="520">0x0004CEC4049D8E02572219C9385FDB4D9C04D269CAE81106A0920E9851D0CE931BAE5BBE8684485CE197FE912DB19A89B0A64B0FDF7F8838C1E5B33DCBF7FD19A102</BIT_STRING>
    </NODE>
   </SEQUENCE>
  </OCTET_STRING>
 </SEQUENCE>
```

将如下内容写入到命名为“sm2_private_key.pem”的文件中:

```ignorelang
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgWvjzcDbf9sMDtl31JnS2uCabzfHXDcYwXZP5ddyiRpqgCgYIKoEcz1UBgi2hRANCAATOxASdjgJXIhnJOF/bTZwE0mnK6BEGoJIOmFHQzpMbrlu+hoRIXOGX/pEtsZqJsKZLD99/iDjB5bM9y/f9GaEC
-----END PRIVATE KEY-----
```

执行如下命令,查看EC密钥的信息:

```shell
openssl ec -in sm2_private_key.pem -text
```
```ignorelang
read EC key
Private-Key: (256 bit)
priv:
    5a:f8:f3:70:36:df:f6:c3:03:b6:5d:f5:26:74:b6:
    b8:26:9b:cd:f1:d7:0d:c6:30:5d:93:f9:75:dc:a2:
    46:9a
pub:
    04:ce:c4:04:9d:8e:02:57:22:19:c9:38:5f:db:4d:
    9c:04:d2:69:ca:e8:11:06:a0:92:0e:98:51:d0:ce:
    93:1b:ae:5b:be:86:84:48:5c:e1:97:fe:91:2d:b1:
    9a:89:b0:a6:4b:0f:df:7f:88:38:c1:e5:b3:3d:cb:
    f7:fd:19:a1:02
ASN1 OID: sm2p256v1
NIST CURVE: SM2
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFr483A23/bDA7Zd9SZ0trgmm83x1w3GMF2T+XXcokaaoAoGCCqBHM9V
AYItoUQDQgAEzsQEnY4CVyIZyThf202cBNJpyugRBqCSDphR0M6TG65bvoaESFzh
l/6RLbGaibCmSw/ff4g4weWzPcv3/RmhAg==
-----END EC PRIVATE KEY-----

```

后续可以正常执行转成DER命令:

```shell
openssl pkcs8 -topk8 -inform PEM -outform DER -in sm2_private_key.pem -out sm2_private_key.der -nocrypt
```

相关文档