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循环即可。
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;
}
测试效果
但是
这不是IMSI 所以上面的代码有问题,我们来抓一下IMSI的数据包来看一下
解释一下就是: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;
}
验证结果: