Java/Android - 使用4字节MIC解密AES/CCM
问题描述:
我试图解密一些蓝牙模块加密的测试数据。如果有问题,蓝牙的固件是用C编程的。Java/Android - 使用4字节MIC解密AES/CCM
加密的数据是:
// Test Bytes - 16 bytes
byte[] testInput = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
// Test key - 16 bytes, 128-bit
byte[] keyBytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
// Test nonce - 13 bytes, 104-bit
byte[] nonce = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
0x0a,0x0b,0x0c};
这里的问题。使用AES/CCM对C中的数据进行加密,产生一个16字节的输出和一个4字节的MIC。当我使用Java中的AES/CCM/NoPadding加密数据时,输出也是16个字节,但有8个字节的MAC。术语MAC和MIC似乎不明确,其中MIC用于蓝牙术语。
当我使用Java对上述testInput进行加密时,我得到了与C编程加密相同的16字节输出。但是,由于MIC和MAC的长度不同,我无法解密任何一端的数据。
有没有解决方案?
我增加了我的Java代码:
Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding", "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(nonce);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(testInput);
// The first 16 bytes print out equivalently with the C-language AES/CCM
下面是我输出的图像:
下面是C输出的图像。
BLE广告包
答
下面的Java代码将产生输出的C代码相同:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Security;
public class Main {
// Test Bytes - 16 bytes
static byte[] testInput = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
// Test key - 16 bytes, 128-bit
static byte[] keyBytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
// Test nonce - 13 bytes, 104-bit
static byte[] nonce = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c};
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
GCMParameterSpec parameterSpec = new GCMParameterSpec(32, nonce);
Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, parameterSpec);
cipher.updateAAD(new byte[]{0x01});
System.out.println(DatatypeConverter.printHexBinary(cipher.doFinal(testInput)));
}
}
不过,我不知道如何找到要提供给Cipher.updateAAD()
的字节。 0x01
是通过试验和错误发现的。试图阅读蓝牙4.0规范是相当痛苦的。该规范似乎认为该字节是数据包头的第一个字节,其中3个位(NESN,SN,MD)被强制归零。剩下的部分我仍然试图弄清楚。
对于蓝牙,MIC计算超过3个附加字节 - 0x00,0x01,以及从PDU报头的第一个字节计算的字节。没有那个字节,你不能得到相同的MIC。 –
@JamesKPolk你如何建议我来回传递数据?我一直在寻找解决方案的天。如果你能进一步帮助我,我会非常感激。 – FoxDonut
首先我要弄清楚MIC是如何生成的/ –