阿里云短信服务接口的c++实现

最近在调用阿里云短信服务接口发现并没有c++的资料,网上查询发现也是零星描述,由于自身项目基础累积了C++的太多,不想掺杂太多语言,就自行实现c++的阿里云短信接口,其难点就在于签名而已,希望能给大家提供参考。

1)我的网页调用接口采用acl_master实现的,acl_master是一个跨平台c/c++库,提供了网络通信库及服务器编程框架,同时提供更多的实用功能库及示例。(下载地址:Github: https://github.com/acl-dev/acl),读者可采用其他库实现。

2)参考阿里云的“HTTP协议及签名”(https://help.aliyun.com/document_detail/56189.html?spm=a2c4g.11186623.6.581.fy2faU)描述文档,先做一些必要的准备:

    *注册阿里云,有需要的阿里云产品通用代金券的可以点击下面链接进行领取:

https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pfb80n4a

开通短信服务后,在你账户头像下AccessKeys选项进入用户信息管理界面,获取到你的AccessKeyId和AccessKeySecret,具体请参考阿里云短信服务的资料完成操作

    *根据"http协议及签名”描述文档,定义了短信请求参数结构,初始化中带*的请自行写入自己实际参数:

struct HttpMsgArg
{
	HttpMsgArg()
		: addr_("dysmsapi.aliyuncs.com")
		, path_("")
		, port_(80)
		//
		, AccessKeyId("********")
		, AccessKeySecret("***************")
		, Timestamp("2018-04-13T10:10:10Z")
		, Format("XML")
		, SignatureMethod("HMAC-SHA1")
		, SignatureVersion("1.0")
		, SignatureNonce("1")
		, Signature("")
		//
		, Action("SendSms")
		, Version("2017-05-25")
		, RegionId("cn-hangzhou")
		, PhoneNumbers("137********")
		, SignName("短信测试")
		, TemplateCode("SMS_*******")
		, TemplateParam("")
		, SmsUpExtendCode("")
		, OutId("123")
	{

	};
	//
	std::string addr_;			// web 服务器地址  
	std::string path_;			// 本地请求的数据文件  
	int port_;
	//
	std::string AccessKeyId;		//
	std::string AccessKeySecret;	//
	std::string Timestamp;			//格式为:yyyy-MM-dd’T’HH:mm:ss’Z’;时区为:GMT
	std::string Format;				//没传默认为JSON,可选填值:XML
	std::string SignatureMethod;	//建议固定值:HMAC-SHA1
	std::string SignatureVersion;	//建议固定值:1.0
	std::string SignatureNonce;		//用于请求的防重放攻击,每次请求唯一,JAVA语言建议用:java.util.UUID.randomUUID()生成即可
	std::string Signature;			//最终生成的签名结果值

	std::string Action;				//API的命名,固定值,如发送短信API的值为:SendSms
	std::string Version;			//API的版本,固定值,如短信API的值为:2017-05-25
	std::string RegionId;			//API支持的RegionID,如短信API的值为:cn-hangzhou
	/*
	*短信接收号码,支持以逗号分隔的形式进行批量调用,
	*批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,
	*验证码类型的短信推荐使用单条调用的方式
	*/
	std::string PhoneNumbers;
	std::string SignName;			//短信签名
	std::string TemplateCode;		//短信模板ID
	/*
	短信模板变量替换JSON串,友情提示:如果JSON中需要带换行符,请参照标准的JSON协议。
	*/
	std::string TemplateParam;
	std::string SmsUpExtendCode;	//上行短信扩展码,无特殊需要此字段的用户请忽略此字段
	std::string OutId;				//外部流水扩展字段
};

*url格式转换需求:

unsigned char ToHex(unsigned char x)
{
	return  x > 9 ? x + 55 : x + 48;
}

unsigned char FromHex(unsigned char x)
{
	unsigned char y;
	if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
	else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
	else if (x >= '0' && x <= '9') y = x - '0';
	else assert(0);
	return y;
}

std::string UrlEncode(const std::string& str)
{
	std::string strTemp = "";
	size_t length = str.length();
	for (size_t i = 0; i < length; i++)
	{
		if (isalnum((unsigned char)str[i]) ||
			(str[i] == '-') ||
			(str[i] == '_') ||
			(str[i] == '.') ||
			(str[i] == '~'))
			strTemp += str[i];
		else if (str[i] == ' ')
			strTemp += "+";
		else
		{
			strTemp += '%';
			strTemp += ToHex((unsigned char)str[i] >> 4);
			strTemp += ToHex((unsigned char)str[i] % 16);
		}
	}
	return strTemp;
}

std::string UrlDecode(const std::string& str)
{
	std::string strTemp = "";
	size_t length = str.length();
	for (size_t i = 0; i < length; i++)
	{
		if (str[i] == '+') strTemp += ' ';
		else if (str[i] == '%')
		{
			assert(i + 2 < length);
			unsigned char high = FromHex((unsigned char)str[++i]);
			unsigned char low = FromHex((unsigned char)str[++i]);
			strTemp += high * 16 + low;
		}
		else strTemp += str[i];
	}
	return strTemp;
}

*UUID的生成实现函数:

std::string getUUID() {
#ifdef WIN32
	char buffer[GUID_LEN] = { 0 };
	GUID guid;

	if (CoCreateGuid(&guid))
	{
		fprintf(stderr, "create guid error\n");
		return "";
	}
	_snprintf(buffer, sizeof(buffer),
		"%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",
		guid.Data1, guid.Data2, guid.Data3,
		guid.Data4[0], guid.Data4[1], guid.Data4[2],
		guid.Data4[3], guid.Data4[4], guid.Data4[5],
		guid.Data4[6], guid.Data4[7]);
	printf("guid: %s\n", buffer);
	return std::string(buffer);
#else
	uuid_t uuid;
	uuid_generate(uuid);

	char buf[64] = { 0 };
	uuid_unparse(uuid, buf);
	return std::string(buf);
#endif
};

*用于ascii和utf-8的字符格式转换,一些其他的格式转换也一并给出,防止特定需要,主要是阿里参数中文可能需要用到

/////////////hpp////////////////////
#ifdef WIN32
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#endif

#ifndef STRCHANGE_HPP
#define STRCHANGE_HPP

#include <string>
#include <vector>

#ifdef WIN32
#include <iostream>
#include <windows.h>
#endif

//using namespace std;

bool containStr(std::string _str, std::string _strsub);

#ifdef WIN32
//UTF-8 to Unicode
std::wstring Utf82Unicode(const std::string& utf8string);
//unicode to ascii
std::string WideByte2Acsi(std::wstring& wstrcode);
//ascii to Unicode
std::wstring Acsi2WideByte(std::string& strascii);
//Unicode to Utf8
std::string Unicode2Utf8(const std::wstring& widestring);
#endif

#ifdef __linux__
int code_convert(char *from_charset,char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen);
int u2g(char *inbuf,int inlen,char *outbuf,int outlen);
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen);
int u2a(char *inbuf,int inlen,char *outbuf,int outlen);
int a2u(char *inbuf,int inlen,char *outbuf,int outlen);
int u2k(char *inbuf,int inlen,char *outbuf,int outlen);
int k2u(char *inbuf,int inlen,char *outbuf,int outlen);
#endif

