All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.siashan.toolkit.crypt.util.SmUtil Maven / Gradle / Ivy
package com.siashan.toolkit.crypt.util;
import com.siashan.toolkit.crypt.CryptException;
import com.siashan.toolkit.crypt.asymmetric.SM2;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.signers.StandardDSAEncoding;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import java.io.IOException;
import java.math.BigInteger;
/**
* SM国密算法工具类
* 此工具类依赖org.bouncycastle:bcprov-jdk15to18
*
* @author siashan
* @since 1.0.7
*/
public class SmUtil {
/**
* SM2推荐曲线参数(来自https://github.com/ZZMarquis/gmhelper)
*/
public static final ECDomainParameters SM2_DOMAIN_PARAMS;
private final static int RS_LEN = 32;
static {
SM2_DOMAIN_PARAMS = BCUtil.toDomainParams(GMNamedCurves.getByName(SM2.SM2_CURVE_NAME));
}
/**
* bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2
*
* @param c1c2c3 加密后的bytes,顺序为C1C2C3
* @param ecDomainParameters {@link ECDomainParameters}
* @return 加密后的bytes,顺序为C1C3C2
*/
public static byte[] changeC1C2C3ToC1C3C2(byte[] c1c2c3, ECDomainParameters ecDomainParameters) {
// sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
final int c1Len = (ecDomainParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;
final int c3Len = 32; // new SM3Digest().getDigestSize();
byte[] result = new byte[c1c2c3.length];
System.arraycopy(c1c2c3, 0, result, 0, c1Len); // c1
System.arraycopy(c1c2c3, c1c2c3.length - c3Len, result, c1Len, c3Len); // c3
System.arraycopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.length - c1Len - c3Len); // c2
return result;
}
/**
* bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密
*
* @param c1c3c2 加密后的bytes,顺序为C1C3C2
* @param ecDomainParameters {@link ECDomainParameters}
* @return c1c2c3 加密后的bytes,顺序为C1C2C3
*/
public static byte[] changeC1C3C2ToC1C2C3(byte[] c1c3c2, ECDomainParameters ecDomainParameters) {
// sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
final int c1Len = (ecDomainParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;
final int c3Len = 32; // new SM3Digest().getDigestSize();
byte[] result = new byte[c1c3c2.length];
System.arraycopy(c1c3c2, 0, result, 0, c1Len); // c1: 0->65
System.arraycopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.length - c1Len - c3Len); // c2
System.arraycopy(c1c3c2, c1Len, result, c1c3c2.length - c3Len, c3Len); // c3
return result;
}
/**
* BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
* 来自:https://blog.csdn.net/pridas/article/details/86118774
*
* @param rsDer rs in asn1 format
* @return sign result in plain byte array
*/
public static byte[] rsAsn1ToPlain(byte[] rsDer) {
final BigInteger[] decode;
try {
decode = StandardDSAEncoding.INSTANCE.decode(SM2_DOMAIN_PARAMS.getN(), rsDer);
} catch (IOException e) {
throw new CryptException(e);
}
final byte[] r = bigIntToFixedLengthBytes(decode[0]);
final byte[] s = bigIntToFixedLengthBytes(decode[1]);
return addAll(r, s);
}
/**
* BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
* 来自:https://blog.csdn.net/pridas/article/details/86118774
*
* @param sign in plain byte array
* @return rs result in asn1 format
*/
public static byte[] rsPlainToAsn1(byte[] sign) {
if (sign.length != RS_LEN * 2) {
throw new CryptException("err rs. ");
}
BigInteger r = new BigInteger(1, Arrays.copyOfRange(sign, 0, RS_LEN));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(sign, RS_LEN, RS_LEN * 2));
try {
return StandardDSAEncoding.INSTANCE.encode(SM2_DOMAIN_PARAMS.getN(), r, s);
} catch (IOException e) {
throw new CryptException(e);
}
}
// -------------------------------------------------------------------------------------------------------- Private method start
/**
* BigInteger转固定长度bytes
*
* @param rOrS {@link BigInteger}
* @return 固定长度bytes
*/
private static byte[] bigIntToFixedLengthBytes(BigInteger rOrS) {
// for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
// r and s are the result of mod n, so they should be less than n and have length<=32
byte[] rs = rOrS.toByteArray();
if (rs.length == RS_LEN) {
return rs;
} else if (rs.length == RS_LEN + 1 && rs[0] == 0) {
return Arrays.copyOfRange(rs, 1, RS_LEN + 1);
} else if (rs.length < RS_LEN) {
byte[] result = new byte[RS_LEN];
Arrays.fill(result, (byte) 0);
System.arraycopy(rs, 0, result, RS_LEN - rs.length, rs.length);
return result;
} else {
throw new CryptException("Error rs: " + Hex.toHexString(rs));
}
}
// -------------------------------------------------------------------------------------------------------- Private method end
/**
* 将多个数组合并在一起
* 忽略null的数组
*
* @param arrays 数组集合
* @return 合并后的数组
*/
public static byte[] addAll(byte[]... arrays) {
if (arrays.length == 1) {
return arrays[0];
}
// 计算总长度
int length = 0;
for (byte[] array : arrays) {
if (null != array) {
length += array.length;
}
}
final byte[] result = new byte[length];
length = 0;
for (byte[] array : arrays) {
if (null != array) {
System.arraycopy(array, 0, result, length, array.length);
length += array.length;
}
}
return result;
}
}