【安信可首款4G模组CA-01直连阿里物联网平台④】HmacMD5算法

系列专题

1.【安信可首款4G模组CA-01直连阿里物联网平台①】产品创建
2.【安信可首款4G模组CA-01直连阿里物联网平台②】一机一密认证方式连接
3.【安信可首款4G模组CA-01直连阿里物联网平台③】一型一密认证方式连接
4.【安信可首款4G模组CA-01直连阿里物联网平台④】HmacMD5算法
5.【安信可首款4G模组CA-01直连阿里物联网平台⑤】空间数据可视化,将你的物联网设备位置快速接入到地图上
    
    
    

一.前言

    4G模块连接阿里云都用到一个sign,这个sign是HmacMD5 算法计算出来的哈希值。什么是HmacMD5 ?
1、比如你和对方共享了一个密钥K,现在你要发消息给对方,既要保证消息没有被篡改,又要能证明信息确实是你本人发的,那么就把原信息和使用K计算的HMAC的值一起发过去。对方接到之后,使用自己手中的K把消息计算一下HMAC,如果和你发送的HMAC一致,那么可以认为这个消息既没有被篡改也没有冒充。
2、MD5就是通过散列对要输出的数据进行摘要,接收到数据时,再同样进行MD5散列,与给定的MD5散列值比较,一致不一致就很清楚了。通常来说,传输的数据和MD5是不同的渠道给出的,比如网页上显示MD5,下载链接是某个镜像网站的。如果要通过同一个渠道发送数据和散列值的话(比如消息认证码),就要考虑数据和MD5同时被篡改的问题,如果第三方修改了数据,然后进行MD5散列,并一块发给接收方,接收方并不能察觉到数据被篡改。HMAC-MD5就可以用一把发送方和接收方都有的key进行计算,而没有这把key的第三方是无法计算出正确的散列值的,这样就可以防止数据被篡改。

二.HmacMD5 算法计算流程:

(1) 在密钥key后面添加0来创建一个长为B(64字节)的字符串(str)。
(2) 将上一步生成的字符串(str)与ipad(0x36)做异或运算,形成结果字符串(istr)。
(3) 将数据流data附加到第二步的结果字符串(istr)的末尾。
(4) 做md5运算于第三步生成的数据流(istr)。
(5) 将第一步生成的字符串(str)与opad(0x5c)做异或运算,形成结果字符串(ostr)。
(6) 再将第四步的结果(istr)附加到第五步的结果字符串(ostr)的末尾。
(7) 做md5运算于第六步生成的数据流(ostr),输出最终结果(out)。

三.3.HmacMD5 算法实现

/*
 * function: AXK_HMAC_MD5
 * parameter: u8 *inBuffer - 需要加密的字符串
 *            u16 len - 字符串长度
 *            u8 *ky - 初始密钥
 *            u8 output[16] - 输出
 */
void AXK_HMAC_MD5(unsigned char *inBuffer, unsigned int len, unsigned char *ky, unsigned char *pUserOut)
 {
	int i, j;
	unsigned char output[16], str[32];
	unsigned char *tempBuffer = (unsigned char *) mymalloc(len + 64); //第一次HASH的参数
	unsigned char Buffer2[80];  //第二次HASH

	unsigned char key[64];
	unsigned char ipad[64], opad[64];

	memset(key, 0, 64);

	if (strlen(ky) > 64) {			// 如果密钥长度大于64,使用key的md5值替换key
		AXK_MD5Digest(ky, strlen(ky), key);
	} else {
		strncpy(key, ky, 64);
	}

	for (i = 0; i < 64; i++) {
		ipad[i] = 0x36;
		opad[i] = 0x5c;
	}

	for (i = 0; i < 64; i++) {
		ipad[i] = key[i] ^ ipad[i];   ///K ⊕ ipad
		opad[i] = key[i] ^ opad[i];   //K ⊕ opad
	}

	for (i = 0; i < 64; i++) {
		tempBuffer[i] = ipad[i];
	}

	for (i = 64; i < len + 64; i++) {
		tempBuffer[i] = inBuffer[i - 64];
	}

	AXK_MD5Digest(tempBuffer, len + 64, output); //做md5运算

	for (j = 0; j < 64; j++) {
		Buffer2[j] = opad[j];
	}

	for (i = 64; i < 80; i++) {
		Buffer2[i] = output[i - 64];
	}

	AXK_MD5Digest(Buffer2, 80, output);// 做md5运算

	//  再一次转换为字符串
	for (i = 0; i < 16; i++) {
		str[2 * i] = output[i] >> 4;
		str[2 * i + 1] = output[i] & 0xf;
	}
	for (i = 0; i < 33; i++) {
		sprintf(&pUserOut[i], "%x", str[i]);
	}
	pUserOut[32] = '\0';

	myfree(tempBuffer);
}

