java mac pos_pos终端mac国密(sm4)算法(java实现)
概念理解
mac算法是(Message Authentication Codes 消息認證碼算法),是含有密鑰散列函數算法。主要通過異或運算,再配合其他加密算法實現mac值的運算,用于校驗。
實現過程
將需要加密計算的字符串轉換為16進制字符串
例如:
密鑰:"12345678901234567890123456789012"
待加密數據(字符串形式):
6000112018111411003020170930101010120171025000755000000005553
轉化為16進制:
36303030 31313230 31383131 31343131 30303330 32303137 30393330 31303130 31303132 30313731 30323530 30303735 35303030 30303030 30353535 33
將轉換過的16字符串進行補位分組
部位后的數據(部位規則:字符長度%32!=0補位)
36303030 31313230 31383131 31343131 30303330 32303137 30393330 31303130 31303132 30313731 30323530 30303735 35303030 30303030 30353535 33000000
分組后的數據
第 0組明文:36303030 31313230 31383131 31343131
第 1組明文:30303330 32303137 30393330 31303130
第 2組明文:31303132 30313731 30323530 30303735
第 3組明文:35303030 30303030 30353535 33000000
將分組過的字符串數組逐步進行異或運算
異或流程
第 0組明文: 36303030 31313230 31383131 31343131
第 1組明文: 30303330 32303137 30393330 31303130
第 1組異或結果:06000300 03010307 01010201 00040001
第 2組明文:31303132 30313731 30323530 30303735
第 2組異或結果:37303232 33303436 31333731 30343734
第3組明文:35303030 30303030 30353535 33000000
與第2組密文異或:02000202 03000406 01060204 03343734
將最后異或結果轉化為16進制字符串
轉換為16進制
30323030 30323032 30333030 30343036 30313036 30323034 30333334 33373334
取前16位和后16位,前16位進行sm4加密,加密結果與后16位異或后再加密
前16位
30323030 30323032 30333030 30343036
后16位
30313036 30323034 30333334 33373334
前16位加密結果
B038A2B2 F3FFE3C8 AC60B377 C70C2DB1
與后16位異或結果
80099284 C3CDD3FC 9C538043 F43B1E85
再加密結果
1E80F373 40B0FEE6 2C81F356 AFB20BF1
取前16個字符作為mac值
mac值:1E80F37340B0FEE6
具體實現過程
準備工作
數據轉換工具類 TransferUtils.java
字符串轉換為16進制字符串
public static String StringToHexString(String str) {
String data = bytesToHexString(str.getBytes(), 32);
return data;
}
字節數組轉換為16進制字符串
/**
* 字節數組轉化為十六進制字符串 并按照len的倍數進行補"0"
* @param bytes 字節數據
* @param len 部位原則 不夠len倍數補"0"
* @return
*/
public static String bytesToHexString(byte[] bytes, int len) {
StringBuffer hexStr = new StringBuffer();
for (byte b : bytes) {
hexStr.append(String.format("%02x", new Integer(b & 0xff)));
}
//長度不滿32的整數倍 在后邊添加 "0"
while (hexStr.length() % len != 0) {
hexStr.append("0");
}
return hexStr.toString();
}
將字符串str 按照長度len 進行分組
/**
* 將字符串str 按照長度len 進行分組
* @param str 字符串
* @param len 每組字符長度
* @return
*/
public static String[] dataGrouping(String str, int len) {
int lenth = str.length() % len == 0 ? str.length() / len : str.length() / len + 1;
String[] data = new String[lenth];
for (int i = 0; i < lenth; i++) {
data[i] = str.substring(i * len, i * len + len);
}
return data;
}
將字符串數組進行異或運算
public static String handleXOrStringArr(String[] strs){
String result = "";
for (int i = 1;i < strs.length;i++){
if (i == 1){
result = xOr(strs[0],strs[1]);
}else {
result = xOr(strs[i],result);
}
}
return result;
}
異或運算
/**
* 異或運算
* @param s1
* @param s2
* @return
*/
public static String xOr(String s1, String s2) {
String data = IntArr2String(xOr(String2IntArr(s1),String2IntArr(s2)));
return data;
}
public static int [] xOr(int[] i1,int[] i2){
int[] xor = new int[i1.length];
for (int i = 0;i < i1.length & i < i2.length;i++){
xor[i] = i1[i]^i2[i];
}
return xor;
}
加密工具類
sm4加密
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;
}
調用過程
將密鑰轉換為字節數組,將需要加密計算的字符串轉換為16進制字符串并補位
例如:
密鑰:"12345678901234567890123456789012"
待加密數據(字符串形式):
6000112018111411003020170930101010120171025000755000000005553
//將key轉換為字節數組
byte[] keys = TransformUtils.HexStringToByteArr(key);
//將加密數據轉換為16進制字符串
String hexData = TransformUtils.StringToHexString(data);
將轉換過的16字符串進行分組
//將數據分組 32位為一組
String[] dataGroup = TransformUtils.dataGrouping(hexData, 32);
將分組過的字符串數組逐步進行異或運算
//進行異或運算
String xorData = TransformUtils.handleXOrStringArr(dataGroup);
將最后異或結果轉化為16進制字符串
//將異或結果轉化為16進制字符串
String hexOxrData = TransformUtils.StringToHexString(xorData);
取前16字節和后16字節,前16字節進行sm4加密,加密結果與后16字節異或后再加密
//取前16字節和后16字節 兩個16進制位表示一個字節
String start32Bit = hexOxrData.substring(0,32);
String end32Bit = hexOxrData.substring(hexOxrData.length() - 32,hexOxrData.length());
//前16位進行首次加密
byte[] encodeSMS4_1 = SMS4.encodeSMS4(TransformUtils.HexStringToByteArr(start32Bit), keys);
//加密結果與后16位進行異或
String xOrEnd = TransformUtils.xOr(TransformUtils.bytesToHexString(encodeSMS4_1, 16), end32Bit);
//異或結果轉成字節數組
byte[] bytes = TransformUtils.HexStringToByteArr(xOrEnd);
//進行二次加密
byte[] resultByte = SMS4.encodeSMS4(bytes, keys);
//將加密結果轉換成16進制字符串 并取前八個字符作為mac值返回
String result = TransformUtils.bytesToHexString(resultByte, 16);
取前16個字符作為mac值
//取前8字節作為mac值返回
result = result.substring(0,16);
后記
此處是pos終端mac國密(sm4)算法,之前還有一個pos終端mac國際算法(雙倍長 3des),兩者的區別在于 分組的時候分組長度不太一樣,國際是16個16進制字符(8字節)分組,國密是32個16進制字符(16字節)分組,再有不同的地方就是加密算法不同,國密是sm4加密算法,國際是雙倍長3des加密算法,其他基本都是一樣的,這個加密算法也是根據需求可以進行更改的 ,比如改為RSA 或AES也是可以的,這個就需要雙方溝通了 統一加密算法就可以了
總結
以上是生活随笔為你收集整理的java mac pos_pos终端mac国密(sm4)算法(java实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win7 mysql添加到服务_MySQ
- 下一篇: git master代码被删除 怎么恢复