1. 前言
如果你也在做加解密相关的需求,比如调用国密标准0018接口的对称加密/解密接口。就会遇到需要自己填充数据原文为16字节的整数倍(因为SM4分组算法的加密数据长度必须是其密钥大小的整数倍,SM4密钥大小是128bit,即:16字节)。
2. 代码实现
下面两种实现的效果是一样的,只不过写法上有一些区别。
2.1 PKCS5填充实现方式一
/**
* PKCS5填充方式一
*
* @param sourceData 原文数据对应的字节数组
* @param blockSize 分组大小(比如国密SM4算法的分组大小是16字节)
* @return
*/
public byte[] PKCS5Padding_v1(byte[] sourceData, int blockSize) {
int newLeng = (sourceData.length / blockSize + 1) * blockSize;
byte[] ret = new byte[newLeng];
System.arraycopy(sourceData, 0, ret, 0, sourceData.length);
for (int i = sourceData.length; i < ret.length; ++i) {
ret[i] = (byte) (ret.length - sourceData.length);
}
return ret;
}
2.2 PKCS5填充实现方式二
/**
* PKCS5填充方式二
*
* @param sourceData 原文数据对应的字节数组
* @param blockSize 分组大小(比如国密SM4算法的分组大小是16字节)
* @return
*/
private byte[] PKCS5Padding_v2(byte[] sourceData, int blockSize) {
int paddingLength = blockSize - (sourceData.length % blockSize);
byte[] paddingBytes = new byte[paddingLength];
for (int i = 0; i < paddingLength; i++) {
paddingBytes[i] = (byte) paddingLength;
}
byte[] paddedTextBytes = new byte[sourceData.length + paddingLength];
System.arraycopy(sourceData, 0, paddedTextBytes, 0, sourceData.length);
System.arraycopy(paddingBytes, 0, paddedTextBytes, sourceData.length, paddingLength);
return paddedTextBytes;
}
2.3 去除填充
/**
* 去除PKCS5填充
*
* @param tempPadData 已经填充后的数据
* @param blockSize 分组大小(比如国密SM4算法的分组大小是16字节)
* @return
*/
public byte[] unPad(byte[] tempPadData, int blockSize) {
int paddingLength = tempPadData[tempPadData.length - 1] & 0xFF;
if (paddingLength > blockSize) {
throw new IllegalArgumentException("Invalid padding length");
}
byte[] plainTextBytes = new byte[tempPadData.length - paddingLength];
System.arraycopy(tempPadData, 0, plainTextBytes, 0, tempPadData.length - paddingLength);
for (int i = 0; i < paddingLength; i++) {
if (tempPadData[tempPadData.length - 1 - i] != paddingLength) {
throw new IllegalArgumentException("Invalid padding value");
}
}
return plainTextBytes;
}
3. 测试验证
3.1 测试代码一
@Test
public void test10() {
// 原文数据
String str = "1";
System.out.println("原文数据长度(byte):" + str.getBytes().length);
// 使用PKCS5填充(方式一)
byte[] b1 = PKCS5Padding_v1(str.getBytes(), 16);
System.out.println("填充后的大小(byte):" + b1.length + " 填充后的数据(经过Base64编码):" + Base64.getEncoder().encodeToString(b1));
// 使用PKCS5填充(方式二)
byte[] b2 = PKCS5Padding_v2(str.getBytes(), 16);
System.out.println("填充后的大小(byte):" + b1.length + " 填充后的数据(经过Base64编码):" + Base64.getEncoder().encodeToString(b2));
System.out.println("-------去除PKCS5填充--------");
byte[] bytes = unPad(b1, 16);
System.out.println(new String(bytes));
}
3.2 测试代码二
@Test
public void test10() {
// 原文数据
String str = "1236547899963214";
System.out.println("原文数据长度(byte):" + str.getBytes().length);
// 使用PKCS5填充(方式一)
byte[] b1 = PKCS5Padding_v1(str.getBytes(), 16);
System.out.println("填充后的大小(byte):" + b1.length + " 填充后的数据(经过Base64编码):" + Base64.getEncoder().encodeToString(b1));
// 使用PKCS5填充(方式二)
byte[] b2 = PKCS5Padding_v2(str.getBytes(), 16);
System.out.println("填充后的大小(byte):" + b1.length + " 填充后的数据(经过Base64编码):" + Base64.getEncoder().encodeToString(b2));
System.out.println("\n-------去除PKCS5填充,得到的原文数据--------");
byte[] bytes = unPad(b1, 16);
System.out.println(new String(bytes));
}
3.3 测试代码三
@Test
public void test10() {
// 原文数据
String str = "12365478999632141";
System.out.println("原文数据长度(byte):" + str.getBytes().length);
// 使用PKCS5填充(方式一)
byte[] b1 = PKCS5Padding_v1(str.getBytes(), 16);
System.out.println("填充后的大小(byte):" + b1.length + " 填充后的数据(经过Base64编码):" + Base64.getEncoder().encodeToString(b1));
// 使用PKCS5填充(方式二)
byte[] b2 = PKCS5Padding_v2(str.getBytes(), 16);
System.out.println("填充后的大小(byte):" + b1.length + " 填充后的数据(经过Base64编码):" + Base64.getEncoder().encodeToString(b2));
System.out.println("\n-------去除PKCS5填充,得到的原文数据--------");
byte[] bytes = unPad(b1, 16);
System.out.println(new String(bytes));
}
如果此篇文章对你有帮助,感谢点个赞~~