MD5算法实现

typedef struct {
	unsigned int count[2];
	unsigned int state[4];
	unsigned char buffer[64];
} AXK_MD5_CTX;

#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))

#define FF(a,b,c,d,x,s,ac) do{ \
a += F(b, c, d) + x + ac; \
a = ROTATE_LEFT(a, s); \
a += b; \
} while(0)

#define GG(a,b,c,d,x,s,ac) do { \
a += G(b, c, d) + x + ac; \
a = ROTATE_LEFT(a, s); \
a += b; \
} while(0)

#define HH(a,b,c,d,x,s,ac) do { \
a += H(b, c, d) + x + ac; \
a = ROTATE_LEFT(a, s); \
a += b; \
}while(0)

#define II(a,b,c,d,x,s,ac) do{ \
a += I(b, c, d) + x + ac; \
a = ROTATE_LEFT(a, s); \
a += b; \
}while(0)

unsigned char PADDING[] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

void AXK_MD5Init(AXK_MD5_CTX *context) {
	context->count[0] = 0;
	context->count[1] = 0;
	context->state[0] = 0x67452301;
	context->state[1] = 0xEFCDAB89;
	context->state[2] = 0x98BADCFE;
	context->state[3] = 0x10325476;
}

void AXK_MD5Update(AXK_MD5_CTX *context, unsigned char *input,
		unsigned int inputlen) {
	unsigned int i = 0, index = 0, partlen = 0;
	index = (context->count[0] >> 3) & 0x3F;
	partlen = 64 - index;
	context->count[0] += inputlen << 3;
	if (context->count[0] < (inputlen << 3))
		context->count[1]++;
	context->count[1] += inputlen >> 29;

	if (inputlen >= partlen) {
		memcpy(&context->buffer[index], input, partlen);
		AXK_MD5Transform(context->state, context->buffer);
		for (i = partlen; i + 64 <= inputlen; i += 64)
			AXK_MD5Transform(context->state, &input[i]);
		index = 0;
	} else {
		i = 0;
	}
	memcpy(&context->buffer[index], &input[i], inputlen - i);
}

void AXK_MD5Final(AXK_MD5_CTX *context, unsigned char digest[16]) {
	unsigned int index = 0, padlen = 0;
	unsigned char bits[8];
	index = (context->count[0] >> 3) & 0x3F;
	padlen = (index < 56) ? (56 - index) : (120 - index);
	AXK_MD5Encode(bits, context->count, 8);
	AXK_MD5Update(context, PADDING, padlen);
	AXK_MD5Update(context, bits, 8);
	AXK_MD5Encode(digest, context->state, 16);
}

void AXK_MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) {
	unsigned int i = 0, j = 0;
	while (j < len) {
		output[j] = input[i] & 0xFF;
		output[j + 1] = (input[i] >> 8) & 0xFF;
		output[j + 2] = (input[i] >> 16) & 0xFF;
		output[j + 3] = (input[i] >> 24) & 0xFF;
		i++;
		j += 4;
	}
}
void AXK_MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) {
	unsigned int i = 0, j = 0;
	while (j < len) {
		output[i] = (input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16)
				| (input[j + 3] << 24);
		i++;
		j += 4;
	}
}

