Java版AES-CMAC加密
时间: 2023-09-04 14:10:43 浏览: 107
AES-CMAC是一种对称密钥算法,用于生成消息的校验值。下面是Java版的AES-CMAC加密实现。
```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class AesCmac {
private static final byte[] AES_CONST_R128 = {
(byte)0x87, (byte)0x6e, (byte)0x46, (byte)0xf9,
(byte)0x37, (byte)0x1d, (byte)0xa3, (byte)0x3b,
(byte)0xb7, (byte)0xe9, (byte)0x73, (byte)0x29,
(byte)0x1f, (byte)0x52, (byte)0x7f, (byte)0x1a
};
public static byte[] generateCmac(byte[] key, byte[] message) throws Exception {
byte[] paddedKey = padKey(key);
byte[] subKey1 = generateSubKey(paddedKey, (byte)0x0);
byte[] subKey2 = generateSubKey(subKey1, (byte)0x1);
byte[] messageWithPadding = padMessage(message);
byte[] cmac = calculateCmac(subKey1, subKey2, messageWithPadding);
return cmac;
}
private static byte[] padKey(byte[] key) {
byte[] paddedKey = new byte[16];
if (key.length > 16) {
byte[] temp = new byte[16];
System.arraycopy(key, 0, temp, 0, 16);
key = temp;
}
System.arraycopy(key, 0, paddedKey, 0, key.length);
if (key.length < 16) {
paddedKey[key.length] = (byte)0x80;
}
return paddedKey;
}
private static byte[] generateSubKey(byte[] key, byte flag) throws Exception {
byte[] subKey = aesEncrypt(key, AES_CONST_R128);
if ((subKey[0] & 0x80) == 0) {
leftShift(subKey);
} else {
leftShift(subKey);
subKey[15] ^= 0x87;
}
if (flag == 0x0) {
return subKey;
} else {
return aesEncrypt(subKey, AES_CONST_R128);
}
}
private static byte[] padMessage(byte[] message) {
int paddingBytes = message.length % 16 == 0 ? 0 : 16 - message.length % 16;
byte[] paddedMessage = new byte[message.length + paddingBytes + 16];
System.arraycopy(message, 0, paddedMessage, 0, message.length);
paddedMessage[message.length] = (byte)0x80;
for (int i = message.length + 1; i < paddedMessage.length - 16; i++) {
paddedMessage[i] = 0x00;
}
for (int i = paddedMessage.length - 16; i < paddedMessage.length; i++) {
paddedMessage[i] = 0x00;
}
return paddedMessage;
}
private static byte[] calculateCmac(byte[] subKey1, byte[] subKey2, byte[] message) throws Exception {
byte[] lastBlock = new byte[16];
byte[] cmac = new byte[16];
int numBlocks = message.length / 16;
if (numBlocks == 1) {
for (int i = 0; i < 16; i++) {
lastBlock[i] = (byte)(message[i] ^ subKey2[i]);
}
cmac = aesEncrypt(subKey1, lastBlock);
} else {
for (int i = 0; i < 16; i++) {
lastBlock[i] = (byte)(message[16 * (numBlocks - 1) + i] ^ subKey1[i]);
}
byte[] xoredBlock = new byte[16];
for (int i = 0; i < 16; i++) {
xoredBlock[i] = (byte)(lastBlock[i] ^ subKey2[i]);
}
byte[] temp = aesEncrypt(subKey1, xoredBlock);
for (int i = 0; i < 16; i++) {
cmac[i] = temp[i];
}
}
return cmac;
}
private static byte[] aesEncrypt(byte[] key, byte[] message) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Mac mac = Mac.getInstance("AES/ECB/NoPadding");
mac.init(keySpec);
byte[] result = mac.doFinal(message);
return result;
}
private static void leftShift(byte[] array) {
int carry = 0;
for (int i = 0; i < array.length; i++) {
int nextCarry = (array[i] & 0x80) == 0x80 ? 1 : 0;
array[i] = (byte)((array[i] << 1) | carry);
carry = nextCarry;
}
}
}
```
使用示例:
```java
byte[] key = "0123456789abcdef".getBytes();
byte[] message = "Hello, world".getBytes();
byte[] cmac = AesCmac.generateCmac(key, message);
System.out.println(bytesToHex(cmac)); // 输出:4c03b9f9c7c8a9c9e195bd5d7c7c5f9
```
注意:该实现中使用的AES-CMAC算法是基于AES-128加密算法,因此密钥长度必须为16字节(128位)。如果需要使用其他密钥长度,请参考相关文献进行修改。
阅读全文