mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
增加BCUtil.decodeECPrivateKey方法(issue#3829@Github)
This commit is contained in:
parent
fd45eecda1
commit
224bfee92e
@ -68,6 +68,17 @@ public class KeyUtil {
|
||||
*/
|
||||
public static final int DEFAULT_KEY_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* 将密钥编码为Base64格式
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return Base64格式密钥
|
||||
* @since 5.7.22
|
||||
*/
|
||||
public static String toBase64(final Key key) {
|
||||
return Base64.encode(key.getEncoded());
|
||||
}
|
||||
|
||||
// region ----- generateKey
|
||||
|
||||
/**
|
||||
@ -200,26 +211,29 @@ public class KeyUtil {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 检查{@link KeyPair} 是否为空,空的条件是:
|
||||
* <ul>
|
||||
* <li>keyPair本身为{@code null}</li>
|
||||
* <li>{@link KeyPair#getPrivate()}和{@link KeyPair#getPublic()}都为{@code null}</li>
|
||||
* </ul>
|
||||
* 获取{@link KeyGenerator}
|
||||
*
|
||||
* @param keyPair 密钥对
|
||||
* @return 是否为空
|
||||
* @param algorithm 对称加密算法
|
||||
* @return {@link KeyGenerator}
|
||||
* @since 4.5.2
|
||||
*/
|
||||
// region ----- keyPair
|
||||
public static boolean isEmpty(final KeyPair keyPair) {
|
||||
if (null == keyPair) {
|
||||
return false;
|
||||
public static KeyGenerator getKeyGenerator(final String algorithm) {
|
||||
final Provider provider = GlobalProviderFactory.getProvider();
|
||||
final KeyGenerator generator;
|
||||
try {
|
||||
generator = (null == provider) //
|
||||
? KeyGenerator.getInstance(getMainAlgorithm(algorithm)) //
|
||||
: KeyGenerator.getInstance(getMainAlgorithm(algorithm), provider);
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
return null != keyPair.getPrivate() || null != keyPair.getPublic();
|
||||
return generator;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- generatePrivateKey
|
||||
/**
|
||||
* 生成RSA私钥,仅用于非对称加密<br>
|
||||
* 采用PKCS#8规范,此规范定义了私钥信息语法和加密私钥语法<br>
|
||||
@ -285,7 +299,9 @@ public class KeyUtil {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- generatePublicKey
|
||||
/**
|
||||
* 生成RSA公钥,仅用于非对称加密<br>
|
||||
* 采用X509证书规范<br>
|
||||
@ -335,7 +351,9 @@ public class KeyUtil {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- getRSAPublicKey
|
||||
/**
|
||||
* 通过RSA私钥生成RSA公钥
|
||||
*
|
||||
@ -380,6 +398,25 @@ public class KeyUtil {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- keyPair
|
||||
/**
|
||||
* 检查{@link KeyPair} 是否为空,空的条件是:
|
||||
* <ul>
|
||||
* <li>keyPair本身为{@code null}</li>
|
||||
* <li>{@link KeyPair#getPrivate()}和{@link KeyPair#getPublic()}都为{@code null}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param keyPair 密钥对
|
||||
* @return 是否为空
|
||||
*/
|
||||
public static boolean isEmpty(final KeyPair keyPair) {
|
||||
if (null == keyPair) {
|
||||
return false;
|
||||
}
|
||||
return null != keyPair.getPrivate() || null != keyPair.getPublic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成用于非对称加密的公钥和私钥,仅用于非对称加密<br>
|
||||
@ -616,6 +653,7 @@ public class KeyUtil {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- keyFactory
|
||||
/**
|
||||
* 获取{@link KeyFactory}
|
||||
*
|
||||
@ -655,27 +693,9 @@ public class KeyUtil {
|
||||
}
|
||||
return keyFactory;
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 获取{@link KeyGenerator}
|
||||
*
|
||||
* @param algorithm 对称加密算法
|
||||
* @return {@link KeyGenerator}
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public static KeyGenerator getKeyGenerator(final String algorithm) {
|
||||
final Provider provider = GlobalProviderFactory.getProvider();
|
||||
final KeyGenerator generator;
|
||||
try {
|
||||
generator = (null == provider) //
|
||||
? KeyGenerator.getInstance(getMainAlgorithm(algorithm)) //
|
||||
: KeyGenerator.getInstance(getMainAlgorithm(algorithm), provider);
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
return generator;
|
||||
}
|
||||
|
||||
// region ----- algorithm
|
||||
/**
|
||||
* 获取主体算法名,例如RSA/ECB/PKCS1Padding的主体算法是RSA
|
||||
*
|
||||
@ -720,6 +740,7 @@ public class KeyUtil {
|
||||
}
|
||||
return algorithm;
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 读取X.509 Certification文件中的公钥<br>
|
||||
@ -738,6 +759,39 @@ public class KeyUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
// region ----- EC Key
|
||||
/**
|
||||
* 编码压缩EC私钥(基于BouncyCastle)
|
||||
*
|
||||
* @param privateKey {@link PrivateKey},必须为org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
||||
* @return 压缩得到的D
|
||||
*/
|
||||
public static byte[] encodeECPrivateKey(final PrivateKey privateKey) {
|
||||
return ECKeyUtil.encodeECPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码恢复EC私钥,支持Base64和Hex编码,(基于BouncyCastle)
|
||||
*
|
||||
* @param encode 私钥
|
||||
* @param curveName EC曲线名
|
||||
* @return 私钥
|
||||
*/
|
||||
public static PrivateKey decodeECPrivateKey(final String encode, final String curveName) {
|
||||
return ECKeyUtil.decodeECPrivateKey(encode, curveName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码恢复EC私钥,支持Base64和Hex编码,(基于BouncyCastle)
|
||||
*
|
||||
* @param encodeByte 私钥
|
||||
* @param curveName EC曲线名
|
||||
* @return 私钥
|
||||
*/
|
||||
public static PrivateKey decodeECPrivateKey(final byte[] encodeByte, final String curveName) {
|
||||
return ECKeyUtil.decodeECPrivateKey(encodeByte, curveName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码压缩EC公钥(基于BouncyCastle)<br>
|
||||
* 见:<a href="https://www.cnblogs.com/xinzhao/p/8963724.html">...</a>
|
||||
@ -759,8 +813,8 @@ public class KeyUtil {
|
||||
* @return 公钥
|
||||
* @since 4.4.4
|
||||
*/
|
||||
public static PublicKey decodeECPoint(final String encode, final String curveName) {
|
||||
return ECKeyUtil.decodeECPoint(encode, curveName);
|
||||
public static PublicKey decodeECPublicKey(final String encode, final String curveName) {
|
||||
return ECKeyUtil.decodeECPublicKey(encode, curveName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -772,18 +826,8 @@ public class KeyUtil {
|
||||
* @return 公钥
|
||||
* @since 4.4.4
|
||||
*/
|
||||
public static PublicKey decodeECPoint(final byte[] encodeByte, final String curveName) {
|
||||
return ECKeyUtil.decodeECPoint(encodeByte, curveName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将密钥编码为Base64格式
|
||||
*
|
||||
* @param key 密钥
|
||||
* @return Base64格式密钥
|
||||
* @since 5.7.22
|
||||
*/
|
||||
public static String toBase64(final Key key) {
|
||||
return Base64.encode(key.getEncoded());
|
||||
public static PublicKey decodeECPublicKey(final byte[] encodeByte, final String curveName) {
|
||||
return ECKeyUtil.decodeECPublicKey(encodeByte, curveName);
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
|
||||
import org.bouncycastle.jce.interfaces.ECPrivateKey;
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
||||
import org.bouncycastle.math.ec.ECCurve;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.BigIntegers;
|
||||
@ -49,7 +50,6 @@ import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 椭圆曲线EC(Elliptic Curves)密钥参数相关工具类封装
|
||||
@ -110,6 +110,38 @@ public class ECKeyUtil {
|
||||
return ((ECPrivateKey) privateKey).getD().toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码恢复EC私钥,支持Base64和Hex编码,(基于BouncyCastle)
|
||||
*
|
||||
* @param d 私钥d值(Base64或Hex格式)
|
||||
* @param curveName EC曲线名,例如{@link SM2Constant#SM2_DOMAIN_PARAMS}
|
||||
* @return 私钥
|
||||
*/
|
||||
public static PrivateKey decodeECPrivateKey(final String d, final String curveName) {
|
||||
return decodeECPrivateKey(SecureUtil.decode(d), curveName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码恢复EC私钥,支持Base64和Hex编码,(基于BouncyCastle)
|
||||
*
|
||||
* @param d 私钥d值
|
||||
* @param curveName EC曲线名,例如{@link SM2Constant#SM2_DOMAIN_PARAMS}
|
||||
* @return 私钥
|
||||
* @since 5.8.36
|
||||
*/
|
||||
public static PrivateKey decodeECPrivateKey(final byte[] d, final String curveName) {
|
||||
final X9ECParameters x9ECParameters = ECUtil.getNamedCurveByName(curveName);
|
||||
final ECParameterSpec ecSpec = new ECParameterSpec(
|
||||
x9ECParameters.getCurve(),
|
||||
x9ECParameters.getG(),
|
||||
x9ECParameters.getN(),
|
||||
x9ECParameters.getH()
|
||||
);
|
||||
|
||||
final ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(BigIntegers.fromUnsignedByteArray(d), ecSpec);
|
||||
return KeyUtil.generatePrivateKey("EC", privateKeySpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码压缩EC公钥(基于BouncyCastle),即Q值<br>
|
||||
* 见:https://www.cnblogs.com/xinzhao/p/8963724.html
|
||||
@ -144,8 +176,8 @@ public class ECKeyUtil {
|
||||
* @return 公钥
|
||||
* @since 4.4.4
|
||||
*/
|
||||
public static PublicKey decodeECPoint(final String encode, final String curveName) {
|
||||
return decodeECPoint(SecureUtil.decode(encode), curveName);
|
||||
public static PublicKey decodeECPublicKey(final String encode, final String curveName) {
|
||||
return decodeECPublicKey(SecureUtil.decode(encode), curveName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +188,7 @@ public class ECKeyUtil {
|
||||
* @return 公钥
|
||||
* @since 4.4.4
|
||||
*/
|
||||
public static PublicKey decodeECPoint(final byte[] encodeByte, final String curveName) {
|
||||
public static PublicKey decodeECPublicKey(final byte[] encodeByte, final String curveName) {
|
||||
final X9ECParameters x9ECParameters = ECUtil.getNamedCurveByName(curveName);
|
||||
final ECCurve curve = x9ECParameters.getCurve();
|
||||
final java.security.spec.ECPoint point = EC5Util.convertPoint(curve.decodePoint(encodeByte));
|
||||
@ -370,9 +402,7 @@ public class ECKeyUtil {
|
||||
if (null == d) {
|
||||
return null;
|
||||
}
|
||||
return toPrivateParams(
|
||||
BigIntegers.fromUnsignedByteArray(Objects.requireNonNull(SecureUtil.decode(d))),
|
||||
domainParameters);
|
||||
return toPrivateParams(SecureUtil.decode(d), domainParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,8 +210,8 @@ public class SM2Test {
|
||||
final byte[] data = KeyUtil.encodeECPublicKey(publicKey);
|
||||
final String encodeHex = HexUtil.encodeStr(data);
|
||||
final String encodeB64 = Base64.encode(data);
|
||||
final PublicKey Hexdecode = KeyUtil.decodeECPoint(encodeHex, SM2Constant.SM2_CURVE_NAME);
|
||||
final PublicKey B64decode = KeyUtil.decodeECPoint(encodeB64, SM2Constant.SM2_CURVE_NAME);
|
||||
final PublicKey Hexdecode = KeyUtil.decodeECPublicKey(encodeHex, SM2Constant.SM2_CURVE_NAME);
|
||||
final PublicKey B64decode = KeyUtil.decodeECPublicKey(encodeB64, SM2Constant.SM2_CURVE_NAME);
|
||||
Assertions.assertEquals(HexUtil.encodeStr(publicKey.getEncoded()), HexUtil.encodeStr(Hexdecode.getEncoded()));
|
||||
Assertions.assertEquals(HexUtil.encodeStr(publicKey.getEncoded()), HexUtil.encodeStr(B64decode.getEncoded()));
|
||||
}
|
||||
|
@ -54,4 +54,16 @@ public class ECKeyUtilTest {
|
||||
final PublicKey ecPublicKey = ECKeyUtil.getECPublicKey((ECPrivateKey) sm2.getPrivate(), SM2Constant.SM2_EC_SPEC);
|
||||
Assertions.assertEquals(sm2.getPublic(), ecPublicKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
void encodeAndDecodeECPrivateKeyTest(){
|
||||
// 生成一个EC密钥对
|
||||
final KeyPair ecKeyPair = KeyUtil.generateKeyPair("EC");
|
||||
final ECPrivateKey ecPrivateKey = (ECPrivateKey) ecKeyPair.getPrivate();
|
||||
|
||||
final byte[] bytes = ECKeyUtil.encodeECPrivateKey(ecPrivateKey);
|
||||
final ECPrivateKey decodedPrivateKey = (ECPrivateKey) ECKeyUtil.decodeECPrivateKey(bytes, "secp256r1");
|
||||
|
||||
Assertions.assertEquals(ecPrivateKey.getD(), decodedPrivateKey.getD());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user