sm2分組加密 如果被加密的內容超過136的話就需要分組加密了 漁翁加密卡支持: sm2加密最大數據長度是136位
GBK編碼,一個漢字佔兩個字節。UTF-8編碼是變長編碼,通常漢字佔三個字節,擴展B區以後的漢字佔四個字節。
GBK編碼,一個漢字佔兩個字節。UTF-8編碼是變長編碼,通常漢字佔三個字節,擴展B區以後的漢字佔四個字節。
* UTF-16編碼,通常漢字佔兩個字節,擴展D區中的漢字佔四個字節 中文字支持45分組 特殊字符支持136分組 sm2分組解密數據特性:
下面是國密硬件字節分組算法實現
/**
* 字符串按照佔字節數大小進行切分分組
*
* @param src
* @param bytes
* @return
*/
public static List<String> chineseSplitFunction(String src, int bytes) {
try {
if (src == null) {
return null;
}
List<String> splitList = new ArrayList<String>();
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<String> 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<byte[]> 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<byte[]> suByteGroupData(byte[] src, int count) {
ArrayList<byte[]> listByte = new ArrayList<byte[]>();
// 獲取原始數據的字節長度
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<String> chineseSplitFunction(String src, int bytes) {
try {
if (src == null) {
return null;
}
List<String> splitList = new ArrayList<String>();
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<String> 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<String> getStrList(String inputString, int length,
int size) {
List<String> list = new ArrayList<String>();
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);
}
}
/**
* 計算中英文字符串的字節長度 <br/>
* 一箇中文佔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;
}
}