//utf-8 to ascii
std::string UTF_82ASCII(std::string& strUtf8Code);
//ascii to Utf8
std::string ASCII2UTF_8(std::string& strAsciiCode);

#endif //STRCHANGE_HPP

/////////////////////////////////////////////
#include "strchange.h"

#include <stdio.h>
#include <stdlib.h>
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#endif
//using namespace std;

bool containStr(std::string _str, std::string _strsub)
{
	std::string::size_type pos = _str.find(_strsub);//
	if(pos!=std::string::npos){
		return true;
	}

	return false;
};

void strToHex16(char *in,unsigned char *out,int size)
{
	unsigned int ch;
	int index=0;
	while(sscanf(in,"%2x",&ch)!=EOF&&index<size)
	{
		out[index++]=ch;
		in+=2;
	}
	out[index<size?index:(size-1)]='\0';
};

void strFromHex16(unsigned char *in,char *out,int size)
{
	int i=0;
	while('\0'!=in[i]&&(2*i<size))
	{
		//char ch[2]={0};
		sprintf(out+i*2,"%02x",in[i]);
		i++;
	}
	out[2*i<size?2*i:(size-1)]='\0';
};

#ifdef WIN32
//UTF-8 to Unicode
std::wstring Utf82Unicode(const std::string& utf8string)
{
	int widesize = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, NULL, 0);
	if (widesize == ERROR_NO_UNICODE_TRANSLATION)
	{
		throw std::exception("Invalid UTF-8 sequence.");
	}
	if (widesize == 0)
	{
		throw std::exception("Error in conversion.");
	}

	std::vector<wchar_t> resultstring(widesize);

	int convresult = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, &resultstring[0], widesize);

	if (convresult != widesize)
	{
		throw std::exception("La falla!");
	}

	return std::wstring(&resultstring[0]);
};

