下面是国密硬件字节分组算法实现
/**
* 字符串按照占字节数大小进行切分分组
*
* @param src
* @param bytes
* @return
*/
public static List chineseSplitFunction(String src, int bytes) {
try {
if (src == null) {
return null;
}
List splitList = new ArrayList();
int startIndex = 0; // 字符串截取起始位置
int endIndex = bytes > src.length() ? src.length() : bytes; // 字符串截取结束位置
while (startIndex < src.length()) {
String subString = src.substring(startIndex, endIndex);
// 截取的字符串的字节长度大于需要截取的长度时,说明包含中文字符
// 在GBK编码中,一个中文字符占2个字节,UTF-8编码格式,一个中文字符占3个字节。
while (subString.getBytes(ENCODE_UTF).length > bytes) {
--endIndex;
subString = src.substring(startIndex, endIndex);
}
splitList.add(src.substring(startIndex, endIndex));
startIndex = endIndex;
// 判断结束位置时要与字符串长度比较(src.length()),之前与字符串的bytes长度比较了,导致越界异常。
endIndex = (startIndex + bytes) > src.length() ? src.length()
: startIndex + bytes;
}
return splitList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
注意:分组加密后是2进制的乱码,如果存在不同系统之间的交互,可以把每一个分组的加密的密文信息转换成16进制后,在解密的时候将16进制转换成二进制再分组解密。(分组解密字节加密卡最大支持260,不过这个不用考虑,硬件136字节能加密就能解密)
附送 工具类
package com.people.utils;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* sm2分组加密 如果被加密的内容超过136的话就需要分组加密了 渔翁加密卡支持: sm2加密最大数据长度是136位
* GBK编码,一个汉字占两个字节。UTF-8编码是变长编码,通常汉字占三个字节,扩展B区以后的汉字占四个字节。
* UTF-16编码,通常汉字占两个字节,扩展D区中的汉字占四个字节 中文字支持45分组 特殊字符支持136分组 sm2分组解密数据特性:
* 解密内容长度最大246
*
* @author zhaozhiqiang
*
*/
public class Sm2GroupEncryUtils {
// 编码方式
private static final String ENCODE_UTF = "UTF-8";
public static final String chineseString = "13132,,,,,,我是testStsdfgdgagagaasdasfasfdring哈哈哈";
public static void main(String[] arg) throws Exception {
// List splitStringList = chineseSplitFunction(chineseString,
// 5);
// for (String split:splitStringList) {
// System.out.println(split);
// }
byte[] ss = new byte[531];
for (int i = 0; i < ss.length; i++) {
ss[i] = (byte) i;
}
int num=0;
ArrayList suByteGroupData = suByteGroupData(ss,246);
for (byte[] bs : suByteGroupData) {
System.out.println("解密分组内容长度"+bs.length);
num=num+bs.length;
}
System.out.println("解密内容长度"+num);
}
/**
* sm2解密分组数据
* @param src
* @param start 第一次是0
* @param preCount 前面的字节数据大小
* @param count 动态分组的密文字节大小
* @return
*/
public static byte[] suByteGroupForeverData(byte[] src,int start,int preCount, int count) {
if(start==0&&preCount==0){
byte[] subBytes = subBytes(src, 0, count);
return subBytes;
}else{
byte[] subBytes = subBytes(src, src.length-preCount, count);
return subBytes;
}
}
/**
* sm2解密分组数据
*
* @param src
* 原始数据
* @param count
* 分组的字节长度,sm2解密字节长度最大支持246
* @return
*/
public static ArrayList suByteGroupData(byte[] src, int count) {
ArrayList listByte = new ArrayList();
// 获取原始数据的字节长度
int srcLenth = src.length;
double f1 = new BigDecimal((float) srcLenth / count).setScale(2,
BigDecimal.ROUND_HALF_UP).doubleValue();
int ceil = (int) Math.ceil(f1);
System.out.println("解密分组次数:"+ceil);
// 比较原始数据和当前的分组字节长度
if (srcLenth <= count) {
byte[] subBytes = subBytes(src, 0, srcLenth);
listByte.add(subBytes);
return listByte;
} else {// 原始数据字节长度大于分组长度需要截取分组
for (int i = 1; i <= ceil; i++) {
if ((src.length % count) == 0) {// 刚好整除
byte[] subBytes1 = subBytes(src, i * count, count);
listByte.add(subBytes1);
} else {// 没有整除,分两部分,一部分是整除的部分(count)还有余下的部分(srcLenth-count*(i-1))
if (i <= ceil - 1) {
byte[] subBytes2 = subBytes(src, (i-1)* (count), count);
listByte.add(subBytes2);
} else {
byte[] subBytes3 = subBytes(src, (i-1)* (count), srcLenth
- (i-1)* (count));
listByte.add(subBytes3);
}
}
}
}
return listByte;
}
/**
* 在字节数组中截取指定长度数组
*
* @param src
* @param begin
* @param count
* @return
*/
public static byte[] subBytes(byte[] src, int begin, int count) {
byte[] bs = new byte[count];
System.arraycopy(src, begin, bs, 0, count);
return bs;
}
/**
* 字符串按照占字节数大小进行切分分组
*
* @param src
* @param bytes
* @return
*/
public static List chineseSplitFunction(String src, int bytes) {
try {
if (src == null) {
return null;
}
List splitList = new ArrayList();
int startIndex = 0; // 字符串截取起始位置
int endIndex = bytes > src.length() ? src.length() : bytes; // 字符串截取结束位置
while (startIndex < src.length()) {
String subString = src.substring(startIndex, endIndex);
// 截取的字符串的字节长度大于需要截取的长度时,说明包含中文字符
// 在GBK编码中,一个中文字符占2个字节,UTF-8编码格式,一个中文字符占3个字节。
while (subString.getBytes(ENCODE_UTF).length > bytes) {
--endIndex;
subString = src.substring(startIndex, endIndex);
}
splitList.add(src.substring(startIndex, endIndex));
startIndex = endIndex;
// 判断结束位置时要与字符串长度比较(src.length()),之前与字符串的bytes长度比较了,导致越界异常。
endIndex = (startIndex + bytes) > src.length() ? src.length()
: startIndex + bytes;
}
return splitList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 字符串按照占字节数大小进行切分分组 当前场景适用于不带,符号的字符串
*
* @param value
* @param length
* @return
* @throws Exception
* @throws Exception
*/
public static String splitBySize(String value, int length) throws Exception {
char[] cs = value.toCharArray();
String str = "";
int index = 0;
boolean flag = false;
for (char c : cs) {
index += String.valueOf(c).getBytes(ENCODE_UTF).length;
if (index > length) {
if (flag) {
if ((index % length) == 0) {
if (str.substring(str.length() - 1).equals(",")) {
str = str + c;
} else {
str = str + c + ",";
}
} else {
String[] split = str.split(",");
String string = split[split.length - 1];
if ((String.valueOf(c).getBytes(ENCODE_UTF).length + String
.valueOf(string).getBytes(ENCODE_UTF).length) > length) {
if (str.substring(str.length() - 1).equals(",")) {
str = str + c;
} else {
str = str + "," + c;
}
} else {
str = str + c;
}
}
} else {
if ((index % length) == 0) {
String[] split = str.split(",");
String string = split[split.length - 1];
if ((String.valueOf(c).getBytes(ENCODE_UTF).length + String
.valueOf(string).getBytes(ENCODE_UTF).length) > length) {
str = str + "," + c;
} else {
str = str + c;
}
flag = true;
} else {
String[] split = str.split(",");
String string = split[split.length - 1];
if ((String.valueOf(c).getBytes(ENCODE_UTF).length + String
.valueOf(string).getBytes(ENCODE_UTF).length) > length) {
str = str + "," + c;
} else {
str = str + c;
}
}
}
} else {
if (index < length) {
str = str + c;
} else if (index == length) {
str = str + c + ",";
flag = true;
}
}
}
return str;
}
/**
* java截取字符串中字节长度,超出的舍弃
*
* @param str
* @param subSLength
* @return
*/
public static String subByteStr(String str, int subSLength) {
String subStr = "";
try {
if (str == null)
return "";
else {
int tempSubLength = subSLength;// 截取字节数
subStr = str.substring(0,
str.length() < subSLength ? str.length() : subSLength);// 截取的子串
int subStrByetsL = subStr.getBytes(ENCODE_UTF).length;// 截取子串的字节长度
// 说明截取的字符串中包含有汉字
while (subStrByetsL > tempSubLength) {
int subSLengthTemp = --subSLength;
subStr = str.substring(0,
subSLengthTemp > str.length() ? str.length()
: subSLengthTemp);
subStrByetsL = subStr.getBytes(ENCODE_UTF).length;
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return subStr;
}
/**
* 把原始字符串分割成指定长度的字符串列表
*
* @param inputString
* 原始字符串
* @param length
* 指定长度
* @return
*/
public static List getStrList(String inputString, int length) {
int size = inputString.length() / length;
if (inputString.length() % length != 0) {
size += 1;
}
return getStrList(inputString, length, size);
}
/**
* 把原始字符串分割成指定长度的字符串列表
*
* @param inputString
* 原始字符串
* @param length
* 指定长度
* @param size
* 指定列表大小
* @return
*/
public static List getStrList(String inputString, int length,
int size) {
List list = new ArrayList();
for (int index = 0; index < size; index++) {
String childStr = substring(inputString, index * length,
(index + 1) * length);
list.add(childStr);
}
return list;
}
/**
* 分割字符串,如果开始位置大于字符串长度,返回空
*
* @param str
* 原始字符串
* @param f
* 开始位置
* @param t
* 结束位置
* @return
*/
public static String substring(String str, int f, int t) {
if (f > str.length())
return null;
if (t > str.length()) {
return str.substring(f, str.length());
} else {
return str.substring(f, t);
}
}
/**
* 计算中英文字符串的字节长度
* 一个中文占3个字节
*
* @param str
* @return int 字符串的字节长度
*/
public static int getChinaAndEnglishStrLength(String str) {
if (str == null || str.length() == 0) {
return 0;
}
try {
return str.getBytes(ENCODE_UTF).length;
} catch (UnsupportedEncodingException e) {
System.out.println("计算中英文字符串的字节长度失败," + e);
}
return 0;
}
/**
* 计算中英文字符串的字节长度
*
* @param str
* @return int
*/
public static int getEnglishAndChinaStrLength(String str) {
if (str == null || str.length() == 0) {
return 0;
}
int len = 0;
for (int i = 0, j = str.length(); i < j; i++) {
// UTF-8编码格式中文占三个字节,GBK编码格式 中文占两个字节 ;
len += (str.charAt(i) > 255 ? 3 : 1);
}
return len;
}
}