BLE 加密详解

Posted 车子 chezi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BLE 加密详解相关的知识,希望对你有一定的参考价值。


BLE 协议里面的加密,可以用硬件实现,也可以用软件实现。本文讨论如何用软件实现,借用开源代码。

求 MIC

MIC 占 4 个字节。先说如何计算 MIC。

B0

B0 = 0x49 || nonce || length

B0 的格式是协议规定的

注意:||表示串联,左边是低字节,右边是高字节

length 占 2 个字节

Nonce

低 39 bits 是 packetCounter,然后是 1 bit 的方向位(M 到 S 是 1,S 到 M 是 0),最后是 8 字节的 IV

B1

B1 = 0x0001 || headermasked || 0x00000000000000000000000000

headermasked 是什么,其实就是 2 bits 的 LLID

B2 和 B3

B2 contains the payload data from octets 0 to 15.

B3 contains the payload data from octets 16 to 26.

计算公式

弄明白了 B0-B3,就能看懂协议上的数据了。

补充一下,B0 中的 packetCounter 是 0,方向是 1;B1 中的 03 表示 LLID;B2 中的 06 是 payload,是 START_ENC_RSP 的明文。

计算 MIC 的公式是:

因为没有 B3,所以只用计算前 3 行。公式中的 X0 是协议里面的 X1,公式中的 X1 是协议里面的 X2,公式中的 X2 是协议里面的 X3,只是叫法不一样。

先把结果摆出来,看看怎么编程实现。

代码

char *SK_str = "99AD1B5226A37E3E058E3B8E27C2C666";  // MS-LS
char *B0_str = "49000000008024ABDCBABEBAAFDE0001";  // LS-MS
char *B1_str = "00010300000000000000000000000000";  // LS-MS
char *B2_str = "06000000000000000000000000000000";  // LS-MS


int hex_string_to_u8(const char *hex_str, char *out)
{
    if(strlen(hex_str) & 1){
        printf("字符串的长度是奇数!");
        return -1;
    }
    
    char byte[3] = {0};
    const char *p = hex_str;
    int j = 0;
       
    for(int i=0; i<strlen(hex_str); i+=2){
        memcpy(byte, &p[i], 2);
        out[j++] = strtol(byte, NULL, 16);
    } 
    return 0;
}

int main(void)
{    
    uint8_t temp[16] = {0};
    uint8_t X1[16] = {0};
    uint8_t X2[16] = {0};
    uint8_t X3[16] = {0};
  
    hex_string_to_u8(SK_str, SK);
    hex_string_to_u8(B0_str, B0);
    hex_string_to_u8(B1_str, B1);
    hex_string_to_u8(B2_str, B2);
    
// X1 = E(B0)
// X2 = E(X1 xor B1)
// X3 = E(X1 xor B2)

	aes128_calc_cyphertext(SK, B0, X1);
    hexdump("X1", X1, 16);
    
    xor(X1, B1, temp, 16);
    aes128_calc_cyphertext(SK, temp, X2);  
    hexdump("X2", X2, 16);
    
    xor(X2, B2, temp, 16);
    aes128_calc_cyphertext(SK, temp, X3);
    hexdump("X3", X3, 16);
    
	hexdump("MIC", X3, 4);
}

hex_string_to_u8 这个函数的作用是把十六进制的字符串转成数字,解释见我的博文:C语言16进制字符串转数字_车子(chezi)-CSDN博客

SK_str 经这样转换后,其实是大端序,低地址存放着高字节;

B0_str 等转换后是小端序;

aes128_calc_cyphertext 这个函数是别人的代码,注释是我加的。

/**
 * @brief Calculate ciphertext with AES-128
 * @key: [in] note: big endian
 * @plaintext :[in]  little endian
 * @cyphertext:[out] little endian
 * @returns void
 */
void aes128_calc_cyphertext(uint8_t key[16], 
                            uint8_t plaintext[16], uint8_t cyphertext[16])
{
	uint32_t rk[RKLENGTH(KEYBITS)];
	int nrounds = rijndaelSetupEncrypt(rk, &key[0], KEYBITS);
	rijndaelEncrypt(rk, nrounds, plaintext, cyphertext);
}

xor 这个函数是我写的,用来求异或。文末会附上完整的代码。

hexdump 是一个简单的打印函数。

运行结果是:

X1: 71 2E AA AA E6 06 03 52 1D 24 5E 50 78 6E EF E4 
X2: DE BC 43 78 2A 02 26 75 FC A0 AA 6F 08 54 F1 AB 
X3: 63 99 91 3F ED E5 FA 11 1B DB 99 3B BF B9 BE 06 
MIC: 63 99 91 3F 

和协议相符。

求加密数据

Ai

对照协议中的

A0 = 01000000008024ABDCBABEBAAFDE0000
A1 = 01000000008024ABDCBABEBAAFDE0001

注意:

  • counter i 是块计数器,在加密净荷的前 16 字节时,块计数器应设为 0x0001
  • 在加密净荷的后 11 字节时,块计数器应设为 0x0002
  • 对 MIC 进行加密的时候,块计数器应设为 0x0000

因为要加密的净荷只有 1 个字节,所以没有 A2

计算公式

协议给出:

S0 = ae3e6577f64a8f25408c9c10d53acf8e
S1 = 99190d88f4aa1b60b97ecfe6f5fee777

S0 = E(A0)

S1 = E(A1)

公式中的 CMIC 应该是 S0 的低 4 个字节

公式中的 CBlock1 就是 S1

第二个公式中的 Block1 表示净荷的前 16 字节,就是前文的 B2;Block2 表示净荷的后 11 字节,就是前文的 B3

综上,计算出 S0 和 S1 是关键

代码

// S0 = E(A0)    
// S1 = E(A1)      
    uint8_t S0[16] = {0};
    uint8_t S1[16] = {0};
    hex_string_to_u8(A0_str, A0);   
    hex_string_to_u8(A1_str, A1);
    
    aes128_calc_cyphertext(SK, A0, S0);
    hexdump("S0", S0, 16);
    
    aes128_calc_cyphertext(SK, A1, S1);
    hexdump("S1", S1, 16);   
    
    // encrypted MIC = S0 xor X3
    xor(S0, X3, temp, 4);
    hexdump("encrypted MIC", temp, 4);
    // encrypted packet payload  = S1 xor B2
    xor(S1, B2, temp, 4);
    hexdump("encrypted packet payload", temp, 1);

执行结果是:

S0: AE 3E 65 77 F6 4A 8F 25 40 8C 9C 10 D5 3A CF 8E 
S1: 99 19 0D 88 F4 AA 1B 60 B9 7E CF E6 F5 FE E7 77 
encrypted MIC: CD A7 F4 48 
encrypted packet payload: 9F 

和协议的结果比较一下:

So, encrypted packet payload = 9F
    encrypted MIC = CDA7F448

遗留问题

对于 5.0,payload 的长度可以是 255,那是不是还有 B4,B5,B6,…?

参考资料

【1】《Bluetooth Core Specification v 5.0》 P2699

【2】http://www.efgh.com/software/rijndael.htm

【3】《Bluetooth Low Energy :The Developer’s Handbook》7.9. Encryption

完整代码

rijndael.h

// =============================== RIJNDAEL.H   ===============================
// from http://www.efgh.com/software/rijndael.htm,
// License: Public Domain, 
// Author:  Philip J. Erdelsky

#ifndef H__RIJNDAEL
#define H__RIJNDAEL

#include <stdint.h>

int rijndaelSetupEncrypt(uint32_t *rk, const uint8_t *key, int keybits);
int rijndaelSetupDecrypt(uint32_t *rk, const uint8_t *key, int keybits);
void rijndaelEncrypt(const uint32_t *rk, int nrounds, const uint8_t plaintext[16], uint8_t ciphertext[16]);
void rijndaelDecrypt(const uint32_t *rk, int nrounds, const uint8_t ciphertext[16], uint8_t plaintext[16]);
	
#define KEYBITS 128

#define KEYLENGTH(keybits) ((keybits)/8)
#define RKLENGTH(keybits)  ((keybits)/8+28)
#define NROUNDS(keybits)   ((keybits)/32+6)

#endif

rijndael.c

//=============================== RIJNDAEL.C   ===============================
// from http://www.efgh.com/software/rijndael.htm,
// License: Public Domain, 
// Author:  Philip J. Erdelsky

#define FULL_UNROLL
//#include <stdio.h>
#include "rijndael.h"

typedef uint32_t u32;
typedef uint8_t   u8;

static const u32 Te0[256] =
{
  0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
  0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
  0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
  0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
  0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
  0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
  0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
  0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
  0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
  0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
  0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
  0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
  0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
  0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
  0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
  0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
  0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
  0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
  0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
  0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
  0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
  0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
  0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
  0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
  0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
  0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
  0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
  0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
  0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
  0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
  0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
  0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
  0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
  0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
  0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
  0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
  0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
  0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
  0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
  0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
  0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
  0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
  0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
  0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
  0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
  0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
  0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
  0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
  0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
  0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
  0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
  0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
  0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
  0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
  0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
  0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
  0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
  0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
  0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
  0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
  0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
  0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
  0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
  0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};

static const u32 Te1[256] =
{
  0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
  0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
  0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
  0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
  0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
  0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
  0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
  0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
  0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
  0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
  0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
  0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
  0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
  0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
  0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
  0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
  0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
  0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
  0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
  0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
  0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
  0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
  0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
  0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
  0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
  0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
  0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
  0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
  0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
  0xad3f9292U如何使用 Bluez5.50 使用 BLE 连接加密数据

低功耗蓝牙BLE之AES-128加密算法

详解BLE 空中包格式—兼BLE Link layer协议解析

如何在 bt 4.0 加密狗中禁用蓝牙经典

蓝牙协议分析(11)_BLE安全机制之SM

Android BLE基础框架使用详解