1. 程式人生 > >阿里雲簡訊服務介面的c++實現

阿里雲簡訊服務介面的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)描述文件,先做一些必要的準備:

    *註冊阿里雲,有需要的阿里雲產品通用代金券的可以點選下面連結進行領取:

開通簡訊服務後,在你賬戶頭像下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)最終呈現效果

圖二的簽名與圖一部一致是因為兩張圖片分別來自兩個請求的截圖

5)阿里雲簡訊介面的http實現關鍵是做好籤名,然後按通用的http訪問請求實現即可,另外需要特別注意的是注意阿里裡面簡訊定義要求,例如變數不能包含限制字元,變數長度不能超過20等等