import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.engines.SM2Engine.Mode;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import java.math.BigInteger;
import java.security.SecureRandom;
/**
* SM2算法工具
*
*/
public final class SM2Utils
{
/**
* Begin: SM2推荐曲线参数
*/
private static final String SM2_ECC_GY_VAL = "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0";
private static final String SM2_ECC_GX_VAL = "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7";
private static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
private final static BigInteger SM2_ECC_N = CURVE.getOrder();
private final static BigInteger SM2_ECC_H = CURVE.getCofactor();
private final static BigInteger SM2_ECC_GX = new BigInteger(SM2_ECC_GX_VAL, 16);
private final static BigInteger SM2_ECC_GY = new BigInteger(SM2_ECC_GY_VAL, 16);
private static final ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
private static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT, SM2_ECC_N, SM2_ECC_H);
/**
* End: SM2推荐曲线参数
*/
private SM2Utils()
{
}
/**
* 生成ECC密钥对
*
* @return ECC密钥对
*/
public static AsymmetricCipherKeyPair generateKeyPairParameter()
{
final SecureRandom random = new SecureRandom();
return BCECUtils.generateKeyPairParameter(DOMAIN_PARAMS, random);
}
/**
* @param pubKey
* 公钥
* @param srcData
* 原文
* @return 默认输出C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @throws InvalidCipherTextException
*/
public static byte[] encrypt(final BCECPublicKey pubKey, final byte[] srcData) throws InvalidCipherTextException
{
return encrypt(Mode.C1C3C2, pubKey, srcData);
}
/**
* @param pubKeyParams
* 公钥
* @param srcData
* 原文
* @return 默认输出C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @throws InvalidCipherTextException
*/
public static byte[] encrypt(final ECPublicKeyParameters pubKeyParams, final byte[] srcData) throws InvalidCipherTextException
{
return encrypt(Mode.C1C3C2, pubKeyParams, srcData);
}
/**
* @param priKey
* 私钥
* @param sm2Cipher
* 默认输入C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。
* @throws InvalidCipherTextException
*/
public static byte[] decrypt(final BCECPrivateKey priKey, final byte[] sm2Cipher) throws InvalidCipherTextException
{
return decrypt(Mode.C1C3C2, priKey, sm2Cipher);
}
/**
* @param priKeyParams
* 私钥
* @param sm2Cipher
* 默认输入C1C3C2顺序的密文。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。
* @throws InvalidCipherTextException
*/
public static byte[] decrypt(final ECPrivateKeyParameters priKeyParams, final byte[] sm2Cipher)
throws InvalidCipherTextException
{
return decrypt(Mode.C1C3C2, priKeyParams, sm2Cipher);
}
/**
* 签名
*
* @param priKey
* 私钥
* @param srcData
* 原文
* @return DER编码后的签名值
* @throws CryptoException
*/
public static byte[] sign(BCECPrivateKey priKey, byte[] srcData) throws CryptoException
{
return sign(priKey, null, srcData);
}
/**
* 签名,默认withId为字节数组:"1234567812345678".getBytes()
*
* @param priKeyParams
* 私钥
* @param srcData
* 原文
* @return DER编码后的签名值
* @throws CryptoException
*/
public static byte[] sign(final ECPrivateKeyParameters priKeyParams, final byte[] srcData) throws CryptoException
{
return sign(priKeyParams, null, srcData);
}
/**
* 验签
*
* @param pubKey
* 公钥
* @param srcData
* 原文
* @param sign
* DER编码的签名值
* @return boolean
*/
public static boolean verify(final BCECPublicKey pubKey, final byte[] srcData, final byte[] sign)
{
return verify(pubKey, null, srcData, sign);
}
/**
* 验签 不指定withId,则默认withId为字节数组:"1234567812345678".getBytes()
*
* @param pubKeyParams
* 公钥
* @param srcData
* 原文
* @param sign
* DER编码的签名值
* @return 验签成功返回true,失败返回false
*/
public static boolean verify(final ECPublicKeyParameters pubKeyParams, final byte[] srcData, final byte[] sign)
{
return verify(pubKeyParams, null, srcData, sign);
}
/**
* @param mode
* 指定密文结构,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
* @param pubKey
* 公钥
* @param srcData
* 原文
* @return 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @throws InvalidCipherTextException
*/
private static byte[] encrypt(final Mode mode, final BCECPublicKey pubKey, final byte[] srcData)
throws InvalidCipherTextException
{
final ECPublicKeyParameters pubKeyParams = BCECUtils.convertPublicKeyToParameters(pubKey);
return encrypt(mode, pubKeyParams, srcData);
}
/**
* @param mode
* 指定密文结构,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
* @param pubKeyParams
* 公钥
* @param srcData
* 原文
* @return 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @throws InvalidCipherTextException
*/
private static byte[] encrypt(final Mode mode, final ECPublicKeyParameters pubKeyParams, final byte[] srcData)
throws InvalidCipherTextException
{
final SM2Engine engine = new SM2Engine(mode);
final ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParams, new SecureRandom());
engine.init(true, pwr);
return engine.processBlock(srcData, 0, srcData.length);
}
/**
* 验签
*
* @param pubKey
* 公钥
* @param withId
* 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData
* 原文
* @param sign
* DER编码的签名值
* @return boolean
*/
private static boolean verify(final BCECPublicKey pubKey, final byte[] withId, final byte[] srcData, final byte[] sign)
{
final ECPublicKeyParameters pubKeyParams = BCECUtils.convertPublicKeyToParameters(pubKey);
return verify(pubKeyParams, withId, srcData, sign);
}
/**
* @param mode
* 指定密文结构,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
* @param priKey
* 私钥
* @param sm2Cipher
* 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。
* @throws InvalidCipherTextException
*/
private static byte[] decrypt(final Mode mode, final BCECPrivateKey priKey, final byte[] sm2Cipher)
throws InvalidCipherTextException
{
final ECPrivateKeyParameters priKeyParams = BCECUtils.convertPrivateKeyToParameters(priKey);
return decrypt(mode, priKeyParams, sm2Cipher);
}
/**
* @param mode
* 指定密文结构,新的[《SM2密码算法使用规范》 GM/T 0009-2012]标准为C1C3C2
* @param priKeyParams
* 私钥
* @param sm2Cipher
* 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
* @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。
* @throws InvalidCipherTextException
*/
private static byte[] decrypt(final Mode mode, final ECPrivateKeyParameters priKeyParams, final byte[] sm2Cipher)
throws InvalidCipherTextException
{
final SM2Engine engine = new SM2Engine(mode);
engine.init(false, priKeyParams);
return engine.processBlock(sm2Cipher, 0, sm2Cipher.length);
}
/**
* 私钥签名
*
* @param priKey
* 私钥
* @param withId
* 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData
* 原文
* @return DER编码后的签名值
* @throws CryptoException
*/
private static byte[] sign(final BCECPrivateKey priKey, final byte[] withId, final byte[] srcData) throws CryptoException
{
final ECPrivateKeyParameters priKeyParams = BCECUtils.convertPrivateKeyToParameters(priKey);
return sign(priKeyParams, withId, srcData);
}
/**
* 签名
*
* @param priKeyParams
* 私钥
* @param withId
* 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData
* 源数据
* @return DER编码后的签名值
* @throws CryptoException
*/
private static byte[] sign(final ECPrivateKeyParameters priKeyParams, final byte[] withId, final byte[] srcData)
throws CryptoException
{
SM2Signer signer = new SM2Signer();
CipherParameters param = null;
ParametersWithRandom pwr = new ParametersWithRandom(priKeyParams, new SecureRandom());
if (withId != null)
{
param = new ParametersWithID(pwr, withId);
}
else
{
param = pwr;
}
signer.init(true, param);
signer.update(srcData, 0, srcData.length);
return signer.generateSignature();
}
/**
* 验签
*
* @param pubKeyParams
* 公钥
* @param withId
* 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()
* @param srcData
* 原文
* @param sign
* DER编码的签名值
* @return 验签成功返回true,失败返回false
*/
private static boolean verify(final ECPublicKeyParameters pubKeyParams, final byte[] withId, final byte[] srcData,
final byte[] sign)
{
final SM2Signer signer = new SM2Signer();
CipherParameters param;
if (withId != null)
{
param = new ParametersWithID(pubKeyParams, withId);
}
else
{
param = pubKeyParams;
}
signer.init(false, param);
signer.update(srcData, 0, srcData.length);
return signer.verifySignature(sign);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)