SM256 JS JAVA 前后端加解迷 整套奉献

SM256 JS JAVA 前后端加解迷 整套奉献

前后端js和java的解密加密请看
https://www.cnblogs.com/BoyTNT/p/13086321.html

后端基于以上链接中的java 解密增加加密代码

package com.lb.base.commons.base.utils.crypto.client;

import com.lb.base.commons.base.exception.ServiceException;
import com.lb.base.commons.base.utils.crypto.CryptoPsCode;
import com.lb.base.commons.base.utils.crypto.bo.CryptoBO;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * @author tangzedong.programmer@gamil.com
 * @apiNote SM2加密的变种,可以用于前端加密的解密
 * @since 2020/10/24 10:44
 */
@Slf4j
public class SM2P256CryptoPsCodeClient implements CryptoPsCode {

    private static final String ALGORITHM = "sm2p256v1";
    private ECDomainParameters domainParameters;

    public SM2P256CryptoPsCodeClient() {
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(ALGORITHM);
        domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
    }


    /**
     * 生成私钥公钥
     *
     * @return 私钥公钥
     */
    @Override
    public CryptoBO generateKey() {
        try {
            ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();

            //私钥,16进制格式,自己保存,格式如a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853
            BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
            String privateKeyHex = privatekey.toString(16);

            //公钥,16进制格式,发给前端,格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba
            ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
            String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
            return new CryptoBO().setPubKey(publicKeyHex).setPriKey(privateKeyHex);
        } catch (Exception e) {
            throw new ServiceException(e, "生成公钥私钥失败!");
        }
    }

    /**
     * 加密密码
     *
     * @param psCode    明文密码
     * @param publicKey 公钥
     * @return 加密后的密码
     */
    @Override
    public String cryptoPsCode(String psCode, String publicKey) {
        try {
            //提取公钥点
            ECPoint pukPoint = domainParameters.getCurve().decodePoint(hexString2byte(publicKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(pukPoint, domainParameters);
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(pubKey, new SecureRandom()));
            byte[] in = Base64.getEncoder().encode(psCode.getBytes(StandardCharsets.UTF_8));
            return Hex.toHexString(sm2Engine.processBlock(in, 0, in.length));
        } catch (Exception e) {
            log.error("加密失败!", e);
            throw new ServiceException(e, "加密失败!");
        }
    }

    /**
     * @param hexString 16进制字符串    如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
     * @return
     * @Title: hexString2byte
     * @Description: 16进制字符串转字节数组
     * @since: 0.0.1
     */
    public static byte[] hexString2byte(String hexString) {
        if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
            return null;
        }
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
        }
        return bytes;
    }

    public static void main(String[] args) {
        String priKey = "962a8fe61218485d8e55d77bbe381f2f6e228367fcfd083834117b867e4b107";
        String pubKey = "04e71a4d21bc6ec2e1e5a404ef014845153b4a5882f2cdff5450bb62398363d5c261e5cbc4f4f0c23a64e06d506e0c043162d2dcc5bf9eedb5c24aa1313c438d3f";
        SM2P256CryptoPsCodeClient client = new SM2P256CryptoPsCodeClient();
        String psCode = client.cryptoPsCode("123abc..", pubKey);
        System.out.println("======cipher======:" + psCode);
        psCode = client.decryptPsCode(psCode, priKey);
        System.out.println("======psCode======:" + psCode);
    }


    /**
     * 解密密码
     *
     * @param cipher 密码
     * @param priKey 秘钥
     * @return 解密后密码明文
     */
    @Override
    public String decryptPsCode(String cipher, String priKey) {

        try {
            //JS加密产生的密文
            byte[] cipherDataByte = Hex.decode(cipher);
            //刚才的私钥Hex,先还原私钥
            ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(priKey, 16), domainParameters);
            //用私钥解密
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, privateKeyParameters);
            //processBlock得到Base64格式,记得解码
            return new String(Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length)));
        } catch (Exception e) {
            log.error("数据完整性被破坏!", e);
            throw new ServiceException(e, "数据完整性被破坏!");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值