IMSI编码规则与奇偶校验算法

来源:互联网 发布:医学生必备软件 编辑:程序博客网 时间:2024/06/10 07:11

1. 背景

在TS311.02中,介绍了IMSI的编码规则,其中涉及到奇偶校验算法。本文以此为引子,简单介绍奇偶校验的C算法,可作为C练习题的素材。


1.1 SIM卡

在手机中,都会插上一个SIM卡。当然,大家经常会在媒体上听到3G、4G等概念,从这个意义上,我们不能简单地称为SIM卡,即存在SIM、USIM、R-SIM等区别。不过这已经超出本文的讨论范围了。本文就简单地说成SIM卡。


1.2 IMSI号

在SIM卡中,存储了大量的数据,其中就有IMSI号。IMSI号是一串十进制数,通常是15位(本文简单地假定为15位)。在SIM卡中存储这个IMSI信息的格式,在3GPP TS31.102协议中有具体的规定。截图如下:


在Byte2的低四位比特,b4是奇偶校验码。


1.3 奇偶校验码

奇偶校验码是数字电路或数字逻辑中的一个基本概念,其思想就是通过检查码流中每个比特位取1的总个数为奇数或偶数。为此,会在码流中定义个比特位(术语即为冗余位),称为奇偶校验码。通过设置这个比特位为0或1,让整个码流中1的个数为偶数或奇数。如果要求从个数为偶数,就称为偶校验;如果为奇数,则是奇校验。


就本文的IMSI存储来讲,使用的是偶校验。即通过设置Byte2-b4为0或1,让整个IMSI码流的9个字节(包括表示长度的第一个字节)中1的总数为偶数个。


至此,引出本文的重点,奇偶校验算法。


2. 奇偶校验算法

2.1 问题简化

我们可以假定byte2-b4=0,然后计算整个码流的奇偶校验结果。如果是偶数个1,则byte2-b4保持不变;否则设置为1。由此,问题简化为:计算一个码流中比特为1的个数,如果是偶数个,则返回0x00;否则,返回0x01。即函数原型如下:

/* return:            0x00: All the number of the 1-bit is even.           0x01: All the number of the 1-bit is odd.*/unsigned char even_parity(const unsigned char *buffer, unsigned int len);


2.2 最自然&简单的算法

首先我们给出最简单的一种算法,即扫描码流中的每一个比特,给出奇偶判别结果。需要指出的是,因为只需要给出奇偶结果,而不是具体的个数,所以这里使用异或运算。


代码如下:

#include <stdio.h>/* return:            0x00: All the number of the 1-bit is even.           0x01: All the number of the 1-bit is odd.*/unsigned char even_parity(const unsigned char *buffer, unsigned int len){    unsigned int i, j;    unsigned char check_bit = 0;        for (i = 0; i < len; i++) {        for (j = 0; j < 8; j++) {            check_bit ^= (buffer[i] >> j) & 0x01;        }    }    return check_bit;}/* For simplity, the gtest is not used here. */void my_assert(const char* testcase_name, int value){    if (value) {        printf("PASS: %s\n", testcase_name);    } else {        printf("FAIL: %s\n", testcase_name);    }}void test() {    unsigned char test_data1[] = {0x00};    unsigned char expect1 = 0;    unsigned char test_data2[] = {0x80};    unsigned char expect2 = 1;    unsigned char test_data3[] = {0x00, 0x80};    unsigned char expect3 = 1;    unsigned char test_data4[] = {0x00, 0xc0};    unsigned char expect4 = 0;    my_assert("testcase1", expect1 == even_parity(test_data1, sizeof(test_data1)));    my_assert("testcase2", expect2 == even_parity(test_data2, sizeof(test_data2)));    my_assert("testcase3", expect3 == even_parity(test_data3, sizeof(test_data3)));    my_assert("testcase4", expect4 == even_parity(test_data4, sizeof(test_data4)));}int main(){    test();    return 0;}


执行结果:

PASS: testcase1PASS: testcase2PASS: testcase3PASS: testcase4

2.3 比特运算改成字节运算

前面的代码采用的是逐个比特的运算,如果清楚了异或的运算特点,我们可以把比特级运算改造成字节级运算。对应的代码如下:

unsigned char even_parity(const unsigned char *buffer, unsigned int len){    unsigned int i, j;    unsigned char check_bit = 0;    unsigned char temp = 0x00;        for (i = 0; i < len; i++) {        temp ^= buffer[i];    }    for (j = 0; j < 8; j++) {        check_bit ^= (temp >> j) & 0x01;    }    return check_bit;}

2.4 进一步消除循环

在上面的算法的思路下,可以进一步把计算一个字节的奇偶性改成折半异或算法。代码如下:

unsigned char even_parity(const unsigned char *buffer, unsigned int len){    unsigned int i, j;    unsigned char temp = 0x00;        for (i = 0; i < len; i++) {        temp ^= buffer[i];    }    /* temp: B7 B6 B5 B4 B3 B2 B1 B0 */    temp = (temp & 0x0F) ^ (temp >> 4);  /* B7B6B5B4 ^ B3B2B1B0*/    temp = (temp & 0x03) ^ (temp >> 2);  /* B3B2 ^ B1B0*/    temp = (temp & 0x01) ^ (temp >> 1);  /* B1 ^ B0*/    return temp;}

2.5 小结

对于奇偶校验算法,我们给出了几种算法。通过这种简单代码的比较,来体现代码结构优化、算法优化、或性能优化,以及代码可读性、可维护性等质量维度。


3. 附录 3GPP协议

感兴趣的读者,可以下载本文提到的协议文档。下载入口网址是http://www.3gpp.org/ftp/Specs/,或者(例如)http://www.3gpp.org/DynaReport/31102.htm。 对于后一种方式,直接把网址后面的写成自己要下载的协议的数字串即可。


0 0
原创粉丝点击