BCD码与IMSI信令

441 阅读3分钟

8421BCD码与IMSI信令

国际移动用户识别码(英语:IMSI,International Mobile Subscriber Identity),是用于区分蜂窝网络中不同用户的、在所有蜂窝网络中不重复的识别码。手机将IMSI存储于一个64比特的字段发送给网络。

BCD码又被称为8421BCD码。用4个二进制的数字来表示一个10进制数 例如example:

1   0001
2   0010
3   0011
4   0100
5   0101
6   0110
7   0111
8   1000
9   1001

十进制最大值是9 即对应的8421BCD码就是1001


目标:将传进来的ascii码转成BCD码

示例: 12345678 <-> 0001 0010 0011 0100 0101 0110 01111 0000 0000 0000 0000 0000 0000 0000

算法:

第一个ascii数 左移63 [64 - 4*0 - 1]

第二个ascii数 左移59 [64 - 4*1 - 1]

第三个ascii数 左移55 [64 - 4*2 - 1]

...

第n个ascii数 左移[64 - 4*(n-1) -1]位置

进行或运算即可得到。

剩下的数字依次loop循环即可。 e927af3f8dfa996803ae68da259d4e3.jpg

BCD编码

/*
 * @brief : check string whether alldigits
 * @param : str  : 
 * @return: str is alldigits return true.
 *          otherwise return false.
*/
static int isAlldigit(char * str)
{
    char * tmp = str;
    while(*tmp)
    {
        if(!isdigit(*tmp))
        {
            return false;
        }
        tmp++;
    }
    return true;
}

/*
 * @brief : asciicode convert bcdencode
 * @param : ascii  : ascii to be converted
 *          ascii_size : length of ascii
 *          bcd : bcd encoding after conversion
 * @return: success return zero.
 *          fail return -1.
 *  
 * @example:12345678 <-> 0001 0010 0011 0100 0101 0110 01111 0000 0000 0000 0000 0000 0000 0000 0000 0000
*/
int bcd_encode(char *ascii, int ascii_size, __uint64_t *bcd)
{
    if (!ascii || !isAlldigit(ascii) || !bcd || ascii_size > 16)
    {
        return -1;
    }
    /* loop variable */
    int idx = 0;
    /* 1B <-> 8bits */
    int bcd_max_idx = sizeof(*bcd) * 2;
    for (idx = 0; idx < ascii_size; idx++)
    {
        *bcd |= ((__uint64_t)(ascii[idx] - '0') & 0XF) << ((bcd_max_idx - idx  - 1) * 4); 
    }
    return 0;
}

打印

static __uint64_t bit64_mask(__uint64_t bcd, int whichbit)
{
    __uint64_t bit_check = 0;

    bit_check = bcd << (63 - whichbit);
    bit_check = bit_check >> 63;

    return bit_check;
}

void bit64_mask_print(__uint64_t bcd)
{
    /* 8B = 64bit as loop variable */
    int bitlen = sizeof(bcd) * 8;
    int idx = bitlen - 1;
    for (idx; idx >= 0; --idx)
    {
        printf("%c", (int)bit64_mask(bcd, idx) + '0');
        if (idx % 4 == 0)
        {
            printf(" ");    /* 4 bits once interval */
        }
    }
    printf("\n");
}

测试代码

int main()
{
    char *str = "123456789";
     __uint64_t bcd = 0;
    bcd_encode(str, strlen(str), &bcd);
    
    printf("str:%s\n", str);
    printf("bcd:%lu\n", bcd);
    bit64_mask_print(bcd);
    
    return 0;
}

测试效果 image.png


但是

这不是IMSI 所以上面的代码有问题,我们来抓一下IMSI的数据包来看一下

企业微信截图_16670079982560.png

解释一下就是:460013281320884 其中strlen("460013281320884") = 15 不足8Bytes的需要用0XF补齐。

重新编码:

/* Definition of Struct*/
typedef struct KEY
{
    union
    {
        __uint64_t bcd;
        struct
        {
            __uint8_t data[8];
        }__attribute__((packed)) tmpdata;
    };
}__attribute__((packed)) KEY_T;

/*
 * @brief : asciicode convert bcdencode
 * @param : ascii  : ascii to be converted
 *          ascii_size : length of ascii
 *          bcd : bcd encoding after conversion
 * @return: success return zero.
 *          fail return -1.
 *  
 * @example: 460013281320884 
 *          HEX <-> 0X64 0X0 0X31 0X82 0X31 0X2 0X88 0Xf4
 *          <-> 0110 0100 | 0000 0000 | 0011 0001 | 1000 0010 | 0011 0001 | 0000 0010 | 1000 1000 | 1111 0100
*/
int bcd_encode(char *ascii, int ascii_size)
{
    if (!ascii || ascii_size > 16)
    {
        return -1;
    }
    /* loop variable */
    int idx = 0;

    /* 1B <-> 8bits */
    KEY_T key;
    for (idx = 0; (idx < 8) && ((idx * 2) < ascii_size); idx++)
    {
        key.tmpdata.data[idx] = (((ascii[idx * 2] - '0') & 0XF) | ((ascii[idx * 2 + 1] - '0') & 0XF) << 4);
        printf("0X%x ", key.tmpdata.data[idx]);
    }
    printf("\n");
    return 0;
}

测试代码

int main()
{
    int idx = 0;
    char buf1[128] = "460013281320884";
    char buf2[128] = "123456789";
    char buf3[128] = "1234567890";

    int len1 = strlen(buf1);
    int len2 = strlen(buf2);
    int len3 = strlen(buf3);

    printf("buf1:%s\n", buf1);
    for (idx = len1; idx < 16; ++idx)
    {
        buf1[idx] = 0xf + '0';
    }
    bcd_encode(buf1, strlen(buf1));

    printf("buf2:%s\n", buf2);
    for (idx = len2; idx < 16; ++idx)
    {
        buf2[idx] = 0xf + '0';
    }
    bcd_encode(buf2, strlen(buf2));

    /* 对于buf3 单独处理 验证字节序的问题 */
    printf("buf3:%s\n", buf3);
    if (len3 % 2)
    {
        buf3[idx] = 0xf + '0';
    }
    len3 = strlen(buf3);
    bcd_encode(buf3, len3);

    printf("buf3:%s\n", buf3);
    for (idx = len3; idx < 16; ++idx)
    {
        buf3[idx] = 0xf + '0';
    }
    bcd_encode(buf3, strlen(buf3));

    return 0;
}

验证结果:

image.png