//unicode to ascii

std::string WideByte2Acsi(std::wstring& wstrcode)
{
	int asciisize = ::WideCharToMultiByte(CP_OEMCP, 0, wstrcode.c_str(), -1, NULL, 0, NULL, NULL);
	if (asciisize == ERROR_NO_UNICODE_TRANSLATION)
	{
		throw std::exception("Invalid UTF-8 sequence.");
	}
	if (asciisize == 0)
	{
		throw std::exception("Error in conversion.");
	}
	std::vector<char> resultstring(asciisize);
	int convresult =::WideCharToMultiByte(CP_OEMCP, 0, wstrcode.c_str(), -1, &resultstring[0], asciisize, NULL, NULL);

	if (convresult != asciisize)
	{
		throw std::exception("La falla!");
	}

	return std::string(&resultstring[0]);
};

//////////////////////////////cpp/////////////////////////////////////////

//ascii to Unicode

std::wstring Acsi2WideByte(std::string& strascii)
{
	int widesize = MultiByteToWideChar (CP_ACP, 0, (char*)strascii.c_str(), -1, NULL, 0);
	if (widesize == ERROR_NO_UNICODE_TRANSLATION)
	{
		throw std::exception("Invalid UTF-8 sequence.");
	}
	if (widesize == 0)
	{
		throw std::exception("Error in conversion.");
	}
	std::vector<wchar_t> resultstring(widesize);
	int convresult = MultiByteToWideChar (CP_ACP, 0, (char*)strascii.c_str(), -1, &resultstring[0], widesize);

	if (convresult != widesize)
	{
		throw std::exception("La falla!");
	}

	return std::wstring(&resultstring[0]);
};

//Unicode to Utf8

std::string Unicode2Utf8(const std::wstring& widestring)
{
	int utf8size = ::WideCharToMultiByte(CP_UTF8, 0, widestring.c_str(), -1, NULL, 0, NULL, NULL);
	if (utf8size == 0)
	{
		throw std::exception("Error in conversion.");
	}

	std::vector<char> resultstring(utf8size);

	int convresult = ::WideCharToMultiByte(CP_UTF8, 0, widestring.c_str(), -1, &resultstring[0], utf8size, NULL, NULL);

	if (convresult != utf8size)
	{
		throw std::exception("La falla!");
	}

	return std::string(&resultstring[0]);
};
#endif

#ifdef __linux__
//
int code_convert(char *from_charset,char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
    iconv_t cd;
    //int rc;
    char **pin = &inbuf;
    char **pout = &outbuf;

    cd = iconv_open(to_charset,from_charset);
    if (cd==0) return -1;
    memset(outbuf,0,outlen);
    if (-1==(int)iconv(cd,pin,&inlen,pout,&outlen))
	return -1;
    iconv_close(cd);
    return 0;
}
//
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{
	char _fbuf[32]="utf-8";
	char _tbuf[32]="gb2312";
    return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}
//
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
	char _fbuf[32]="gb2312";
	char _tbuf[32]="utf-8";
    return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}

int u2a(char *inbuf,int inlen,char *outbuf,int outlen)
{
	char _fbuf[32]="utf-8";
	char _tbuf[32]="ascii";
    return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}

int a2u(char *inbuf,int inlen,char *outbuf,int outlen)
{
	char _fbuf[32]="ascii";
	char _tbuf[32]="utf-8";
    return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}

int u2k(char *inbuf,int inlen,char *outbuf,int outlen)
{
	char _fbuf[32]="utf-8";
	char _tbuf[32]="gbk";
    return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}

int k2u(char *inbuf,int inlen,char *outbuf,int outlen)
{
	char _fbuf[32]="gbk";
	char _tbuf[32]="utf-8";
    return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}

#endif

//utf-8 to ascii

std::string UTF_82ASCII(std::string& strUtf8Code)
{
	#ifdef WIN32
	std::string strRet("");
	//
	std::wstring wstr = Utf82Unicode(strUtf8Code);
	//
	strRet = WideByte2Acsi(wstr);
	return strRet;
	#endif
	#ifdef __linux__
	char lpszBuf[256]={0};
	u2k(const_cast<char*>(strUtf8Code.c_str()),strUtf8Code.size(),lpszBuf,256);
	return std::string(lpszBuf);
	// char lpszBuf[256]={0};
	// u2a(const_cast<char*>(strUtf8Code.c_str()),strUtf8Code.size(),lpszBuf,256);
	// return std::string(lpszBuf);
	// return std::string(strUtf8Code);
	#endif
};

//ascii to Utf8

std::string ASCII2UTF_8(std::string& strAsciiCode)
{
	#ifdef WIN32
	std::string strRet("");
	//
	std::wstring wstr = Acsi2WideByte(strAsciiCode);
	//
	strRet = Unicode2Utf8(wstr);
	return strRet;
	#endif
	#ifdef __linux__
	char lpszBuf[256]={0};
	k2u(const_cast<char*>(strAsciiCode.c_str()),strAsciiCode.size(),lpszBuf,256);
	return std::string(lpszBuf);
	// char lpszBuf[256]={0};
	// a2u(const_cast<char*>(strAsciiCode.c_str()),strAsciiCode.size(),lpszBuf,256);
	// return std::string(lpszBuf);
	// return std::string(strAsciiCode);
	#endif
};

 *阿里云短信接口参数的时间格式要求:

std::string getCurentTimeDesc()
{
	time_t _t = time(NULL);
	char bufTime[64] = { 0 };
	struct tm* _tt;
	//localtime_s(&_tt, &_t);//系统本地时间
	_tt = gmtime(&_t);//格林时间
	_tt->tm_year += 1900;
	_tt->tm_mon += 1;
	sprintf(bufTime, "%04d-%02d-%02dT%02d:%02d:%02dZ"
		, _tt->tm_year,_tt->tm_mon,_tt->tm_mday,_tt->tm_hour,_tt->tm_min,_tt->tm_sec);
	return std::string(bufTime);
}

 *重点一,签名算法实现,来源网上公开的一些资料,经过实践实用c语言函数

//////////////////HMACSHA1.h///////////////////
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __HMACSHA1_H__
#define __HMACSHA1_H__

typedef unsigned long    __u32;
typedef unsigned char    __u8;

typedef struct
{
	__u32 state[5];
	__u32 count[2];
	__u8  buffer[64];
} SHA1_CTX;

#if defined(rol)
#undef rol
#endif

#define SHA1HANDSOFF

#define __LITTLE_ENDIAN 

#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#ifdef __LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
    |(rol(block->l[i],8)&0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
    ^block->l[(i+2)&15]^block->l[i&15],1))

/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);


/* Hash a single 512-bit block. This is the core of the algorithm. */

void SHA1Transform(__u32 state[5], __u8 buffer[64]);
void SHA1Init(SHA1_CTX *context);
void SHA1Update(SHA1_CTX *context, unsigned char *data, __u32 len);
void SHA1Final(unsigned char digest[20], SHA1_CTX *context);
//void hmac_sha1(unsigned char *to_mac,unsigned int to_mac_length, unsigned char *key,unsigned int key_length, unsigned char *out_mac);
void hmac_sha
(
	char* k,    /* 秘钥 secret key */
	int lk,     /*  秘钥长度 length of the key in bytes */
	char* d,    /* 数据 data */
	int ld,     /*  数据长度 length of data in bytes */
	char* out,  /* 输出的字符串 output buffer, at least "t" bytes */
	int t
);

#endif
///////////////////////////////HMACSHA1.cpp///////////////////////////////////////////////
#include "HMACSHA1.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#ifndef SHA_DIGESTSIZE
#define SHA_DIGESTSIZE 20
#endif

#ifndef SHA_BLOCKSIZE
#define SHA_BLOCKSIZE 64
#endif


/* Hash a single 512-bit block. This is the core of the algorithm. */

void SHA1Transform(__u32 state[5], __u8 buffer[64])
{
	__u32 a, b, c, d, e;
	typedef union {
		unsigned char c[64];
		__u32 l[16];
	} CHAR64LONG16;

	CHAR64LONG16* block;

#ifdef SHA1HANDSOFF

	static unsigned char workspace[64];
	block = (CHAR64LONG16*)workspace;
	//    NdisMoveMemory(block, buffer, 64);
	memcpy(block, buffer, 64);
#else
	block = (CHAR64LONG16*)buffer;
#endif
	/* Copy context->state[] to working vars */
	a = state[0];
	b = state[1];
	c = state[2];
	d = state[3];
	e = state[4];
	/* 4 rounds of 20 operations each. Loop unrolled. */
	R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3);
	R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7);
	R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11);
	R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15);
	R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19);
	R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23);
	R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27);
	R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31);
	R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35);
	R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39);
	R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43);
	R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47);
	R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51);
	R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55);
	R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59);
	R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63);
	R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67);
	R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71);
	R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75);
	R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79);
	/* Add the working vars back into context.state[] */
	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;
	state[4] += e;
	/* Wipe variables */
	a = b = c = d = e = 0;
}


/* SHA1Init - Initialize new context */

void SHA1Init(SHA1_CTX* context)
{
	/* SHA1 initialization constants */
	context->state[0] = 0x67452301;
	context->state[1] = 0xEFCDAB89;
	context->state[2] = 0x98BADCFE;
	context->state[3] = 0x10325476;
	context->state[4] = 0xC3D2E1F0;
	context->count[0] = context->count[1] = 0;
}


/* Run your data through this. */

void SHA1Update(SHA1_CTX* context, unsigned char* data, __u32 len)
{
	__u32 i, j;

	j = context->count[0];
	if ((context->count[0] += len << 3) < j)
		context->count[1]++;
	context->count[1] += (len >> 29);
	j = (j >> 3) & 63;
	if ((j + len) > 63) {
		//        NdisMoveMemory(&context->buffer[j], data, (i = 64-j));
		memcpy(&context->buffer[j], data, (i = 64 - j));
		SHA1Transform(context->state, context->buffer);
		for (; i + 63 < len; i += 64) {
			SHA1Transform(context->state, &data[i]);
		}
		j = 0;
	}
	else i = 0;
	//    NdisMoveMemory(&context->buffer[j], &data[i], len - i);
	memcpy(&context->buffer[j], &data[i], len - i);
}


/* Add padding and return the message digest. */

