/**
* 算法邏輯
* @param key
* @param data
* @return
*/
public static byte[] Aes_Cmac01(byte[] key, byte[] data){
// 子密鑰生成
// 步驟1,將具有密鑰K的AES-128應用於全零輸入塊。
byte[] L = AesEncrypt(key, new byte[16], new byte[16]);
// 步驟2,通過以下操作得出K1:
//如果L的最高有效位等於0,則K1是L的左移1位。
byte[] FirstSubkey = Rol(L);
if ((L[0] & 0x80) == 0x80) {
// 否則,K1是const_Rb的異或和L左移1位。
FirstSubkey[15] ^= 0x87;
}
// 步驟3,通過以下操作得出K2:
//如果K1的最高有效位等於0,則K2是K1左移1位
byte[] SecondSubkey = Rol(FirstSubkey);
if ((FirstSubkey[0] & 0x80) == 0x80) {
// 否則,K2是const_Rb的異或,且K1左移1位
SecondSubkey[15] ^= 0x87;
}
// MAC 計算
if (((data.length != 0) && (data.length % 16 == 0)) == true) {
//如果輸入消息塊的大小等於塊大小(128位)
// 最后一個塊在處理之前應與K1異或
for (int j = 0; j < FirstSubkey.length; j++){
data[data.length - 16 + j] ^= FirstSubkey[j];
}
} else {
// 否則,最后一個塊應填充10 ^ i
byte[] padding = new byte[16 - data.length % 16];
padding[0] = (byte) 0x80;
byte[] newData=new byte[data.length+padding.length];
System.arraycopy(data,0,newData,0,data.length);
System.arraycopy(padding,0,newData,data.length,padding.length);
// data = data.Concat<byte>(padding.AsEnumerable()).ToArray();
// 並與K2進行異或運算
for (int j = 0; j < SecondSubkey.length; j++){
newData[newData.length - 16 + j] ^= SecondSubkey[j];
}
data=newData;
}
// 先前處理的結果將是最后一次加密的輸入。
byte[] encResult = AesEncrypt(key, new byte[16], data);
byte[] HashValue = new byte[16];
System.arraycopy(encResult, encResult.length - HashValue.length, HashValue, 0, HashValue.length);
return HashValue;
}
private static byte[] Rol(byte[] b)
{
byte[] r = new byte[b.length];
byte carry = 0;
for (int i = b.length - 1; i >= 0; i--)
{
short u = (short)(b[i] << 1);
r[i] = (byte)((u & 0xff) + carry);
carry = (byte)((u & 0xff00) >> 8);
}
return r;
}
/**
* AES加密
* @param keys
* @param iv
* @param data
* @return
*/
private static byte[] AesEncrypt(byte[] keys, byte[] iv, byte[] data) {
try {
//1.根據字節數組生成AES密鑰
SecretKey key=new SecretKeySpec(keys, "AES");
//2.根據指定算法AES自成密碼器 "算法/模式/補碼方式"
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
//3.CBC模式需要向量vi
IvParameterSpec ivps = new IvParameterSpec(iv);
//4.初始化密碼器,第一個參數為加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二個參數為使用的KEY
cipher.init(Cipher.ENCRYPT_MODE, key,ivps);
//5.獲取加密內容的字節數組(這里要設置為utf-8)不然內容中如果有中文和英文混合中文就會解密為亂碼
byte [] byte_encode=data;
//6.根據密碼器的初始化方式--加密:將數據加密
byte [] byte_AES=cipher.doFinal(byte_encode);
//7.返回
return byte_AES;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}