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前后端交互加解密(已联调测通)的主要内容,如果未能解决你的问题,请参考以下文章