void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
	__u32 i, j;
	unsigned char finalcount[8];

	for (i = 0; i < 8; i++) {
		finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
			>> ((3 - (i & 3)) * 8)) & 255);  /* Endian independent */
	}
	SHA1Update(context, (unsigned char *)"\200", 1);
	while ((context->count[0] & 504) != 448) {
		SHA1Update(context, (unsigned char *)"\0", 1);
	}
	SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
	for (i = 0; i < 20; i++) {
		digest[i] = (unsigned char)
			((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
	}
	/* Wipe variables */
	i = j = 0;
	//    NdisZeroMemory(context->buffer, 64);
	//    NdisZeroMemory(context->state, 20);
	//    NdisZeroMemory(context->count, 8);
	//    NdisZeroMemory(&finalcount, 8);
	memset(context->buffer, 0x00, 64);
	memset(context->state, 0x00, 20);
	memset(context->count, 0x00, 8);
	memset(&finalcount, 0x00, 8);

#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */
	SHA1Transform(context->state, context->buffer);
#endif
}



/* Function to print the digest
打印输出*/
void pr_sha(FILE* fp, unsigned char* s, int t)
{
	int i;

	for (i = 0; i<t; i++)
		printf("%02x", s[i]);
	printf("\n");

}

void truncate
(
	char* d1, /* data to be truncated */
	char* d2, /* truncated data */
	int len /* length in bytes to keep */
)
{
	int i;
	for (i = 0; i < len; i++) d2[i] = d1[i];
}

/* Function to compute the digest
加密算法的主要操作函数 */
void hmac_sha
(
	char* k,    /* 秘钥 secret key */
	int lk,     /*  秘钥长度 length of the key in bytes */
	char* d,    /* 数据 data */
	int ld,     /*  数据长度 length of data in bytes */
	char* out,  /* 输出的字符串 output buffer, at least "t" bytes */
	int t
)
{
	SHA1_CTX ictx, octx;
	char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE];
	char key[SHA_DIGESTSIZE];
	char buf[SHA_BLOCKSIZE];
	int i;

	if (lk > SHA_BLOCKSIZE)
	{
		SHA1_CTX tctx;
		SHA1Init(&tctx);
		SHA1Update(&tctx, (unsigned char*)k, lk);
		SHA1Final((unsigned char*)key, &tctx);

		k = key;
		lk = SHA_DIGESTSIZE;
	}

	/**** Inner Digest ****/

	SHA1Init(&ictx);

	/* Pad the key for inner digest */
	for (i = 0; i < lk; ++i) buf[i] = k[i] ^ 0x36;
	for (i = lk; i < SHA_BLOCKSIZE; ++i) buf[i] = 0x36;

	SHA1Update(&ictx, (unsigned char*)buf, SHA_BLOCKSIZE);
	SHA1Update(&ictx, (unsigned char*)d, ld);

	SHA1Final((unsigned char*)isha, &ictx);

	/**** Outter Digest ****/

	SHA1Init(&octx);

	/* Pad the key for outter digest */

	for (i = 0; i < lk; ++i) buf[i] = k[i] ^ 0x5C;
	for (i = lk; i < SHA_BLOCKSIZE; ++i) buf[i] = 0x5C;

	SHA1Update(&octx, (unsigned char*)buf, SHA_BLOCKSIZE);
	SHA1Update(&octx, (unsigned char*)isha, SHA_DIGESTSIZE);

	SHA1Final((unsigned char*)osha, &octx);

	/* truncate and print the results */
	t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t;
	truncate(osha, out, t);
	pr_sha(stdout, (unsigned char*)out, t);

}

*重点二,Base64算法实现

//////////////////////////ZBase64.h///////////////////////////////////
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef ___BASE_64_H___
#define ___BASE_64_H___

#include <string>

class ZBase64
{
public:
	/*编码
	DataByte
	[in]输入的数据长度,以字节为单位
	*/
	static std::string Encode(const unsigned char* Data, int DataByte);
	/*解码
	DataByte
	[in]输入的数据长度,以字节为单位
	OutByte
	[out]输出的数据长度,以字节为单位,请不要通过返回值计算
	输出数据的长度
	*/
	static std::string Decode(const char* Data, int DataByte, int& OutByte);
};

#endif
//////////////////////////////////ZBase64.cpp/////////////////////////////////////////////
#include "Base64.h"

std::string ZBase64::Encode(const unsigned char* Data, int DataByte)
{
	//编码表
	const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	//返回值
	std::string strEncode;
	unsigned char Tmp[4] = { 0 };
	int LineLength = 0;
	for (int i = 0; i<(int)(DataByte / 3); i++)
	{
		Tmp[1] = *Data++;
		Tmp[2] = *Data++;
		Tmp[3] = *Data++;
		strEncode += EncodeTable[Tmp[1] >> 2];
		strEncode += EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
		strEncode += EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
		strEncode += EncodeTable[Tmp[3] & 0x3F];
		if (LineLength += 4, LineLength == 76) { strEncode += "\r\n"; LineLength = 0; }
	}
	//对剩余数据进行编码
	int Mod = DataByte % 3;
	if (Mod == 1)
	{
		Tmp[1] = *Data++;
		strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
		strEncode += EncodeTable[((Tmp[1] & 0x03) << 4)];
		strEncode += "==";
	}
	else if (Mod == 2)
	{
		Tmp[1] = *Data++;
		Tmp[2] = *Data++;
		strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
		strEncode += EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
		strEncode += EncodeTable[((Tmp[2] & 0x0F) << 2)];
		strEncode += "=";
	}

	return strEncode;
}

std::string ZBase64::Decode(const char* Data, int DataByte, int& OutByte)
{
	//解码表
	const char DecodeTable[] =
	{
		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,
		62, // '+'
		0, 0, 0,
		63, // '/'
		52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
		0, 0, 0, 0, 0, 0, 0,
		0, 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, // 'A'-'Z'
		0, 0, 0, 0, 0, 0,
		26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
		39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
	};
	//返回值
	std::string strDecode;
	int nValue;
	int i = 0;
	while (i < DataByte)
	{
		if (*Data != '\r' && *Data != '\n')
		{
			nValue = DecodeTable[*Data++] << 18;
			nValue += DecodeTable[*Data++] << 12;
			strDecode += (nValue & 0x00FF0000) >> 16;
			OutByte++;
			if (*Data != '=')
			{
				nValue += DecodeTable[*Data++] << 6;
				strDecode += (nValue & 0x0000FF00) >> 8;
				OutByte++;
				if (*Data != '=')
				{
					nValue += DecodeTable[*Data++];
					strDecode += nValue & 0x000000FF;
					OutByte++;
				}
			}
			i += 4;
		}
		else// 回车换行,跳过
		{
			Data++;
			i++;
		}
	}
	return strDecode;
}

 

3)准备工作完成,开始短信申请全过程,本人借助acl-master库实现,用其他网页访问接口的请斟酌参考

 

    acl::string aclurl, acladdr;//定义网站、地址
    aclurl.format("http://%s%s", myArgHttp.addr_.c_str(), myArgHttp.path_.c_str());
    acladdr.format("%s:%d", myArgHttp.addr_.c_str(), myArgHttp.port_);

    acl::http_request req(acladdr);
    //请求构造

    acl::http_header& header = req.request_header();

   //访问类型为Get
    header.set_method(acl::HTTP_METHOD_GET);

    header.set_keep_alive(false);//

    header.accept_gzip(accept_gzip ? true : false);//

   //url
    header.set_url(aclurl);
    //host
    if (header.get_host() == NULL)
    {
        header.set_host(myArgHttp.addr_.c_str());
        printf(">>>set host: %s\r\n", myArgHttp.addr_.c_str());
    }
    else
        printf(">>>host: %s\r\n", header.get_host());

    //签名内容缓存
    std::string sortQueryStringTmp = "";
    sortQueryStringTmp.append("GET&").append(UrlEncode("/"));
    //签名内容项,参数key的字符串排序
    std::string  bufNonce = getUUID();
    std::string Timestamp = getCurentTimeDesc();

    myArgHttp.TemplateParam = ASCII2UTF_8(templateParam_);

    acl::url_coder coder;//注意中文字段UTF-8表述
    coder.set("AccessKeyId", myArgHttp.AccessKeyId.c_str());
    coder.set("Action", myArgHttp.Action.c_str());
    coder.set("Format", myArgHttp.Format.c_str());
    coder.set("OutId", myArgHttp.OutId.c_str());
    coder.set("PhoneNumbers", myArgHttp.PhoneNumbers.c_str());
    coder.set("RegionId", myArgHttp.RegionId.c_str());
    coder.set("SignName", ASCII2UTF_8(myArgHttp.SignName).c_str());
    coder.set("SignatureMethod", myArgHttp.SignatureMethod.c_str());
    coder.set("SignatureNonce", bufNonce.c_str());
    coder.set("SignatureVersion", myArgHttp.SignatureVersion.c_str());
    coder.set("TemplateCode", myArgHttp.TemplateCode.c_str());
    coder.set("TemplateParam", myArgHttp.TemplateParam.c_str());
    coder.set("Timestamp", Timestamp.c_str());
    coder.set("Version", myArgHttp.Version.c_str());
    //

    std::string urlcode = std::string(coder.to_string().c_str());//

   printf( "排序参数集:\r\n%s\r\n", urlcode.c_str());

    sortQueryStringTmp.append("&").append(UrlEncode(urlcode));

    printf( "待签名的请求字符串UrlEncode:\r\n%s\r\n", sortQueryStringTmp.c_str());

    //生成签名,调用签名算法函数,注意阿里的AccessKeySecret+&才是真正的AccessKeySecret
    char hmac_buf[256] = { 0 };
    std::string KeySecret_ali = (myArgHttp.AccessKeySecret + "&");
    hmac_sha((char*)(ASCII2UTF_8(KeySecret_ali)).c_str(), (int)KeySecret_ali.length()
        , (char*)ASCII2UTF_8(sortQueryStringTmp).c_str(), (int)sortQueryStringTmp.length(), hmac_buf, 20);

    std::string hmac = std::string(hmac_buf,strlen(hmac_buf));

   printf( "密钥+HmacSHA1算法:\r\n%s\r\n", hmac.c_str());

   //base64算法调用,前面签名算法结果作为输入参数,得到最终签名

    hmac = ZBase64::Encode((const unsigned char*)hmac.c_str(), static_cast<int>(hmac.length()));

   printf( "HmacSHA1算法+Base64:\r\n%s\r\n", hmac.c_str());

   //将签名加入请求字段

    header.add_param("Signature", hmac.c_str());

   //其他参数加入,注意中文字段UTF-8表述

