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

com.dahuatech.hutool.crypto.asymmetric.SM2 Maven / Gradle / Ivy

package com.dahuatech.hutool.crypto.asymmetric;

import com.dahuatech.hutool.crypto.CryptoException;
import com.dahuatech.hutool.crypto.SecureUtil;
import com.dahuatech.hutool.crypto.asymmetric.SM2Engine.SM2Mode;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;

import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * 国密SM2算法实现,基于BC库
* SM2算法只支持公钥加密,私钥解密
* 参考:https://blog.csdn.net/pridas/article/details/86118774 * * @author looly * @since 4.3.2 */ public class SM2 extends AbstractAsymmetricCrypto { /** 算法EC */ private static final String ALGORITHM_SM2 = "SM2"; protected SM2Engine engine; protected SM2Signer signer; private SM2Mode mode; private ECPublicKeyParameters publicKeyParams; private ECPrivateKeyParameters privateKeyParams; // ------------------------------------------------------------------ Constructor start /** 构造,生成新的私钥公钥对 */ public SM2() { this((byte[]) null, (byte[]) null); } /** * 构造
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 * * @param privateKeyStr 私钥Hex或Base64表示 * @param publicKeyStr 公钥Hex或Base64表示 */ public SM2(String privateKeyStr, String publicKeyStr) { this(SecureUtil.decode(privateKeyStr), SecureUtil.decode(publicKeyStr)); } /** * 构造
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 * * @param privateKey 私钥 * @param publicKey 公钥 */ public SM2(byte[] privateKey, byte[] publicKey) { this( // SecureUtil.generatePrivateKey(ALGORITHM_SM2, privateKey), // SecureUtil.generatePublicKey(ALGORITHM_SM2, publicKey) // ); } /** * 构造
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 * * @param privateKey 私钥 * @param publicKey 公钥 */ public SM2(PrivateKey privateKey, PublicKey publicKey) { super(ALGORITHM_SM2, privateKey, publicKey); } // ------------------------------------------------------------------ Constructor end /** * 初始化
* 私钥和公钥同时为空时生成一对新的私钥和公钥
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密(签名)或者解密(校验) * * @param privateKey 私钥 * @param publicKey 公钥 * @return this */ public SM2 init(PrivateKey privateKey, PublicKey publicKey) { return this.init(ALGORITHM_SM2, privateKey, publicKey); } @Override protected SM2 init(String algorithm, PrivateKey privateKey, PublicKey publicKey) { super.init(algorithm, privateKey, publicKey); return initCipherParams(); } // --------------------------------------------------------------------------------- Encrypt /** * 加密,SM2非对称加密的结果由C1,C2,C3三部分组成,其中: * *
   * C1 生成随机数的计算出的椭圆曲线点
   * C2 密文数据
   * C3 SM3的摘要值
   * 
* * @param data 被加密的bytes * @param keyType 私钥或公钥 {@link KeyType} * @return 加密后的bytes * @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常 */ @Override public byte[] encrypt(byte[] data, KeyType keyType) throws CryptoException { if (KeyType.PublicKey != keyType) { throw new IllegalArgumentException("Encrypt is only support by public key"); } checkKey(keyType); lock.lock(); final SM2Engine engine = getEngine(); try { engine.init(true, new ParametersWithRandom(getCipherParameters(keyType))); return engine.processBlock(data, 0, data.length); } finally { lock.unlock(); } } // --------------------------------------------------------------------------------- Decrypt /** * 解密 * * @param data SM2密文,实际包含三部分:ECC公钥、真正的密文、公钥和原文的SM3-HASH值 * @param keyType 私钥或公钥 {@link KeyType} * @return 加密后的bytes * @throws CryptoException 包括InvalidKeyException和InvalidCipherTextException的包装异常 */ @Override public byte[] decrypt(byte[] data, KeyType keyType) throws CryptoException { if (KeyType.PrivateKey != keyType) { throw new IllegalArgumentException("Decrypt is only support by private key"); } checkKey(keyType); lock.lock(); final SM2Engine engine = getEngine(); try { engine.init(false, getCipherParameters(keyType)); return engine.processBlock(data, 0, data.length); } finally { lock.unlock(); } } // --------------------------------------------------------------------------------- Sign and // Verify /** * 用私钥对信息生成数字签名 * * @param data 加密数据 * @return 签名 */ public byte[] sign(byte[] data) { return sign(data, null); } /** * 用私钥对信息生成数字签名 * * @param data 加密数据 * @param id 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() * @return 签名 */ public byte[] sign(byte[] data, byte[] id) { lock.lock(); final SM2Signer signer = getSigner(); try { CipherParameters param = new ParametersWithRandom(getCipherParameters(KeyType.PrivateKey)); if (id != null) { param = new ParametersWithID(param, id); } signer.init(true, param); signer.update(data, 0, data.length); return signer.generateSignature(); } catch (Exception e) { throw new CryptoException(e); } finally { lock.unlock(); } } /** * 用公钥检验数字签名的合法性 * * @param data 数据 * @param sign 签名 * @return 是否验证通过 */ public boolean verify(byte[] data, byte[] sign) { return verify(data, sign, null); } /** * 用公钥检验数字签名的合法性 * * @param data 数据 * @param sign 签名 * @param id 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes() * @return 是否验证通过 */ public boolean verify(byte[] data, byte[] sign, byte[] id) { lock.lock(); final SM2Signer signer = getSigner(); try { CipherParameters param = getCipherParameters(KeyType.PublicKey); if (id != null) { param = new ParametersWithID(param, id); } signer.init(false, param); signer.update(data, 0, data.length); return signer.verifySignature(sign); } catch (Exception e) { throw new CryptoException(e); } finally { lock.unlock(); } } @Override public SM2 setPrivateKey(PrivateKey privateKey) { super.setPrivateKey(privateKey); // 重新初始化密钥参数,防止重新设置密钥时导致密钥无法更新 this.privateKeyParams = null; initCipherParams(); return this; } @Override public SM2 setPublicKey(PublicKey publicKey) { super.setPublicKey(publicKey); // 重新初始化密钥参数,防止重新设置密钥时导致密钥无法更新 this.publicKeyParams = null; initCipherParams(); return this; } /** * 设置加密类型 * * @param mode {@link SM2Mode} * @return this */ public SM2 setMode(SM2Mode mode) { this.mode = mode; if (null != this.engine) { this.engine.setMode(mode); } return this; } // ------------------------------------------------------------------------------------------------------------------------- Private method start /** * 初始化加密解密参数(包括私钥和公钥参数) * * @return this */ private SM2 initCipherParams() { try { if (null != this.publicKey) { this.publicKeyParams = (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(this.publicKey); } if (null != privateKey) { this.privateKeyParams = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(this.privateKey); } } catch (InvalidKeyException e) { throw new CryptoException(e); } return this; } /** * 获取密钥类型对应的加密参数对象{@link CipherParameters} * * @param keyType Key类型枚举,包括私钥或公钥 * @return {@link CipherParameters} */ private CipherParameters getCipherParameters(KeyType keyType) { switch (keyType) { case PublicKey: return this.publicKeyParams; case PrivateKey: return this.privateKeyParams; } return null; } /** * 检查对应类型的Key是否存在 * * @param keyType key类型 */ private void checkKey(KeyType keyType) { switch (keyType) { case PublicKey: if (null == this.publicKey) { throw new NullPointerException("No public key provided"); } break; case PrivateKey: if (null == this.privateKey) { throw new NullPointerException("No private key provided"); } break; } } /** * 获取{@link SM2Engine} * * @return {@link SM2Engine} */ private SM2Engine getEngine() { if (null == this.engine) { this.engine = new SM2Engine(this.mode); } return this.engine; } /** * 获取{@link SM2Signer} * * @return {@link SM2Signer} */ private SM2Signer getSigner() { if (null == this.signer) { this.signer = new SM2Signer(); } return this.signer; } // ------------------------------------------------------------------------------------------------------------------------- Private method end }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy