whyczh
2021-12-10 1ab06fa644b400182dde1621c60f904c4711f2b6
接口更新
4个文件已修改
9个文件已添加
1306 ■■■■■ 已修改文件
pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/controller/BattInfController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/controller/LoginController.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/dto/SignDTO.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/encryption/ByteConvertUtil.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/encryption/SM2.java 845 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/encryption/SM2KeyPair.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/encryption/SM3.java 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/mapper/LicenseMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/pojo/License.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/service/LicenseService.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/service/UserService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/LicenseMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -133,6 +133,11 @@
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.54</version>
        </dependency>
        <!--添加aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
src/main/java/com/whyc/controller/BattInfController.java
@@ -80,7 +80,7 @@
    }
    @GetMapping("/add")
    @PostMapping("/add")
    @ApiOperation("新增电池组")
    public Response addBattinf(@RequestBody Battinf battinf){
        UserInf userInf = (UserInf) ActionUtil.getUser();
src/main/java/com/whyc/controller/LoginController.java
@@ -1,7 +1,11 @@
package com.whyc.controller;
import com.whyc.dto.Response;
import com.whyc.dto.SignDTO;
import com.whyc.pojo.UserInf;
import com.whyc.service.LoginService;
import com.whyc.service.UserService;
import com.whyc.util.ActionUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@@ -13,6 +17,7 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.*;
import java.io.IOException;
@RequestMapping("login")
@@ -22,6 +27,8 @@
    @Autowired
    private LoginService service;
    @Autowired
    private UserService userService;
    @PostMapping("login")
    @ApiOperation(value ="登录-账号密码")
@@ -35,6 +42,50 @@
        return service.loginWithUKey(userName,password,request);
    }
    @GetMapping("/getRandom")
    @ApiOperation(value = "uKey校验前生成随机数")
    public Response getRandom(){
        int randomNum = (int)((Math.random()*9+1)*10000);
        ActionUtil.getSession().setAttribute("uKeyRandom",String.valueOf(randomNum));
        return new Response().set(1,randomNum);
    }
    @PostMapping("/verify")
    @ApiOperation(value = "校验签名")
    public Response verify(@RequestBody SignDTO signDTO){
        Response response = new Response();
        //前端将字符\替换成了huodongwei,这里再转回来
        signDTO.setInPath(signDTO.getInPath().replace("huodongwei","\\"));
        //通过uKeyId获取公钥XY
        UserInf userInf = userService.getPublicXYByUKeyId(signDTO.getUKeyId());
        //获取之前生成的随机数
        String uKeyRandom = (String) ActionUtil.getSession().getAttribute("uKeyRandom");
        boolean b = com.whyc.softkey.jsyunew3.YtVerfiy(userInf.getUName(), uKeyRandom, signDTO.getPublicX(), signDTO.getPublicY(), signDTO.getSign(), signDTO.getInPath());
        long lastError = com.whyc.softkey.jsyunew3.get_LastError();
        if(b && lastError==0){
            response.set(1,"校验成功");
        }else {
            if (lastError == 0){
                response.set(0,"校验失败");
            }else{
                String baseMsg ="校验失败,原因为:";
                switch ((int) lastError){
                    case -82 : response.setMsg(baseMsg+"写数据到加密锁储存器时错误,可能是写密码错误");break;
                    case -81 :
                    case -88 : response.setMsg(baseMsg+"输入的地址空间超出");break;
                    case -47 : response.setMsg(baseMsg+"进行读写字符串时,地址空间超出");break;
                    case -92 : response.setMsg(baseMsg+"不存在指定的加密锁");break;
                    case -93 :
                    case -94 : response.setMsg(baseMsg+"操作加密锁时错误");break;
                    case -83 : response.setMsg(baseMsg+"从加密锁读取数据时错误,可能是读密码错误");break;
                    case -46 : response.setMsg(baseMsg+"使用控件时,输入的字符不能是空字符串");break;
                    case -51 : response.setMsg(baseMsg+"打开USB文件句柄失败(iKey)");break;
                }
            }
        }
        return response;
    }
    @PostMapping("logout")
    @ApiOperation(value ="退出登录")
    public void logout(){
src/main/java/com/whyc/dto/SignDTO.java
New file
@@ -0,0 +1,14 @@
package com.whyc.dto;
import lombok.Data;
@Data
public class SignDTO {
    private String sign;
    private String inPath;
    private String userName;
    private String uKeyId;
    private String publicX;
    private String publicY;
}
src/main/java/com/whyc/encryption/ByteConvertUtil.java
New file
@@ -0,0 +1,41 @@
package com.whyc.encryption;
public class ByteConvertUtil {
    public static String bytesToHexString(byte[] bArr) {
        StringBuffer sb = new StringBuffer(bArr.length);
        String sTmp;
        for (int i = 0; i < bArr.length; i++) {
            sTmp = Integer.toHexString(0xFF & bArr[i]);
            if (sTmp.length() < 2){
                sb.append(0);
            }
            sb.append(sTmp.toUpperCase());
        }
        return sb.toString();
    }
    /**
     * hex字符串转byte数组
     * @param inHex 待转换的Hex字符串
     * @return  转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex){
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1){
            //奇数
            hexlen++;
            result = new byte[(hexlen/2)];
            inHex="0"+inHex;
        }else {
            //偶数
            result = new byte[(hexlen/2)];
        }
        int j=0;
        for (int i = 0; i < hexlen; i+=2){
            result[j]=(byte)Integer.parseInt(inHex.substring(i,i+2),16);
            j++;
        }
        return result;
    }
}
src/main/java/com/whyc/encryption/SM2.java
New file
@@ -0,0 +1,845 @@
package com.whyc.encryption;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import java.io.*;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;
/**
 * SM2公钥加密算法实现 包括 -签名,验签 -密钥交换 -公钥加密,私钥解密
 */
public class SM2 {
    private static BigInteger n = new BigInteger(
            "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "7203DF6B" + "21C6052B" + "53BBF409" + "39D54123", 16);
    private static BigInteger p = new BigInteger(
            "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFF", 16);
    private static BigInteger a = new BigInteger(
            "FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFC", 16);
    private static BigInteger b = new BigInteger(
            "28E9FA9E" + "9D9F5E34" + "4D5A9E4B" + "CF6509A7" + "F39789F5" + "15AB8F92" + "DDBCBD41" + "4D940E93", 16);
    private static BigInteger gx = new BigInteger(
            "32C4AE2C" + "1F198119" + "5F990446" + "6A39C994" + "8FE30BBF" + "F2660BE1" + "715A4589" + "334C74C7", 16);
    private static BigInteger gy = new BigInteger(
            "BC3736A2" + "F4F6779C" + "59BDCEE3" + "6B692153" + "D0A9877C" + "C62A4740" + "02DF32E5" + "2139F0A0", 16);
    private static ECDomainParameters ecc_bc_spec;
    private static int w = (int) Math.ceil(n.bitLength() * 1.0 / 2) - 1;
    private static BigInteger _2w = new BigInteger("2").pow(w);
    private static final int DIGEST_LENGTH = 32;
    private static SecureRandom random = new SecureRandom();
    private static ECCurve.Fp curve;
    private static ECPoint G;
    private boolean debug = false;
    public boolean isDebug() {
        return debug;
    }
    public void setDebug(boolean debug) {
        this.debug = debug;
    }
    /**
     * �?16进制打印字节数组
     *
     * @param b
     */
    public static void printHexString(byte[] b) {
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            System.out.print(hex.toUpperCase());
        }
        System.out.println();
    }
    /**
     * 随机数生成器
     *
     * @param max
     * @return
     */
    private static BigInteger random(BigInteger max) {
        BigInteger r = new BigInteger(256, random);
        // int count = 1;
        while (r.compareTo(max) >= 0) {
            r = new BigInteger(128, random);
            // count++;
        }
        // System.out.println("count: " + count);
        return r;
    }
    /**
     * 判断字节数组是否�?0
     *
     * @param buffer
     * @return
     */
    private boolean allZero(byte[] buffer) {
        for (int i = 0; i < buffer.length; i++) {
            if (buffer[i] != 0)
                return false;
        }
        return true;
    }
    /**
     * 公钥加密
     *
     * @param input
     *            加密原文
     * @param publicKey
     *            公钥
     * @return
     */
    public byte[] encrypt(String input, ECPoint publicKey) {
        byte[] inputBuffer = input.getBytes();
        if (debug)
            printHexString(inputBuffer);
        byte[] C1Buffer;
        ECPoint kpb;
        byte[] t;
        do {
            /* 1 产生随机数k,k属于[1, n-1] */
            BigInteger k = random(n);
            if (debug) {
                System.out.print("k: ");
                printHexString(k.toByteArray());
            }
            /* 2 计算椭圆曲线点C1 = [k]G = (x1, y1) */
            ECPoint C1 = G.multiply(k);
            C1Buffer = C1.getEncoded(false);
            if (debug) {
                System.out.print("C1: ");
                printHexString(C1Buffer);
            }
            /*
             * 3 计算椭圆曲线�? S = [h]Pb
             */
            BigInteger h = ecc_bc_spec.getH();
            if (h != null) {
                ECPoint S = publicKey.multiply(h);
                if (S.isInfinity())
                    throw new IllegalStateException();
            }
            /* 4 计算 [k]PB = (x2, y2) */
            kpb = publicKey.multiply(k).normalize();
            /* 5 计算 t = KDF(x2||y2, klen) */
            byte[] kpbBytes = kpb.getEncoded(false);
            t = KDF(kpbBytes, inputBuffer.length);
            // DerivationFunction kdf = new KDF1BytesGenerator(new
            // ShortenedDigest(new SHA256Digest(), DIGEST_LENGTH));
            //
            // t = new byte[inputBuffer.length];
            // kdf.init(new ISO18033KDFParameters(kpbBytes));
            // kdf.generateBytes(t, 0, t.length);
        } while (allZero(t));
        /* 6 计算C2=M^t */
        byte[] C2 = new byte[inputBuffer.length];
        for (int i = 0; i < inputBuffer.length; i++) {
            C2[i] = (byte) (inputBuffer[i] ^ t[i]);
        }
        /* 7 计算C3 = Hash(x2 || M || y2) */
        byte[] C3 = sm3hash(kpb.getXCoord().toBigInteger().toByteArray(), inputBuffer,
                kpb.getYCoord().toBigInteger().toByteArray());
        /* 8 输出密文 C=C1 || C2 || C3 */
        byte[] encryptResult = new byte[C1Buffer.length + C2.length + C3.length];
        System.arraycopy(C1Buffer, 0, encryptResult, 0, C1Buffer.length);
        System.arraycopy(C2, 0, encryptResult, C1Buffer.length, C2.length);
        System.arraycopy(C3, 0, encryptResult, C1Buffer.length + C2.length, C3.length);
        if (debug) {
            System.out.print("密文: ");
            printHexString(encryptResult);
        }
        return encryptResult;
    }
    /**
     * 私钥解密
     *
     * @param encryptData
     *            密文数据字节数组
     * @param privateKey
     *            解密私钥
     * @return
     */
    public String decrypt(byte[] encryptData, BigInteger privateKey) {
        if (debug)
            System.out.println("encryptData length: " + encryptData.length);
        byte[] C1Byte = new byte[65];
        System.arraycopy(encryptData, 0, C1Byte, 0, C1Byte.length);
        ECPoint C1 = curve.decodePoint(C1Byte).normalize();
        /*
         * 计算椭圆曲线�? S = [h]C1 是否为无穷点
         */
        BigInteger h = ecc_bc_spec.getH();
        if (h != null) {
            ECPoint S = C1.multiply(h);
            if (S.isInfinity())
                throw new IllegalStateException();
        }
        /* 计算[dB]C1 = (x2, y2) */
        ECPoint dBC1 = C1.multiply(privateKey).normalize();
        /* 计算t = KDF(x2 || y2, klen) */
        byte[] dBC1Bytes = dBC1.getEncoded(false);
        int klen = encryptData.length - 65 - DIGEST_LENGTH;
        byte[] t = KDF(dBC1Bytes, klen);
        // DerivationFunction kdf = new KDF1BytesGenerator(new
        // ShortenedDigest(new SHA256Digest(), DIGEST_LENGTH));
        // if (debug)
        // System.out.println("klen = " + klen);
        // kdf.init(new ISO18033KDFParameters(dBC1Bytes));
        // kdf.generateBytes(t, 0, t.length);
        if (allZero(t)) {
            System.err.println("all zero");
            throw new IllegalStateException();
        }
        /* 5 计算M'=C2^t */
        byte[] M = new byte[klen];
        for (int i = 0; i < M.length; i++) {
            M[i] = (byte) (encryptData[C1Byte.length + i] ^ t[i]);
        }
        if (debug)
            printHexString(M);
        /* 6 计算 u = Hash(x2 || M' || y2) 判断 u == C3是否成立 */
        byte[] C3 = new byte[DIGEST_LENGTH];
        if (debug)
            try {
                System.out.println("M = " + new String(M, "UTF8"));
            } catch (UnsupportedEncodingException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        System.arraycopy(encryptData, encryptData.length - DIGEST_LENGTH, C3, 0, DIGEST_LENGTH);
        byte[] u = sm3hash(dBC1.getXCoord().toBigInteger().toByteArray(), M,
                dBC1.getYCoord().toBigInteger().toByteArray());
        if (Arrays.equals(u, C3)) {
            if (debug)
                System.out.println("解密成功");
            try {
                return new String(M, "UTF8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return null;
        } else {
            if (debug) {
                System.out.print("u = ");
                printHexString(u);
                System.out.print("C3 = ");
                printHexString(C3);
                System.err.println("解密验证失败");
            }
            return null;
        }
    }
    // /**
    // * SHA摘要
    // * @param x2
    // * @param M
    // * @param y2
    // * @return
    // */
    // private byte[] calculateHash(BigInteger x2, byte[] M, BigInteger y2) {
    // ShortenedDigest digest = new ShortenedDigest(new SHA256Digest(),
    // DIGEST_LENGTH);
    // byte[] buf = x2.toByteArray();
    // digest.update(buf, 0, buf.length);
    // digest.update(M, 0, M.length);
    // buf = y2.toByteArray();
    // digest.update(buf, 0, buf.length);
    //
    // buf = new byte[DIGEST_LENGTH];
    // digest.doFinal(buf, 0);
    //
    // return buf;
    // }
    /**
     * 判断是否在范围内
     *
     * @param param
     * @param min
     * @param max
     * @return
     */
    private boolean between(BigInteger param, BigInteger min, BigInteger max) {
        if (param.compareTo(min) >= 0 && param.compareTo(max) < 0) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 判断生成的公钥是否合�?
     *
     * @param publicKey
     * @return
     */
    private boolean checkPublicKey(ECPoint publicKey) {
        if (!publicKey.isInfinity()) {
            BigInteger x = publicKey.getXCoord().toBigInteger();
            BigInteger y = publicKey.getYCoord().toBigInteger();
            if (between(x, new BigInteger("0"), p) && between(y, new BigInteger("0"), p)) {
                BigInteger xResult = x.pow(3).add(a.multiply(x)).add(b).mod(p);
                if (debug)
                    System.out.println("xResult: " + xResult.toString());
                BigInteger yResult = y.pow(2).mod(p);
                if (debug)
                    System.out.println("yResult: " + yResult.toString());
                if (yResult.equals(xResult) && publicKey.multiply(n).isInfinity()) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 生成密钥�?
     *
     * @return
     */
    public SM2KeyPair generateKeyPair() {
        BigInteger d = random(n.subtract(new BigInteger("1")));
        SM2KeyPair keyPair = new SM2KeyPair(G.multiply(d).normalize(), d);
        if (checkPublicKey(keyPair.getPublicKey())) {
            if (debug)
                System.out.println("generate key successfully");
            return keyPair;
        } else {
            if (debug)
                System.err.println("generate key failed");
            return null;
        }
    }
    public SM2() {
        curve = new ECCurve.Fp(p, // q
                a, // a
                b); // b
        G = curve.createPoint(gx, gy);
        ecc_bc_spec = new ECDomainParameters(curve, G, n);
    }
    public SM2(boolean debug) {
        this();
        this.debug = debug;
    }
    /**
     * 导出公钥到本�?
     *
     * @param publicKey
     * @param path
     */
    public void exportPublicKey(ECPoint publicKey, String path) {
        File file = new File(path);
        try {
            if (!file.exists())
                file.createNewFile();
            byte buffer[] = publicKey.getEncoded(false);
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(buffer);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 从本地导入公�?
     *
     * @param path
     * @return
     */
    public ECPoint importPublicKey(String path) {
        File file = new File(path);
        try {
            if (!file.exists())
                return null;
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte buffer[] = new byte[16];
            int size;
            while ((size = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, size);
            }
            fis.close();
            return curve.decodePoint(baos.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 导出私钥到本�?
     *
     * @param privateKey
     * @param path
     */
    public void exportPrivateKey(BigInteger privateKey, String path) {
        File file = new File(path);
        try {
            if (!file.exists())
                file.createNewFile();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
            oos.writeObject(privateKey);
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 从本地导入私�?
     *
     * @param path
     * @return
     */
    public BigInteger importPrivateKey(String path) {
        File file = new File(path);
        try {
            if (!file.exists()) {
                return null;
            }
            FileInputStream fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis);
            BigInteger res = (BigInteger) (ois.readObject());
            ois.close();
            fis.close();
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 字节数组拼接
     *
     * @param params
     * @return
     */
    private static byte[] join(byte[]... params) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] res = null;
        try {
            for (int i = 0; i < params.length; i++) {
                baos.write(params[i]);
            }
            res = baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }
    /**
     * sm3摘要
     *
     * @param params
     * @return
     */
    private static byte[] sm3hash(byte[]... params) {
        byte[] res = null;
        try {
            res = SM3.hash(join(params));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return res;
    }
    /**
     * 取得用户标识字节数组
     *
     * @param IDA
     * @param aPublicKey
     * @return
     */
    private static byte[] ZA(String IDA, ECPoint aPublicKey) {
        byte[] idaBytes = IDA.getBytes();
        int entlenA = idaBytes.length * 8;
        byte[] ENTLA = new byte[] { (byte) (entlenA & 0xFF00), (byte) (entlenA & 0x00FF) };
        byte[] ZA = sm3hash(ENTLA, idaBytes, a.toByteArray(), b.toByteArray(), gx.toByteArray(), gy.toByteArray(),
                aPublicKey.getXCoord().toBigInteger().toByteArray(),
                aPublicKey.getYCoord().toBigInteger().toByteArray());
        return ZA;
    }
    /**
     * 签名
     *
     * @param M
     *            签名信息
     * @param IDA
     *            签名方唯�?标识
     * @param keyPair
     *            签名方密钥对
     * @return 签名
     */
    public Signature sign(String M, String IDA, SM2KeyPair keyPair) {
        byte[] ZA = ZA(IDA, keyPair.getPublicKey());
        byte[] M_ = join(ZA, M.getBytes());
        BigInteger e = new BigInteger(1, sm3hash(M_));
        // BigInteger k = new BigInteger(
        // "6CB28D99 385C175C 94F94E93 4817663F C176D925 DD72B727 260DBAAE
        // 1FB2F96F".replace(" ", ""), 16);
        BigInteger k;
        BigInteger r;
        do {
            k = random(n);
            ECPoint p1 = G.multiply(k).normalize();
            BigInteger x1 = p1.getXCoord().toBigInteger();
            r = e.add(x1);
            r = r.mod(n);
        } while (r.equals(BigInteger.ZERO) || r.add(k).equals(n));
        BigInteger s = ((keyPair.getPrivateKey().add(BigInteger.ONE).modInverse(n))
                .multiply((k.subtract(r.multiply(keyPair.getPrivateKey()))).mod(n))).mod(n);
        return new Signature(r, s);
    }
    /**
     * 验签
     *
     * @param M
     *            签名信息
     * @param signature
     *            签名
     * @param IDA
     *            签名方唯�?标识
     * @param aPublicKey
     *            签名方公�?
     * @return true or false
     */
    public boolean verify(String M, Signature signature, String IDA, ECPoint aPublicKey) {
        if (!between(signature.r, BigInteger.ONE, n))
            return false;
        if (!between(signature.s, BigInteger.ONE, n))
            return false;
        byte[] M_ = join(ZA(IDA, aPublicKey), M.getBytes());
        BigInteger e = new BigInteger(1, sm3hash(M_));
        BigInteger t = signature.r.add(signature.s).mod(n);
        if (t.equals(BigInteger.ZERO))
            return false;
        ECPoint p1 = G.multiply(signature.s).normalize();
        ECPoint p2 = aPublicKey.multiply(t).normalize();
        BigInteger x1 = p1.add(p2).normalize().getXCoord().toBigInteger();
        BigInteger R = e.add(x1).mod(n);
        if (R.equals(signature.r))
            return true;
        return false;
    }
    /**
     * 密钥派生函数
     *
     * @param Z
     * @param klen
     *            生成klen字节数长度的密钥
     * @return
     */
    private static byte[] KDF(byte[] Z, int klen) {
        int ct = 1;
        int end = (int) Math.ceil(klen * 1.0 / 32);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            for (int i = 1; i < end; i++) {
                baos.write(sm3hash(Z, SM3.toByteArray(ct)));
                ct++;
            }
            byte[] last = sm3hash(Z, SM3.toByteArray(ct));
            if (klen % 32 == 0) {
                baos.write(last);
            } else
                baos.write(last, 0, klen % 32);
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 传输实体�?
     *
     * @author Potato
     *
     */
    private static class TransportEntity implements Serializable {
        final byte[] R; //R�?
        final byte[] S; //验证S
        final byte[] Z; //用户标识
        final byte[] K; //公钥
        public TransportEntity(byte[] r, byte[] s,byte[] z,ECPoint pKey) {
            R = r;
            S = s;
            Z=z;
            K=pKey.getEncoded(false);
        }
    }
    /**
     * 密钥协商辅助�?
     *
     * @author Potato
     *
     */
    public static class KeyExchange {
        BigInteger rA;
        ECPoint RA;
        ECPoint V;
        byte[] Z;
        byte[] key;
        String ID;
        SM2KeyPair keyPair;
        public KeyExchange(String ID, SM2KeyPair keyPair) {
            this.ID=ID;
            this.keyPair = keyPair;
            this.Z=ZA(ID, keyPair.getPublicKey());
        }
        /**
         * 密钥协商发起第一�?
         *
         * @return
         */
        public TransportEntity keyExchange_1() {
            rA = random(n);
            // rA=new BigInteger("83A2C9C8 B96E5AF7 0BD480B4 72409A9A 327257F1
            // EBB73F5B 073354B2 48668563".replace(" ", ""),16);
            RA = G.multiply(rA).normalize();
            return new TransportEntity(RA.getEncoded(false), null,Z,keyPair.getPublicKey());
        }
        /**
         * 密钥协商响应�?
         *
         * @param entity 传输实体
         * @return
         */
        public TransportEntity keyExchange_2(TransportEntity entity) {
            BigInteger rB = random(n);
            // BigInteger rB=new BigInteger("33FE2194 0342161C 55619C4A 0C060293
            // D543C80A F19748CE 176D8347 7DE71C80".replace(" ", ""),16);
            ECPoint RB = G.multiply(rB).normalize();
            this.rA=rB;
            this.RA=RB;
            BigInteger x2 = RB.getXCoord().toBigInteger();
            x2 = _2w.add(x2.and(_2w.subtract(BigInteger.ONE)));
            BigInteger tB = keyPair.getPrivateKey().add(x2.multiply(rB)).mod(n);
            ECPoint RA = curve.decodePoint(entity.R).normalize();
            BigInteger x1 = RA.getXCoord().toBigInteger();
            x1 = _2w.add(x1.and(_2w.subtract(BigInteger.ONE)));
            ECPoint aPublicKey=curve.decodePoint(entity.K).normalize();
            ECPoint temp = aPublicKey.add(RA.multiply(x1).normalize()).normalize();
            ECPoint V = temp.multiply(ecc_bc_spec.getH().multiply(tB)).normalize();
            if (V.isInfinity())
                throw new IllegalStateException();
            this.V=V;
            byte[] xV = V.getXCoord().toBigInteger().toByteArray();
            byte[] yV = V.getYCoord().toBigInteger().toByteArray();
            byte[] KB = KDF(join(xV, yV, entity.Z, this.Z), 16);
            key = KB;
            System.out.print("协商得B密钥:");
            printHexString(KB);
            byte[] sB = sm3hash(new byte[] { 0x02 }, yV,
                    sm3hash(xV, entity.Z, this.Z, RA.getXCoord().toBigInteger().toByteArray(),
                            RA.getYCoord().toBigInteger().toByteArray(), RB.getXCoord().toBigInteger().toByteArray(),
                            RB.getYCoord().toBigInteger().toByteArray()));
            return new TransportEntity(RB.getEncoded(false), sB,this.Z,keyPair.getPublicKey());
        }
        /**
         * 密钥协商发起方第二�
         *
         * @param entity 传输实体
         */
        public TransportEntity keyExchange_3(TransportEntity entity) {
            BigInteger x1 = RA.getXCoord().toBigInteger();
            x1 = _2w.add(x1.and(_2w.subtract(BigInteger.ONE)));
            BigInteger tA = keyPair.getPrivateKey().add(x1.multiply(rA)).mod(n);
            ECPoint RB = curve.decodePoint(entity.R).normalize();
            BigInteger x2 = RB.getXCoord().toBigInteger();
            x2 = _2w.add(x2.and(_2w.subtract(BigInteger.ONE)));
            ECPoint bPublicKey=curve.decodePoint(entity.K).normalize();
            ECPoint temp = bPublicKey.add(RB.multiply(x2).normalize()).normalize();
            ECPoint U = temp.multiply(ecc_bc_spec.getH().multiply(tA)).normalize();
            if (U.isInfinity())
                throw new IllegalStateException();
            this.V=U;
            byte[] xU = U.getXCoord().toBigInteger().toByteArray();
            byte[] yU = U.getYCoord().toBigInteger().toByteArray();
            byte[] KA = KDF(join(xU, yU,
                    this.Z, entity.Z), 16);
            key = KA;
            System.out.print("协商得A密钥:");
            printHexString(KA);
            byte[] s1= sm3hash(new byte[] { 0x02 }, yU,
                    sm3hash(xU, this.Z, entity.Z, RA.getXCoord().toBigInteger().toByteArray(),
                            RA.getYCoord().toBigInteger().toByteArray(), RB.getXCoord().toBigInteger().toByteArray(),
                            RB.getYCoord().toBigInteger().toByteArray()));
            if(Arrays.equals(entity.S, s1))
                System.out.println("B->A 密钥确认成功");
            else
                System.out.println("B->A 密钥确认失败");
            byte[] sA= sm3hash(new byte[] { 0x03 }, yU,
                    sm3hash(xU, this.Z, entity.Z, RA.getXCoord().toBigInteger().toByteArray(),
                            RA.getYCoord().toBigInteger().toByteArray(), RB.getXCoord().toBigInteger().toByteArray(),
                            RB.getYCoord().toBigInteger().toByteArray()));
            return new TransportEntity(RA.getEncoded(false), sA,this.Z,keyPair.getPublicKey());
        }
        /**
         * 密钥确认�?后一�?
         *
         * @param entity 传输实体
         */
        public void keyExchange_4(TransportEntity entity) {
            byte[] xV = V.getXCoord().toBigInteger().toByteArray();
            byte[] yV = V.getYCoord().toBigInteger().toByteArray();
            ECPoint RA = curve.decodePoint(entity.R).normalize();
            byte[] s2= sm3hash(new byte[] { 0x03 }, yV,
                    sm3hash(xV, entity.Z, this.Z, RA.getXCoord().toBigInteger().toByteArray(),
                            RA.getYCoord().toBigInteger().toByteArray(), this.RA.getXCoord().toBigInteger().toByteArray(),
                            this.RA.getYCoord().toBigInteger().toByteArray()));
            if(Arrays.equals(entity.S, s2))
                System.out.println("A->B 密钥确认成功");
            else
                System.out.println("A->B 密钥确认失败");
        }
    }
    public static void main(String[] args) throws UnsupportedEncodingException {
        SM2 sm02 = new SM2();
        /*
         BigInteger px = new BigInteger(
         "0AE4C779 8AA0F119 471BEE11 825BE462 02BB79E2 A5844495 E97C04FF 4DF2548A".replace(" ", ""), 16);
         BigInteger py = new BigInteger(
         "7C0240F8 8F1CD4E1 6352A73C 17B7F16F 07353E53 A176D684 A9FE0C6B B798E857".replace(" ", ""), 16);
         ECPoint publicKey = sm02.curve.createPoint(px, py);
         BigInteger privateKey = new BigInteger(
         "128B2FA8 BD433C6C 068C8D80 3DFF7979 2A519A55 171B1B65 0C23661D 15897263".replace(" ", ""), 16);
         */
        SM2KeyPair keyPair = sm02.generateKeyPair();
        ECPoint publicKey=keyPair.getPublicKey();
        BigInteger privateKey=keyPair.getPrivateKey();
        sm02.exportPublicKey(publicKey, "E:/publickey.pem");
        sm02.exportPrivateKey(privateKey, "E:/privatekey.pem");
        System.out.println("-----------------公钥加密与解�?-----------------");
        /*ECPoint*/ publicKey = sm02.importPublicKey("E:/publickey.pem");
        /*BigInteger*/ privateKey = sm02.importPrivateKey("E:/privatekey.pem");
        byte[] data = sm02.encrypt("测试加密aaaaaaaaaaa123aabb", publicKey);
        System.out.print("密文:");
        SM2.printHexString(data);
        System.out.println("解密后明�?:" + sm02.decrypt(data, privateKey));
        System.out.println("-----------------签名与验�?-----------------");
        String IDA = "Heartbeats";
        String M = "要签名的信息";
        Signature signature = sm02.sign(M, IDA, new SM2KeyPair(publicKey, privateKey));
        System.out.println("用户标识:" + IDA);
        System.out.println("签名信息:" + M);
        System.out.println("数字签名:" + signature);
        System.out.println("验证签名:" + sm02.verify(M, signature, IDA, publicKey));
        System.out.println("-----------------密钥协商-----------------");
        String aID = "AAAAAAAAAAAAA";
        SM2KeyPair aKeyPair = sm02.generateKeyPair();
        KeyExchange aKeyExchange = new KeyExchange(aID,aKeyPair);
        String bID = "BBBBBBBBBBBBB";
        SM2KeyPair bKeyPair = sm02.generateKeyPair();
        KeyExchange bKeyExchange = new KeyExchange(bID,bKeyPair);
        TransportEntity entity1 = aKeyExchange.keyExchange_1();
        TransportEntity entity2 = bKeyExchange.keyExchange_2(entity1);
        TransportEntity entity3 = aKeyExchange.keyExchange_3(entity2);
        bKeyExchange.keyExchange_4(entity3);
    }
    public static class Signature {
        BigInteger r;
        BigInteger s;
        public Signature(BigInteger r, BigInteger s) {
            this.r = r;
            this.s = s;
        }
        public String toString() {
            return r.toString(16) + "," + s.toString(16);
        }
    }
}
src/main/java/com/whyc/encryption/SM2KeyPair.java
New file
@@ -0,0 +1,30 @@
package com.whyc.encryption;
import org.bouncycastle.math.ec.ECPoint;
import java.math.BigInteger;
/**
 * SM2密钥对Bean
 * @author Potato
 *
 */
public class SM2KeyPair {
    private final ECPoint publicKey;
    private final BigInteger privateKey;
    SM2KeyPair(ECPoint publicKey, BigInteger privateKey) {
        this.publicKey = publicKey;
        this.privateKey = privateKey;
    }
    public ECPoint getPublicKey() {
        return publicKey;
    }
    public BigInteger getPrivateKey() {
        return privateKey;
    }
}
src/main/java/com/whyc/encryption/SM3.java
New file
@@ -0,0 +1,213 @@
package com.whyc.encryption;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
/**
 * SM3杂凑算法实现
 * @author Potato
 *
 */
public class SM3 {
    private static char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
            '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    private static final String ivHexStr = "7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e";
    private static final BigInteger IV = new BigInteger(ivHexStr.replaceAll(" ",
            ""), 16);
    private static final Integer Tj15 = Integer.valueOf("79cc4519", 16);
    private static final Integer Tj63 = Integer.valueOf("7a879d8a", 16);
    private static final byte[] FirstPadding = {(byte) 0x80};
    private static final byte[] ZeroPadding = {(byte) 0x00};
    private static int T(int j) {
        if (j >= 0 && j <= 15) {
            return Tj15.intValue();
        } else if (j >= 16 && j <= 63) {
            return Tj63.intValue();
        } else {
            throw new RuntimeException("data invalid");
        }
    }
    private static Integer FF(Integer x, Integer y, Integer z, int j) {
        if (j >= 0 && j <= 15) {
            return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());
        } else if (j >= 16 && j <= 63) {
            return Integer.valueOf((x.intValue() & y.intValue())
                    | (x.intValue() & z.intValue())
                    | (y.intValue() & z.intValue()));
        } else {
            throw new RuntimeException("data invalid");
        }
    }
    private static Integer GG(Integer x, Integer y, Integer z, int j) {
        if (j >= 0 && j <= 15) {
            return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue());
        } else if (j >= 16 && j <= 63) {
            return Integer.valueOf((x.intValue() & y.intValue())
                    | (~x.intValue() & z.intValue()));
        } else {
            throw new RuntimeException("data invalid");
        }
    }
    private static Integer P0(Integer x) {
        return Integer.valueOf(x.intValue()
                ^ Integer.rotateLeft(x.intValue(), 9)
                ^ Integer.rotateLeft(x.intValue(), 17));
    }
    private static Integer P1(Integer x) {
        return Integer.valueOf(x.intValue()
                ^ Integer.rotateLeft(x.intValue(), 15)
                ^ Integer.rotateLeft(x.intValue(), 23));
    }
    private static byte[] padding(byte[] source) throws IOException {
        if (source.length >= 0x2000000000000000l) {
            throw new RuntimeException("src data invalid.");
        }
        long l = source.length * 8;
        long k = 448 - (l + 1) % 512;
        if (k < 0) {
            k = k + 512;
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(source);
        baos.write(FirstPadding);
        long i = k - 7;
        while (i > 0) {
            baos.write(ZeroPadding);
            i -= 8;
        }
        baos.write(long2bytes(l));
        return baos.toByteArray();
    }
    private static byte[] long2bytes(long l) {
        byte[] bytes = new byte[8];
        for (int i = 0; i < 8; i++) {
            bytes[i] = (byte) (l >>> ((7 - i) * 8));
        }
        return bytes;
    }
    public static byte[] hash(byte[] source) throws IOException {
        byte[] m1 = padding(source);
        int n = m1.length / (512 / 8);
        byte[] b;
        byte[] vi = IV.toByteArray();
        byte[] vi1 = null;
        for (int i = 0; i < n; i++) {
            b = Arrays.copyOfRange(m1, i * 64, (i + 1) * 64);
            vi1 = CF(vi, b);
            vi = vi1;
        }
        return vi1;
    }
    private static byte[] CF(byte[] vi, byte[] bi) throws IOException {
        int a, b, c, d, e, f, g, h;
        a = toInteger(vi, 0);
        b = toInteger(vi, 1);
        c = toInteger(vi, 2);
        d = toInteger(vi, 3);
        e = toInteger(vi, 4);
        f = toInteger(vi, 5);
        g = toInteger(vi, 6);
        h = toInteger(vi, 7);
        int[] w = new int[68];
        int[] w1 = new int[64];
        for (int i = 0; i < 16; i++) {
            w[i] = toInteger(bi, i);
        }
        for (int j = 16; j < 68; j++) {
            w[j] = P1(w[j - 16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15))
                    ^ Integer.rotateLeft(w[j - 13], 7) ^ w[j - 6];
        }
        for (int j = 0; j < 64; j++) {
            w1[j] = w[j] ^ w[j + 4];
        }
        int ss1, ss2, tt1, tt2;
        for (int j = 0; j < 64; j++) {
            ss1 = Integer
                    .rotateLeft(
                            Integer.rotateLeft(a, 12) + e
                                    + Integer.rotateLeft(T(j), j), 7);
            ss2 = ss1 ^ Integer.rotateLeft(a, 12);
            tt1 = FF(a, b, c, j) + d + ss2 + w1[j];
            tt2 = GG(e, f, g, j) + h + ss1 + w[j];
            d = c;
            c = Integer.rotateLeft(b, 9);
            b = a;
            a = tt1;
            h = g;
            g = Integer.rotateLeft(f, 19);
            f = e;
            e = P0(tt2);
        }
        byte[] v = toByteArray(a, b, c, d, e, f, g, h);
        for (int i = 0; i < v.length; i++) {
            v[i] = (byte) (v[i] ^ vi[i]);
        }
        return v;
    }
    private static int toInteger(byte[] source, int index) {
        StringBuilder valueStr = new StringBuilder("");
        for (int i = 0; i < 4; i++) {
            valueStr.append(hexDigits[(byte) ((source[index * 4 + i] & 0xF0) >> 4)]);
            valueStr.append(hexDigits[(byte) (source[index * 4 + i] & 0x0F)]);
        }
        return Long.valueOf(valueStr.toString(), 16).intValue();
    }
    private static byte[] toByteArray(int a, int b, int c, int d, int e, int f,
                                      int g, int h) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
        baos.write(toByteArray(a));
        baos.write(toByteArray(b));
        baos.write(toByteArray(c));
        baos.write(toByteArray(d));
        baos.write(toByteArray(e));
        baos.write(toByteArray(f));
        baos.write(toByteArray(g));
        baos.write(toByteArray(h));
        return baos.toByteArray();
    }
    public static byte[] toByteArray(int i) {
        byte[] byteArray = new byte[4];
        byteArray[0] = (byte) (i >>> 24);
        byteArray[1] = (byte) ((i & 0xFFFFFF) >>> 16);
        byteArray[2] = (byte) ((i & 0xFFFF) >>> 8);
        byteArray[3] = (byte) (i & 0xFF);
        return byteArray;
    }
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n = 256 + n;
        int d1 = n / 16;
        int d2 = n % 16;
        return ""+hexDigits[d1] + hexDigits[d2];
    }
    public static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }
    public static void main(String[] args) throws IOException {
        System.out.println(SM3.byteArrayToHexString(SM3.hash("test sm3 hash".getBytes())));
    }
}
src/main/java/com/whyc/mapper/LicenseMapper.java
New file
@@ -0,0 +1,6 @@
package com.whyc.mapper;
import com.whyc.pojo.License;
public interface LicenseMapper extends CustomMapper<License> {
}
src/main/java/com/whyc/pojo/License.java
New file
@@ -0,0 +1,15 @@
package com.whyc.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@TableName(schema = "web_site",value = "tb_license")
@ApiModel(value="凭证", description="项目允许凭证")
public class License {
    private Integer id;
    private String serialNumber;
    private String duration;
    private String timeInUse;
}
src/main/java/com/whyc/service/LicenseService.java
New file
@@ -0,0 +1,69 @@
package com.whyc.service;
import com.whyc.dto.Response;
import com.whyc.encryption.ByteConvertUtil;
import com.whyc.encryption.SM2;
import org.springframework.stereotype.Service;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
public class LicenseService {
    /**
     * 证书文件校验,检查有效性并将文件存储在数据库
     */
    public Response checkLicense(String license){
        Response model = new Response();
        boolean res = true;
        String origin = "Company: Fuguang Electronic\n"
                + "Project:BTS monitor platform\n"
                + "Licence type:";
        //初始化sm2参数x
        SM2 x = new SM2();
//        String realPath = ServletActionContext.getServletContext().getRealPath("/");
//        BigInteger privKey = x.importPrivateKey(realPath+"WEB-INF/classes/pri_key.ksm");
        BigInteger privKey = x.importPrivateKey("WEB-INF/classes/pri_key.ksm");
        //解密
        try {
            byte[] bytes = ByteConvertUtil.hexToByteArray(license);
            String decryptResult = x.decrypt(bytes, privKey);
            if(decryptResult.indexOf(origin)!=-1){
                String[] split = decryptResult.split("Valid time:");
                if(split.length>1){
                    String validTime=split[1];
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String today = dateFormat.format(new Date());
                    if(validTime.compareTo(today)<0){
                        res=false;
                    }
                }
            }else{
                res=false;
            }
        }catch (Exception e){
            res=false;
            e.printStackTrace();
        }
        //license校验通过,校验数据库中是否已经存在
        if(res){
//            res =!(new User_infImpl().licenseExist(license));
        }
        if(res){
            model.setCode(1);
        }else{
            model.setMsg("无效的license");
        }
        return model;
    }
}
src/main/java/com/whyc/service/UserService.java
@@ -1,5 +1,6 @@
package com.whyc.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.whyc.dto.Response;
@@ -10,6 +11,7 @@
import com.whyc.util.DigestsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.catalina.Wrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
@@ -94,4 +96,11 @@
        map.put(user.getUName(), new UserClient(ActionUtil.getRequest().getRemoteAddr(),user,login_time));
        application.setAttribute("users", map);
    }
    public UserInf getPublicXYByUKeyId(String uKeyId){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("uKey_ID",uKeyId);
        UserInf userInf = userMapper.selectOne(queryWrapper);
        return userInf;
    }
}
src/main/resources/mapper/LicenseMapper.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whyc.mapper.LicenseMapper" >
</mapper>