//TemplateParam,例如,"{\"customer\":\"test\"}",

//进行传输短信的变量与你阿里短信服务模版的变量一致,(如都存在”customer“变量)

//如果模版变量个数在 TemplateParam没有全含括或任意字段不匹配,都无法正常短信发送

//变量的描述字段限制20位,例如,test不能超过20个字符长度,否则出错   

    header.add_param("AccessKeyId", myArgHttp.AccessKeyId.c_str());

    header.add_param("Action", myArgHttp.Action.c_str());
    header.add_param("Format", myArgHttp.Format.c_str());
    header.add_param("OutId", myArgHttp.OutId.c_str());
    header.add_param("PhoneNumbers", myArgHttp.PhoneNumbers.c_str());
    header.add_param("RegionId", myArgHttp.RegionId.c_str());
    header.add_param("SignName", ASCII2UTF_8(myArgHttp.SignName).c_str());
    header.add_param("SignatureMethod", myArgHttp.SignatureMethod.c_str());
    header.add_param("SignatureNonce", bufNonce.c_str());
    header.add_param("SignatureVersion", myArgHttp.SignatureVersion.c_str());
    header.add_param("TemplateCode", myArgHttp.TemplateCode.c_str());
    header.add_param("TemplateParam", myArgHttp.TemplateParam.c_str());
    header.add_param("Timestamp", Timestamp.c_str());

    header.add_param("Version", myArgHttp.Version.c_str());

   bool rc = req.request(NULL, 0);//http请求
    // 将 build_request 放在 req.request 后面,是因为
    // req.request 内部可能会修改请求头中的字段
    acl::string hdr;
    header.build_request(hdr);
   printf("request header:\r\n%s\r\n", hdr.c_str());

    if (rc == false)
    {
        printf( "send request error");
        return;
    }
 

    printf("send request ok!\r\n");

   // 取出 HTTP 响应头的 Content-Type 字段  

    const char* p = req.header_value("Content-Type");
    if (p == NULL || *p == 0)
    {
        printf( "no Content-Type");
        return;

    }

// 分析 HTTP 响应头的数据类型  
    acl::http_ctype content_type;
    content_type.parse(p);

    // 响应头数据类型的子类型  
    const char* stype = content_type.get_stype();

    bool ret;
    if (stype != NULL)

        ret = do_plain(req);

  if (ret == true)

        printf("read ok!");

4)最终呈现效果

阿里云短信服务接口的c++实现

图二的签名与图一部一致是因为两张图片分别来自两个请求的截图

阿里云短信服务接口的c++实现

5)阿里云短信接口的http实现关键是做好签名,然后按通用的http访问请求实现即可,另外需要特别注意的是注意阿里里面短信定义要求,例如变量不能包含限制字符,变量长度不能超过20等等

上一篇:在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口


下一篇:考察数据科学家支持向量机(SVM)知识的25道题,快来测测吧