您现在的位置是:首页 > 文章详情

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

日期:2018-04-25点击:374

最近在调用阿里云短信服务接口发现并没有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)最终呈现效果

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

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

原文链接:https://yq.aliyun.com/articles/630447
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章