2017-09-26 108 views
1

我試圖解密一些藍牙模塊加密的測試數據。如果有問題,藍牙的固件是用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 

下面是我輸出的圖像:

enter image description here

下面是C輸出的圖像。

enter image description here

BLE廣告包

enter image description here

+1

對於藍牙,MIC計算超過3個附加字節 - 0x00,0x01,以及從PDU報頭的第一個字節計算的字節。沒有那個字節,你不能得到相同的MIC。 –

+0

@JamesKPolk你如何建議我來回傳遞數據?我一直在尋找解決方案的天。如果你能進一步幫助我,我會非常感激。 – FoxDonut

+1

首先我要弄清楚MIC是如何生成的/ –

回答

1

下面的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)被強制歸零。剩下的部分我仍然試圖弄清楚。

+0

雖然0x01是這個頭文件頭的第一個字節,但是我們是否認爲這應該總是這樣? – FoxDonut

+0

@FoxDonut:不,我認爲有三個可能的值,1,2和3.但規範是相當混亂。你有權訪問標題? –

+0

我的工程師在控制代碼的C部分。我會要求他送我一切可用的頭球。我應該特別要求什麼? – FoxDonut