All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.shepherdviolet.glacimon.java.crypto.SM2KeyGenerator Maven / Gradle / Ivy

There is a newer version: 2024.6.0
Show newest version
/*
 * Copyright (C) 2022-2022 S.Violet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Project GitHub: https://github.com/shepherdviolet/glacimon
 * Email: [email protected]
 */

package com.github.shepherdviolet.glacimon.java.crypto;

import com.github.shepherdviolet.glacimon.java.crypto.base.BaseBCAsymKeyGenerator;
import com.github.shepherdviolet.glacimon.java.crypto.base.SM2DefaultCurve;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import com.github.shepherdviolet.glacimon.java.conversion.Base64Utils;
import com.github.shepherdviolet.glacimon.java.conversion.ByteUtils;
import com.github.shepherdviolet.glacimon.java.crypto.base.CommonCryptoException;

import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;

/**
 * 

SM2秘钥生成工具


* *

BouncyCastle是使用XXXKeyParameters密钥实例的, 而JDK默认使用XXXKey密钥实例, 本工具类在加解密加解签时, 统一使用BouncyCastle * 的XXXKeyParameters密钥实例, 这与RSA/ECDSA工具类中使用XXXKey实例不同. 另外, 本工具类提供将密钥实例转换为JDK密钥实例的方法.


* *

SM2算法首先要选择一个合适的椭圆曲线, 椭圆曲线参数包含: Curve (P A B) / G-Point (X Y) / N / H , SM2算法的公钥是一个这个 * 椭圆曲线上的点Q(X Y), 私钥是次数D, PKCS8/X509编码的私钥公钥除了Q点和次数D以外, 也包含的椭圆曲线参数.


* *

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @author shepherdviolet */ public class SM2KeyGenerator { /** * 密钥类型:SM2 */ public static final String SM2_KEY_ALGORITHM = "SM2"; public static final String EC_KEY_ALGORITHM = "EC"; /** * 随机生成SM2密钥对(sm2p256v1) * * @return 密钥对(与JDK的密钥实例不同) */ public static SM2KeyParamsPair generateKeyParamsPair() { AsymmetricCipherKeyPair asymKeyPair = BaseBCAsymKeyGenerator.generateEcKeyParamsPair(SM2DefaultCurve.DOMAIN_PARAMS, null); return new SM2KeyParamsPair((ECPublicKeyParameters)asymKeyPair.getPublic(), (ECPrivateKeyParameters)asymKeyPair.getPrivate()); } /** * 将PKCS8私钥数据解析为私钥实例(与JDK的密钥实例不同) * @param pkcs8 PKCS8私钥数据 * @deprecated 实际项目中很少使用PKCS8格式的SM2私钥 */ public static ECPrivateKeyParameters generatePrivateKeyParamsByPKCS8(byte[] pkcs8) throws InvalidKeySpecException { return BaseBCAsymKeyGenerator.ecPrivateKeyToEcPrivateKeyParams( //SM2的密钥标记为EC BaseBCAsymKeyGenerator.parseEcPrivateKeyByPkcs8(pkcs8, EC_KEY_ALGORITHM) ); } /** * 将X509公钥数据解析为公钥实例(与JDK的密钥实例不同) * @param x509 X509公钥数据 * @deprecated 实际项目中很少使用X509格式的SM2公钥 */ public static ECPublicKeyParameters generatePublicKeyParamsByX509(byte[] x509) throws InvalidKeySpecException { return BaseBCAsymKeyGenerator.ecPublicKeyToEcPublicKeyParams( //SM2的密钥标记为EC BaseBCAsymKeyGenerator.parseEcPublicKeyByX509(x509, EC_KEY_ALGORITHM) ); } /** *

根据已知的D值生成SM2私钥实例(sm2p256v1).

*

如果D值是Base64字符串, 转成byte[], 然后new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

*

如果D值是Hex字符串, 直接new BigInteger(string, 16)

*
*

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @param d D值 * @return 私钥实例(与JDK的密钥实例不同) */ public static ECPrivateKeyParameters generatePrivateKeyParams(BigInteger d) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPrivateKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, d); } /** *

根据已知的D值生成SM2私钥实例(sm2p256v1).

* *

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @param dBytes D值, 二进制 * @return 私钥实例(与JDK的密钥实例不同) */ public static ECPrivateKeyParameters generatePrivateKeyParams(byte[] dBytes) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPrivateKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, new BigInteger(ByteUtils.bytesToHex(dBytes), 16)); } /** *

根据已知的D值生成SM2私钥实例(sm2p256v1).

* *

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @param dHex D值, 十六进制字符串(HEX) * @return 私钥实例(与JDK的密钥实例不同) */ public static ECPrivateKeyParameters generatePrivateKeyParams(String dHex) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPrivateKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, new BigInteger(dHex, 16)); } /** * 根据已知的坐标(ASN.1编码数据)生成SM2公钥实例(sm2p256v1), * 某些工具生成的SM2公钥不符合ASN1标准, 长度只有64字节, 直接是X和Y的二进制数据拼接而成, 请在前面增加一个字节: 0x04 * * @param asn1Hex 公钥坐标点, ASN.1编码十六进制字符串(HEX) * @return 公钥实例(与JDK的密钥实例不同) */ public static ECPublicKeyParameters generatePublicKeyParamsByASN1(String asn1Hex) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPublicKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, ByteUtils.hexToBytes(asn1Hex)); } /** * 根据已知的坐标(ASN.1编码数据)生成SM2公钥实例(sm2p256v1), * 某些工具生成的SM2公钥不符合ASN1标准, 长度只有64字节, 直接是X和Y的二进制数据拼接而成, 请在前面增加一个字节: 0x04 * * @param asn1Encoding 公钥坐标点, ASN.1编码数据 * @return 公钥实例(与JDK的密钥实例不同) */ public static ECPublicKeyParameters generatePublicKeyParamsByASN1(byte[] asn1Encoding) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPublicKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, asn1Encoding); } /** *

根据已知的坐标(X/Y)生成SM2公钥实例(sm2p256v1)


* *

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @param x 坐标X * @param y 坐标Y * @return 公钥实例(与JDK的密钥实例不同) */ public static ECPublicKeyParameters generatePublicKeyParams(BigInteger x, BigInteger y) throws CommonCryptoException { if (x == null || y == null) { throw new NullPointerException("x or y is null"); } return BaseBCAsymKeyGenerator.parseEcPublicKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, x.toByteArray(), y.toByteArray()); } /** *

根据已知的坐标(X/Y)生成SM2公钥实例(sm2p256v1)


* *

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @param xBytes 坐标X, 二进制数据 * @param yBytes 坐标Y, 二进制数据 * @return 公钥实例(与JDK的密钥实例不同) */ public static ECPublicKeyParameters generatePublicKeyParams(byte[] xBytes, byte[] yBytes) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPublicKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, xBytes, yBytes); } /** *

根据已知的坐标(X/Y)生成SM2公钥实例(sm2p256v1)


* *

D值 / Q值(X/Y) 获取方法 + 各种格式转换:

*

获取D值: ecPrivateKeyParameters.getD()

*

获取Q(X)值: ecPublicKeyParameters.getQ().getAffineXCoord().toBigInteger()

*

获取Q(Y)值: ecPublicKeyParameters.getQ().getAffineYCoord().toBigInteger()

*

BigInteger转HexString: bigInteger.toString(16)

*

BigInteger转byte[]: ByteUtils.leftTrim(bigInteger.toByteArray())), 注意!!!要去掉头部的0x00!!!

*

HexString转BigInteger: new BigInteger(string, 16)

*

byte[]转BigInteger: new BigInteger(ByteUtils.bytesToHex(bytes), 16). 不要new BigInteger(bytes), 因为如果bytes第一个字节大于等于0x80会变负数!!!

* * @param xHex 坐标X, 十六进制字符串(hex) * @param yHex 坐标Y, 十六进制字符串(hex) * @return 公钥实例(与JDK的密钥实例不同) */ public static ECPublicKeyParameters generatePublicKeyParams(String xHex, String yHex) throws CommonCryptoException { return BaseBCAsymKeyGenerator.parseEcPublicKeyParams(SM2DefaultCurve.DOMAIN_PARAMS, ByteUtils.hexToBytes(xHex), ByteUtils.hexToBytes(yHex)); } // Encode ////////////////////////////////////////////////////////////////////////////////////////////////////// /** * 将私钥实例转换为PKCS8编码的数据 * * @param privateKeyParams 私钥, BouncyCastle的XXXKeyParameters密钥实例 * @param publicKeyParams 公钥, 可为空(但送空会导致openssl无法读取PKCS8数据), BouncyCastle的XXXKeyParameters密钥实例 * @return 私钥的PKCS8编码数据 */ public static byte[] encodePrivateKeyParamsToPKCS8(ECPrivateKeyParameters privateKeyParams, ECPublicKeyParameters publicKeyParams) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPrivateKeyParamsToEcPrivateKey(privateKeyParams, publicKeyParams, EC_KEY_ALGORITHM).getEncoded(); } /** * 将私钥实例转换为PKCS8编码的私钥数据, openssl无法读取这种方法生成的数据, 需要用openssl请用 * encodePrivateKeyParamsToPKCS8(ECPrivateKeyParameters, ECPublicKeyParameters)方法 * * @param privateKeyParams 私钥, BouncyCastle的XXXKeyParameters密钥实例 * @return 私钥的PKCS8编码数据 */ public static byte[] encodePrivateKeyParamsToPKCS8(ECPrivateKeyParameters privateKeyParams) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPrivateKeyParamsToEcPrivateKey(privateKeyParams, null, EC_KEY_ALGORITHM).getEncoded(); } /** * 将公钥实例转换为X509编码的公钥数据 * * @param publicKeyParams 公钥, BouncyCastle的XXXKeyParameters密钥实例 * @return 公钥的X509编码数据 */ public static byte[] encodePublicKeyParamsToX509(ECPublicKeyParameters publicKeyParams) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPublicKeyParamsToEcPublicKey(publicKeyParams, EC_KEY_ALGORITHM).getEncoded(); } // Conversion /////////////////////////////////////////////////////////////////////////////////////////////////// /** * 将BouncyCastle的XXXKeyParameters私钥实例转换为JDK的XXXKey私钥实例, 用于与JDK加密工具适配, 或获取PKCS8编码的私钥数据 * * @param privateKeyParams 私钥, BouncyCastle的XXXKeyParameters密钥实例 * @param publicKeyParams 公钥, 可为空(但送空会导致openssl无法读取PKCS8数据), BouncyCastle的XXXKeyParameters密钥实例 * @return JDK的XXXKey密钥实例, 可以调用ECPrivateKey.getEncoded()方法获取PKCS8编码的私钥数据(甚至进一步转为PEM等格式) */ public static BCECPrivateKey privateKeyParamsToPrivateKey(ECPrivateKeyParameters privateKeyParams, ECPublicKeyParameters publicKeyParams) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPrivateKeyParamsToEcPrivateKey(privateKeyParams, publicKeyParams, EC_KEY_ALGORITHM); } /** * 将BouncyCastle的XXXKeyParameters公钥实例转换为JDK的XXXKey公钥实例, 用于与JDK加密工具适配, 或获取X509编码的公钥数据 * * @param publicKeyParams 公钥, BouncyCastle的XXXKeyParameters密钥实例 * @return JDK的XXXKey密钥实例, 可以调用ECPublicKey.getEncoded()方法获取X509编码的公钥数据(甚至进一步转为PEM等格式) */ public static BCECPublicKey publicKeyParamsToPublicKey(ECPublicKeyParameters publicKeyParams) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPublicKeyParamsToEcPublicKey(publicKeyParams, EC_KEY_ALGORITHM); } /** * 将JDK的XXXKey私钥实例转换为BouncyCastle的XXXKeyParameters私钥实例 * * @param privateKey JDK的XXXKey私钥实例 * @return BouncyCastle的XXXKeyParameters私钥实例 */ public static ECPrivateKeyParameters privateKeyToPrivateKeyParams(BCECPrivateKey privateKey) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPrivateKeyToEcPrivateKeyParams(privateKey); } /** * 将JDK的XXXKey公钥实例转换为BouncyCastle的XXXKeyParameters公钥实例 * * @param publicKey JDK的XXXKey公钥实例 * @return BouncyCastle的XXXKeyParameters公钥实例 */ public static ECPublicKeyParameters publicKeyToPublicKeyParams(BCECPublicKey publicKey) { //SM2的密钥标记为EC return BaseBCAsymKeyGenerator.ecPublicKeyToEcPublicKeyParams(publicKey); } /** * 从证书中提取SM2公钥 * @param certificate 证书 * @return 公钥 */ public static ECPublicKeyParameters parsePublicKeyParamsFromCertificate(X509Certificate certificate) { return BaseBCAsymKeyGenerator.parseEcPublicKeyParamsFromCertificate(SM2DefaultCurve.DOMAIN_PARAMS, certificate); } // Key Pair ///////////////////////////////////////////////////////////////////////////////////////////////////// public static class SM2KeyParamsPair { private ECPublicKeyParameters publicKeyParams; private ECPrivateKeyParameters privateKeyParams; public SM2KeyParamsPair(ECPublicKeyParameters publicKeyParams, ECPrivateKeyParameters privateKeyParams) { this.publicKeyParams = publicKeyParams; this.privateKeyParams = privateKeyParams; } /** * [常用]获取公钥实例, 用于加解签操作(与JDK的密钥实例不同) */ public ECPublicKeyParameters getPublicKeyParams() { return publicKeyParams; } /** * [常用]获取私钥实例, 用于加解签操作(与JDK的密钥实例不同) */ public ECPrivateKeyParameters getPrivateKeyParams() { return privateKeyParams; } /** * 获取JDK的XXXKey公钥实例, 用于适配 */ public BCECPublicKey getJdkPublicKey() { return publicKeyParamsToPublicKey(publicKeyParams); } /** * 获取JDK的XXXKey私钥实例, 用于适配 */ public BCECPrivateKey getJdkPrivateKey() { return privateKeyParamsToPrivateKey(privateKeyParams, publicKeyParams); } /** * 获取公钥坐标点的ASN.1编码数据(非压缩). * 未压缩格式开头有个0x04, 有些加解密工具没0x04. */ public byte[] getPublicASN1Encoding(){ return publicKeyParams.getQ().getEncoded(false); } /** * 获取公钥坐标点的ASN.1编码十六进制字符串(非压缩). * 未压缩格式开头有个0x04, 有些加解密工具没0x04. */ public String getPublicASN1EncodingHex(){ return ByteUtils.bytesToHex(publicKeyParams.getQ().getEncoded(false)); } /** *

