2023年7月31日发(作者:)
阿⾥云短信服务接⼝的c++实现最近在调⽤阿⾥云短信服务接⼝发现并没有c++的资料,⽹上查询发现也是零星描述,由于⾃⾝项⽬基础累积了C++的太多,不想掺杂太多语⾔,就⾃⾏实现c++的阿⾥云短信接⼝,其难点就在于签名⽽已,希望能给⼤家提供参考。 *注册阿⾥云,有需要的阿⾥云产品通⽤代⾦券的可以点击下⾯链接进⾏领取:开通短信服务后,在你账户头像下AccessKeys选项进⼊⽤户信息管理界⾯,获取到你的AccessKeyId和AccessKeySecret,具体请参考阿⾥云短信服务的资料完成操作 *根据"http协议及签名”描述⽂档,定义了短信请求参数结构,初始化中带*的请⾃⾏写⼊⾃⼰实际参数:struct HttpMsgArg{ HttpMsgArg() : addr_("") , 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语⾔建议⽤:UUID()⽣成即可 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 = (); 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 = (); 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 errorn"); return ""; } _snprintf(buffer, sizeof(buffer), "%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X", 1, 2, 3, 4[0], 4[1], 4[2], 4[3], 4[4], 4[5], 4[6], 4[7]); printf("guid: %sn", 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 #include #ifdef WIN32#include #include #endif//using namespace std;bool containStr(std::string _str, std::string _strsub);#ifdef WIN32//UTF-8 to Unicodestd::wstring Utf82Unicode(const std::string& utf8string);//unicode to asciistd::string WideByte2Acsi(std::wstring& wstrcode);//ascii to Unicodestd::wstring Acsi2WideByte(std::string& strascii);//Unicode to Utf8std::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 asciistd::string UTF_82ASCII(std::string& strUtf8Code);//ascii to Utf8std::string ASCII2UTF_8(std::string& strAsciiCode);#endif //STRCHANGE_HPP/#include "strchange.h"#include #include #ifdef __linux__#include #include #include #include #endif//using namespace std;bool containStr(std::string _str, std::string _strsub){ std::string::size_type pos = _(_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 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 asciistd::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 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 Unicodestd::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 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 Utf8std::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 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 asciistd::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(strUtf8Code.c_str()),(),lpszBuf,256); return std::string(lpszBuf); // char lpszBuf[256]={0}; // u2a(const_cast(strUtf8Code.c_str()),(),lpszBuf,256); // return std::string(lpszBuf); // return std::string(strUtf8Code); #endif};//ascii to Utf8std::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(strAsciiCode.c_str()),(),lpszBuf,256); return std::string(lpszBuf); // char lpszBuf[256]={0}; // a2u(const_cast(strAsciiCode.c_str()),(),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#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//////#include "HMACSHA1.h"#include #include #include #include #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); 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 [] */ 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); 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 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); 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 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///#include "Base64.h"std::string ZBase64::Encode(const unsigned char* Data, int DataByte){ //编码表 const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; //返回值 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 += "rn"; 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;//定义⽹站、地址 ("%s%s", _.c_str(), _.c_str()); ("%s:%d", _.c_str(), _); acl::http_request req(acladdr); //请求构造 acl::http_header& header = t_header(); //访问类型为Get _method(acl::HTTP_METHOD_GET); _keep_alive(false);// _gzip(accept_gzip ? true : false);// //url _url(aclurl); //host if (_host() == NULL) { _host(_.c_str()); printf(">>>set host: %srn", _.c_str()); } else printf(">>>host: %srn", _host()); //签名内容缓存 std::string sortQueryStringTmp = ""; ("GET&").append(UrlEncode("/")); //签名内容项,参数key的字符串排序 std::string bufNonce = getUUID(); std::string Timestamp = getCurentTimeDesc(); teParam = ASCII2UTF_8(templateParam_); acl::url_coder coder;//注意中⽂字段UTF-8表述 ("AccessKeyId", KeyId.c_str()); ("Action", .c_str()); ("Format", .c_str()); ("OutId", .c_str()); ("PhoneNumbers", umbers.c_str()); ("RegionId", Id.c_str()); ("SignName", ASCII2UTF_8(me).c_str()); ("SignatureMethod", ureMethod.c_str()); ("SignatureNonce", bufNonce.c_str()); ("SignatureVersion", ureVersion.c_str()); ("TemplateCode", teCode.c_str()); ("TemplateParam", teParam.c_str()); ("Timestamp", Timestamp.c_str()); ("Version", n.c_str()); // std::string urlcode = std::string(_string().c_str());// printf( "排序参数集:rn%srn", urlcode.c_str()); ("&").append(UrlEncode(urlcode)); printf( "待签名的请求字符串UrlEncode:rn%srn", sortQueryStringTmp.c_str()); //⽣成签名,调⽤签名算法函数,注意阿⾥的AccessKeySecret+&才是真正的AccessKeySecret char hmac_buf[256] = { 0 }; std::string KeySecret_ali = (KeySecret + "&"); hmac_sha((char*)(ASCII2UTF_8(KeySecret_ali)).c_str(), (int)KeySecret_() , (char*)ASCII2UTF_8(sortQueryStringTmp).c_str(), (int)(), hmac_buf, 20); std::string hmac = std::string(hmac_buf,strlen(hmac_buf)); printf( "密钥+HmacSHA1算法:rn%srn", hmac.c_str()); //base64算法调⽤,前⾯签名算法结果作为输⼊参数,得到最终签名 hmac = ZBase64::Encode((const unsigned char*)hmac.c_str(), static_cast(())); printf( "HmacSHA1算法+Base64:rn%srn", hmac.c_str()); //将签名加⼊请求字段 _param("Signature", hmac.c_str()); //其他参数加⼊,注意中⽂字段UTF-8表述//TemplateParam,例如,"{"customer":"test"}",//进⾏传输短信的变量与你阿⾥短信服务模版的变量⼀致,(如都存在”customer“变量)//如果模版变量个数在 TemplateParam没有全含括或任意字段不匹配,都⽆法正常短信发送//变量的描述字段限制20位,例如,test不能超过20个字符长度,否则出错
_param("AccessKeyId", KeyId.c_str()); _param("Action", .c_str()); _param("Format", .c_str()); _param("OutId", .c_str()); _param("PhoneNumbers", umbers.c_str()); _param("RegionId", Id.c_str()); _param("SignName", ASCII2UTF_8(me).c_str()); _param("SignatureMethod", ureMethod.c_str()); _param("SignatureNonce", bufNonce.c_str()); _param("SignatureVersion", ureVersion.c_str()); _param("TemplateCode", teCode.c_str()); _param("TemplateParam", teParam.c_str()); _param("Timestamp", Timestamp.c_str()); _param("Version", n.c_str()); bool rc = t(NULL, 0);//http请求 // 将 build_request 放在 t 后⾯,是因为 // t 内部可能会修改请求头中的字段 acl::string hdr; _request(hdr); printf("request header:rn%srn", hdr.c_str()); if (rc == false) { printf( "send request error"); return; }
printf("send request ok!rn"); // 取出 HTTP 响应头的 Content-Type 字段
const char* p = _value("Content-Type"); if (p == NULL || *p == 0) { printf( "no Content-Type"); return; }// 分析 HTTP 响应头的数据类型
acl::http_ctype content_type; content_(p); // 响应头数据类型的⼦类型
const char* stype = content__stype(); bool ret; if (stype != NULL) ret = do_plain(req); if (ret == true) printf("read ok!");4)最终呈现效果图⼆的签名与图⼀部⼀致是因为两张图⽚分别来⾃两个请求的截图5)阿⾥云短信接⼝的http实现关键是做好签名,然后按通⽤的http访问请求实现即可,另外需要特别注意的是注意阿⾥⾥⾯短信定义要求,例如变量不能包含限制字符,变量长度不能超过20等等
2023年7月31日发(作者:)
阿⾥云短信服务接⼝的c++实现最近在调⽤阿⾥云短信服务接⼝发现并没有c++的资料,⽹上查询发现也是零星描述,由于⾃⾝项⽬基础累积了C++的太多,不想掺杂太多语⾔,就⾃⾏实现c++的阿⾥云短信接⼝,其难点就在于签名⽽已,希望能给⼤家提供参考。 *注册阿⾥云,有需要的阿⾥云产品通⽤代⾦券的可以点击下⾯链接进⾏领取:开通短信服务后,在你账户头像下AccessKeys选项进⼊⽤户信息管理界⾯,获取到你的AccessKeyId和AccessKeySecret,具体请参考阿⾥云短信服务的资料完成操作 *根据"http协议及签名”描述⽂档,定义了短信请求参数结构,初始化中带*的请⾃⾏写⼊⾃⼰实际参数:struct HttpMsgArg{ HttpMsgArg() : addr_("") , 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语⾔建议⽤:UUID()⽣成即可 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 = (); 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 = (); 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 errorn"); return ""; } _snprintf(buffer, sizeof(buffer), "%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X", 1, 2, 3, 4[0], 4[1], 4[2], 4[3], 4[4], 4[5], 4[6], 4[7]); printf("guid: %sn", 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 #include #ifdef WIN32#include #include #endif//using namespace std;bool containStr(std::string _str, std::string _strsub);#ifdef WIN32//UTF-8 to Unicodestd::wstring Utf82Unicode(const std::string& utf8string);//unicode to asciistd::string WideByte2Acsi(std::wstring& wstrcode);//ascii to Unicodestd::wstring Acsi2WideByte(std::string& strascii);//Unicode to Utf8std::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 asciistd::string UTF_82ASCII(std::string& strUtf8Code);//ascii to Utf8std::string ASCII2UTF_8(std::string& strAsciiCode);#endif //STRCHANGE_HPP/#include "strchange.h"#include #include #ifdef __linux__#include #include #include #include #endif//using namespace std;bool containStr(std::string _str, std::string _strsub){ std::string::size_type pos = _(_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 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 asciistd::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 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 Unicodestd::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 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 Utf8std::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 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 asciistd::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(strUtf8Code.c_str()),(),lpszBuf,256); return std::string(lpszBuf); // char lpszBuf[256]={0}; // u2a(const_cast(strUtf8Code.c_str()),(),lpszBuf,256); // return std::string(lpszBuf); // return std::string(strUtf8Code); #endif};//ascii to Utf8std::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(strAsciiCode.c_str()),(),lpszBuf,256); return std::string(lpszBuf); // char lpszBuf[256]={0}; // a2u(const_cast(strAsciiCode.c_str()),(),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#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//////#include "HMACSHA1.h"#include #include #include #include #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); 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 [] */ 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); 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 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); 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 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///#include "Base64.h"std::string ZBase64::Encode(const unsigned char* Data, int DataByte){ //编码表 const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; //返回值 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 += "rn"; 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;//定义⽹站、地址 ("%s%s", _.c_str(), _.c_str()); ("%s:%d", _.c_str(), _); acl::http_request req(acladdr); //请求构造 acl::http_header& header = t_header(); //访问类型为Get _method(acl::HTTP_METHOD_GET); _keep_alive(false);// _gzip(accept_gzip ? true : false);// //url _url(aclurl); //host if (_host() == NULL) { _host(_.c_str()); printf(">>>set host: %srn", _.c_str()); } else printf(">>>host: %srn", _host()); //签名内容缓存 std::string sortQueryStringTmp = ""; ("GET&").append(UrlEncode("/")); //签名内容项,参数key的字符串排序 std::string bufNonce = getUUID(); std::string Timestamp = getCurentTimeDesc(); teParam = ASCII2UTF_8(templateParam_); acl::url_coder coder;//注意中⽂字段UTF-8表述 ("AccessKeyId", KeyId.c_str()); ("Action", .c_str()); ("Format", .c_str()); ("OutId", .c_str()); ("PhoneNumbers", umbers.c_str()); ("RegionId", Id.c_str()); ("SignName", ASCII2UTF_8(me).c_str()); ("SignatureMethod", ureMethod.c_str()); ("SignatureNonce", bufNonce.c_str()); ("SignatureVersion", ureVersion.c_str()); ("TemplateCode", teCode.c_str()); ("TemplateParam", teParam.c_str()); ("Timestamp", Timestamp.c_str()); ("Version", n.c_str()); // std::string urlcode = std::string(_string().c_str());// printf( "排序参数集:rn%srn", urlcode.c_str()); ("&").append(UrlEncode(urlcode)); printf( "待签名的请求字符串UrlEncode:rn%srn", sortQueryStringTmp.c_str()); //⽣成签名,调⽤签名算法函数,注意阿⾥的AccessKeySecret+&才是真正的AccessKeySecret char hmac_buf[256] = { 0 }; std::string KeySecret_ali = (KeySecret + "&"); hmac_sha((char*)(ASCII2UTF_8(KeySecret_ali)).c_str(), (int)KeySecret_() , (char*)ASCII2UTF_8(sortQueryStringTmp).c_str(), (int)(), hmac_buf, 20); std::string hmac = std::string(hmac_buf,strlen(hmac_buf)); printf( "密钥+HmacSHA1算法:rn%srn", hmac.c_str()); //base64算法调⽤,前⾯签名算法结果作为输⼊参数,得到最终签名 hmac = ZBase64::Encode((const unsigned char*)hmac.c_str(), static_cast(())); printf( "HmacSHA1算法+Base64:rn%srn", hmac.c_str()); //将签名加⼊请求字段 _param("Signature", hmac.c_str()); //其他参数加⼊,注意中⽂字段UTF-8表述//TemplateParam,例如,"{"customer":"test"}",//进⾏传输短信的变量与你阿⾥短信服务模版的变量⼀致,(如都存在”customer“变量)//如果模版变量个数在 TemplateParam没有全含括或任意字段不匹配,都⽆法正常短信发送//变量的描述字段限制20位,例如,test不能超过20个字符长度,否则出错
_param("AccessKeyId", KeyId.c_str()); _param("Action", .c_str()); _param("Format", .c_str()); _param("OutId", .c_str()); _param("PhoneNumbers", umbers.c_str()); _param("RegionId", Id.c_str()); _param("SignName", ASCII2UTF_8(me).c_str()); _param("SignatureMethod", ureMethod.c_str()); _param("SignatureNonce", bufNonce.c_str()); _param("SignatureVersion", ureVersion.c_str()); _param("TemplateCode", teCode.c_str()); _param("TemplateParam", teParam.c_str()); _param("Timestamp", Timestamp.c_str()); _param("Version", n.c_str()); bool rc = t(NULL, 0);//http请求 // 将 build_request 放在 t 后⾯,是因为 // t 内部可能会修改请求头中的字段 acl::string hdr; _request(hdr); printf("request header:rn%srn", hdr.c_str()); if (rc == false) { printf( "send request error"); return; }
printf("send request ok!rn"); // 取出 HTTP 响应头的 Content-Type 字段
const char* p = _value("Content-Type"); if (p == NULL || *p == 0) { printf( "no Content-Type"); return; }// 分析 HTTP 响应头的数据类型
acl::http_ctype content_type; content_(p); // 响应头数据类型的⼦类型
const char* stype = content__stype(); bool ret; if (stype != NULL) ret = do_plain(req); if (ret == true) printf("read ok!");4)最终呈现效果图⼆的签名与图⼀部⼀致是因为两张图⽚分别来⾃两个请求的截图5)阿⾥云短信接⼝的http实现关键是做好签名,然后按通⽤的http访问请求实现即可,另外需要特别注意的是注意阿⾥⾥⾯短信定义要求,例如变量不能包含限制字符,变量长度不能超过20等等
发布评论