Java国密相关算法(bouncycastle)
公用类算法:
XxxKeyPair.java
/** * @Author: dzy * @Date: 2018/9/27 14:18 * @Describe: 公私钥对 */ @Data @AllArgsConstructor @NoArgsConstructor public class XxxKeyPair { private String priKey; //私钥 private String pubKey; //公钥 }
CommonUtils.java
import org.apache.commons.lang3.StringUtils; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * @ClassName: CommonUtils * @Description: 通用工具类 * @since: 0.0.1 * @author: dzy * @date: 2017年2月22日 上午11:46:44 */ public class CommonUtils { /** * @param date 日期 * @param pattern 模式 如:yyyyMMdd等 * @return * @Title: formatDate * @Description: 格式化日期 * @since: 0.0.1 */ public static String formatDate(Date date, String pattern) { SimpleDateFormat formatter = new SimpleDateFormat(pattern); return formatter.format(date); } /** * @param strDate String类型日期 * @param pattern 日期显示模式 * @return * @Title: parseDate * @Description: 将String日期转换为Date类型日期 * @since: 0.0.1 */ public static Date parseDate(String strDate, String pattern) { SimpleDateFormat formatter = null; if (StringUtils.isBlank(strDate)) { return null; } formatter = new SimpleDateFormat(pattern); try { return formatter.parse(strDate); } catch (Exception e) { e.printStackTrace(); return null; } } /** * @param date 操作前的日期 * @param field 日期的部分如:年,月,日 * @param amount 增加或减少的值(负数表示减少) * @return * @Title: dateAdd * @Description: 日期的加减操作 * @since: 0.0.1 */ public static Date dateAdd(Date date, int field, int amount) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(field, amount); return calendar.getTime(); } /** * @param source 源字符串 * @param offset 填充开始的位置, 0-在左边, source.getBytes().length 在右边, 如果有中文时需小心位置 * @param c 用于填充的字符 * @param length 最后字符串的字节长度 * @return * @Title: fill * @Description: 填充字符串, 长度是按字节计算, 不是字符 * @since: 0.0.1 */ public static String fill(String source, int offset, char c, int length) throws UnsupportedEncodingException { if (null == source) { source = ""; } if (source.getBytes(CustomConstants.CHARSET_UTF8).length == length) { return source; } byte[] buf = new byte[length]; byte[] src = source.getBytes(CustomConstants.CHARSET_UTF8); if (src.length > length) { System.arraycopy(src, src.length - length, buf, 0, length); return new String(buf, CustomConstants.CHARSET_UTF8); } if (offset > src.length) { offset = src.length; } else if (offset < 0) { offset = 0; } int n = length - src.length; System.arraycopy(src, 0, buf, 0, offset); for (int i = 0; i < n; i++) { buf[i + offset] = (byte) c; } System.arraycopy(src, offset, buf, offset + n, src.length - offset); return new String(buf, CustomConstants.CHARSET_UTF8); } /** * @param original 原字符串 * @param offset 填充开始的位置, 0-在左边, original.getBytes().length 在右边, 如果有中文时需小心位置 * @param length 替换的字节数 * @param c 用于替换的字符 * @return * @Title: replace * @Description: 替换字符串, 长度是按字节计算, 不是字符 * @since: 0.0.1 */ public static String replace(String original, int offset, int length, char c) throws UnsupportedEncodingException { if (original == null) { original = ""; } if (original.getBytes(CustomConstants.CHARSET_UTF8).length <= offset) { return original; } if (original.getBytes(CustomConstants.CHARSET_UTF8).length < offset + length) { length = original.getBytes(CustomConstants.CHARSET_UTF8).length - offset; } byte[] buf = new byte[original.length()]; byte[] src = original.getBytes(CustomConstants.CHARSET_UTF8); System.arraycopy(src, 0, buf, 0, offset); for (int i = offset; i < offset + length; i++) { buf[i] = (byte) c; } System.arraycopy(src, offset + length, buf, offset + length, src.length - offset - length); return new String(buf, CustomConstants.CHARSET_UTF8); } /** * @param s 16进制字符串 * @return * @Title: hexToByte * @Description: 16进制字符串转字节数组 * @since: 0.0.1 */ public static byte[] hexToByte(String s) { byte[] result = null; try { int i = s.length(); // if (i % 2 == 1) { // throw new Exception("字符串长度不是偶数."); // } if (i % 2 != 0) { throw new Exception("字符串长度不是偶数."); } result = new byte[i / 2]; for (int j = 0; j < result.length; j++) { result[j] = (byte) Integer.parseInt(s.substring(j * 2, j * 2 + 2), 16); } } catch (Exception e) { result = null; e.printStackTrace(); // log.error("16进制字符串转字节数组时出现异常:", e); } return result; } /** * @param bytes 字节数组 * @return * @Title: byte2hexString * @Description: 字节数组转换为16进制字符串 //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用 * @since: 0.0.1 */ public static String byte2hexString(byte[] bytes) { StringBuffer buf = new StringBuffer(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { if (((int) bytes[i] & 0xff) < 0x10) { buf.append("0"); } buf.append(Long.toString((int) bytes[i] & 0xff, 16)); } return buf.toString().toUpperCase(); } /** * @param hexString 16进制字符串 如:"33d20046" 转换为 0x33 0xD2 0x00 0x46 * @return * @Title: hexString2byte * @Description: 16进制字符串转字节数组 * @since: 0.0.1 */ public static byte[] hexString2byte(String hexString) { if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) { return null; } byte[] bytes = new byte[hexString.length() / 2]; for (int i = 0; i < hexString.length(); i += 2) { bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff); } return bytes; } /** * @param i 需要转的int类型数字 * @return * @Title: byte1ToBcd2 * @Description: int类型转BCD码 * @since: 0.0.1 */ public static String byte1ToBcd2(int i) { // return (new Integer(i / 16).toString() + (new Integer(i % 16)).toString()); return Integer.toString(i / 16) + Integer.toString(i % 16); } /** * @param b 字节数组 * @return * @Title: byteToHex2 * @Description: 字节数组转换为16进制字符串 For example, byte[] {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF} will be changed to String "0123456789ABCDEF" * @since: 0.0.1 */ public static String byteToHex2(byte[] b) { StringBuffer result = new StringBuffer(); String tmp = ""; for (int i = 0; i < b.length; i++) { tmp = Integer.toHexString(b[i] & 0xff); if (tmp.length() == 1) { result.append("0" + tmp); } else { result.append(tmp); } } return result.toString().toUpperCase(); } /** * @param num 数字 * @param len 字节数组长度 * @return * @Title: intToHexBytes * @Description: int类型转16进制字节数组 */ public static byte[] intToHexBytes(int num, int len) { byte[] bytes = null; String hexString = Integer.toHexString(num); if (len > 0) { int length = len * 2; hexString = CustomStringUtils.leftFill(hexString, '0', length); bytes = CommonUtils.hexString2byte(hexString); } return bytes; } /** * @param str 需要转换编码的字符串 * @return * @Title: iso2Gbk * @Description: 将ISO-8859-1编码的字符串转成GBK编码的字符串 * @since: 0.0.1 */ public static String iso2Gbk(String str) { if (null == str) { return str; } try { return new String(str.getBytes("ISO-8859-1"), "GBK"); } catch (UnsupportedEncodingException e) { // log.error("不支持的编码异常:", e); e.printStackTrace(); return str; } }//byte数组转成long /** * @param b 将字节数组转long类型 位置为小端 * @return */ public static long byteToLong(byte[] b) { long s = 0; long s0 = b[0] & 0xff;// 最低位 long s1 = b[1] & 0xff; long s2 = b[2] & 0xff; long s3 = b[3] & 0xff; long s4 = b[4] & 0xff;// 最低位 long s5 = b[5] & 0xff; long s6 = b[6] & 0xff; long s7 = b[7] & 0xff; // s0不变 s1 <<= 8; s2 <<= 16; s3 <<= 24; s4 <<= 8 * 4; s5 <<= 8 * 5; s6 <<= 8 * 6; s7 <<= 8 * 7; s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7; return s; } /** * @param b 将字节数组转int类型 位置为小端 * @return */ public static int byteToInt(byte[] b) { int s = 0; int s0 = b[0] & 0xff;// 最低位 int s1 = b[1] & 0xff; int s2 = b[2] & 0xff; int s3 = b[3] & 0xff; // s0不变 s1 <<= 8; s2 <<= 16; s3 <<= 24; s = s0 | s1 | s2 | s3; return s; } /** * int类型转换小端的byte数组 * @param i * @return */ public static byte[] intToLittleBytes(int i) { ByteBuffer byteBuffer = ByteBuffer.allocate(4); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); byteBuffer.asIntBuffer().put(i); byte[] littleBytes = byteBuffer.array(); return littleBytes; } /** * 将一个字节转成10进制 * @param b * @return */ public static int byteToInt(byte b) { int value = b & 0xff; return value; } /** * 字节数组合并 * @param bt1 字节数组bt1 * @param bt2 字节数组bt2 * @return */ public static byte[] byteMerger(byte[] bt1, byte[] bt2){ byte[] bt3 = new byte[bt1.length+bt2.length]; System.arraycopy(bt1, 0, bt3, 0, bt1.length); System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length); return bt3; } }
CustomStringUtils.java
import org.apache.commons.lang3.StringUtils; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Map; import java.util.Random; /** * @ClassName: StringTools * @Description: 自定义字符串工具类 * @since: 1.0.0 * @author: dzy * @date: 2016年11月3日 下午3:08:39 */ public class CustomStringUtils { /** * @Title: leftFill * @Description: 长度不足,左补字符 * <p>用于要求定长字符串的,长度不足时左补字符串的场景.</p> * @since: 1.0.0 * @param str 原字符串 * @param ch 长度不足时要补的字符 * @param len 定长字段的长度(要补够多长) * @return */ public static String leftFill(String str, char ch, int len){ if (null == str) { str = ""; } int diff = len - str.length(); if (0 < diff) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < diff; i++) { buf.append(ch); } buf.append(str); str = buf.toString(); } // while (str.length() < len) { // str = ch + str; // } return str; } /** * @Title: rightFill * @Description: 长度不足,左补字符 * <p>用于要求定长字符串的,长度不足时右补字符串的场景.</p> * @since: 1.0.0 * @param str 原字符串 * @param ch 长度不足时要补的字符 * @param len 定长字段的长度(要补够多长) * @return */ public static String rightFill(String str, char ch, int len){ if (null == str) { str = ""; } int diff = len - str.length(); if (0 < diff) { StringBuffer buf = new StringBuffer(); buf.append(str); for (int i = 0; i < diff; i++) { buf.append(ch); } str = buf.toString(); } // while (str.length() < len) { // str = str + ch; // } return str; } /** * @Title: append * @Description: 拼接字符串 * @since: 1.0.0 * @param objs 需要拼接的对象 * @return */ public static String append(Object... objs) { if (null == objs || objs.length == 0) { return ""; } StringBuffer buffer = new StringBuffer(); for (Object obj : objs) { buffer.append(obj); } return buffer.toString(); } /** * @Title: nullToBlank * @Description: 如果字符串为空(null),则返回空字符 * @since: 1.0.0 * @param str * @return */ public static String nullToBlank(String str){ return str == null ? "" : str; } /** * @Title: convertMapToString * @Description: 将map转换成字符串 * @since: 1.0.0 * @param map 需要转字符串的Map对象 * @param symbol 转成字符串之后键值对之间的间隔符号 * @return String,如果symbol为& 则返回格式为:key1=value1&key2=value2... */ public static String convertMapToString(Map<String, String> map, String symbol){ if (null == map || map.isEmpty() || StringUtils.isEmpty(symbol)) { return null; } StringBuffer buffer = new StringBuffer(); boolean first = true; for (Map.Entry<String, String> entry : map.entrySet()) { if (first) { buffer.append(entry.getKey()).append("=").append(entry.getValue()); first = false; } else { buffer.append(symbol).append(entry.getKey()).append("=").append(entry.getValue()); } } return buffer.toString(); } /** * @Title: convertMapToString * @Description: 将map转化成字符串,并对map.value进行URL编码(当参数值为null时,则忽略该参数) * @since: 1.0.0 * @param map 需要转字符串的Map对象 * @param symbol 转成字符串之后键值对之间的间隔符号 * @param encoding 对map.value进行编码的编码格式(utf-8,gbk等) * @return */ public static String convertMapToString(Map<String, String> map, String symbol, String encoding){ if (map == null || map.isEmpty() || StringUtils.isEmpty(symbol)) { return null; } StringBuffer buffer = new StringBuffer(); boolean first = true; for (Map.Entry<String, String> entry : map.entrySet()) { if (first) { buffer.append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding)); first = false; } else { buffer.append(symbol).append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding)); } } return buffer.toString(); } /** * @Title: urlEncode * @Description: 对字符串进行URL编码 * @since: 1.0.0 * @param str 需要编码的字符串 * @param encoding 编码格式(utf-8,gbk等) * @return String 编码后的字符串 */ public static String urlEncode(String str, String encoding) { if (StringUtils.isEmpty(str)) { return str; } try { return URLEncoder.encode(str, encoding); } catch (UnsupportedEncodingException e) { System.err.println(append("URL encode string error. str=", str, ", encoding=", encoding) + e); return str; } } /** * @Title: urlDecode * @Description: 对字符串进行URL解码 * @since: 1.0.0 * @param str 需要解码的字符串 * @param encoding 解码的编码(utf-8,gbk等) * @return */ public static String urlDecode(String str, String encoding){ if (StringUtils.isEmpty(str)) { return str; } try { return URLDecoder.decode(str, encoding); } catch (UnsupportedEncodingException e) { System.err.println(append("URL decode string error. str=", str, ", encoding=", encoding) + e); return str; } } /** * @Title: generate * @Description: 随机生成指定长度的16进制的字符串 * @since: 0.0.1 * @param len 长度 * @return */ public static String generateRandomHex(int len){ if (len < 1) { return null; } StringBuffer sb = new StringBuffer(); Random random = new Random(); for (int i = 0; i < len; i++) { sb.append(Integer.toHexString(random.nextInt(16))); } return sb.toString().toUpperCase(); } /** * @Title: generateConformOddCheckHex * @Description: 生成符合奇校验的字符串 * @since: 0.0.1 * @param len 字节长度 * @return */ public static String generateConformOddCheckHex(int len) { byte[] bytes = new byte[len]; for (int i = 0; i < len; i++) { Random random = new Random(); int randomInt = random.nextInt(255); String binaryString = Integer.toBinaryString(randomInt); boolean oddCheck = isConformOddCheck(binaryString); if (!oddCheck) { randomInt ^= 1; } byte b = (byte) randomInt; bytes[i] = b; } String hexString = CommonUtils.byte2hexString(bytes); return hexString; } /** * @Title: oddCheck * @Description: 检验是否符合奇校验 * @since: 0.0.1 * @param binaryString * @return */ private static boolean isConformOddCheck(String binaryString) { int sum = 0; char[] charArray = binaryString.toCharArray(); for(char c : charArray){ if (c == '1') { sum ++; } } if (sum%2 == 1) { return true; } return false; } public static String replaceStr(String str, int startIndex, String newPart) throws Exception { int length = str.length(); if (startIndex < 0 || startIndex > length) { throw new RuntimeException("索引不在允许范围内."); } int newPartLen = newPart.length(); int secondStartIndex = startIndex + newPartLen; if (secondStartIndex > length) { throw new RuntimeException("索引不在允许范围内或替换的新字段过长."); } String beforeStr = ""; if (startIndex > 0) { beforeStr = str.substring(0, startIndex); } String afterStr = ""; if (secondStartIndex < length-1) { afterStr = str.substring(secondStartIndex); } String newStr = append(beforeStr, newPart, afterStr); return newStr; } }
SM2算法:
package com.pcidata.common.tools.encrypt; import com.pcidata.common.tools.CommonUtils; import com.pcidata.common.tools.CustomStringUtils; import com.pcidata.modules.key.modelvo.response.XxxKeyPair; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.*; import org.bouncycastle.crypto.signers.SM2Signer; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; /** * @Author: dzy * @Date: 2018/9/28 15:53 * @Describe: SM2工具类 */ @Slf4j public class SM2Util { /** * 生成SM2公私钥对 * @return */ private static AsymmetricCipherKeyPair genKeyPair0() { //获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); //构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); //1.创建密钥生成器 ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); //2.初始化生成器,带上随机数 try { keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG"))); } catch (NoSuchAlgorithmException e) { log.error("生成公私钥对时出现异常:", e); // e.printStackTrace(); } //3.生成密钥对 AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair(); return asymmetricCipherKeyPair; } /** * 生成公私钥对(默认压缩公钥) * @return */ public static XxxKeyPair genKeyPair() { return genKeyPair(true); } /** * 生成公私钥对 * @param compressedPubKey 是否压缩公钥 * @return */ public static XxxKeyPair genKeyPair(boolean compressedPubKey) { AsymmetricCipherKeyPair asymmetricCipherKeyPair = genKeyPair0(); //提取公钥点 ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ(); //公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04 String pubKey = Hex.toHexString(ecPoint.getEncoded(compressedPubKey)); BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD(); String priKey = privatekey.toString(16); XxxKeyPair keyPair = new XxxKeyPair(priKey, pubKey); return keyPair; } /** * 私钥签名 * @param privateKey 私钥 * @param content 待签名内容 * @return */ public static String sign(String privateKey, String content) { //待签名内容转为字节数组 byte[] message = Hex.decode(content); //获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); //构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); BigInteger privateKeyD = new BigInteger(privateKey, 16); ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters); //创建签名实例 SM2Signer sm2Signer = new SM2Signer(); //初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678 try { sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678"))); } catch (NoSuchAlgorithmException e) { log.error("签名时出现异常:", e); } //生成签名,签名分为两部分r和s,分别对应索引0和1的数组 BigInteger[] bigIntegers = sm2Signer.generateSignature(message); byte[] rBytes = modifyRSFixedBytes(bigIntegers[0].toByteArray()); byte[] sBytes = modifyRSFixedBytes(bigIntegers[1].toByteArray()); byte[] signBytes = ByteUtils.concatenate(rBytes, sBytes); String sign = Hex.toHexString(signBytes); return sign; } /** * 将R或者S修正为固定字节数 * @param rs * @return */ private static byte[] modifyRSFixedBytes(byte[] rs) { int length = rs.length; int fixedLength = 32; byte[] result = new byte[fixedLength]; if (length < 32) { System.arraycopy(rs, 0, result, fixedLength - length, length); } else { System.arraycopy(rs, length - fixedLength, result, 0, fixedLength); } return result; } /** * 验证签名 * @param publicKey 公钥 * @param content 待签名内容 * @param sign 签名值 * @return */ public static boolean verify(String publicKey, String content, String sign) { //待签名内容 byte[] message = Hex.decode(content); byte[] signData = Hex.decode(sign); // 获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); // 构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); //提取公钥点 ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey)); // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04 ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters); //获取签名 BigInteger R = null; BigInteger S = null; byte[] rBy = new byte[33]; System.arraycopy(signData, 0, rBy, 1, 32); rBy[0] = 0x00; byte[] sBy = new byte[33]; System.arraycopy(signData, 32, sBy, 1, 32); sBy[0] = 0x00; R = new BigInteger(rBy); S = new BigInteger(sBy); //创建签名实例 SM2Signer sm2Signer = new SM2Signer(); ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678")); sm2Signer.init(false, parametersWithID); //验证签名结果 boolean verify = sm2Signer.verifySignature(message, R, S); return verify; } /** * SM2加密算法 * @param publicKey 公钥 * @param data 数据 * @return */ public static String encrypt(String publicKey, String data){ // 获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); // 构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); //提取公钥点 ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey)); // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04 ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters); SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom())); byte[] arrayOfBytes = null; try { byte[] in = data.getBytes("utf-8"); arrayOfBytes = sm2Engine.processBlock(in, 0, in.length); } catch (Exception e) { log.error("SM2加密时出现异常:", e); } return Hex.toHexString(arrayOfBytes); } /** * SM2加密算法 * @param publicKey 公钥 * @param data 明文数据 * @return */ public static String encrypt(PublicKey publicKey, String data) { ECPublicKeyParameters ecPublicKeyParameters = null; if (publicKey instanceof BCECPublicKey) { BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey; ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters); } SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom())); byte[] arrayOfBytes = null; try { byte[] in = data.getBytes("utf-8"); arrayOfBytes = sm2Engine.processBlock(in,0, in.length); } catch (Exception e) { log.error("SM2加密时出现异常:", e); } return Hex.toHexString(arrayOfBytes); } /** * SM2解密算法 * @param privateKey 私钥 * @param cipherData 密文数据 * @return */ public static String decrypt(String privateKey, String cipherData) { byte[] cipherDataByte = Hex.decode(cipherData); //获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); //构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); BigInteger privateKeyD = new BigInteger(privateKey, 16); ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters); SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(false, privateKeyParameters); String result = null; try { byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length); return new String(arrayOfBytes, "utf-8"); } catch (Exception e) { log.error("SM2解密时出现异常:", e); } return result; } /** * SM2解密算法 * @param privateKey 私钥 * @param cipherData 密文数据 * @return */ public static String decrypt(PrivateKey privateKey, String cipherData) { byte[] cipherDataByte = Hex.decode(cipherData); BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey; ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(), ecDomainParameters); SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(false, ecPrivateKeyParameters); String result = null; try { byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length); return new String(arrayOfBytes, "utf-8"); } catch (Exception e) { log.error("SM2解密时出现异常:", e); } return result; } /** * 将未压缩公钥压缩成压缩公钥 * @param pubKey 未压缩公钥(16进制,不要带头部04) * @return */ public static String compressPubKey(String pubKey) { pubKey = CustomStringUtils.append("04", pubKey); //将未压缩公钥加上未压缩标识. // 获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); // 构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); //提取公钥点 ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(pubKey)); // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04 // ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters); String compressPubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.TRUE)); return compressPubKey; } /** * 将压缩的公钥解压为非压缩公钥 * @param compressKey 压缩公钥 * @return */ public static String unCompressPubKey(String compressKey) { // 获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); // 构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); //提取公钥点 ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(compressKey)); // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04 // ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters); String pubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.FALSE)); pubKey = pubKey.substring(2); //去掉前面的04 (04的时候,可以去掉前面的04) return pubKey; } }
SM3算法:
import lombok.extern.slf4j.Slf4j; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; import java.security.MessageDigest; /** * @Author: dzy * @Date: 2018/10/19 16:36 * @Describe: SM3工具类(杂凑算法-hash算法) */ @Slf4j public class SM3Util { /** * 16进制字符串SM3生成HASH签名值算法 * @param hexString 16进制字符串 * @return */ public static String hexEncrypt(String hexString) { byte[] srcData = Hex.decode(hexString); byte[] encrypt = encrypt(srcData); String cipherStr = Hex.toHexString(encrypt); return cipherStr; } /** * 16进制字符串SM3生成HASH签名值算法 * @param hexKey 16进制密钥 * @param hexString 16进制字符串 * @return */ public static String hexEncrypt(String hexKey, String hexString) { byte[] key = Hex.decode(hexKey); byte[] srcData = Hex.decode(hexString); byte[] encrypt = encrypt(key, srcData); String cipherStr = Hex.toHexString(encrypt); return cipherStr; } /** * 普通文本SM3生成HASH签名算法 * @param plain 待签名数据 * @return */ public static String plainEncrypt(String plain) { // 将返回的hash值转换成16进制字符串 String cipherStr = null; try { //将字符串转换成byte数组 byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8); //调用encrypt计算hash byte[] encrypt = encrypt(srcData); //将返回的hash值转换成16进制字符串 cipherStr = Hex.toHexString(encrypt); } catch (Exception e) { log.error("将字符串转换为字节时出现异常:", e); } return cipherStr; } /** * 普通文本SM3生成HASH签名算法 * @param hexKey 密钥 * @param plain 待签名数据 * @return */ public static String plainEncrypt(String hexKey, String plain) { // 将返回的hash值转换成16进制字符串 String cipherStr = null; try { //将字符串转换成byte数组 byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8); //密钥 byte[] key = Hex.decode(hexKey); //调用encrypt计算hash byte[] encrypt = encrypt(key, srcData); //将返回的hash值转换成16进制字符串 cipherStr = Hex.toHexString(encrypt); } catch (Exception e) { log.error("将字符串转换为字节时出现异常:", e); } return cipherStr; } /** * SM3计算hashCode * @param srcData 待计算数据 * @return */ public static byte[] encrypt(byte[] srcData) { SM3Digest sm3Digest = new SM3Digest(); sm3Digest.update(srcData, 0, srcData.length); byte[] encrypt = new byte[sm3Digest.getDigestSize()]; sm3Digest.doFinal(encrypt, 0); return encrypt; } /** * 通过密钥进行加密 * @param key 密钥byte数组 * @param srcData 被加密的byte数组 * @return */ public static byte[] encrypt(byte[] key, byte[] srcData) { KeyParameter keyParameter = new KeyParameter(key); SM3Digest digest = new SM3Digest(); HMac mac = new HMac(digest); mac.init(keyParameter); mac.update(srcData, 0, srcData.length); byte[] result = new byte[mac.getMacSize()]; mac.doFinal(result, 0); return result; } /** * SM3计算hashCode * @param srcData 待计算数据 * @return * @throws Exception */ public static byte[] encrypt_0(byte[] srcData) throws Exception { MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC"); byte[] digest = messageDigest.digest(srcData); return digest; } }
SM4算法:
import org.bouncycastle.crypto.engines.SM4Engine; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; /** * @Author: dzy * @Date: 2018/10/9 16:41 * @Describe: SM4算法 */ public class SM4Util { //加解密的字节快大小 public static final int BLOCK_SIZE = 16; /** * SM4ECB加密算法 * @param in 待加密内容 * @param keyBytes 密钥 * @return */ public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) { SM4Engine sm4Engine = new SM4Engine(); sm4Engine.init(true, new KeyParameter(keyBytes)); int inLen = in.length; byte[] out = new byte[inLen]; int times = inLen / BLOCK_SIZE; for (int i = 0; i < times; i++) { sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE); } return out; } /** * SM4ECB加密算法 * @param in 待加密内容 * @param keyBytes 密钥 * @return */ public static String encryptByEcb(byte[] in, byte[] keyBytes) { byte[] out = encryptByEcb0(in, keyBytes); String cipher = Hex.toHexString(out); return cipher; } /** * SM4的ECB加密算法 * @param content 待加密内容 * @param key 密钥 * @return */ public static String encryptByEcb(String content, String key) { byte[] in = Hex.decode(content); byte[] keyBytes = Hex.decode(key); String cipher = encryptByEcb(in, keyBytes); return cipher; } /** * SM4的ECB解密算法 * @param in 密文内容 * @param keyBytes 密钥 * @return */ public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) { SM4Engine sm4Engine = new SM4Engine(); sm4Engine.init(false, new KeyParameter(keyBytes)); int inLen = in.length; byte[] out = new byte[inLen]; int times = inLen / BLOCK_SIZE; for (int i = 0; i < times; i++) { sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE); } return out; } /** * SM4的ECB解密算法 * @param in 密文内容 * @param keyBytes 密钥 * @return */ public static String decryptByEcb(byte[] in, byte[] keyBytes) { byte[] out = decryptByEcb0(in, keyBytes); String plain = Hex.toHexString(out); return plain; } /** * SM4的ECB解密算法 * @param cipher 密文内容 * @param key 密钥 * @return */ public static String decryptByEcb(String cipher, String key) { byte[] in = Hex.decode(cipher); byte[] keyBytes = Hex.decode(key); String plain = decryptByEcb(in, keyBytes); return plain; } }
talk less,do more!