获取公钥的X值 (QX).

*

转byte[], ByteUtils.leftTrim(SM2KeyParamsPair.getPublicX().toByteArray())), 注意!!!要去掉头部的0x00!!!

*

转Hex, SM2KeyParamsPair.getPublicX().toString(16).

*/ public BigInteger getPublicX(){ return publicKeyParams.getQ().getAffineXCoord().toBigInteger(); } /** *

获取公钥的X值 (QX).

*

转Hex, SM2KeyParamsPair.getPublicX().toString(16).

*/ public byte[] getPublicXBytes(){ return ByteUtils.leftTrim(publicKeyParams.getQ().getAffineXCoord().toBigInteger().toByteArray()); } /** *

获取公钥的X值 (QX).

*/ public String getPublicXHex(){ return publicKeyParams.getQ().getAffineXCoord().toBigInteger().toString(16); } /** *

获取公钥的Y值 (QY).

*

转byte[], ByteUtils.leftTrim(SM2KeyParamsPair.getPublicY().toByteArray())), 注意!!!要去掉头部的0x00!!!

*

转Hex, SM2KeyParamsPair.getPublicY().toString(16).

*/ public BigInteger getPublicY(){ return publicKeyParams.getQ().getAffineYCoord().toBigInteger(); } /** *

获取公钥的Y值 (QY).

*

转Hex, SM2KeyParamsPair.getPublicY().toString(16).

*/ public byte[] getPublicYBytes(){ return ByteUtils.leftTrim(publicKeyParams.getQ().getAffineYCoord().toBigInteger().toByteArray()); } /** *

获取公钥的Y值 (QY).

*/ public String getPublicYHex(){ return publicKeyParams.getQ().getAffineYCoord().toBigInteger().toString(16); } /** *

获取私钥的D值.

*

转byte[], ByteUtils.leftTrim(SM2KeyParamsPair.getPrivateD().toByteArray())), 注意!!!要去掉头部的0x00!!!

*

转Hex, SM2KeyParamsPair.getPrivateD().toString(16).

*/ public BigInteger getPrivateD(){ return privateKeyParams.getD(); } /** *

获取私钥的D值.

*

转Hex, SM2KeyParamsPair.getPrivateD().toString(16).

*/ public byte[] getPrivateDBytes(){ return ByteUtils.leftTrim(privateKeyParams.getD().toByteArray()); } /** *

获取私钥的D值的十六进制字符串.

*/ public String getPrivateDHex(){ return privateKeyParams.getD().toString(16); } /** * @deprecated 实际项目中很少使用X509格式的SM2公钥 */ public byte[] getX509EncodedPublicKey() { return encodePublicKeyParamsToX509(publicKeyParams); } /** * @deprecated 实际项目中很少使用PKCS8的SM2私钥 */ public byte[] getPKCS8EncodedPrivateKey() { return encodePrivateKeyParamsToPKCS8(privateKeyParams, publicKeyParams); } @Override public String toString() { try { return "SM2KeyParamsPair\n" + getPublicASN1EncodingHex() + "\n" + getPrivateDHex(); } catch (Exception e) { return "SM2KeyParamsPair\n" + e.getMessage(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy