关于C#:用于将十六进制字符串转换为字节数组的预处理器宏

Pre-processor macro to convert an hex string to a byte array

我在我的IDE中定义了一个aes-128密钥作为构建符号,因此它调用gcc如下:

1
arm-none-eabi-gcc -D"AES_KEY=3B7116E69E222295163FF1CAA1681FAC" ...

(相当于#define AES_KEY 3B7116E69E222295163FF1CAA1681FAC)

其优点是,相同的符号也可以作为参数自动传递给构建后的CLI脚本,该脚本使用此密钥加密已编译的代码(例如,用于安全固件更新)。

但是如何将这个键作为字节数组存储在我的代码?我想定义一个执行转换的预处理器宏:

1
uint8_t aes_key[] = { SPLIT_MACRO(AES_KEY) };

1
uint8_t aes_key[] = {0x3B, 0x71, 0x16, 0xE6, 0x9E, 0x22, 0x22, 0x95, ...};

换言之,GCC预处理器可以将密钥字符串拆分为2个字符块,并在它们之间添加", 0x"。


有点笨拙,但是如果你事先知道钥匙的长度,你可以按如下方式接近它:

  • 定义将十六进制数字转换为数字的宏HEXTONIBBLE
  • 定义使用HEXTONIBBLE从十六进制中获取字节的宏HEXTOBYTE
  • 使用正确参数化的HEXTOBYTE初始化数组
  • 如果您的KEY不是字符串形式,即用双引号括起来,则使用stringify运算符#(使用可变宏的技巧,以便在用作参数或另一个参数时扩展宏):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    //           01234567890123456789012345678901
    #define K    3B7116E69E222295163FF1CAA1681FAC

    #define STRINGIFY_HELPER(A) #A
    #define STRINGIFY(...) STRINGIFY_HELPER(__VA_ARGS__)

    #define KEY  STRINGIFY(K)

    #define HEXTONIBBLE(c) (*(c) >= 'A' ? (*(c) - 'A')+10 : (*(c)-'0'))

    #define HEXTOBYTE(c) (HEXTONIBBLE(c)*16 + HEXTONIBBLE(c+1))

    uint8_t aes_key[] = {
        HEXTOBYTE(KEY+0),
        HEXTOBYTE(KEY+2),
        HEXTOBYTE(KEY+4),
        HEXTOBYTE(KEY+6),
        HEXTOBYTE(KEY+8),
        HEXTOBYTE(KEY+10),
        HEXTOBYTE(KEY+12),
        HEXTOBYTE(KEY+14),
        HEXTOBYTE(KEY+16),
        HEXTOBYTE(KEY+18),
        HEXTOBYTE(KEY+20),
        HEXTOBYTE(KEY+22),
        HEXTOBYTE(KEY+24),
        HEXTOBYTE(KEY+26),
        HEXTOBYTE(KEY+28),
        HEXTOBYTE(KEY+30)
    };

    int main() {

        for (int i=0; i<sizeof(aes_key); i++) {
            printf("%02X", aes_key[i]);
        }

        return 0;
    }

    输出:

    1
    3B 71 16 E6 9E 22 22 95 16 3F F1 CA A1 68 1F AC


    这不会回答原始问题,但如果密钥可以改为这种格式:

    1
    #define AES_KEY 3B,71,16,E6,9E,22,22,95,16,3F,F1,CA,A1,68,1F,AC

    以下宏将工作,即使在GCC下:

    1
    2
    3
    4
    5
    6
    #define BA(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) {0x##a,0x##b,0x##c,0x##d,\
    0x##e,0x##f,0x##g,0x##h,0x##i,0x##j,0x##k,0x##l,0x##m,0x##n,0x##o,0x##p}


    #define TO_BYTEARRAY(...) BA(__VA_ARGS__)

    uint8_t aes_key[] = TO_BYTEARRAY(AES_KEY);

    参见串联、参数预扫描和变量宏