/**
* SM4 mac计算
* 1.数据不为16的倍数,需要补0
* 2.将数据16个字节进行异或,再将异或的结果与下一个16个字节异或,一直到最后
* 3.将异或运算后的最后16个字节 转换成32 个HEXDECIMAL:
* 4.取前16 个字节用MAK加密
* 5.将加密后的结果与后16 个字节异或
* 6.用异或的结果TEMP BLOCK 再进行一次SM4密钥算法运算
* 7.将运算后的结果(ENC BLOCK2)转换成32 个HEXDECIMAL
* 8.取前8个字节作为MAC值。
* @param input
* @param key
* @return
* @throws Exception
*/
public static byte[] toCountMAC_SM4(byte[] input,byte[] key) {
int length = input.length;
//不足16的整数倍补位0
int x = length % 16;
int addLen = 0;
if (x != 0) {
addLen = 16 - (length % 16);
}
byte[] data = new byte[length + addLen];//byte 默认值00
System.arraycopy(input, 0, data, 0, length);
int startPoint = 0;
//每16字节分组,循环异或
byte[] resultBlock = new byte[16];
for(int i = 0; i < data.length / 16; i++) {
byte[] temp = new byte[16];
System.arraycopy(data, startPoint, temp, 0, 16);
startPoint = startPoint + 16;
if(i == 0) {
resultBlock = temp;
} else {
resultBlock = bytesXOR(resultBlock, temp);//进行异或运算
}
}
//c) 将异或运算后的最后16个字节(RESULT BLOCK)转换成32 个HEXDECIMAL
String resultBlockStr = ISOUtils.hexString(resultBlock);
System.out.println("[resultBlockStr:"+resultBlockStr+"]");
byte[] hex = resultBlockStr.getBytes();
//d) 取前16 个字节用MAK加密
byte[] hex16b = new byte[16]; //before 8
byte[] hex16a = new byte[16]; //after 8
System.arraycopy(hex, 0, hex16b, 0, 16);
System.arraycopy(hex, 16, hex16a, 0, 16);byte[] encBlock1 = null;
encBlock1 = encodeSMS4(hex16b, key);
System.out.println("[encBlock1:"+ DumpUtils.bytesToHex(encBlock1)+"]");
//e) 将加密后的结果与后16 个字节异或
byte[] tempBlock = bytesXOR(encBlock1, hex16a);
//f) 用异或的结果TEMP BLOCK 再进行一次SM4密钥算法运算。
byte[] encBlock2 = SMS4.encodeSMS4(tempBlock, key);
//g) 将运算后的结果(ENC BLOCK2)转换成32 个HEXDECIMAL
String macAllStr = ISOUtils.hexString(encBlock2);
byte[] macAll = macAllStr.getBytes();//h) 取前8个字节作为MAC值。
byte[] mac = new byte[8];
System.arraycopy(macAll, 0, mac, 0, 8);
return mac;
}/**
* 不限明文长度的SMS4加密
*
* @param plaintext
* @param key
* @return
*/
public static byte[] encodeSMS4(byte[] plaintext, byte[] key) {
byte[] ciphertext = new byte[plaintext.length];
int k = 0;
int plainLen = plaintext.length;
while (k + 16 <= plainLen) {
byte[] cellPlain = new byte[16];
for (int i = 0; i < 16; i++) {
cellPlain[i] = plaintext[k + i];
}
byte[] cellCipher = encode16(cellPlain, key);
for (int i = 0; i < cellCipher.length; i++) {
ciphertext[k + i] = cellCipher[i];
}
k += 16;
}
return ciphertext;
}