SM2前后端交互加解密(已联调测通)

Posted yyihan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SM2前后端交互加解密(已联调测通)相关的知识,希望对你有一定的参考价值。

准备工作:后端(jar包)、前端(js文件)

阿里云盘:
所需文件: https://www.aliyundrive.com/s/wmYT1TMx4az

 

 1.后端java代码SM2工具类:

import com.antherd.smcrypto.sm2.Keypair;
import com.antherd.smcrypto.sm2.Sm2;
import io.netty.util.internal.StringUtil;

public class SM2Encryptor 
    /**
     * 加密,使用公钥
     *
     * @param publicKey
     * @param originalText
     * @return
     */
    public static String encryptText(String publicKey, String originalText) throws Exception 
        if (StringUtil.isNullOrEmpty(publicKey)) 
            throw new Exception("密钥不能为空...");
        
        if (StringUtil.isNullOrEmpty(originalText)) 
            throw new Exception("明文不能为空...");
        

        try 
            return Sm2.doEncrypt(originalText, publicKey);//HexUtil.encodeHexStr(cipherText); // 加密结果
         catch (Exception e) 
            throw new Exception("加密错误:密钥不正确...");
        
    

    /**
     * 解密,使用私钥
     *
     * @param privateKey
     * @param cipherText
     * @return
     */
    public static String decryptText(String privateKey, String cipherText) throws Exception 
        if (StringUtil.isNullOrEmpty(privateKey)) 
            throw new Exception("密钥不能为空...");
        
        if (StringUtil.isNullOrEmpty(cipherText)) 
            throw new Exception("明文不能为空...");
        
        try 
            return Sm2.doDecrypt(cipherText, privateKey); // new String(sm2.decrypt(sourceData,prvKey)); // 解密结果
         catch (Exception e) 
            throw new Exception("解密错误:密钥不正确...");
        
    

    /**
     * 获取sm2密钥对,
     *
     * @return 返回String[];第0个为公钥,第1个为私钥
     * @throws Exception
     */
    public static String[] generateKeyPair() throws Exception 
        try 
            Keypair keypair = Sm2.generateKeyPairHex();
            String[] result = new String[2];
            if (keypair != null) 
                result[0] = keypair.getPublicKey(); //公钥
                result[1] = keypair.getPrivateKey(); // 私钥
            
            return result;
         catch (Exception e) 
            throw new Exception("生成密钥对失败...");
        
    

    public static void main(String[] args) throws Exception 
        //调用内部jar方法,生成一对公私钥
        String[] keys = generateKeyPair();
        //公钥
        String publicKey = keys[0];
        System.out.println("公钥" + publicKey);
        //私钥
        String privateKey = keys[1];
        System.out.println("私钥" + privateKey);

        String str = "测试使用SM2加密、解密";

        //加密字符串
        String encryptText = SM2Encryptor.encryptText(publicKey, str);
        System.out.println(encryptText);
        //解密字符串
        String decryptText = SM2Encryptor.decryptText(privateKey, encryptText);
        System.out.println(decryptText);

    

2.前端调用样例

<script>

    $(function () 
        //公钥
        var publicKey = "0496f201087c127de90a49496c8704b7e1d7aa10f12c8874711fcb6639cf617070bc16c5da0e2ef095f39b735837f9afd7df8965b0534023ac1345e6ab93bbe138";
        //私钥
        var privateKey = "0faa8deba74595e0aeb74718cb4b41ae40c3baeb25a0d335e95a19f69baf29d8";
        
        var str = "测试SM2加解密文本ZZ123";
        
        //加密
        var encrText = sm2.doEncrypt(str ,publicKey);
        console.log(encrText)

       //解密
       var decryptText = sm2.doDecrypt(encrText,privateKey)
       console.log(decryptText)
     )
</script>

 

aes加解密前后端-后台

一、web.xml:

  <filter>
        <filter-name>fastLoginFilter</filter-name>
        <filter-class>com.shencai.xf.common.util.FastLoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>fastLoginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

配置文件中配置一下访问路径可以用作过滤时候判断,可以直接放行和加密不加密操作:

passUrls=.html;.css;.js;/main/img/;/main/common/;/mlsc-upload/service/sys/file/upload;\

其中,访问静态资源肯定是直接放行不过滤不加密的;

二、java代码:

package com.xxx

/**
 * 用于快速登录的过滤器,仅放行passUrlList中的路径
 */
public class FastLoginFilter implements Filter 
    public static final String TICKET_ID = "ticketId";
    public static Logger logger = LoggerUtil.getLoggerByName("system", "loginFilter");

    public static String HOME_URL = "/index.html";
    public static String LOGIN_URL = "/login.html";
    public static String INVALID_URL = "/login.html";

    /**
     * 用于拦截快速登录的请求
     */
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException 
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        String requestURL = request.getRequestURI();
        String retUrl = request.getHeader("Referer");

        // 保留未登录websocket通信
        if(requestURL.indexOf("/websocket/") == -1)
            if(retUrl==null&&!requestURL.equals(LOGIN_URL)||retUrl!=null&&!checkWebReferer(retUrl))
                response.sendRedirect(LOGIN_URL);
                return;
            
        


        if (checkIsPassUrl(requestURL)) 
            chain.doFilter(req, resp);
            return;
        

        Object ticketId = request.getSession().getAttribute(TICKET_ID);
//        Object ticketId = request.getParameter(TICKET_ID);
        String requestType = request.getHeader("x-requested-with");
        String userAgent = request.getHeader("user-agent");
        if (ticketId == null) 
            if ((requestType != null && requestType.equals("XMLHttpRequest")) || checkApp(userAgent)) 
                writeUnloginInfo((HttpServletResponse) response);
             else 
                response.sendRedirect(LOGIN_URL);
            
            return;
        
        boolean isLogged = this.isLogged(ticketId.toString());
        String checkLoginStatus = request.getParameter("checkLoginStatus");
        if (StringUtils.isNotNullOrEmpty(checkLoginStatus)) 
            resp.getWriter().write(String.valueOf(isLogged));
            return;
        
        UserInfo userInfo = CacheUtil.getUserByTicket(ticketId.toString(), UserInfo.class);
        if (userInfo != null && StringUtils.isNotNullOrEmpty(userInfo.getUserId())) 
            CacheUtil.refreshTicket(ticketId.toString(), userInfo.getUserId());
            String token = request.getHeader("token");
            String contentType=request.getContentType();
            if("1".equals(ConfigUtil.get("aesOpen"))&&"XMLHttpRequest".equals(requestType)&&StringUtils.isNotNullOrEmpty(token)
                    &&"encryption".equals(token)) //和前台一样的判断是否需要加解密操作
                String requestBodyMw = null;
                String rsaResult=null;
                try 
                    String p="";
                    if("application/json".equals(contentType))
                        String requestBody = getRequestParam((HttpServletRequest) request);
                        logger.info(requestBody);
                        JSONObject jsonObject=JSONObject.parseObject(requestBody);
                        p=jsonObject.getString("p"); //获取前台传的加密之后的参数p
                    else
                        p=request.getParameter("p");
                    
                    requestBodyMw = CryptionUtil.aesDecrypt(p.trim(), ConfigUtil.get("aecKey")); //先将请求参数进行aes解密
                    rsaResult= RSAEncryptUtils.decrypt(requestBodyMw); //再将前台传的参数进行RSA解密,步骤与前台相反
                 catch (Exception e) 
                    writeUnloginInfo((HttpServletResponse) response);
                    return;
                
                WrapperedResponse wrapResponse = new WrapperedResponse((HttpServletResponse) response); //封装的响应对象
                WrapperedRequest wrapRequest = new WrapperedRequest((HttpServletRequest) request, rsaResult); //封装的请求对象
                chain.doFilter(wrapRequest, wrapResponse); //调用自己框架的过滤器方法,获取当前用户之类的
                byte[] data = wrapResponse.getResponseData();
                String resData=new String(data, "utf-8");
                JSONObject resultObj=new JSONObject();
                try 
                    resultObj.put("data",CryptionUtil.aesEncrypt(resData, ConfigUtil.get("aecKey"))); //返回的参数也是aes加密的
                 catch (Exception e) 
                    e.printStackTrace();
                
                writeResponse(response, resultObj.toJSONString());
                return;
            
         else 
            if ((requestType != null && requestType.equals("XMLHttpRequest")) || checkApp(userAgent)) 
                writeUnloginInfo((HttpServletResponse) response);
             else 
                response.sendRedirect(INVALID_URL);
            
            return;
        
        chain.doFilter(req, resp);
        return;
    

    private boolean checkWebReferer(String retUrl)
        boolean flag=false;
        String configWebReferer=ConfigUtil.get("webReferer");
        String[] webRefererArr=configWebReferer.split(",");
        for(int i=0;i<webRefererArr.length;i++)
            if(retUrl.startsWith(webRefererArr[i]))
                flag=true;
                break;
            
        
        return flag;
    
    private void writeResponse(ServletResponse response, String responseString)
            throws IOException 
        PrintWriter out = response.getWriter();
        response.setContentLength(responseString.length());
        out.print(responseString);
        out.flush();
        out.close();
    
    private String getRequestParam(HttpServletRequest request)
        ServletInputStream inputStream = null;
        StringBuilder sb = new StringBuilder();
        try 
            inputStream = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            String line = "";
            while ((line = br.readLine()) != null) 
                sb.append(line);
            
         catch (IOException e) 
            e.printStackTrace();
        
        return sb.toString();
    
    // 获取请求路径,如果是:/fastLoginWS,则直接放行
    public boolean checkIsPassUrl(String requestURL) throws IOException, ServletException 
        boolean isPass = false;
        if (StringUtils.isNotNullOrEmpty(requestURL)) 
            // 判断访问的路径是否为路径放行集合中的路径,如果含有,则直接放行
            for (String url : ConfigUtil.PASS_URLS)  //配置文件中可以配置一下访问路径,用于不用过滤,不用进行加解密操作等
                if (requestURL.indexOf(url) != -1) 
                    isPass = true;
                    break;
                
            
        
        return isPass;
    
    private boolean checkApp(String userAgent) 
        if (userAgent != null) 
            if (userAgent.indexOf("okhttp") != -1) 
                return true;
            
            if (userAgent.indexOf("Darwin") != -1) 
                return true;
            
            if(userAgent.indexOf("MicroMessenger")>-1)
                return true;
            
        
        return false;
    
    private void writeUnloginInfo(HttpServletResponse response) 
        response.setStatus(HttpStatus.UNAUTHORIZED.value()); //设置状态码
        response.setContentType(MediaType.APPLICATION_JSON_VALUE); //设置ContentType
        response.setCharacterEncoding("UTF-8"); //避免乱码
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        try 
            response.getWriter().write("\"statusCode\":1001,\"loginUrl\":\"" + LOGIN_URL + "\",\"success\":false,\"msg\":\"用户身份已经失效! \"");
         catch (IOException e) 
            logger.error("与客户端通讯异常:" + e.getMessage(), e);
        
    
    public static boolean isLogged(String ticketId) 
        if (ticketId == null) 
            return false;
         else 
            return CacheUtil.isExist(CacheUtil.PREFIX_TICKET_USER.concat(ticketId));
        
    
    public void init(FilterConfig arg0) throws ServletException 
        String homeUrl = ConfigUtil.get("homeUrl");
        if (StringUtils.isNotNullOrEmpty(homeUrl)) 
            HOME_URL = homeUrl;
        
        String loginUrl = ConfigUtil.get("loginUrl");
        if (StringUtils.isNotNullOrEmpty(loginUrl)) 
            LOGIN_URL = loginUrl;
        
        String invalidUrl = ConfigUtil.get("invalidUrl");
        if (StringUtils.isNotNullOrEmpty(invalidUrl)) 
            INVALID_URL = invalidUrl;
        
    

    public void destroy() 
    

 封装请求对象WrapperedRequest:

package com.xxx
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;


public class WrapperedRequest extends HttpServletRequestWrapper 
    private String requestBody = null;
    HttpServletRequest req = null;
    public WrapperedRequest(HttpServletRequest request) 
        super(request);
        this.req = request;
    

    public WrapperedRequest(HttpServletRequest request, String requestBody) 
        super(request);
        this.requestBody = requestBody;
        this.req = request;
    

    /*
     * (non-Javadoc)
     *
     * @see javax.servlet.ServletRequestWrapper#getReader()
     */
    @Override
    public BufferedReader getReader() throws IOException 
        return new BufferedReader(new StringReader(requestBody));
    

    /*
     * (non-Javadoc)
     *
     * @see javax.servlet.ServletRequestWrapper#getInputStream()
     */
    @Override
    public ServletInputStream getInputStream() throws IOException 
        return new ServletInputStream() 
            @Override
            public boolean isFinished() 
                return false;
            

            @Override
            public boolean isReady() 
                return false;
            

            @Override
            public void setReadListener(ReadListener readListener) 

            

            private InputStream in = new ByteArrayInputStream(
                    requestBody.getBytes(req.getCharacterEncoding()));

            @Override
            public int read() throws IOException 
                return in.read();
            
        ;
    

 封装响应对象WrapperedResponse:

package com.xxx

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;

public class WrapperedResponse extends HttpServletResponseWrapper 
    private ByteArrayOutputStream buffer = null;
    private ServletOutputStream out = null;
    private PrintWriter writer = null;

    public WrapperedResponse(HttpServletResponse resp) throws IOException 
        super(resp);
        buffer = new ByteArrayOutputStream();// 真正存储数据的流
        out = new WapperedOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer,
                this.getCharacterEncoding()));
    

    /** 重载父类获取outputstream的方法 */
    @Override
    public ServletOutputStream getOutputStream() throws IOException 
        return out;
    

    /** 重载父类获取writer的方法 */
    @Override
    public PrintWriter getWriter() throws UnsupportedEncodingException 
        return writer;
    

    /** 重载父类获取flushBuffer的方法 */
    @Override
    public void flushBuffer() throws IOException 
        if (out != null) 
            out.flush();
        
        if (writer != null) 
            writer.flush();
        
    

    @Override
    public void reset() 
        buffer.reset();
    

    /** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */
    public byte[] getResponseData() throws IOException 
        flushBuffer();
        return buffer.toByteArray();
    

    /** 内部类,对ServletOutputStream进行包装 */
    private class WapperedOutputStream extends ServletOutputStream 
        private ByteArrayOutputStream bos = null;

        public WapperedOutputStream(ByteArrayOutputStream stream)
                throws IOException 
            bos = stream;
        

        @Override
        public void write(int b) throws IOException 
            bos.write(b);
        

        @Override
        public void write(byte[] b) throws IOException 
            bos.write(b, 0, b.length);
        

        @Override
        public boolean isReady() 
            return false;
        

        @Override
        public void setWriteListener(WriteListener writeListener) 

        
    

 aes加解密的java封装类:

package com.xxx

import java.math.BigInteger;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import sun.misc.BASE64Decoder;

/**
 * AES的加密和解密
 * @author libo
 */
public class CryptionUtil 
    //密钥 (需要前端和后端保持一致)
//    private static String KEY = ConfigUtil.get("aecKey");
    //算法
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";

    /**
     * aes解密
     * @param encrypt   内容
     * @return
     * @throws Exception
     */
    public static String aesDecrypt(String encrypt) 
        try 
            return aesDecrypt(encrypt, ConfigUtil.get("aecKey"));
         catch (Exception e) 
            e.printStackTrace();
            return "";
        
    

    /**
     * aes加密
     * @param content
     * @return
     * @throws Exception
     */
    public static String aesEncrypt(String content) 
        try 
            return aesEncrypt(content, ConfigUtil.get("aecKey"));
         catch (Exception e) 
            e.printStackTrace();
            return "";
        
    

    /**
     * 将byte[]转为各种进制的字符串
     * @param bytes byte[]
     * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
     * @return 转换后的字符串
     */
    public static String binary(byte[] bytes, int radix)
        return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
    

    /**
     * base 64 encode
     * @param bytes 待编码的byte[]
     * @return 编码后的base 64 code
     */
    public static String base64Encode(byte[] bytes)
        return Base64.encodeBase64String(bytes);
    

    /**
     * base 64 decode
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) throws Exception
        return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
    


    /**
     * AES加密
     * @param content 待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception 
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));

        return cipher.doFinal(content.getBytes("utf-8"));
    


    /**
     * AES加密为base 64 code
     * @param content 待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的base 64 code
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception 
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    

    /**
     * AES解密
     * @param encryptBytes 待解密的byte[]
     * @param decryptKey 解密密钥
     * @return 解密后的String
     * @throws Exception
     */
    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception 
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);

        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    


    /**
     * 将base 64 code AES解密
     * @param encryptStr 待解密的base 64 code
     * @param decryptKey 解密密钥
     * @return 解密后的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception 
        return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    

    /**
     * 测试
     */
    public static void main(String[] args) throws Exception 
        String content = "123";
        System.out.println("加密前:" + content);
        System.out.println("加密密钥和解密密钥:" + ConfigUtil.get("aecKey"));
        String encrypt = aesEncrypt(content, ConfigUtil.get("aecKey"));
        System.out.println("加密后:" + encrypt);
        String decrypt = aesDecrypt(encrypt, ConfigUtil.get("aecKey"));
        System.out.println("解密后:" + decrypt);
    