void AXK_MD5Transform(unsigned int state[4], unsigned char block[64]) {
	unsigned int a = state[0];
	unsigned int b = state[1];
	unsigned int c = state[2];
	unsigned int d = state[3];
	unsigned int x[64];
	AXK_MD5Decode(x, block, 64);
	FF(a, b, c, d, x[0], 7, 0xd76aa478);
	FF(d, a, b, c, x[1], 12, 0xe8c7b756);
	FF(c, d, a, b, x[2], 17, 0x242070db);
	FF(b, c, d, a, x[3], 22, 0xc1bdceee);
	FF(a, b, c, d, x[4], 7, 0xf57c0faf);
	FF(d, a, b, c, x[5], 12, 0x4787c62a);
	FF(c, d, a, b, x[6], 17, 0xa8304613);
	FF(b, c, d, a, x[7], 22, 0xfd469501);
	FF(a, b, c, d, x[8], 7, 0x698098d8);
	FF(d, a, b, c, x[9], 12, 0x8b44f7af);
	FF(c, d, a, b, x[10], 17, 0xffff5bb1);
	FF(b, c, d, a, x[11], 22, 0x895cd7be);
	FF(a, b, c, d, x[12], 7, 0x6b901122);
	FF(d, a, b, c, x[13], 12, 0xfd987193);
	FF(c, d, a, b, x[14], 17, 0xa679438e);
	FF(b, c, d, a, x[15], 22, 0x49b40821);

	GG(a, b, c, d, x[1], 5, 0xf61e2562);
	GG(d, a, b, c, x[6], 9, 0xc040b340);
	GG(c, d, a, b, x[11], 14, 0x265e5a51);
	GG(b, c, d, a, x[0], 20, 0xe9b6c7aa);
	GG(a, b, c, d, x[5], 5, 0xd62f105d);
	GG(d, a, b, c, x[10], 9, 0x2441453);
	GG(c, d, a, b, x[15], 14, 0xd8a1e681);
	GG(b, c, d, a, x[4], 20, 0xe7d3fbc8);
	GG(a, b, c, d, x[9], 5, 0x21e1cde6);
	GG(d, a, b, c, x[14], 9, 0xc33707d6);
	GG(c, d, a, b, x[3], 14, 0xf4d50d87);
	GG(b, c, d, a, x[8], 20, 0x455a14ed);
	GG(a, b, c, d, x[13], 5, 0xa9e3e905);
	GG(d, a, b, c, x[2], 9, 0xfcefa3f8);
	GG(c, d, a, b, x[7], 14, 0x676f02d9);
	GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);

	HH(a, b, c, d, x[5], 4, 0xfffa3942);
	HH(d, a, b, c, x[8], 11, 0x8771f681);
	HH(c, d, a, b, x[11], 16, 0x6d9d6122);
	HH(b, c, d, a, x[14], 23, 0xfde5380c);
	HH(a, b, c, d, x[1], 4, 0xa4beea44);
	HH(d, a, b, c, x[4], 11, 0x4bdecfa9);
	HH(c, d, a, b, x[7], 16, 0xf6bb4b60);
	HH(b, c, d, a, x[10], 23, 0xbebfbc70);
	HH(a, b, c, d, x[13], 4, 0x289b7ec6);
	HH(d, a, b, c, x[0], 11, 0xeaa127fa);
	HH(c, d, a, b, x[3], 16, 0xd4ef3085);
	HH(b, c, d, a, x[6], 23, 0x4881d05);
	HH(a, b, c, d, x[9], 4, 0xd9d4d039);
	HH(d, a, b, c, x[12], 11, 0xe6db99e5);
	HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
	HH(b, c, d, a, x[2], 23, 0xc4ac5665);

	II(a, b, c, d, x[0], 6, 0xf4292244);
	II(d, a, b, c, x[7], 10, 0x432aff97);
	II(c, d, a, b, x[14], 15, 0xab9423a7);
	II(b, c, d, a, x[5], 21, 0xfc93a039);
	II(a, b, c, d, x[12], 6, 0x655b59c3);
	II(d, a, b, c, x[3], 10, 0x8f0ccc92);
	II(c, d, a, b, x[10], 15, 0xffeff47d);
	II(b, c, d, a, x[1], 21, 0x85845dd1);
	II(a, b, c, d, x[8], 6, 0x6fa87e4f);
	II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
	II(c, d, a, b, x[6], 15, 0xa3014314);
	II(b, c, d, a, x[13], 21, 0x4e0811a1);
	II(a, b, c, d, x[4], 6, 0xf7537e82);
	II(d, a, b, c, x[11], 10, 0xbd3af235);
	II(c, d, a, b, x[2], 15, 0x2ad7d2bb);
	II(b, c, d, a, x[9], 21, 0xeb86d391);
	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;
}

/*
 * function: AXK_MD5Digest
 * parameter: void const *strContent - 需要AXK_MD5的字符串
 *            u16 iLength - 字符串长度
 *            u8 output[16] - 输出
 * description: 生成AXK_MD5摘要
 */
void AXK_MD5Digest(void const *strContent, unsigned int iLength, unsigned char output[16]) {
	unsigned char *q = (unsigned char*) strContent;

	AXK_MD5_CTX AXK_MD5;
	AXK_MD5Init(&AXK_MD5);
	AXK_MD5Update(&AXK_MD5, q, iLength);
	AXK_MD5Final(&AXK_MD5, output);
}

官方文档资料:https://docs.ai-thinker.com/gprs

  • 共勉!有疑问请留言,或邮箱:support@aithinker.com