mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
- 新增ISV用户平台
- 新增门户网站(portal) - 新增`C++`,`Rust`语言SDK
This commit is contained in:
133
sop-sdk/sdk-c++/common/OpenClient.cpp
Normal file
133
sop-sdk/sdk-c++/common/OpenClient.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "OpenClient.h"
|
||||
#include "httplib.h"
|
||||
#include "tool.h"
|
||||
#include "sign.h"
|
||||
|
||||
#include "../thirdparty/CJsonObject/CJsonObject.hpp"
|
||||
|
||||
httplib::Headers headers = {
|
||||
{"Accept-Encoding", "identity"}
|
||||
};
|
||||
|
||||
const string ERROR_NODE = "error_response";
|
||||
|
||||
OpenClient::OpenClient(const string &appId, const string &privateKeyFilePath, const string &url) {
|
||||
this->appId = appId;
|
||||
this->privateKeyFilePath = privateKeyFilePath;
|
||||
|
||||
char *_url = const_cast<char *>(url.c_str());
|
||||
char *host;
|
||||
int port;
|
||||
char *path;
|
||||
tool::parse_url(_url, &host, &port, &path);
|
||||
this->hostInfo = HostInfo{
|
||||
host = host,
|
||||
port = port,
|
||||
path = path
|
||||
};
|
||||
}
|
||||
|
||||
neb::CJsonObject OpenClient::execute(BaseRequest *request) {
|
||||
return this->execute(request, "");
|
||||
}
|
||||
|
||||
neb::CJsonObject OpenClient::execute(BaseRequest *request, const string &token) {
|
||||
string method = request->getMethod();
|
||||
string version = request->getVersion();
|
||||
RequestType requestType = request->getRequestType();
|
||||
map<string, string> bizModel = request->bizModel;
|
||||
// 创建HTTP请求客户端
|
||||
httplib::Client cli(this->hostInfo.host, this->hostInfo.port);
|
||||
// 构建请求参数
|
||||
map<string, string> allParams = this->buildParams(request, token);
|
||||
char *path = this->hostInfo.path;
|
||||
string responseBody;
|
||||
// 如果有文件上传
|
||||
if (!request->getFiles().empty()) {
|
||||
httplib::MultipartFormDataItems items = OpenClient::getMultipartFormDataItems(
|
||||
allParams, request->getFiles());
|
||||
responseBody = cli.Post(path, headers, items)->body;
|
||||
} else {
|
||||
switch (requestType) {
|
||||
case GET: {
|
||||
responseBody = cli.Get(path, allParams, headers)->body;
|
||||
break;
|
||||
}
|
||||
case POST_FORM: {
|
||||
responseBody = cli.Post(path, headers, OpenClient::getParams(allParams))->body;
|
||||
break;
|
||||
}
|
||||
case POST_JSON: {
|
||||
string json = tool::mapToJson(allParams);
|
||||
responseBody = cli.Post(path, json, "application/json")->body;
|
||||
break;
|
||||
}
|
||||
case POST_FILE: {
|
||||
httplib::MultipartFormDataItems items = OpenClient::getMultipartFormDataItems(
|
||||
allParams, request->getFiles());
|
||||
responseBody = cli.Post(path, headers, items)->body;
|
||||
}
|
||||
}
|
||||
}
|
||||
return OpenClient::parseResponse(responseBody, request);
|
||||
}
|
||||
|
||||
|
||||
httplib::Params OpenClient::getParams(map<string, string> allParams) {
|
||||
httplib::Params params;
|
||||
map<string, string>::iterator it;
|
||||
for (it = allParams.begin(); it != allParams.end(); ++it) {
|
||||
params.emplace(it->first, it->second);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
map<string, string> OpenClient::buildParams(BaseRequest *request, const string &token) {
|
||||
map<string, string> allParams;
|
||||
allParams["app_id"] = this->appId;
|
||||
allParams["method"] = request->getMethod();
|
||||
allParams["charset"] = "UTF-8";
|
||||
allParams["sign_type"] = "RSA2";
|
||||
allParams["timestamp"] = tool::getTime();
|
||||
allParams["version"] = request->getVersion();
|
||||
|
||||
if (!token.empty()) {
|
||||
allParams["app_auth_token"] = token;
|
||||
}
|
||||
|
||||
map<string, string> bizModel = request->bizModel;
|
||||
|
||||
allParams.insert(bizModel.begin(), bizModel.end());
|
||||
|
||||
// 生成签名
|
||||
string sign = signutil::createSign(allParams, this->privateKeyFilePath, "RSA2");
|
||||
allParams["sign"] = sign;
|
||||
return allParams;
|
||||
}
|
||||
|
||||
httplib::MultipartFormDataItems
|
||||
OpenClient::getMultipartFormDataItems(map<string, string> allParams, vector<FileInfo> fileInfoList) {
|
||||
httplib::MultipartFormDataItems items = {};
|
||||
map<string, string>::iterator it;
|
||||
for (it = allParams.begin(); it != allParams.end(); ++it) {
|
||||
items.push_back({it->first, it->second, "", ""});
|
||||
}
|
||||
// 添加上传文件
|
||||
vector<FileInfo>::iterator vit;
|
||||
for (vit = fileInfoList.begin(); vit != fileInfoList.end(); vit++) {
|
||||
string content = tool::getFileContent(vit->filepath);
|
||||
items.push_back({vit->name, content, tool::getFilename(vit->filepath), "application/octet-stream"});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
neb::CJsonObject OpenClient::parseResponse(const string& responseBody, BaseRequest *request) {
|
||||
neb::CJsonObject oJson(responseBody);
|
||||
neb::CJsonObject data = oJson[ERROR_NODE];
|
||||
if (data.IsEmpty()) {
|
||||
string method = request->getMethod();
|
||||
string nodeName = tool::replace(method.c_str(),".","_") + "_response";
|
||||
data = oJson[nodeName];
|
||||
}
|
||||
return data;
|
||||
}
|
66
sop-sdk/sdk-c++/common/OpenClient.h
Normal file
66
sop-sdk/sdk-c++/common/OpenClient.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef SDK_CXX_OPENCLIENT_H
|
||||
#define SDK_CXX_OPENCLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include "httplib.h"
|
||||
#include "../request/BaseRequest.h"
|
||||
#include "../thirdparty/CJsonObject/CJsonObject.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct HostInfo {
|
||||
string host;
|
||||
int port;
|
||||
char *path;
|
||||
};
|
||||
|
||||
/**
|
||||
* 请求客户端
|
||||
*/
|
||||
class OpenClient {
|
||||
private:
|
||||
/** 应用id */
|
||||
string appId;
|
||||
/** 私钥文件路径 */
|
||||
string privateKeyFilePath;
|
||||
|
||||
public:
|
||||
/**
|
||||
* 创建客户端对象
|
||||
* @param appId 应用ID
|
||||
* @param privateKeyFilePath 应用私钥路径
|
||||
* @param url 请求URL
|
||||
*/
|
||||
OpenClient(const string &appId, const string &privateKeyFilePath, const string &url);
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
* @param request 请求对象,BaseRequest的子类
|
||||
* @param token token
|
||||
* @return 返回响应结果
|
||||
*/
|
||||
neb::CJsonObject execute(BaseRequest *request, const string& token);
|
||||
|
||||
/**
|
||||
* 发送请求
|
||||
* @param request 请求对象,BaseRequest的子类
|
||||
* @return 返回响应结果
|
||||
*/
|
||||
neb::CJsonObject execute(BaseRequest *request);
|
||||
|
||||
private:
|
||||
|
||||
HostInfo hostInfo;
|
||||
|
||||
map<string, string> buildParams(BaseRequest *request, const string& token);
|
||||
|
||||
static httplib::MultipartFormDataItems
|
||||
getMultipartFormDataItems(map<string, string> allParams, vector<FileInfo> fileInfoList);
|
||||
|
||||
static httplib::Params getParams(map<string, string> params);
|
||||
|
||||
static neb::CJsonObject parseResponse(const string& responseBody,BaseRequest *request);
|
||||
};
|
||||
|
||||
|
||||
#endif //SDK_CXX_OPENCLIENT_H
|
94
sop-sdk/sdk-c++/common/RSASign.cpp
Normal file
94
sop-sdk/sdk-c++/common/RSASign.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "stdafx.h"
|
||||
#include "RSASign.h"
|
||||
#include "../thirdparty/base64/base64.h"
|
||||
|
||||
RSA* GetPublicKeyEx(char* szPath)
|
||||
{
|
||||
RSA *pubkey = RSA_new();
|
||||
|
||||
BIO *pubio;
|
||||
|
||||
pubio = BIO_new_file(szPath, "rb");
|
||||
pubkey = PEM_read_bio_RSAPublicKey(pubio, &pubkey, NULL, NULL);
|
||||
|
||||
BIO_free(pubio);
|
||||
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
RSA* GetPrivateKeyEx(char* szPath)
|
||||
{
|
||||
RSA *prikey = RSA_new();
|
||||
|
||||
BIO *priio;
|
||||
|
||||
priio = BIO_new_file(szPath, "rb");
|
||||
prikey = PEM_read_bio_RSAPrivateKey(priio, &prikey, NULL, NULL);
|
||||
|
||||
BIO_free(priio);
|
||||
|
||||
return prikey;
|
||||
}
|
||||
|
||||
bool RSASignAction(const string& strEnData, char *privateKeyFilePath, string &strSigned)
|
||||
{
|
||||
int nlen = strEnData.length();
|
||||
RSA *prsa = NULL;
|
||||
if (NULL == (prsa = GetPrivateKeyEx(privateKeyFilePath)))
|
||||
{
|
||||
RSA_free(prsa);
|
||||
printf("获取私钥失败\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char szTmp[1024] = { 0 };
|
||||
//对待签名数据做SHA1摘要
|
||||
SHA256((const unsigned char*)strEnData.c_str(), nlen, (unsigned char*)szTmp);
|
||||
int nLength;
|
||||
unsigned int nLengthRet;
|
||||
char szTmp1[1024] = { 0 }; //位数一定不能小于等于RSA的128位,没有‘\0’,数据会增加后面位数
|
||||
// unsigned char *szTmp1 = {0};
|
||||
nLength = RSA_sign(NID_sha256, (unsigned char *)szTmp, 32, (unsigned char *)szTmp1, &nLengthRet, prsa);
|
||||
if (nLength != 1)
|
||||
{
|
||||
RSA_free(prsa);
|
||||
return false;
|
||||
}
|
||||
strSigned = base64_encode((unsigned char *)szTmp1, strlen((const char *)szTmp1));
|
||||
RSA_free(prsa);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RSAVerifyAction(string strEnData, string &strSigned)
|
||||
{
|
||||
int nlen = strEnData.length();
|
||||
printf("验签的原始数据:[%s]\n", strEnData.c_str());
|
||||
|
||||
RSA *prsa = NULL;
|
||||
if (NULL == (prsa = GetPublicKeyEx(PUBLIC_KEY_FILE_EX)))
|
||||
{
|
||||
RSA_free(prsa);
|
||||
printf("获取公钥失败\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//对待签名数据做SHA1摘要
|
||||
char szTmp[1024] = { 0 };
|
||||
int nLen = strEnData.length();
|
||||
SHA256((const unsigned char*)strEnData.c_str(), nLen, (unsigned char*)szTmp);
|
||||
|
||||
int nLength;
|
||||
unsigned int nLengthRet = strSigned.length();
|
||||
printf("nLengthRet2 = %d\n", nLengthRet);
|
||||
nLength = RSA_verify(NID_sha256, (unsigned char *)szTmp, 32, (unsigned char*)strSigned.c_str(), nLengthRet, prsa);
|
||||
if (nLength != 1)
|
||||
{
|
||||
RSA_free(prsa);
|
||||
return false;
|
||||
}
|
||||
|
||||
RSA_free(prsa);
|
||||
|
||||
return true;
|
||||
}
|
19
sop-sdk/sdk-c++/common/RSASign.h
Normal file
19
sop-sdk/sdk-c++/common/RSASign.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define PUBLIC_KEY_FILE_EX "publicEx.pem" //公钥文件
|
||||
#define PRIVATE_KEY_FILE_EX "privateEx.pem" //私钥文件
|
||||
|
||||
RSA* GetPublicKeyEx(char* szPath);
|
||||
RSA* GetPrivateKeyEx(char* szPath);
|
||||
|
||||
bool RSASignAction(const string& strEnData,char *privateKeyFilePath, string &strSigned);
|
||||
bool RSAVerifyAction(string strEnData, string &strSigned);
|
11
sop-sdk/sdk-c++/common/RequestType.h
Normal file
11
sop-sdk/sdk-c++/common/RequestType.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef SDK_CXX_REQUESTTYPE_H
|
||||
#define SDK_CXX_REQUESTTYPE_H
|
||||
|
||||
enum RequestType {
|
||||
GET,
|
||||
POST_FORM,
|
||||
POST_JSON,
|
||||
POST_FILE
|
||||
};
|
||||
|
||||
#endif //SDK_CXX_REQUESTTYPE_H
|
5741
sop-sdk/sdk-c++/common/httplib.h
Normal file
5741
sop-sdk/sdk-c++/common/httplib.h
Normal file
File diff suppressed because it is too large
Load Diff
270
sop-sdk/sdk-c++/common/sha256.cpp
Normal file
270
sop-sdk/sdk-c++/common/sha256.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Filename: sha256.cpp
|
||||
* Author: L.Y.
|
||||
* Brief: SHA256算法实现
|
||||
* Version: V1.0.0
|
||||
* Update log:
|
||||
* 1)20191108-20191113 V1.0.0
|
||||
* 1、初次版本。
|
||||
* TODO:
|
||||
* Attention:
|
||||
* 1)输入信息中有中文时,得到的数字指纹与使用SHA256在线加密工具得到数字指纹可能不相同。
|
||||
* 原因是中文的编码方式不同。
|
||||
*/
|
||||
|
||||
#include "sha256.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace digest
|
||||
{
|
||||
|
||||
//////////////////////////////// 静态数据成员初始化 //////////////////////////////////////////
|
||||
|
||||
std::vector<uint32_t> Sha256::initial_message_digest_ =
|
||||
{
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372,
|
||||
0xa54ff53a, 0x510e527f, 0x9b05688c,
|
||||
0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
std::vector<uint32_t> Sha256::add_constant_ =
|
||||
{
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////// 成员函数的定义 //////////////////////////////////////////
|
||||
|
||||
bool Sha256::encrypt(const std::vector<uint8_t>& input_message,
|
||||
std::vector<uint8_t>* _digest)
|
||||
{
|
||||
if (!input_message.empty() && _digest)
|
||||
{
|
||||
//! 文本预处理
|
||||
std::vector<uint8_t> message = input_message;
|
||||
preprocessing(&message);
|
||||
|
||||
//! 将文本分解成连续的64Byte大小的数据块
|
||||
std::vector<std::vector<uint8_t>> chunks;
|
||||
breakTextInto64ByteChunks(message, &chunks);
|
||||
|
||||
//! 由64Byte大小的数据块,构造出64个4Byte大小的字。然后进行循环迭代。
|
||||
std::vector<uint32_t> message_digest(initial_message_digest_); // 初始化信息摘要
|
||||
|
||||
std::vector<uint32_t> words;
|
||||
for (const auto& chunk : chunks)
|
||||
{
|
||||
structureWords(chunk, &words);
|
||||
transform(words, &message_digest);
|
||||
}
|
||||
|
||||
//! 获取最终结果
|
||||
produceFinalHashValue(message_digest, _digest);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Sha256::getHexMessageDigest(const std::string& message)
|
||||
{
|
||||
if (!message.empty())
|
||||
{
|
||||
std::vector<uint8_t> __message;
|
||||
for (auto it = message.begin(); it != message.end(); ++it)
|
||||
{
|
||||
__message.push_back(static_cast<uint8_t>(*it));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> digest;
|
||||
encrypt(__message, &digest);
|
||||
|
||||
std::ostringstream o_s;
|
||||
o_s << std::hex << std::setiosflags(std::ios::uppercase);
|
||||
for (auto it = digest.begin(); it != digest.end(); ++it)
|
||||
{
|
||||
o_s << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<unsigned short>(*it);
|
||||
}
|
||||
|
||||
return o_s.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::preprocessing(std::vector<uint8_t>* _message) const
|
||||
{
|
||||
if (_message)
|
||||
{
|
||||
const uint64_t original_bit_size = _message->size() * 8;
|
||||
|
||||
//! 附加填充比特
|
||||
size_t remainder = _message->size() % 64;
|
||||
if (remainder < 56)
|
||||
{
|
||||
_message->push_back(0x80); // ox80 == 10000000
|
||||
for (size_t i = 1; i < 56 - remainder; ++i)
|
||||
{
|
||||
_message->push_back(0x00);
|
||||
}
|
||||
}
|
||||
else if (remainder == 56)
|
||||
{
|
||||
_message->push_back(0x80);
|
||||
for (size_t i = 1; i < 64; ++i)
|
||||
{
|
||||
_message->push_back(0x00);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message->push_back(0x80);
|
||||
for (size_t i = 1; i < 64 - remainder + 56; ++i)
|
||||
{
|
||||
_message->push_back(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
//! 附加原始文本的长度值
|
||||
for (int i = 1; i <= 8; ++i)
|
||||
{
|
||||
uint8_t c = static_cast<uint8_t>(original_bit_size >> (64 - 8 * i));
|
||||
_message->push_back(c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::breakTextInto64ByteChunks(const std::vector<uint8_t>& message,
|
||||
std::vector<std::vector<uint8_t>>* _chunks) const
|
||||
{
|
||||
if (_chunks && 0 == message.size() % 64)
|
||||
{
|
||||
_chunks->clear(); // 清空输出buffer
|
||||
|
||||
size_t quotient = message.size() / 64;
|
||||
for (size_t i = 0; i < quotient; ++i)
|
||||
{
|
||||
std::vector<uint8_t> temp(message.begin() + i * 64, message.begin() + (i + 1) * 64);
|
||||
_chunks->push_back(temp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::structureWords(const std::vector<uint8_t>& chunk,
|
||||
std::vector<uint32_t>* _words) const
|
||||
{
|
||||
if (_words && 64 == chunk.size())
|
||||
{
|
||||
_words->resize(64);
|
||||
|
||||
auto& words = *_words;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
words[i] = (static_cast<uint32_t>(chunk[i * 4]) << 24)
|
||||
| (static_cast<uint32_t>(chunk[i * 4 + 1]) << 16)
|
||||
| (static_cast<uint32_t>(chunk[i * 4 + 2]) << 8)
|
||||
| static_cast<uint32_t>(chunk[i * 4 + 3]);
|
||||
}
|
||||
for (int i = 16; i < 64; ++i)
|
||||
{
|
||||
words[i] = small_sigma1(words[i - 2])
|
||||
+ words[i - 7]
|
||||
+ small_sigma0(words[i - 15])
|
||||
+ words[i - 16];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::transform(const std::vector<uint32_t>& words,
|
||||
std::vector<uint32_t>* _message_digest) const
|
||||
{
|
||||
if (_message_digest && 8 == _message_digest->size() && 64 == words.size())
|
||||
{
|
||||
std::vector<uint32_t> d = *_message_digest;
|
||||
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
uint32_t temp1 = d[7] + big_sigma1(d[4]) + ch(d[4], d[5], d[6]) + add_constant_[i] + words[i];
|
||||
uint32_t temp2 = big_sigma0(d[0]) + maj(d[0], d[1], d[2]);
|
||||
|
||||
d[7] = d[6];
|
||||
d[6] = d[5];
|
||||
d[5] = d[4];
|
||||
d[4] = d[3] + temp1;
|
||||
d[3] = d[2];
|
||||
d[2] = d[1];
|
||||
d[1] = d[0];
|
||||
d[0] = temp1 + temp2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
(*_message_digest)[i] += d[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sha256::produceFinalHashValue(const std::vector<uint32_t>& input,
|
||||
std::vector<uint8_t>* _output) const
|
||||
{
|
||||
if (_output)
|
||||
{
|
||||
_output->clear();
|
||||
|
||||
for (auto it = input.begin(); it != input.end(); ++it)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_output->push_back(static_cast<uint8_t>((*it) >> (24 - 8 * i)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ly
|
||||
|
||||
|
144
sop-sdk/sdk-c++/common/sha256.hpp
Normal file
144
sop-sdk/sdk-c++/common/sha256.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Filename: sha256.hpp
|
||||
* Author: L.Y.
|
||||
* Brief: SHA256算法实现
|
||||
* Version: V1.0.0
|
||||
* Update log:
|
||||
* 1)20191108-20191113 V1.0.0
|
||||
* 1、初次版本。
|
||||
* TODO:
|
||||
* Attention:
|
||||
* 1)输入信息中有中文时,得到的数字指纹与使用SHA256在线加密工具得到数字指纹可能不相同。
|
||||
* 原因是中文的编码方式不同。
|
||||
*/
|
||||
|
||||
#ifndef SHA256_HPP
|
||||
#define SHA256_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace digest
|
||||
{
|
||||
|
||||
//
|
||||
// \brief: SHA256算法实现
|
||||
//
|
||||
class Sha256
|
||||
{
|
||||
public:
|
||||
//! 默认构造函数
|
||||
Sha256() {}
|
||||
|
||||
//! 析构函数
|
||||
virtual ~Sha256() {}
|
||||
|
||||
/** @brief: 使用SHA256算法,获取输入信息的摘要(数字指纹)
|
||||
@param[in] message: 输入信息
|
||||
@param[out] _digest: 摘要(数字指纹)
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool encrypt(const std::vector<uint8_t>& message,
|
||||
std::vector<uint8_t>* _digest);
|
||||
|
||||
/** @brief: 获取十六进制表示的信息摘要(数字指纹)
|
||||
@param[in] message: 输入信息
|
||||
@return: 十六进制表示的信息摘要(数字指纹)
|
||||
*/
|
||||
std::string getHexMessageDigest(const std::string& message);
|
||||
|
||||
protected:
|
||||
/////// SHA256算法中定义的6种逻辑运算 ///////
|
||||
inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) const;
|
||||
inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z) const;
|
||||
inline uint32_t big_sigma0(uint32_t x) const;
|
||||
inline uint32_t big_sigma1(uint32_t x) const;
|
||||
inline uint32_t small_sigma0(uint32_t x) const;
|
||||
inline uint32_t small_sigma1(uint32_t x) const;
|
||||
|
||||
/** @brief: SHA256算法对输入信息的预处理,包括“附加填充比特”和“附加长度值”
|
||||
附加填充比特: 在报文末尾进行填充,先补第一个比特为1,然后都补0,直到长度满足对512取模后余数是448。需要注意的是,信息必须进行填充。
|
||||
附加长度值: 用一个64位的数据来表示原始消息(填充前的消息)的长度,并将其补到已经进行了填充操作的消息后面。
|
||||
@param[in][out] _message: 待处理的信息
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool preprocessing(std::vector<uint8_t>* _message) const;
|
||||
|
||||
/** @brief: 将信息分解成连续的64Byte大小的数据块
|
||||
@param[in] message: 输入信息,长度为64Byte的倍数
|
||||
@param[out] _chunks: 输出数据块
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool breakTextInto64ByteChunks(const std::vector<uint8_t>& message,
|
||||
std::vector<std::vector<uint8_t>>* _chunks) const;
|
||||
|
||||
/** @brief: 由64Byte大小的数据块,构造出64个4Byte大小的字。
|
||||
构造算法:前16个字直接由数据块分解得到,其余的字由如下迭代公式得到:
|
||||
W[t] = small_sigma1(W[t-2]) + W[t-7] + small_sigma0(W[t-15]) + W[t-16]
|
||||
@param[in] chunk: 输入数据块,大小为64Byte
|
||||
@param[out] _words: 输出字
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool structureWords(const std::vector<uint8_t>& chunk,
|
||||
std::vector<uint32_t>* _words) const;
|
||||
|
||||
/** @breif: 基于64个4Byte大小的字,进行64次循环加密
|
||||
@param[in] words: 64个4Byte大小的字
|
||||
@param[in][out] _message_digest: 信息摘要
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool transform(const std::vector<uint32_t>& words,
|
||||
std::vector<uint32_t>* _message_digest) const;
|
||||
|
||||
/** @brief: 输出最终的哈希值(数字指纹)
|
||||
@param[in] input: 步长为32bit的哈希值
|
||||
@param[out] _output: 步长为8bit的哈希值
|
||||
@return: 是否成功
|
||||
*/
|
||||
bool produceFinalHashValue(const std::vector<uint32_t>& input,
|
||||
std::vector<uint8_t>* _output) const;
|
||||
|
||||
|
||||
private:
|
||||
static std::vector<uint32_t> initial_message_digest_; // 在SHA256算法中的初始信息摘要,这些常量是对自然数中前8个质数的平方根的小数部分取前32bit而来。
|
||||
static std::vector<uint32_t> add_constant_; // 在SHA256算法中,用到64个常量,这些常量是对自然数中前64个质数的立方根的小数部分取前32bit而来。
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////// 内联函数&模版函数的定义 /////////////////////////////////////////
|
||||
|
||||
inline uint32_t Sha256::ch(uint32_t x, uint32_t y, uint32_t z) const
|
||||
{
|
||||
return (x & y) ^ ((~x) & z);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::maj(uint32_t x, uint32_t y, uint32_t z) const
|
||||
{
|
||||
return (x & y) ^ (x & z) ^ (y & z);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::big_sigma0(uint32_t x) const
|
||||
{
|
||||
return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::big_sigma1(uint32_t x) const
|
||||
{
|
||||
return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::small_sigma0(uint32_t x) const
|
||||
{
|
||||
return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3);
|
||||
}
|
||||
|
||||
inline uint32_t Sha256::small_sigma1(uint32_t x) const
|
||||
{
|
||||
return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10);
|
||||
}
|
||||
|
||||
} // namespace ly
|
||||
|
||||
#endif // SHA256_HPP
|
118
sop-sdk/sdk-c++/common/sign.cpp
Normal file
118
sop-sdk/sdk-c++/common/sign.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <utility>
|
||||
|
||||
#include "../thirdparty/base64/base64.h"
|
||||
#include "sign.h"
|
||||
#include "RSASign.h"
|
||||
#include "tool.h"
|
||||
|
||||
namespace signutil {
|
||||
string createSign(map<string, string> params, const string& privateKeyFilepath, const string& signType) {
|
||||
string content = getSignContent(std::move(params));
|
||||
return sign(content, privateKeyFilepath, "");
|
||||
}
|
||||
|
||||
string sign(const string& content, const string& privateKeyFilepath, const string& hash) {
|
||||
BIO *bufio = NULL;
|
||||
RSA *rsa = NULL;
|
||||
EVP_PKEY *evpKey = NULL;
|
||||
bool verify = false;
|
||||
EVP_MD_CTX ctx;
|
||||
int result = 0;
|
||||
unsigned int size = 0;
|
||||
char *sign = NULL;
|
||||
std::string signStr = "";
|
||||
|
||||
//bufio = BIO_new_mem_buf((void*)private_key, -1);
|
||||
//if (bufio == NULL) {
|
||||
// ERR("BIO_new_mem_buf failed");
|
||||
// goto safe_exit;
|
||||
//}
|
||||
bufio = BIO_new(BIO_s_file());
|
||||
// 读取私钥文件
|
||||
BIO_read_filename(bufio, privateKeyFilepath.c_str());
|
||||
|
||||
// 私钥字符串转换成私钥对象
|
||||
rsa = PEM_read_bio_RSAPrivateKey(bufio, NULL, NULL, NULL);
|
||||
if (rsa == NULL) {
|
||||
ERR("PEM_read_bio_RSAPrivateKey failed");
|
||||
goto safe_exit;
|
||||
}
|
||||
|
||||
evpKey = EVP_PKEY_new();
|
||||
if (evpKey == NULL) {
|
||||
ERR("EVP_PKEY_new failed");
|
||||
goto safe_exit;
|
||||
}
|
||||
|
||||
if ((result = EVP_PKEY_set1_RSA(evpKey, rsa)) != 1) {
|
||||
ERR("EVP_PKEY_set1_RSA failed");
|
||||
goto safe_exit;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_init(&ctx);
|
||||
|
||||
// SHA256签名
|
||||
if (result == 1 && (result = EVP_SignInit_ex(&ctx,
|
||||
EVP_sha256(), NULL)) != 1) {
|
||||
ERR("EVP_SignInit_ex failed");
|
||||
}
|
||||
|
||||
if (result == 1 && (result = EVP_SignUpdate(&ctx,
|
||||
content.c_str(), content.size())) != 1) {
|
||||
ERR("EVP_SignUpdate failed");
|
||||
}
|
||||
|
||||
size = EVP_PKEY_size(evpKey);
|
||||
sign = (char*)malloc(size+1);
|
||||
memset(sign, 0, size+1);
|
||||
|
||||
if (result == 1 && (result = EVP_SignFinal(&ctx,
|
||||
(unsigned char*)sign,
|
||||
&size, evpKey)) != 1) {
|
||||
ERR("EVP_SignFinal failed");
|
||||
}
|
||||
|
||||
if (result == 1) {
|
||||
verify = true;
|
||||
} else {
|
||||
ERR("verify failed");
|
||||
}
|
||||
|
||||
signStr = base64_encode((const unsigned char*)sign, size);
|
||||
EVP_MD_CTX_cleanup(&ctx);
|
||||
free(sign);
|
||||
|
||||
safe_exit:
|
||||
if (rsa != NULL) {
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
}
|
||||
|
||||
if (evpKey != NULL) {
|
||||
EVP_PKEY_free(evpKey);
|
||||
evpKey = NULL;
|
||||
}
|
||||
|
||||
if (bufio != NULL) {
|
||||
BIO_free_all(bufio);
|
||||
bufio = NULL;
|
||||
}
|
||||
|
||||
return signStr;
|
||||
|
||||
}
|
||||
|
||||
string getSignContent(map<string, string> params){
|
||||
map<string, string>::iterator iter;
|
||||
string content;
|
||||
for(iter = params.begin(); iter != params.end(); iter++) {
|
||||
content.append("&").append(iter->first + "=" + iter->second);
|
||||
}
|
||||
return content.substr(1);
|
||||
}
|
||||
|
||||
void ERR(const string &msg) {
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
30
sop-sdk/sdk-c++/common/sign.h
Normal file
30
sop-sdk/sdk-c++/common/sign.h
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
#ifndef SDK_CXX_SIGN_H
|
||||
#define SDK_CXX_SIGN_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace signutil {
|
||||
|
||||
string createSign(map<string, string> params, const string& privateKeyFilepath, const string& signType);
|
||||
|
||||
string sign(const string& content, const string& privateKeyFilepath, const string& hash);
|
||||
|
||||
string getSignContent(map<string, string> params);
|
||||
|
||||
void ERR(const string &msg);
|
||||
}
|
||||
|
||||
|
||||
#endif //SDK_CXX_SIGN_H
|
2
sop-sdk/sdk-c++/common/stdafx.cpp
Normal file
2
sop-sdk/sdk-c++/common/stdafx.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "stdafx.h"
|
6
sop-sdk/sdk-c++/common/stdafx.h
Normal file
6
sop-sdk/sdk-c++/common/stdafx.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
|
||||
|
1
sop-sdk/sdk-c++/common/targetver.h
Normal file
1
sop-sdk/sdk-c++/common/targetver.h
Normal file
@@ -0,0 +1 @@
|
||||
|
174
sop-sdk/sdk-c++/common/tool.cpp
Normal file
174
sop-sdk/sdk-c++/common/tool.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#include <clocale>
|
||||
#include "tool.h"
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace tool {
|
||||
bool endWith(const string &str, const string &tail) {
|
||||
return str.compare(str.size() - tail.size(), tail.size(), tail) == 0;
|
||||
}
|
||||
|
||||
bool startWith(const string &str, const string &head) {
|
||||
return str.compare(0, head.size(), head) == 0;
|
||||
}
|
||||
|
||||
string getTime() {
|
||||
time_t timep;
|
||||
time(&timep);
|
||||
char tmp[64];
|
||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&timep));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int parse_url(char *url, char **serverstrp, int *portp, char **pathstrp) {
|
||||
char buf[256];
|
||||
int serverlen, numread = 0;
|
||||
/* go through the url */
|
||||
|
||||
/* reset url to point PAST the http:// */
|
||||
|
||||
/* assume it's always 7 chars! */
|
||||
string _url = url;
|
||||
bool isHttps = startWith(_url, "https");
|
||||
int len = 7;
|
||||
if (isHttps) {
|
||||
len = 8;
|
||||
}
|
||||
url = url + len;
|
||||
/* no http:// now... server is simply up to the next / or : */
|
||||
|
||||
sscanf(url, "%255[^/:]", buf);
|
||||
serverlen = strlen(buf);
|
||||
*serverstrp = (char *) malloc(serverlen + 1);
|
||||
strcpy(*serverstrp, buf);
|
||||
if (url[serverlen] == ':') {
|
||||
/* get the port */
|
||||
|
||||
sscanf(&url[serverlen + 1], "%d%n", portp, &numread);
|
||||
/* add one to go PAST it */
|
||||
|
||||
numread++;
|
||||
|
||||
} else {
|
||||
if (isHttps) {
|
||||
*portp = 443;
|
||||
} else {
|
||||
*portp = 80;
|
||||
}
|
||||
|
||||
}
|
||||
/* the path is a pointer into the rest of url */
|
||||
|
||||
*pathstrp = &url[serverlen + numread];
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string url_encode(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 url_decode(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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
string mapToJson(std::map<string, string> map_info) {
|
||||
// Json::Value jObject;
|
||||
// for (map<string, string>::const_iterator iter = map_info.begin( ); iter != map_info.end( ); ++iter)
|
||||
// {
|
||||
// jObject[iter->first] = iter->second;
|
||||
// }
|
||||
// return jObject.toStyledString();
|
||||
return "{}";
|
||||
}
|
||||
|
||||
string getFilename(string filepath) {
|
||||
{
|
||||
if (filepath.empty()) {
|
||||
return "";
|
||||
}
|
||||
std::string::size_type iPos;
|
||||
#ifdef Q_OS_WIN
|
||||
iPos = strFullName.find_last_of('\\') + 1;
|
||||
#else
|
||||
iPos = filepath.find_last_of('/') + 1;
|
||||
#endif
|
||||
|
||||
return filepath.substr(iPos, filepath.length() - iPos);
|
||||
}
|
||||
}
|
||||
|
||||
string getFileContent(string filepath) {
|
||||
ifstream fin(filepath);
|
||||
stringstream buffer;
|
||||
buffer << fin.rdbuf();
|
||||
string fileContent(buffer.str());
|
||||
fin.close();
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
std::string replace(const char *pszSrc, const char *pszOld, const char *pszNew)
|
||||
{
|
||||
std::string strContent, strTemp;
|
||||
strContent.assign( pszSrc );
|
||||
std::string::size_type nPos = 0;
|
||||
while( true )
|
||||
{
|
||||
nPos = strContent.find(pszOld, nPos);
|
||||
strTemp = strContent.substr(nPos+strlen(pszOld), strContent.length());
|
||||
if ( nPos == std::string::npos )
|
||||
{
|
||||
break;
|
||||
}
|
||||
strContent.replace(nPos,strContent.length(), pszNew );
|
||||
strContent.append(strTemp);
|
||||
nPos +=strlen(pszNew) - strlen(pszOld)+1; //防止重复替换 避免死循环
|
||||
}
|
||||
return strContent;
|
||||
}
|
||||
|
||||
}
|
52
sop-sdk/sdk-c++/common/tool.h
Normal file
52
sop-sdk/sdk-c++/common/tool.h
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
|
||||
#ifndef SDK_CXX_TOOL_H
|
||||
#define SDK_CXX_TOOL_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace tool {
|
||||
|
||||
bool endWith(const string &str, const string &tail);
|
||||
|
||||
bool startWith(const string &str, const string &head);
|
||||
|
||||
string getTime();
|
||||
|
||||
int parse_url(char *url, char **serverstrp, int *portp, char **pathstrp);
|
||||
|
||||
std::string url_encode(const std::string &szToEncode);
|
||||
|
||||
std::string url_decode(const std::string &SRC);
|
||||
|
||||
unsigned char ToHex(unsigned char x);
|
||||
|
||||
unsigned char FromHex(unsigned char x);
|
||||
|
||||
string mapToJson(std::map<string, string> m);
|
||||
|
||||
string getFilename(string filepath);
|
||||
|
||||
string getFileContent(string filepath);
|
||||
|
||||
|
||||
/**
|
||||
* 函数:
|
||||
* replace(替换字符串)
|
||||
* 参数:
|
||||
* pszSrc:源字符串
|
||||
* pszOld:需要替换的字符串
|
||||
* pszNew:新字符串
|
||||
* 返回值:
|
||||
* 返回替换后的字符串
|
||||
* 备注:
|
||||
* 需要添加#include <string>头文件
|
||||
* ssdwujianhua 2017/08/30
|
||||
*/
|
||||
std::string replace(const char *pszSrc, const char *pszOld, const char *pszNew);
|
||||
}
|
||||
|
||||
#endif //SDK_CXX_TOOL_H
|
Reference in New Issue
Block a user