RSA加解密的java封装类:

package com.xxx

import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.ArrayList;

/**
 * RSA帮助类
 * 
 * @author liww
 * 
 */
public class RSAEncryptUtils 

    /**
     * 模
     */
    private static String module = "ybhndrU9d3UJzvD8WSS1chQ2ZLcn7Y/ZF0SZFJbdWxkvZYAcICUzfJBF4SecxG+ia9GseNDoQ30q+mSM5Ae1NaAy2bjmR1esS17AyX/TnSvtZIm0ACIVLIM6ShM+ukMj/TEhugarwHXhiHmEd8ZkMrVu4SW2XPgWjX7yPoEKLFs=";
    
    /**
     * 公钥指数
     */
    private static String exponentString = "AQAB";
    
    private static String delement = "NXVBNhxh5b6GkukadyVbUJg6sgY39qUgiyIKz4ILt5C9FtEUoxA4zNIPMtQkn4pWKOywIHR8mSYatbDgBa5lPxBemwvu5cMHVIh0sD25AL+jXk29alVOIPVTpZ/0TDgy7jd7psYUIX7EO80TnvJIOaNcGUNo060H9qpo19x2iYE=";

    /**
     * 生成加密后的字节数组
     * 
     * @param value
     *            待加密字符串
     * @param keyXmlString
     *            加密字符串
     * @return
     */
    public static ArrayList<byte[]> encryptToByteArrayList(String value, String keyXmlString) 
        try 
            byte[] modulusBytes = org.apache.commons.codec.binary.Base64.decodeBase64(module);
            byte[] exponentBytes = org.apache.commons.codec.binary.Base64.decodeBase64(exponentString);
            BigInteger modulus = new BigInteger(1, modulusBytes);
            BigInteger exponent = new BigInteger(1, exponentBytes);

            RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
            KeyFactory fact = KeyFactory.getInstance("RSA");
            PublicKey pubKey = fact.generatePublic(rsaPubKey);

            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);

            int splitLength = 39;
            ArrayList<byte[]> byteArrayList = new ArrayList<byte[]>();
            int i = 0;
            do
            
                int Length = ((i + 1) * splitLength) >= value.length() ? (value.length() - i * splitLength) : splitLength;
                byte[] byteArray = cipher.doFinal(value.substring(i * splitLength, Length).getBytes("UTF-8"));
                byteArrayList.add(byteArray);
                i++;
             while (i * splitLength < value.length());

            return byteArrayList;
         catch (Exception e) 
            e.printStackTrace();
        
        return null;

    

    /**
     * RSA加密字符串
     * 
     * @param value
     *            需要加密的字符串
     * @param keyXmlString
     *            加密key字符串
     * @return
     */
    public static String encrypt(String value, String keyXmlString)
    
        ArrayList<byte[]> byteArrayList = encryptToByteArrayList(value, keyXmlString);
        StringBuilder sb = new StringBuilder();
        for (byte[] byteArray : byteArrayList)
        
            sb.append(bytesToHexString(byteArray));
            sb.append(",");
        
        if (sb.length() != 0)
        
            sb.delete(sb.length() - 1, sb.length());
        
        return sb.toString();
    

    /**
     * RSA加密字符串
     * 
     * @param value
     *            需要加密的字符串
     * @return
     */
    public static String encrypt(String value)
    
        return encrypt(value, null);
    

    public static byte[] Dencrypt(byte[] encrypted) 
        try 
            byte[] expBytes = org.apache.commons.codec.binary.Base64.decodeBase64(delement);
            byte[] modBytes = org.apache.commons.codec.binary.Base64.decodeBase64(module);

            BigInteger modules = new BigInteger(1, modBytes);
            BigInteger exponent = new BigInteger(1, expBytes);

            KeyFactory factory = KeyFactory.getInstance("RSA");
            Cipher cipher = Cipher.getInstance("RSA");

            RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modules, exponent);

            PrivateKey privKey = factory.generatePrivate(privSpec);
            cipher.init(Cipher.DECRYPT_MODE, privKey);
            byte[] decrypted = cipher.doFinal(encrypted);
            return decrypted;
         catch (Exception e) 
            e.printStackTrace();
        
        return null;
    

    /**
     * RSA解密字节流
     * 
     * @param byteArrayList
     *            需要解密字节流泛型
     * @param keyXmlString
     *            加密key字符串
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String decrypt(ArrayList<byte[]> byteArrayList, String keyXmlString) throws UnsupportedEncodingException
    

        StringBuilder sb = new StringBuilder();
        for (byte[] byteArray : byteArrayList)
        
            sb.append(new String(Dencrypt(byteArray), "UTF-8"));
        
        return sb.toString();
    

    /**
     * RSA解密字符串
     * 
     * @param value
     *            需要解密的字符串
     * @param keyXmlString
     *            加密key字符串
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String decrypt(String value, String keyXmlString) throws UnsupportedEncodingException
    
        ArrayList<byte[]> byteArrayList = new ArrayList<byte[]>();
        if (StringUtils.isNotBlank(value))
        
            String[] strArray = value.split(",");
            int byteArrayLength = 0;
            byte[] byteArray;
            for (String str : strArray)
            
                byteArrayLength = str.length() / 2;
                byteArray = new byte[byteArrayLength];
                for (int i = 0; i < byteArrayLength; i++)
                
                    try 
                        byteArray[i] = Integer.valueOf(str.substring(i * 2, (i + 1) * 2), 16).byteValue();
                     catch (NumberFormatException e) 
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    
                
                byteArrayList.add(byteArray);
            
        
        return decrypt(byteArrayList, keyXmlString);
    

    /**
     * RSA解密字符串
     * 
     * @param value
     *            需要解密的字符串
     * @return
     */
    public static String decrypt(String value)
    
        try 
            return decrypt(value, null);
         catch (UnsupportedEncodingException e) 
            e.printStackTrace();
        
        return null;
    

    /**
     * 将字节数组转换为16进制字符串. 可以将byte转换成int,然后利用Integer.toHexString(int)来转换成16进制字符串。
     * 
     * @param src
     *            字节数组
     * @return hex string
     */
    public static String bytesToHexString(byte[] src) 
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) 
            return null;
        
        for (int i = 0; i < src.length; i++) 
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) 
                stringBuilder.append(0);
            
            stringBuilder.append(hv);
        
        return stringBuilder.toString();
    

    /**
     * 将16进制字符串转换为数组
     * 
     * @param hexString
     *            16进制字符串
     * @return byte[]
     */
    public static byte[] hexStringToBytes(String hexString) 
        if (hexString == null || hexString.equals("")) 
            return null;
        
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) 
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        
        return d;
    

    /**
     * 将字符转换为字节
     * 
     * @param c
     *            待转换的字符
     * @return byte 转换后的字节
     */
    private static byte charToByte(char c) 
        return (byte) "0123456789ABCDEF".indexOf(c);
    

 

以上是关于SM2前后端交互加解密(已联调测通)的主要内容,如果未能解决你的问题,请参考以下文章

前后端RSA互相加解密加签验签密钥对生成(Java)

国密SM2的前端加密,后端解密(Java版本)及SM3 摘要加密

前端端口是怎么交互后端

[SM2/SM3 ]加解密/加解签,部分记录

前后端分离后,接口联调总是甩锅怎么办?

openssl 加解密以及国密算法